AES-256-CBC encryption algorithm in react-native

Viewed 55

Hi am trying to check the compatability of encryption done on BE.

BE provided the below code `

$secret_key = VALUE1`;
$secret_iv = VALUE2;
$encrypt_method = "AES-256-CBC";
$key = hash('sha256', $secret_key);
$iv = substr(hash('sha256', $secret_iv), 0, 16);
openssl_encrypt($string, $encrypt_method, $key, 0, $iv)`

the openssl gave SNtvZ3Dpv1S88Ha6aVBdcg== when input string is abc

I tried few alogritham but I wasnt able to correctly match it with BE

he $key and $iv value I generated same as BE. but when it comes to encryption it doesnt give any result or saying Expected IV length is 16 but got 8

The following are the packages I tried

  1. import Aes from 'react-native-aes-crypto';
  Aes.encrypt(inputText, hash, _IV, 'aes-256-cbc').then(cipher => {
  console.log('cipher', cipher); });

This throws an error Error: expected IV length of 16 but was 8 I checked the length of _IV and it is certanly 16

  1. import CryptoAesCbc from 'react-native-crypto-aes-cbc';
  CryptoAesCbc.encryptInBase64(
              base64.encode(ivHash.substr(0, 16)),
              base64.encode(hash),
              'abc',
              '128',
              )
             
              .then(encryptString => {   
                console.log('encryptString', encryptString);
               })
              .catch(error => {
                console.log('error  ', error);
              });

This the encryptString value prints empty string

Please someone give me some insight into this.

FYI am checking in Android for the time being

EDIT 1

I red in some post about converting to _IV to hex

so I did this

  Aes.encrypt(
                  inputText,
                  hash,
                  Buffer.from(_IV).toString('hex'),
                  'aes-256-cbc',
                )
                  .then(cipherText => console.log('cipherText', cipherText))
                  .catch(error => console.log('error here', error));

It gave me wrong out out cipherText: yLvY847qCMHHGHdachjKGw==

Any help is appreciated

Thanks in advance

1 Answers

In the hash() function of the PHP code, the third parameter is false by default, so $key and $iv are returned as hex encoded strings and not as raw binary data.
For SHA256 with a digest output length of 32 bytes $key therefore has a length of 64 bytes, since $key is not explicitly truncated, unlike $iv.
Nevertheless, only the first 32 bytes of the 64 bytes are used for encryption, because OpenSSL/PHP silently truncates keys that are too large (and pads keys that are too short with 0x00 values) to achieve the specified length (32 bytes for AES-256-CBC).
On the CryptoJS side, both the hex encoding of key and IV must be taken into account as well as the truncation of the key.

A possible implementation with CryptoJS (referring to your solution in the chat) is:

var plaintext = "The quick brown fox";
var keyMaterial = "my key passphrase";
var ivMaterial = "my IV passphrase"

var truncHexKey = CryptoJS.SHA256(keyMaterial).toString().substr(0, 32); // hex encode and truncate
var truncHexIV = CryptoJS.SHA256(ivMaterial).toString().substr(0, 16); // hex encode and truncate 
var key = CryptoJS.enc.Utf8.parse(truncHexKey); 
var iv = CryptoJS.enc.Utf8.parse(truncHexIV); 
var ciphertext = CryptoJS.AES.encrypt(plaintext, key, {iv: iv}); // default values: CBC, PKCS#7 padding

console.log('Ciphertext: ' + ciphertext.toString());
<script src="https://cdnjs.cloudflare.com/ajax/libs/crypto-js/4.0.0/crypto-js.min.js"></script>

which gives the same ciphertext as the PHP code.

In general, it should also be noted that the use of upper and lower case letters is not consistently implemented in hex encoding. However, like PHP's hash() function, CryptoJS uses lowercase letters, so this is not a problem here.

Related