encrypt icon indicating copy to clipboard operation
encrypt copied to clipboard

Compatibility with PHP5.6's openssl AES

Open TaiTair opened this issue 4 years ago • 10 comments

Hi,

I am currently trying to develop an API for a flutter-based mobile app.

I've been having some really strange issues that make me think this module does not use the same algorithms as PHP. For example: If I encrypt the word "Ping" from flutter with my secret key and my IV set to 16 0 bytes then I get: "kU1IVV86Aw7Iuub8KuxmYw=="
If I encrypt the same word from PHP5.6 with the same secret key and same IV then I get: "QdKmZQ=="
Note: I encode the encrypted result in base64.

Here's where it gets really, really strange though:

If I encrypt the word "Ping" from flutter and send it to my API, then decrypt it in PHP and log the decrypted result I get a bad string that seems to be some kind of encoding error or an empty string. But then if I re-encrypt the decrypted message with PHP's functions and send it back it is a perfect copy of the original string: "kU1IVV86Aw7Iuub8KuxmYw=="

What in the world is going on? If I encrypt it straight from PHP I get a different encrypted message but if I send it from flutter, decrypt it in PHP then re-encrypt it in PHP i get the exact same message? If I try to encrypt straight from PHP, flutter never manages to decrypt. What am I missing? It shouldn't ever manage to decrypt if the algorithms are different, right?

I'm thinking the problem might be linked to block-size. Does the Encrypt module use AES-128 or AES-256?

Any insight would be appreciated. I can run some tests if need be.

Note: I tried with several different methods, ofb, cbc, ctr. I always get the same result. PHP's encryption seems to be different from Encrypt's encryption.

TaiTair avatar Feb 11 '21 19:02 TaiTair

I got the same issue way back version 2.1.0. I found solution and add another security on top of it with the folowing.

P.S: without any loss of speed.

  1. nginx
  2. dart aqueduct
  3. php

All the encryption done in dart aqueduct server.

Dart aqueduct and php run seperate server internaly.

Used nginx as proxy and config server.

I have 2 nginx. First one is in dmz and second one behind dmz.

NTMS2017 avatar Feb 11 '21 20:02 NTMS2017

I got the same issue way back version 2.1.0. I found solution and add another security on top of it with the folowing.

P.S: without any loss of speed.

  1. nginx
  2. dart aqueduct
  3. php

All the encryption done in dart aqueduct server.

Dart aqueduct and php run seperate server internaly.

Used nginx as proxy and config server.

I have 2 nginx. First one is in dmz and second one behind dmz.

Thanks for the suggestion. Unfortunately changing the entire server architecture is not a solution for me.
I could potentially change what I use on the client(flutter) but for the server I am stuck with Apache and php5.6.
I just need encryption in flutter that is compatible with PHP5.6's Openssl AES encryption.

TaiTair avatar Feb 11 '21 21:02 TaiTair

Here's what I am doing:
The message in this context is always Ping

If I try to encrypt from Flutter and decrypt from PHP:

(Flutter)

Key _secret = Key.fromUtf8("sQ&947h26s%NbK+Y");
IV _iv = IV.fromLength(16);
Dio dio = new Dio();
Encrypter enc = Encrypter(AES(_secret, mode:AESMode.ctr));
final encrypted = enc.encrypt(msg, iv: _iv);
_response = await dio.get(
    _apiUrl,
    queryParameters: {"message": Uri.encodeComponent(encrypted.base64)}
);

This sends 3EdwOMMQiFr8XNpNDJrA4A%3D%3D Note for transmission through GET I am url encoding the base64.

(PHP)

$_SESSION['iv']=hex2bin('00000000000000000000000000000000');
$cipher = 'aes-128-ctr';
$key = base64_encode("sQ&947h26s%NbK+Y");
$msg = urldecode($msg);
$output = openssl_decrypt($msg, $cipher, $key, 0, base64_encode($_SESSION['iv']));
return base64_decode($output);

Which returns QL<@?_Ò… Obviously not decrypting like the Encrypt module. Note openssl_decrypt is set to use base64 data and return base64 data directly.

Still same IV and same key on both ends. Here's what happens if I try to encrypt from php and decrypt from flutter:

(PHP)

