用PHP加密字符串并在Node.js中解密

用PHP加密字符串并在Node.js中解密,第1张

用PHP加密字符串并在Node.js中解密

我本周在同一个问题上苦苦挣扎,但是却采用相反的方式(PHP加密-> NodeJS解密),并且设法使此代码段起作用:

aes256cbc.js

var crypto = require('crypto');var encrypt = function (plain_text, encryptionMethod, secret, iv) {    var encryptor = crypto.createCipheriv(encryptionMethod, secret, iv);    return encryptor.update(plain_text, 'utf8', 'base64') + encryptor.final('base64');};var decrypt = function (encryptedMessage, encryptionMethod, secret, iv) {    var decryptor = crypto.createDecipheriv(encryptionMethod, secret, iv);    return decryptor.update(encryptedMessage, 'base64', 'utf8') + decryptor.final('utf8');};var textToEncrypt = new Date().toISOString().substr(0,19) + '|My super secret information.';var encryptionMethod = 'AES-256-CBC';var secret = "My32charPasswordAndInitVectorStr"; //must be 32 char lengthvar iv = secret.substr(0,16);var encryptedMessage = encrypt(textToEncrypt, encryptionMethod, secret, iv);var decryptedMessage = decrypt(encryptedMessage, encryptionMethod, secret, iv);console.log(encryptedMessage);console.log(decryptedMessage);

aes256cbc.php

<?phpdate_default_timezone_set('UTC');$textToEncrypt = substr(date('c'),0,19) . "|My super secret information.";$encryptionMethod = "AES-256-CBC";$secret = "My32charPasswordAndInitVectorStr";  //must be 32 char length$iv = substr($secret, 0, 16);$encryptedMessage = openssl_encrypt($textToEncrypt, $encryptionMethod, $secret,0,$iv);$decryptedMessage = openssl_decrypt($encryptedMessage, $encryptionMethod, $secret,0,$iv);echo "$encryptedMessagen";echo "$decryptedMessagen";?>

避免密钥/ iv大小/解密问题下降的秘诀是秘密地拥有32个字符的长度和16个IV的长度。另外,在NodeJS中使用’base64’和’utf8’
非常 重要,因为这些是PHP中的默认设置。

以下是一些示例运行:

