I am trying to implement encryption in my code, I'm using java as a backend and dart for the mobile application but I'm unable to decrypt code in flutter.
This is the java code for encryption this java code is taken from this blog.
public void encrypt(String item) throws Exception {
byte[] ivBytes;
String password="Hello";
/*you can give whatever you want for password. This is for testing purpose*/
SecureRandom random = new SecureRandom();
byte bytes[] = new byte[20];
random.nextBytes(bytes);
byte[] saltBytes = bytes;
// Derive the key
SecretKeyFactory factory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA1");
PBEKeySpec spec = new PBEKeySpec(password.toCharArray(),saltBytes,65556,256);
SecretKey secretKey = factory.generateSecret(spec);
SecretKeySpec secret = new SecretKeySpec(secretKey.getEncoded(), "AES");
System.out.println("saltBytes : " + saltBytes);
//encrypting the word
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
cipher.init(Cipher.ENCRYPT_MODE, secret);
AlgorithmParameters params = cipher.getParameters();
ivBytes = params.getParameterSpec(IvParameterSpec.class).getIV();
System.out.println("ivBytes : " + ivBytes);
byte[] encryptedTextBytes = cipher.doFinal(item.getBytes("UTF-8"));
//prepend salt and vi
byte[] buffer = new byte[saltBytes.length + ivBytes.length + encryptedTextBytes.length];
System.arraycopy(saltBytes, 0, buffer, 0, saltBytes.length);
System.arraycopy(ivBytes, 0, buffer, saltBytes.length, ivBytes.length);
System.arraycopy(encryptedTextBytes, 0, buffer, saltBytes.length + ivBytes.length, encryptedTextBytes.length);
String val = new Base64().encodeToString(buffer);
System.out.println(val);
}
Now in dart I have used multiple plugins but not able to decrypt code in dart.
For dart decryption I have taken code from this stackoverflow discussion.
Dart implementation is something like this
static Uint8List decrypt(String ciphertext,) {
Uint8List ciphertextlist = base64.decode(ciphertext);
print('ciphertextlist => $ciphertextlist');
Uint8List key = generateKey("Hello");
print('key => $key');
CBCBlockCipher cipher = new CBCBlockCipher(new AESFastEngine());
int iv = cipher.blockSize;
Uint8List ivIntList = Uint8List.fromList(iv.toString().codeUnits);
ParametersWithIV<KeyParameter> params =
new ParametersWithIV<KeyParameter>(new KeyParameter(key), ivIntList);
PaddedBlockCipherParameters<ParametersWithIV<KeyParameter>, Null>
paddingParams =
new PaddedBlockCipherParameters<ParametersWithIV<KeyParameter>, Null>(
params, null);
PaddedBlockCipherImpl paddingCipher =
new PaddedBlockCipherImpl(new PKCS7Padding(), cipher);
paddingCipher.init(false, paddingParams);
var val = paddingCipher.process(ciphertextlist);
print('val => $val');}
static Uint8List generateKey(String passphrase) {
Uint8List passphraseInt8List = Uint8List.fromList(passphrase.codeUnits);
Uint8List salt = Uint8List.fromList('20'.codeUnits);
KeyDerivator derivator = PBKDF2KeyDerivator(HMac(SHA1Digest(), 16));
Pbkdf2Parameters params = Pbkdf2Parameters(salt, 65556, 256);
derivator.init(params);
return derivator.process(passphraseInt8List);
After running the code I'm getting this error.
Invalid argument(s): Initialization vector must be the same length as block size
The Dart code lacks the separation of salt, IV and ciphertext. Add in decrypt()
:
var salt = ciphertextlist.sublist(0, 20);
var iv = ciphertextlist.sublist(20, 20 + 16);
var encrypted = ciphertextlist.sublist(20 + 16);
The salt must be passed to generateKey()
and used there to derive the key, iv and ciphertext are applied as follows:
Uint8List key = generateKey("Hello", salt);
...
//int iv = cipher.blockSize;
//Uint8List ivIntList = Uint8List.fromList(iv.toString().codeUnits);
ParametersWithIV<KeyParameter> params = new ParametersWithIV<KeyParameter>(new KeyParameter(key), iv);
...
var val = paddingCipher.process(encrypted);
...
String decrypted = new String.fromCharCodes(val);
print(decrypted);
generateKey()
must take the passed salt into account, also digest block size and key size are not correct, so the following changes are necessary:
static Uint8List generateKey(String passphrase, Uint8List salt) { // pass salt
Uint8List passphraseInt8List = Uint8List.fromList(passphrase.codeUnits);
//Uint8List salt = Uint8List.fromList('20'.codeUnits);
KeyDerivator derivator = PBKDF2KeyDerivator(HMac(SHA1Digest(), 64)); // 64 byte block size
Pbkdf2Parameters params = Pbkdf2Parameters(salt, 65556, 32); // 32 byte key size
derivator.init(params);
return derivator.process(passphraseInt8List);
}
With these changes, decryption works on my machine.