araina1995
araina1995

Reputation: 31

How to encrypt a string using AES-256 in flutter so that it decrypts on the web using openSSL

I tried encrypting a string in dart using encrypt library and It works pretty well other than the fact that when I try the generated encrypted string and the key and iv in an online AES decryptor, It never decrypts successfully. I want to send encrypted data to a server and then that data needs to be decrypted on the server as well as the mobile device and I couldn't find any solution for this My server is using PHP with OpenSSL, and I couldn't find any library for openSSl in flutter except this one but it has 0 documentation.

This is the sample code I used

Attempt 1:

final plainText = 'My Phone number is: 1234567890';
final key = encrypt.Key.fromLength(32);
final iv = encrypt.IV.fromLength(16);
final encrypter = encrypt.Encrypter(encrypt.AES(key));

final encrypted = encrypter.encrypt(plainText, iv: iv);
final decrypted = encrypter.decrypt(encrypted, iv: iv);

print(key.base64); // prints AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=
print(iv.base64); // prints AAAAAAAAAAAAAAAAAAAAAA==
print(encrypted.base64); // prints kezgKMov5+yNJtd58OFSpzp8sNv2dwWNnFWDyf37cYk=

Attempt 2:

This time I used this gist that works using pointy castle to create the same data, but this time the IV was generated in an Array, and my server is expecting it as an int or a string.

Attempt 3:

this time I tried again using encrypt and found a medium link that encrypts data for decryption in the web using cryptoJS. this made me think, are all AES encryption libraries not compatible with each other?

final plainText = 'My Phone number is: 1234567890';
final newKey = Utils.CreateCryptoRandomString(32); // value is lh1uCZN4c8AFL2P4HudHV8B7dEBLzjxarZ09IrCf9cQ=
final encryptedAES = encryptAESCryptoJS(plainText, newKey);

Inside the encryptAESCryptoJS function, I added print statements to print the generated Salt, IV and key, Here are those:

SALT = [112, 161, 85, 133, 146, 178, 232, 83]
KEY = 0IfSLn8F33SIiWlYTyT4j7n6jnNP74xNaKTivqNeksE=
IV = QCl8fNQtg+QQYTQCINV6IA==

I can encrypt and decrypt locally easily using all the methods, but how can I add support so that the encrypted data can be decrypted on the server as well.

some of the websites I tried using to decrypt the data were

https://string-o-matic.com/aes-decrypt and https://www.devglan.com/online-tools/aes-encryption-decryption

both threw errors on adding the key, and iv on the specified fields

Any help would be much appreciated.

Upvotes: 2

Views: 15715

Answers (2)

ArmandoHackCode
ArmandoHackCode

Reputation: 389

I had the same problem, since in php the openssl_decrypt with aes-256-cbc is used to decrypt but in dart it didn't work for me, until I found a code snippet on github solutions, which served as the basis for proposing a solution to make it decode a text encrypted with php Lumen and AES openssl, I hope it will help you.

// code decrypt in PHP
 $key = '**********key secred';
 $encrypted = $request->get('encrypted');
 $payload = json_decode(base64_decode($encrypted), true);
 $iv = base64_decode($payload['iv']);
 $decrypted = openssl_decrypt($payload['value'], 'aes-256-cbc', 
 base64_decode($key), 0, $iv, '');
 $response['decrypted'] = unserialize($decrypted);
 return $this->successResponse($response);

/// code decrypt in dart
 import 'dart:convert';
 import 'package:encrypt/encrypt.dart' as enc;
 import 'dart:async';
 import 'package:php_serializer/php_serializer.dart';

 Future<String> decryptInfo(String data) async {
       var encodedKey = 'FCAcEA0HBAoRGyALBQIeCAcaDxYWEQQPBxcXH****** example';
       var decoded = base64.decode(data);
      var payload = json.decode(String.fromCharCodes(decoded));
      String encodedIv = payload["iv"]?? "";
      String value = payload["value"] ?? "";
      print(decoded);
      print(payload);
      print (encodedIv);
      final key1 = enc.Key.fromBase64(encodedKey);
      final iv = enc.IV.fromBase64(encodedIv);
     final encrypter = enc.Encrypter(enc.AES(key1, mode: enc.AESMode.cbc));
     final decrypted = encrypter.decrypt(enc.Encrypted.fromBase64(value), iv: iv);
     print(phpDeserialize(decrypted));
   return decrypted;
  } 

Upvotes: 2

gusto2
gusto2

Reputation: 12085

couldn't find any library for openSSl in flutter except this one but it has 0 documentation.

Yes, seems this is a problem. As well I consider important that someone understands basics regardless of the language implementation

I want to send encrypted data to a server and then that data needs to be decrypted on the server as well as the mobile device and I couldn't find any solution for this

That is a task of the TLS

The data needs to be stored encrypted as well so that no one working in the backend can look at the data

Just use the same encryption and decryption parameters. The problem with your code I see is it's missing some of the parameters and using defaults (defaults can differ in different libraries) or assuming you are using different parameters.

Symmetric encryption (AES specifically) needs to define:

  • key - for AES it's always 128, 192 or 256 bit (depending on the strength). Some libraries zero-pad or trim the input to match the required key length what I consider a terrible practice. Simply - a key needs to be a byte array of the specific length.

When encrypting multiple blocks of data:

  • padding - how input is padded to match the encryption block size (usually pkcs#7 padding)
  • mode of operation
  • IV - see the documentation about the mode of operation, IV must be unique and for some modes IV needs to be unpredictable (random).

SALT is used to create an encryption key from a password. So where you see any salt in use, check if you are providing a key or a password. Password can have any length and is usually user-handled (having lower entropy) and there are multiple ways how to derive a key from the password and salt.

var encrypted = encryptAESCryptoJS(plainText, "password");

See the source code, the encryptAESCryptoJS expects a password as input and then generates a salt and derives a key and IV (this is a practice from OpenSSL, but may not be compatible with other libraries).

This is a problem with some libraries, mainly when missing documentation.

Are all AES encryption libraries not compatible with each other?

AS cipher is AES cipher. You need to get the Cipher, Key, Padding, IV and the mode of operation the same for encryption and decryption regardless the programming language or platform. There are some most common defaults (AES-128, CBC mode, PKCS#7 padding, ..) but it's better to properly specify the parameters to be sure.

but this time the IV was generated in an Array, and my server is expecting it as an int or a string.

Encryption always works on top of byte arrays. You may encode a byte array as base64 or hex encoded string.

Edit: extra security measure

What I miss in this solution (in many other solutions in fact) is an authentication tag. Most of the encryption modes are malleable, the ciphertext can be changed and then the decryption would successfully decrypt to a different plaintext without detecting any problem with integrity. I consider using any HMAC necessary, but missing in many implementations.

Upvotes: 2

Related Questions