$ node aes256cbc.js && php aes256cbc.phpzra3FX4iyCc7qPc1dZs+G3ZQ40f5bSw8P9n5OtWl1t86nV5Qfh4zNRPFbsciyyHyU3Qi4Ga1oTiTwzrPIZQXLw==2015-01-27T18:29:12|My super secret information.zra3FX4iyCc7qPc1dZs+G3ZQ40f5bSw8P9n5OtWl1t86nV5Qfh4zNRPFbsciyyHyU3Qi4Ga1oTiTwzrPIZQXLw==2015-01-27T18:29:12|My super secret information.$ node aes256cbc.js && php aes256cbc.phpzra3FX4iyCc7qPc1dZs+G6B6+8aavHNc/Ymv9L6Omod8Di3tMbvOa2B7O2Yiyoutm9fy9l0G+P5VJT9z2qNESA==2015-01-27T18:29:15|My super secret information.zra3FX4iyCc7qPc1dZs+G6B6+8aavHNc/Ymv9L6Omod8Di3tMbvOa2B7O2Yiyoutm9fy9l0G+P5VJT9z2qNESA==2015-01-27T18:29:15|My super secret information.$ node aes256cbc.js && php aes256cbc.phpzra3FX4iyCc7qPc1dZs+G4oD1Fr5yLByON6QDE56UOqP6kkfGJzpyH6TbwZYX2oGlh2JGv+aHYUMh0qQnAj/uw==2015-01-27T18:29:29|My super secret information.zra3FX4iyCc7qPc1dZs+G4oD1Fr5yLByON6QDE56UOqP6kkfGJzpyH6TbwZYX2oGlh2JGv+aHYUMh0qQnAj/uw==2015-01-27T18:29:29|My super secret information.$ node aes256cbc.js && php aes256cbc.phpzra3FX4iyCc7qPc1dZs+G5OVCbCaUy8a0LLF+Bn8UT4X3nYbtynO0Zt2mvXnnli9dRxrxMw43uWnkh8MIwVHXA==2015-01-27T18:29:31|My super secret information.zra3FX4iyCc7qPc1dZs+G5OVCbCaUy8a0LLF+Bn8UT4X3nYbtynO0Zt2mvXnnli9dRxrxMw43uWnkh8MIwVHXA==2015-01-27T18:29:31|My super secret information.$ node aes256cbc.js && php aes256cbc.phpfdsqSyHBJjlwD0jYfOUZM2FrONG6Fk5d7FOItYEdbnaZIhhmg/apa8/jPwKFkDXD9eNqWC3w0JzY5wjtZADiBA==2015-01-27T18:30:08|My super secret information.fdsqSyHBJjlwD0jYfOUZM2FrONG6Fk5d7FOItYEdbnaZIhhmg/apa8/jPwKFkDXD9eNqWC3w0JzY5wjtZADiBA==2015-01-27T18:30:08|My super secret information.$ node aes256cbc.js && php aes256cbc.phpfdsqSyHBJjlwD0jYfOUZM4SRfi6jG5EoDFEF6d9xCIyluXSiMaKlhd89ovpeOz/YyEIlPbYR4ly00gf6hWfKHw==2015-01-27T18:30:45|My super secret information.fdsqSyHBJjlwD0jYfOUZM4SRfi6jG5EoDFEF6d9xCIyluXSiMaKlhd89ovpeOz/YyEIlPbYR4ly00gf6hWfKHw==2015-01-27T18:30:45|My super secret information.

注意:

我使用“ 时间戳 | 消息 ”格式来避免 中间人的攻击
。例如,如果加密的消息包含要验证的ID,则MitM可以捕获该消息,并在每次他想要重新验证时将其重新发送。

因此,我可以检查加密邮件上的时间戳是否在较短的时间间隔内。这样,同一条消息由于时间戳而每秒进行不同的加密,因此无法在此固定时间间隔内使用。

编辑:

在这里,我在滥用初始化向量(IV)。作为 @ArtjomB。
解释说,IV应该是加密消息的第一部分,也应该是随机值。还建议

hmac
在HTTP标头(
x-hmac:*value*
)中使用一个值,以验证消息是否源自有效来源(但这不能解决前面所述的“重新发送”消息问题)。

这是改进的版本,包括

hmac
用于php和node以及IV作为加密消息的一部分:

aes256cbc.js(v2)

