I used sample code provided on this site by user. I need to encrypt password and store in file for future use. When user try to use system, I fetch password from file, decrypt it and use it for further processing. So I can't use different key during each encryption/decryption request. So I use fixed byte[] to store key instead of calling KeyGenerator.generateKey(). Below is full code.
public class App
{
static byte[] seckey=null;
static
{
try
{
KeyGenerator kgen = KeyGenerator.getInstance("AES");
kgen.init(128);
// Generate the secret key specs.
// SecretKey skey = kgen.generateKey();
// seckey = skey.getEncoded();
// above won't work as can't generate new secret key for decrypt. Have to use same key for encrypt and decrypt
// seckey = new byte[]{0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f};
seckey = new byte[]{(byte)172,(byte)236,(byte)125,(byte)222,(byte)188,(byte)33,(byte)210,(byte)4,(byte)202,(byte)31,(byte)188,(byte)152,(byte)220,(byte)104,(byte)62,(byte)64};
} catch (NoSuchAlgorithmException e)
{
e.printStackTrace();
}
}
public static void main( String[] args )
{
String password = encrypt("A123456"); //working
System.out.println(password);
System.out.println(decrypt(password));
String password = encrypt("A*501717"); //NOT working
System.out.println(password);
System.out.println(decrypt(password));
}
public static String encrypt(String passwd)
{
SecretKeySpec key = new SecretKeySpec(seckey, "AES");
byte[] output;
try
{
Cipher cipher = Cipher.getInstance("AES");
// encryption pass
cipher.init(Cipher.ENCRYPT_MODE, key);
output = cipher.doFinal(passwd.getBytes());
} catch (Exception e)
{
System.out.println("Unable to encrypt password.");
output = "".getBytes();
}
return new String(output);
}
public static String decrypt(String passwd)
{
if (!StringUtils.isNotBlank(passwd))
return "";
SecretKeySpec key = new SecretKeySpec(seckey, "AES");
byte[] output;
try
{
Cipher cipher = Cipher.getInstance("AES");
// decryption pass
cipher.init(Cipher.DECRYPT_MODE, key);
output = cipher.doFinal(passwd.getBytes());
} catch (Exception e)
{
System.out.println("Unable to decrypt password");
output = "".getBytes();
}
return new String(output);
}
}
The issue is, it works for most of the time but for certain character sequence it is faling to decrypt. e.g. presently not working for A123456. Then I changed secret key to below
seckey = new byte[]{0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f};
after that it worked for A123456 but then failed for A*3qwe (which worked with earlier secret key. So I am totally not able to understand why is it not working for only some data?
Could someone help me please where am I doing wrong?
I resolved this issue by using Base64Encoder. Basically encrypted data can have some characters not possible to store in normal txt file and so decryption will fail. So I used Base64Encoder to encode encrypted string. This encoded characters are normal ascii characters and can be easily stored in txt file. Reverse thing is required to get original data i.e. first decode and then decrypt the string stored in file.
Related
I'm currently trying to implement file decryption on my Android app.
The file will be encrypted on host(Linux) using something like :
openssl aes-128-ecb -salt -k $HASH -in somefile.in -out somefile
openssl aes-256-cbc -salt -K $HASH -iv $IV -md sha1 -in somefile.in -out somefile
openssl aes-256-cbc -d -salt -K $HASH -md sha1 -in somefile.in -out somefile
The problem is that, I CANNOT get any of these combinations(128/256, ecb/cbc, salt/nosalt, -K/-k, -md/none) to properly decrypt on Android.
It either decrypts completely wrong(corrupted), or throws an exception.
Exception at decryptAES
java.io.IOException: Error while finalizing cipher
at javax.crypto.CipherInputStream.fillBuffer(CipherInputStream.java:104)
at javax.crypto.CipherInputStream.read(CipherInputStream.java:155)
at java.io.InputStream.read(InputStream.java:162)
at com.temp.temp.CryptographyHelper.decryptAES(CryptographyHelper.java:58)
at com.temp.temp.MainActivity.__prepFirstLaunch(MainActivity.java:229)
at com.temp.temp.MainActivity.prepFirstLaunch(MainActivity.java:192)
at com.temp.temp.MainActivity$prepthread.run(MainActivity.java:42)
Caused by: javax.crypto.BadPaddingException: EVP_CipherFinal_ex
at com.android.org.conscrypt.NativeCrypto.EVP_CipherFinal_ex(Native Method)
at com.android.org.conscrypt.OpenSSLCipher.doFinalInternal(OpenSSLCipher.java:430)
at com.android.org.conscrypt.OpenSSLCipher.engineDoFinal(OpenSSLCipher.java:490)
at javax.crypto.Cipher.doFinal(Cipher.java:1314)
at javax.crypto.CipherInputStream.fillBuffer(CipherInputStream.java:102)
... 6 more
Here's the current Java code(which is not working) on my Android app.
public static InputStream decryptAES(Context context) {
InputStream ris = null;
try {
InputStream fis = context.getAssets().open("somefile");
FileOutputStream baos = new FileOutputStream("/sdcard/decrypted");
String hash = "SOMEHASH";
String ivs = "SOMEIV";
IvParameterSpec iv = new IvParameterSpec(ivs.getBytes("UTF-8"));
SecretKeySpec sks = new SecretKeySpec(hash.getBytes("UTF-8"), "AES");
// None of these work
Cipher cipher = Cipher.getInstance("AES");
//Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding");
//Cipher cipher = Cipher.getInstance("AES/ECB/ZeroBytePadding");
//Cipher cipher = Cipher.getInstance("AES/CBC/ZeroBytePadding");
//Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
cipher.init(Cipher.DECRYPT_MODE, sks);
//cipher.init(Cipher.DECRYPT_MODE, sks, iv);
CipherInputStream cis = new CipherInputStream(fis, cipher);
int b;
byte[] d = new byte[1024 * 32];
while ((b = cis.read(d)) != -1) {
baos.write(d, 0, b);
}
baos.flush();
baos.close();
cis.close();
} catch (Exception e) {
// Meh
}
return ris;
}
I don't care which encryption method(128/256, salt/nosalt, ecb/cbc) I end up with as nothing critical happens if it gets cracked.
Can anyone suggest me how to tweak the code
or a new code with new openssl command combination?
TL;DR - I need an Android Java code that can decrypt a file that is encrypted on Linux via openssl command.
If I encrypt a file like this using openssl:
> echo "Some test" > test.txt
> openssl aes-128-cbc -K "000102030405060708090A0B0C0D0E0F" -iv "77665544332211000011223344556677" -in test.txt -out test.enc
I can decrypt it like this in java:
public static void main(String[] args) {
try {
byte[] keyBytes = {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F};
byte[] ivBytes = {0x77, 0x66, 0x55, 0x44, 0x33, 0x22, 0x11, 0x00, 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77};
SecretKeySpec sks = new SecretKeySpec(keyBytes, "AES");
IvParameterSpec iv = new IvParameterSpec(ivBytes);
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
cipher.init(Cipher.DECRYPT_MODE, sks, iv);
// read file to byte[]
InputStream is = new FileInputStream("test.enc");
ByteArrayOutputStream baos = new ByteArrayOutputStream();
int b;
while ((b = is.read()) != -1) {
baos.write(b);
}
byte[] fileBytes = baos.toByteArray();
byte[] decrypted = cipher.doFinal(fileBytes);
System.out.println(new String(decrypted));
} catch (Exception e) {
e.printStackTrace();
}
}
Result:
Some test
I can't get a basic AES encryption/decryption round-tripping unit test to pass on Android. Probably something I'm doing, but would greatly appreciate the guidance:
public class EncryptionManager {
private static final byte[] keyBytes = new byte[] { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17 };
private static final byte[] ivBytes = new byte[] { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f };
public byte[] encrypt(byte[] plaintext) throws Exception {
Cipher cipher = getCipher(true);
return cipher.doFinal(plaintext);
}
public byte[] decrypt(byte [] ciphertext) throws Exception {
Cipher cipher = getCipher(false);
return cipher.doFinal(ciphertext);
}
private static Cipher getCipher(boolean encrypt) throws Exception {
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
SecretKeySpec secretKeySpec = new SecretKeySpec(keyBytes, "AES");
IvParameterSpec ivParameterSpec = new IvParameterSpec(ivBytes);
cipher.init(encrypt ? Cipher.ENCRYPT_MODE : Cipher.DECRYPT_MODE,
secretKeySpec, ivParameterSpec);
return cipher;
}
}
The failing unit test looks like this:
public class EncryptionManagerTest extends TestCase {
public void testShouldPbeRoundtrip() throws Exception {
String unencryptedStr = "foobargum";
byte[] unencrypted = unencryptedStr.getBytes();
EncryptionManager encryptionManager = new EncryptionManager();
byte[] encrypted = encryptionManager.encrypt(unencrypted);
String encryptedStr = new String(encrypted);
byte[] decrypted = encryptionManager.decrypt(encrypted);
String decryptedStr = new String(encrypted);
// assert
assertFalse("encryption not done",
unencryptedStr.equalsIgnoreCase(encryptedStr));
assertEquals("decryption didn't work", unencryptedStr,
decryptedStr);
}
}
Error: "decryption didn't work expected:<[foobargum]> but was:<[�3���jw� �|*�]>"
String encryptedStr = new String(encrypted); is a mistake. Encryption produces byte sequences that are not likely to be a valid String for a given charset, in particular not for the UTF-8 charset that is the android default. In converting the byte array encrypted to a String object invalid byte sequences are silently replaced with valid characters in an unrecoverable manner.
I think you have a copy-paste error:
String decryptedStr = new String(encrypted);
Quick one that's thus far been evading me (long night). I'm comparing AES256 in PHP vs Java and noticing discrepancies. Please for simplicity ignore the ascii key and the null IV, those will be replaced in production. But I need to get past this first and can't figure out where I am erring:
PHP:
echo base64_encode(
mcrypt_encrypt(
MCRYPT_RIJNDAEL_128,
"1234567890ABCDEF1234567890ABCDEF",
"This is a test",
MCRYPT_MODE_CBC,
"\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
)
);
Java
byte[] key = "1234567890ABCDEF1234567890ABCDEF".getBytes("UTF-8");
byte[] iv = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
AlgorithmParameterSpec ivSpec = new IvParameterSpec(iv);
SecretKeySpec newKey = new SecretKeySpec(key, "AES");
Cipher cipher = Cipher.getInstance("AES");
cipher.init(Cipher.ENCRYPT_MODE, newKey, ivSpec);
byte[] results = cipher.doFinal("This is a test".getBytes("UTF-8"));
return Base64.encodeToString(results,Base64.DEFAULT);
PHP output: 0KwK+eubMErzDaPU1+mwTQ==
Java output: DEKGJDo3JPtk48tPgCVN3Q==
Not quite what I was expecting o_O !
I've also tried MCRYPT_MODE_CBC, MCRYPT_MODE_CFB, MCRYPT_MODE_ECB, MCRYPT_MODE_NOFB, etc.. none of them produced the Java string.
PHP pads the input bytes with \0 to make it a multiple of the block size. The equivalent in Java would be this (assuming the string you want to encrypt is in data):
Cipher cipher = Cipher.getInstance("AES/CBC/NoPadding");
int blockSize = cipher.getBlockSize();
byte[] inputBytes = data.getBytes();
int byteLength = inputBytes.length;
if (byteLength % blockSize != 0) {
byteLength = byteLength + (blockSize - (byteLength % blockSize));
}
byte[] paddedBytes = new byte[byteLength];
System.arraycopy(inputBytes, 0, paddedBytes, 0, inputBytes.length);
cipher.init(Cipher.ENCRYPT_MODE, newKey, ivSpec);
byte[] results = cipher.doFinal(paddedBytes);
As a warning to this - zero-based padding is not desired. There's no way to determine the difference between \0 characters at the end of your string, and the actual padding. It's better to use PKCS5Padding instead, but you will get different results in PHP. Ask yourself if you NEED the encryption cross-platform like this.
This is my basic symmetric encryption program. As im learning now I want to know how this is working. And I have the following Exception:
Exception in thread "main" java.security.InvalidKeyException: Illegal
key size or default parameters at javax.crypto.Cipher.a(DashoA13*..)
at javax.crypto.Cipher.init(DashoA13*..) at
javax.crypto.Cipher.init(DashoA13*..) at
sample.MainClass.main(MainClass.java:24)
This is my program:
public class MainClass {
public static void main(String[] args) throws Exception {
Security.addProvider(new org.bouncycastle.jce.provider.BouncyCastleProvider());
byte[] input = " www.java2s.com ".getBytes();
byte[] keyBytes = new byte[] { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09,
0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17 };
SecretKeySpec key = new SecretKeySpec(keyBytes, "AES");
Cipher cipher = Cipher.getInstance("AES/ECB/NoPadding", "BC");
System.out.println("input text : " + new String(input));
// encryption pass
byte[] cipherText = new byte[input.length];
cipher.init(Cipher.ENCRYPT_MODE, key);
int ctLength = cipher.update(input, 0, input.length, cipherText, 0);
ctLength += cipher.doFinal(cipherText, ctLength);
System.out.println("cipher text: " + new String(cipherText) + " bytes: " + ctLength);
// decryption pass
byte[] plainText = new byte[ctLength];
cipher.init(Cipher.DECRYPT_MODE, key);
int ptLength = cipher.update(cipherText, 0, ctLength, plainText, 0);
ptLength += cipher.doFinal(plainText, ptLength);
System.out.println("plain text : " + new String(plainText) + " bytes: " + ptLength);
}
}
Can you please tell me how to solve this problem?
This does indeed seem like a duplicate of Java Security: Illegal key size or default parameters? . You probably need to replace your local_policy.jar and US_export_policy.jar with the Unlimited Security versions. You can download them here: http://www.oracle.com/technetwork/java/javase/downloads/jce-6-download-429243.html
These files should be in your jre/lib/security/ folder. Also, for me I had a ton of different JREs in different locations, and the one I was using was inside my jdk folder path. It took me the longest time to figure this crap out
I'm trying to create an application for Android that uses encryption to save user information and I cannot figure out what I'm doing wrong. I'm trying to create an instance of an AES cipher but the application keeps on throwing "InvalidKeyExceptions." Consider the following code:
public static final byte[] IV = new byte[]
{ 0x04, 0x08, 0x15, 0x16, 0x23, 0x42, 0x00, 0x00, 0x00, 0x00,0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f};
protected final IvParameterSpec params = new IvParameterSpec(IV);
protected Cipher myCipher;
public AESEncryptor(String passwd, InputStream source, String destinationFile)
{
try
{
myCipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
Log.d("System.out.println", "Block Size: "+myCipher.getBlockSize());
myCipher.init(Cipher.ENCRYPT_MODE, AESEncryptor.generateSecretKeyFromPassword(passwd),params);
}
catch (Exception e)
{
e.printStackTrace();
}
}
I get this exception:
java.security.InvalidKeyException:
initialisation vector must be the same
length as block size..
The myCipher.init(...) line triggers this exception.
I understand what it's saying but according to myCipher.getBlockSize() the IV byte array should hold 16 bytes, and it does, but it doesn't work. I have also tried byte arrays of length 0-128, and nothing in that range works either.
Oh also, if I take this code, unaltered, and add it to a regular Java application, I get no errors. Compiling for Android seems to be causing this error.
Please help.
Thanks,
Ryan
Have you tried specifying explicitly the block size in your mode parameter?
Ex:
Cipher.getInstance("AES/CBC16/PKCS5Padding");
I noticed here that if you don't specify the block size then it is provider dependent.