skip to Main Content

I am using dart > encrypt package in flutter.
I want to do some encryption-decryption logic in web-worker in flutter-web project. I have tried to use crypto-js package and its vanilla JS https://cdnjs.cloudflare.com/ajax/libs/crypto-js/3.1.2/rollups/aes.js.

I want to verify the results if same encryption and decryption values appear with same key.

I have gone through some solutions in stackoverflow as well but couldn’t find a suitable working which can provide me same generated values.

Following is dart code and its result:

    import 'package:encrypt/encrypt.dart';
    .
    .
    final key = Key.fromUtf8("VishnuTestKeyIsHereLongValid32Ch");
    final encrypter = Encrypter(AES(key));
    final iv = IV.fromLength(16);
    var encrypted = encrypter.encrypt("Vishnu", iv: iv);
    print(encrypted.base64); // prints 8beisXeeEE055QEPq+kumw==

I am expecting same value to be decrypted from Crypto-js. https://jsfiddle.net/vcgupta/grkexuwz/4/

//html:
 <script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/crypto-js/3.1.2/rollups/aes.js"></script>

//js:

var base64Decrypted = '8beisXeeEE055QEPq+kumw=='

var myKey = "VishnuTestKeyIsHereLongValid32Ch"
var result = CryptoJS.AES.decrypt(base64Decrypted, myKey).toString(CryptoJS.enc.Utf8)

console.log(result);

I want to same operations alternatively. Encrypt in javascript and decrypt in dart.

Can anybody help me what I am missing in above solution?

2

Answers


  1. Chosen as BEST ANSWER

    Thanks to @Topaco, his solution worked great.

    Here is an encryption-decryption solution compatible to javascript <-> dart. Hope it will be helpful for others.

    var textToDecrypt = 'Some long test here';
    
    var myKey = "VishnuTestKeyIsHereLongValid32Ch"
    var result = CryptoJS.AES.encrypt(
                     textToDecrypt, 
                     CryptoJS.enc.Utf8.parse(myKey), 
                     {
                         iv: CryptoJS.enc. Utf8.parse("".repeat(16)),
                         mode: CryptoJS.mode.CTR,
                         padding: CryptoJS.pad.Pkcs7
                     }
                 );
    var encryptedString = result.toString();
    console.log(encryptedString);
    
    result = CryptoJS.AES.decrypt(
                     encryptedString, 
                     CryptoJS.enc.Utf8.parse(myKey), 
                     {
                         iv: CryptoJS.enc. Utf8.parse("".repeat(16)),
                         mode: CryptoJS.mode.CTR,
                         padding: CryptoJS.pad.Pkcs7
                     }
                 );
    var decryptedString = result.toString(CryptoJS.enc.Utf8);
    console.log(decryptedString); 
    console.log(decryptedString == textToDecrypt);
    <script src="https://cdnjs.cloudflare.com/ajax/libs/crypto-js/4.1.1/crypto-js.min.js"></script>

    Above code encrypt and decrypt perfectly in JS. Below code for same purpose in dart:

     var textToDecrypt = 'Some long test here';
    
        var myKey = "VishnuTestKeyIsHereLongValid32Ch";
    
        final encrypter = Encrypter(AES(Key.fromUtf8(myKey)));
        final iv = IV.fromLength(16);
        var encrypted = encrypter.encrypt(textToDecrypt, iv: iv);
        var encryptedString = encrypted.base64;
        print(encryptedString);
    
        var decrypted = encrypter.decrypt64(encryptedString, iv: iv);
        var decryptedString = decrypted.toString();
        print(decryptedString == ContentType.text);
    

    The dart code does separately encrypt and decrypts fine. Also it can be done partially in either language.


  2. Dart/encrypt uses CTR mode (aka SIC) and PKCS7 padding by default (i.e. the padding is not implicitly disabled for stream cipher modes). Since you do not specify a mode in the CryptoJS code, the default mode is applied, i.e. CBC (s. here). Thus both codes are incompatible.

    Also, in the CryptoJS code, the key must be passed as WordArray (if it is passed as string, a built-in key derivation is used). Additionally, the IV must be passed explicitly (as WordArray). In the Dart code a zero IV (16 0x00 values) is applied.

    Furthermore, you should use a newer version of CryptoJS (you are running 3.1.2, the current version is 4.1.1).

    Overall, decryption with CryptoJS is:

    var base64Decrypted = '8beisXeeEE055QEPq+kumw=='
    var myKey = "VishnuTestKeyIsHereLongValid32Ch"
    var result = CryptoJS.AES.decrypt(
                     base64Decrypted, 
                     CryptoJS.enc.Utf8.parse(myKey), 
                     {
                         iv: CryptoJS.enc.Utf8.parse("".repeat(16)), // pass IV
                         mode: CryptoJS.mode.CTR,                      // apply CTR (aka SIC)
                         padding: CryptoJS.pad.Pkcs7                   // apply PKCS#7 (CryptoJS default)
                     }
                 );
    
    console.log(result.toString());                   // 566973686e75   // padding removed
    console.log(result.toString(CryptoJS.enc.Utf8));  // Vishnu         // Utf-8 decoded
    <script src="https://cdnjs.cloudflare.com/ajax/libs/crypto-js/4.1.1/crypto-js.min.js"></script>

    Keep in mind that a static IV (like a zero IV) is a vulnerability. Instead, a random IV should be used for each encryption, which is passed along with the ciphertext to the decrypting side, usually concatenated (the IV is not secret).


    Edit: Because of the bug mentioned in the comment: Test for plaintexts longer than 1 block (16 bytes):

    var base64Decrypted = '87a0+WiecyRYz2l3zpRKsWHZyfUbnZ5Ar3nzYokfuD3zN7iV0M2TefRJe4pr4hh+' // from Dart
    var myKey = 'VishnuTestKeyIsHereLongValid32Ch'
    var result = CryptoJS.AES.decrypt(
                     base64Decrypted, 
                     CryptoJS.enc.Utf8.parse(myKey), 
                     {
                         iv: CryptoJS.enc.Utf8.parse(''.repeat(16)), // pass IV
                         mode: CryptoJS.mode.CTR,                      // apply CTR (aka SIC)
                         padding: CryptoJS.pad.Pkcs7                   // apply PKCS#7 (CryptoJS default)
                     }
                 );
    
    console.log(result.toString());                   // 566973686e75   // padding removed
    console.log(result.toString(CryptoJS.enc.Utf8));  // Vishnu         // Utf-8 decoded
    <script src="https://cdnjs.cloudflare.com/ajax/libs/crypto-js/4.1.1/crypto-js.min.js"></script>
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search