Encryption in Java and Decryption in Flutter (AES-256)

746

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.

Share:
746
Shrey Jain
Author by

Shrey Jain

Updated on November 27, 2022

Comments

  • Shrey Jain
    Shrey Jain over 1 year

    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
    
    • Samson Ayalew
      Samson Ayalew about 2 years
      Which package did you use for the Flutter code?
    • Shrey Jain
      Shrey Jain almost 2 years
      Hi @SamsonAyalew I used pointycastle for the implementation.
  • Shrey Jain
    Shrey Jain almost 3 years
    I cannot thank you enough for this problem solved. But still I don't get why salt = ciphertextlist.sublist(0, 20); and other values like iv = ciphertextlist.sublist(20, 36); and encrypted = ciphertextlist.sublist(36); keys whereas in java salt was 20?
  • Topaco
    Topaco almost 3 years
    @ShreyJain - ciphertextlist corresponds to the byte array buffer in the Java code and contains salt, IV and ciphertext in that order. sublist(start[, end]) returns the fraction from start inclusive to end exclusive. The size of the salt is defined at the beginning of the Java code to 20 bytes. The size of the IV is equal to the block size (16 bytes for AES). This results in the limits 0/20 for the salt, 20/20+16 for the IV and 20+16 for the ciphertext.
  • yong ho
    yong ho almost 2 years
    I want to encrypt in Futter and decrypt in Java. Can you give me a example?
  • Topaco
    Topaco almost 2 years
    @yongho - Please check what is on topic for SO and if appropriate ask a new question with all the information needed to answer it. Thx.