$_SESSION['iv']=hex2bin('00000000000000000000000000000000');
$cipher = 'aes-128-ctr';
$key = "sQ&947h26s%NbK+Y";
$encrypted = openssl_encrypt($msg, $cipher, $key, OPENSSL_RAW_DATA, $_SESSION['iv']);
$output = urlencode(base64_encode($encrypted));
echo $output;

Which returns 0psP5Q%3D%3D Note for transmission I am url encoding the base64. Note openssl_encrypt is set to use raw data and return raw data directly.

(Flutter)

_iv = IV.fromLength(16);
Encrypter enc = Encrypter(AES(_secret, mode: AESMode.ctr));
final decrypted = enc.decrypt64(Uri.decodeComponent(_response.data), iv: _iv);
return decrypted;

Which errors out with this:

Unhandled Exception: Invalid argument(s): Input data length must be a multiple of cipher's block size
PaddedBlockCipherImpl.process (package:pointycastle/padded_block_cipher/padded_block_cipher_impl.dart:60:9)
E/flutter ( 4607): #1      AES.decrypt (package:encrypt/src/algorithms/aes.dart:55:22)
E/flutter ( 4607): #2      Encrypter.decryptBytes (package:encrypt/src/encrypter.dart:25:17)
E/flutter ( 4607): #3      Encrypter.decrypt (package:encrypt/src/encrypter.dart:31:17)
E/flutter ( 4607): #4      Encrypter.decrypt64 (package:encrypt/src/encrypter.dart:41:12)

@leocavalcante Could you show me how to encrypt "Ping" in flutter and decrypt it correctly on the php side? Normally openssl_encrypt uses PKCS7 like the Encrypt module. Feels like I'm missing something trivial.

TaiTair avatar Feb 12 '21 21:02 TaiTair

@TaiTair I did a quick search for "php" in the repository issues. See if one of these gives you some clues:

  • https://github.com/leocavalcante/encrypt/issues/42#issuecomment-495820762
  • https://github.com/leocavalcante/encrypt/issues/69#issuecomment-526865580
  • https://github.com/leocavalcante/encrypt/issues/87#issuecomment-549619391

leocavalcante avatar Feb 12 '21 22:02 leocavalcante

Thanks a lot Leo.

https://github.com/leocavalcante/encrypt/issues/87#issuecomment-549619391 seems to work in my environment.

I'm going to use what you sent me and make it work. Thanks again.

TaiTair avatar Feb 12 '21 23:02 TaiTair

Phew, I finally figured it out by breaking your code. I put in my private key and my IV and then it stopped working. So it got me thinking... and I figured it was my key length that was incorrect. Made some proper keys/ivs with php -r "echo base64_encode(openssl_random_pseudo_bytes(length));" and then used with your code everything started working. Except for one thing: CBC worked perfectly in both directions, meaning the algorithms are identical but CTR did not. Same code, same keys, only thing I changed was the algorithm and CTR did not work at all. Try it and see if you get the same result.

TaiTair avatar Feb 13 '21 00:02 TaiTair

@TaiTair Did you try setting padding: null when creating your Encrypter instance? The default is pkcs7, which does not work with (unpadded) CTR. I had the same problem when encrypting in AES-256-CTR in PHP and trying to decrypt in Flutter, but setting padding: null fixed it.

magnuswikhog avatar Mar 13 '21 15:03 magnuswikhog

@TaiTair "Does the Encrypt module use AES-128 or AES-256?"

Did you get an answer for this?

Also, what is the default iteration count?

OGmetamonkey avatar Jul 23 '21 19:07 OGmetamonkey

@TaiTair "Does the Encrypt module use AES-128 or AES-256?"

Did you get an answer for this?

Also, what is the default iteration count?

Ok, I see it uses 100 iteration count. I still don't see whether it uses s 128 or 256 bit key. Any idea?

OGmetamonkey avatar Jul 23 '21 20:07 OGmetamonkey

@TaiTair "Does the Encrypt module use AES-128 or AES-256?" Did you get an answer for this? Also, what is the default iteration count?

Ok, I see it uses 100 iteration count. I still don't see whether it uses s 128 or 256 bit key. Any idea?

Sorry for the late reply. It's 256 bits.

TaiTair avatar Aug 23 '21 16:08 TaiTair