var crypto = require('crypto');var encrypt = function (message, method, secret, hmac) {    //var iv = crypto.randomBytes(16).toString('hex').substr(0,16);    //use this in production    var iv = secret.substr(0,16);    //using this for testing purposes (to have the same encryption IV in PHP and Node encryptors)    var encryptor = crypto.createCipheriv(method, secret, iv);    var encrypted = new Buffer(iv).toString('base64') + encryptor.update(message, 'utf8', 'base64') + encryptor.final('base64');    hmac.value = crypto.createHmac('md5', secret).update(encrypted).digest('hex');    return encrypted;};var decrypt = function (encrypted, method, secret, hmac) {    if (crypto.createHmac('md5', secret).update(encrypted).digest('hex') == hmac.value) {        var iv = new Buffer(encrypted.substr(0, 24), 'base64').toString();        var decryptor = crypto.createDecipheriv(method, secret, iv);        return decryptor.update(encrypted.substr(24), 'base64', 'utf8') + decryptor.final('utf8');    }};var encryptWithTSValidation = function (message, method, secret, hmac) {    var messageTS = new Date().toISOString().substr(0,19) + message;    return encrypt(messageTS, method, secret, hmac);}var decryptWithTSValidation = function (encrypted, method, secret, hmac, intervalThreshold) {    var decrypted = decrypt(encrypted, method, secret, hmac);    var now = new Date();    var year = parseInt(decrypted.substr(0,4)), month = parseInt(decrypted.substr(5,2)) - 1,    day = parseInt(decrypted.substr(8,2)), hour = parseInt(decrypted.substr(11,2)),     minute = parseInt(decrypted.substr(14,2)), second = parseInt(decrypted.substr(17,2));    var msgDate = new Date(Date.UTC(year, month, day, hour, minute, second))    if (Math.round((now - msgDate) / 1000) <= intervalThreshold) {        return decrypted.substr(19);    }}var message = 'My super secret information.';var method = 'AES-256-CBC';var secret = "My32charPasswordAndInitVectorStr"; //must be 32 char lengthvar hmac = {};//var encrypted = encrypt(message, method, secret, hmac);//var decrypted = decrypt(encrypted, method, secret, hmac);var encrypted = encryptWithTSValidation(message, method, secret, hmac);var decrypted = decryptWithTSValidation(encrypted, method, secret, hmac, 60*60*12); //60*60m*12=12hconsole.log("Use HTTP header 'x-hmac: " + hmac.value + "' for validating against MitM-attacks.");console.log("Encrypted: " + encrypted);console.log("Decrypted: " + decrypted);

请注意,已将

crypto.createHmac(...).digest('hex')
消化
hex
。这是PHP中的默认设置
hmac

aes256cbc.php(v2)

<?phpfunction encrypt ($message, $method, $secret, &$hmac) {    //$iv = substr(bin2hex(openssl_random_pseudo_bytes(16)),0,16);    //use this in production    $iv = substr($secret, 0, 16);        //using this for testing purposes (to have the same encryption IV in PHP and Node encryptors)    $encrypted = base64_enpre($iv) . openssl_encrypt($message, $method, $secret, 0, $iv);    $hmac = hash_hmac('md5', $encrypted, $secret);    return $encrypted;}function decrypt ($encrypted, $method, $secret, $hmac) {    if (hash_hmac('md5', $encrypted, $secret) == $hmac) {        $iv = base64_depre(substr($encrypted, 0, 24));        return openssl_decrypt(substr($encrypted, 24), $method, $secret, 0, $iv);    }}function encryptWithTSValidation ($message, $method, $secret, &$hmac) {    date_default_timezone_set('UTC');    $message = substr(date('c'),0,19) . "$message";    return encrypt($message, $method, $secret, $hmac);}function decryptWithTSValidation ($encrypted, $method, $secret, $hmac, $intervalThreshold) {    $decrypted = decrypt($encrypted, $method, $secret, $hmac);    $now = new DateTime();    $msgDate = new DateTime(str_replace("T"," ",substr($decrypted,0,19)));    if (($now->getTimestamp() - $msgDate->getTimestamp()) <= $intervalThreshold) {        return substr($decrypted,19);    }}$message = "My super secret information.";$method = "AES-256-CBC";$secret = "My32charPasswordAndInitVectorStr";  //must be 32 char length//$encrypted = encrypt($message, $method, $secret, $hmac);//$decrypted = decrypt($encrypted, $method, $secret, $hmac);$encrypted = encryptWithTSValidation($message, $method, $secret, $hmac);$decrypted = decryptWithTSValidation($encrypted, $method, $secret, $hmac, 60*60*12); //60*60m*12=12hecho "Use HTTP header 'x-hmac: $hmac' for validating against MitM-attacks.n";echo "Encrypted: $encryptedn";echo "Decrypted: $decryptedn";?>

以下是一些示例运行:

$ node aes256cbc.js && php aes256cbc.phpUse HTTP header 'x-hmac: 6862972ef0f463bf48523fc9e334bb42' for validating against MitM-attacks.Encrypted: YjE0ZzNyMHNwVm50MGswbQ==I6cAKeoxeSP5TGgtK59PotB/iG2BUSU8Y6NhAhVabN9UB+ZCTn7q2in4JyLwQiGNDecrypted: My super secret information.Use HTTP header 'x-hmac: 6862972ef0f463bf48523fc9e334bb42' for validating against MitM-attacks.Encrypted: YjE0ZzNyMHNwVm50MGswbQ==I6cAKeoxeSP5TGgtK59PotB/iG2BUSU8Y6NhAhVabN9UB+ZCTn7q2in4JyLwQiGNDecrypted: My super secret information.$ node aes256cbc.js && php aes256cbc.phpUse HTTP header 'x-hmac: b2e63f216acde938a82142220652cf59' for validating against MitM-attacks.Encrypted: YjE0ZzNyMHNwVm50MGswbQ==YsFRdKzCLuCk7Yg+U+S1CSgYBBR8dkZytORm8xwEDmD9WB1mpqC3XnSrB+wR3/KWDecrypted: My super secret information.Use HTTP header 'x-hmac: b2e63f216acde938a82142220652cf59' for validating against MitM-attacks.Encrypted: YjE0ZzNyMHNwVm50MGswbQ==YsFRdKzCLuCk7Yg+U+S1CSgYBBR8dkZytORm8xwEDmD9WB1mpqC3XnSrB+wR3/KWDecrypted: My super secret information.$ node aes256cbc.js && php aes256cbc.phpUse HTTP header 'x-hmac: 73181744453d55eb6f81896ffd284cd8' for validating against MitM-attacks.Encrypted: YjE0ZzNyMHNwVm50MGswbQ==YsFRdKzCLuCk7Yg+U+S1CTGik4Lv9PnWuEg5SiADJcdKX1to0LrNKmuCiYIweBAZDecrypted: My super secret information.Use HTTP header 'x-hmac: 73181744453d55eb6f81896ffd284cd8' for validating against MitM-attacks.Encrypted: YjE0ZzNyMHNwVm50MGswbQ==YsFRdKzCLuCk7Yg+U+S1CTGik4Lv9PnWuEg5SiADJcdKX1to0LrNKmuCiYIweBAZDecrypted: My super secret information.$ node aes256cbc.js && php aes256cbc.phpUse HTTP header 'x-hmac: 5372ecca442d65f582866cf3b24cb2b6' for validating against MitM-attacks.Encrypted: YjE0ZzNyMHNwVm50MGswbQ==YsFRdKzCLuCk7Yg+U+S1CYEITF6aozBNp7bA54qY0Ugg9v6ktwoH6nqRyatkFqy8Decrypted: My super secret information.Use HTTP header 'x-hmac: 5372ecca442d65f582866cf3b24cb2b6' for validating against MitM-attacks.Encrypted: YjE0ZzNyMHNwVm50MGswbQ==YsFRdKzCLuCk7Yg+U+S1CYEITF6aozBNp7bA54qY0Ugg9v6ktwoH6nqRyatkFqy8Decrypted: My super secret information.

最后但并非最不重要的一点是,如果您没有在php中安装openssl mod,则可以将其

mcrypt
rijndael128
and
pkcs7
padding(source)结合使用,如下所示:

aes256cbc-mcrypt.php(v2)

<?phpfunction pkcs7pad($message) {    $padding = 16 - (strlen($message) % 16);    return $message . str_repeat(chr($padding), $padding);}function pkcs7unpad($message) {    $padding = ord(substr($message, -1));  //get last char and transform it to Int    return substr($message, 0, -$padding); //remove the last 'padding' string}function encrypt ($message, $method, $secret, &$hmac) {    //$iv = substr(bin2hex(mcrypt_create_iv(mcrypt_get_iv_size($method, MCRYPT_MODE_CBC), MCRYPT_DEV_URANDOM)),0,16);    //use this in production    $iv = substr($secret, 0, 16);    //using this for testing purposes (to have the same encryption IV in PHP and Node encryptors)    $message = pkcs7pad($message);    $encrypted = base64_enpre($iv) . base64_enpre(mcrypt_encrypt($method, $secret, $message, MCRYPT_MODE_CBC, $iv));    $hmac = hash_hmac('md5', $encrypted, $secret);    return $encrypted;}function decrypt ($encrypted, $method, $secret, $hmac) {    if (hash_hmac('md5', $encrypted, $secret) == $hmac) {        $iv = base64_depre(substr($encrypted, 0, 24));        return pkcs7unpad(mcrypt_decrypt($method, $secret , base64_depre(substr($encrypted, 24)) , MCRYPT_MODE_CBC, $iv));    }}function encryptWithTSValidation ($message, $method, $secret, &$hmac) {    date_default_timezone_set('UTC');    $message = substr(date('c'),0,19) . "$message";    return encrypt($message, $method, $secret, $hmac);}function decryptWithTSValidation ($encrypted, $method, $secret, $hmac, $intervalThreshold) {    $decrypted = decrypt($encrypted, $method, $secret, $hmac);    $now = new DateTime();    //echo "Decrypted: $decryptedn";    $msgDate = new DateTime(str_replace("T"," ",substr($decrypted,0,19)));    if (($now->getTimestamp() - $msgDate->getTimestamp()) <= $intervalThreshold) {        return substr($decrypted,19);    }}$message = "My super secret information.";$method = MCRYPT_RIJNDAEL_128;$secret = "My32charPasswordAndInitVectorStr";  //must be 32 char length//$encrypted = encrypt($message, $method, $secret, $hmac);//$decrypted = decrypt($encrypted, $method, $secret, $hmac);$encrypted = encryptWithTSValidation($message, $method, $secret, $hmac);$decrypted = decryptWithTSValidation($encrypted, $method, $secret, $hmac, 60*60*12); //60*60m*12=12hecho "Use HTTP header 'x-hmac: $hmac' for validating against MitM-attacks.n";echo "Encrypted: $encryptedn";echo "Decrypted: $decryptedn";?>

当然,接下来要进行一些测试:

$ php aes256cbc-mcrypt.php && node aes256cbc.js Use HTTP header 'x-hmac: 801282a9ed6b2d5bd2254140d7a17582' for validating against MitM-attacks.Encrypted: YjE0ZzNyMHNwVm50MGswbQ==ipQ+Yah8xoF0C6yjCJr8v9IyatyGeNT2yebrpJZ5xH73H5fFcV1zhqhRGwM0ToGUDecrypted: My super secret information.Use HTTP header 'x-hmac: 801282a9ed6b2d5bd2254140d7a17582' for validating against MitM-attacks.Encrypted: YjE0ZzNyMHNwVm50MGswbQ==ipQ+Yah8xoF0C6yjCJr8v9IyatyGeNT2yebrpJZ5xH73H5fFcV1zhqhRGwM0ToGUDecrypted: My super secret information.$ php aes256cbc-mcrypt.php && node aes256cbc.js Use HTTP header 'x-hmac: 0ab2bc83108e1e250f6ecd483cd65329' for validating against MitM-attacks.Encrypted: YjE0ZzNyMHNwVm50MGswbQ==ipQ+Yah8xoF0C6yjCJr8v79P+j4YUl8ln8eu7FDqEdbxMe1Z7BvW8iVUN1qFCiHMDecrypted: My super secret information.Use HTTP header 'x-hmac: 0ab2bc83108e1e250f6ecd483cd65329' for validating against MitM-attacks.Encrypted: YjE0ZzNyMHNwVm50MGswbQ==ipQ+Yah8xoF0C6yjCJr8v79P+j4YUl8ln8eu7FDqEdbxMe1Z7BvW8iVUN1qFCiHMDecrypted: My super secret information.


欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/zaji/5127046.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-11-17
下一篇 2022-11-17

发表评论

登录后才能评论

评论列表(0条)

保存