AES 256 on the client side (JS) and in the server (PHP)

前端 未结 1 1320
醉话见心
醉话见心 2021-01-13 02:41

I\'m trying to encrypt and decrypt data on the server side and the client using the same type of operation, which is AES-256.

On the server I use PHP and client I us

相关标签:
1条回答
  • 2021-01-13 03:08

    Your code looks fine apart from a padding mismatch. CryptoJS uses PKCS#5/PKCS#7 padding by default whereas MCrypt only supports ZeroPadding.

    If you're only sending textual plaintexts, then you can safely use

    CryptoJS.AES.encrypt("Message", key, { iv: iv, padding: CryptoJS.pad.ZeroPadding });
    

    If not, then you should use proper pkcs7unpad in PHP:

    $plaintext = pkcs7unpad( mcrypt_decrypt( MCRYPT_RIJNDAEL_128, $key, $encrypted, MCRYPT_MODE_CBC, $iv ), 16 );
    

    Other problems with your code are that you directly use CryptoJS.AES.encrypt(...).toString(). This will create an OpenSSL formatted string which is not purely the ciphertext. You need to use

    CryptoJS.AES.encrypt(...).ciphertext.toString(CryptoJS.enc.Base64);
    

    to also be sure about the encoding.


    Right now, this is only obfuscation, since you're sending the key along with the ciphertext. I suspect that you want to derive the key in PHP too. If yes, then you will only need to send the random salt along with the ciphertext under the assumption that the server knows the password.

    PHP provides a PBKDF2 implementation from version 5.5 onwards.


    Full JavaScript part without PBKDF2 involvement:

    var message = 'My string - Could also be an JS array/object';
    var iv = 'a1a2a3a4a5a6a7a8b1b2b3b4b5b6b7b8';
    var key = 'c1c2c3c4c5c6c7c8d1d2d3d4d5d6d7d8c1c2c3c4c5c6c7c8d1d2d3d4d5d6d7d8'; // 256-bit hex encoded
    
    var keyBytes = CryptoJS.enc.Hex.parse(key);
    var ivBytes = CryptoJS.enc.Hex.parse(iv);
    
    var encrypt = CryptoJS.AES.encrypt(message, keyBytes, {
        iv: ivBytes, 
        padding: CryptoJS.pad.ZeroPadding 
    }).ciphertext.toString(CryptoJS.enc.Base64);
    

    produces:

    j86KHBVRsDGKUnOiYdkEotsFL/lY/1tzz/h3Ay+vlEX11fC055m7vaF6q7w13eUj

    Full PHP part without PBKDF2 involvement:

    <?php
    
    $iv = 'a1a2a3a4a5a6a7a8b1b2b3b4b5b6b7b8';
    $key = 'c1c2c3c4c5c6c7c8d1d2d3d4d5d6d7d8c1c2c3c4c5c6c7c8d1d2d3d4d5d6d7d8';
    $ct = 'j86KHBVRsDGKUnOiYdkEotsFL/lY/1tzz/h3Ay+vlEX11fC055m7vaF6q7w13eUj';
    
    $ivBytes = hex2bin($iv);
    $keyBytes = hex2bin($key);
    $ctBytes = base64_decode($ct);
    
    $decrypt = rtrim(mcrypt_decrypt(MCRYPT_RIJNDAEL_128, $keyBytes, $ctBytes, MCRYPT_MODE_CBC, $ivBytes));
    
    echo $decrypt;
    

    produces:

    My string - Could also be an JS array/object

    The same is possible with the OpenSSL extension:

    <?php
    $iv = 'a1a2a3a4a5a6a7a8b1b2b3b4b5b6b7b8';
    $key = 'c1c2c3c4c5c6c7c8d1d2d3d4d5d6d7d8c1c2c3c4c5c6c7c8d1d2d3d4d5d6d7d8';
    $ct = 'j86KHBVRsDGKUnOiYdkEotsFL/lY/1tzz/h3Ay+vlEX11fC055m7vaF6q7w13eUj';
    
    $ivBytes = hex2bin($iv);
    $keyBytes = hex2bin($key);
    $ctBytes = base64_decode($ct);
    
    $decrypt = openssl_decrypt($ctBytes, "aes-256-cbc", $keyBytes, OPENSSL_RAW_DATA | OPENSSL_ZERO_PADDING, $ivBytes);
    echo($decrypt);
    
    0 讨论(0)
提交回复
热议问题