【问题标题】:PHP encrypted data needs to be decrypted in ReactNativePHP加密数据需要在React Native中解密
【发布时间】:2021-03-11 18:42:00
【问题描述】:

我正在使用以下 sn-p 为 PHP 中的 CBC 256 模式进行 AES 加密。

$iv_real = "ahc/2u6F0Yvww12fyQiZWA==";
$decoded_iv = base64_decode($iv_real);
$plaintext_shared_secret = "9b8a3e600073de05e5d095b5d909043e50f5047ffcd0048c01c65ca690b7b4e981e51b59641d4ffd5a140c27f25a761ab0f99e601b59c5ae3427c751bfae9331";
echo "Shared secret: {$plaintext_shared_secret}\r\n";
$aes_key = hash("sha256", "s@keypact.appa62f1bed41166b2c455d82337222723b0287d920"); 
$encrypted_shared_secret = openssl_encrypt(
    $plaintext_shared_secret, 
    "aes-256-cbc", 
    $aes_key,
    OPENSSL_ZERO_PADDING,
    $decoded_iv //Binary data
);
//Base64 encoded, encryped shared secret
echo "\r\nEncrypted, base64_encoded, shared secret\r\n";
var_dump($encrypted_shared_secret);

我得到的加密响应与我在 React Native 中得到的响应相差甚远。我需要在 ReactNative 中解密相同的数据。我试过了

  1. React-native-simple-crypto
  2. react-native-crypto-js

但它们似乎都没有工作并提供解密数据,甚至没有像我使用 PHP 一样获得加密数据。

填充支持不在任何反应模块中。

我选择了 ReactNative Framework,以为它是最先进的框架,但我已经浪费了很多天来解决这个问题,所以不知道如何解决这个问题。

下面是 React 代码

async DecryptSharedSecret() {
//    var plaintext_secret = "9b8a3e600073de05e5d095b5d909043e50f5047ffcd0048c01c65ca690b7b4e981e51b59641d4ffd5a140c27f25a761ab0f99e601b59c5ae3427c751bfae9331";
var strIV = 'ahc/2u6F0Yvww12fyQiZWA==';
var iv_bin = Base64.Decode(strIV, strIV.length);
// Decoded value IV is in Binary when converted to Hex its 6a173fdaee85d18bf0c35d9fc9089958

var shared_secret =
  'n4gIdzwY5UsOpzGtslpRlyNjLwLla7sJWfGkfH0GHadPFjtsOxNGJgqRe9WnjYkbNjCgwvvAvQtYV1kFHTpCIS4zDJa3h/2ADHrDgC7ym3HUyMeVIWgFKRCZYeVKz8SEHmullNxWG6dCjsWEbK6yqVmpNfwJSeh0XHHDFe0/Sak=';
var shared_secret_bin = Base64.Decode(shared_secret, shared_secret.length);
// Decoded Value shared_secret is in Binary when converted to HEx for printing, Value is
// '9f8808773c18e54b0ea731adb25a519723632f02e56bbb0959f1a47c7d061da74f163b6c3b1346260a917bd5a78d891b3630a0c2fbc0bd0b585759051d3a42212e330c96b787fd800c7ac3802ef29b71d4c8c79521680529109961e54acfc4841e6ba594dc561ba7428ec5846caeb2a959a935fc0949e8745c71c315ed3f49a9'

var strKey = 's@keypact.appa62f1bed41166b2c455d82337222723b0287d920';
var keysha256 = await RNSimpleCrypto.SHA.sha256(strKey);
console.log('Key SHA 256 ===== >> ', keysha256);
// var key =
// '074bf4849734a4c3a653fc213f2734d23f5dc63ce9d6244f386276097f032ad7';

let bytes = CryptoJS.AES.decrypt(
  shared_secret_bin,
  CryptoJS.enc.Hex.parse(keysha256),
  {
    iv: iv_bin,
    mode: CryptoJS.mode.CBC,
  },
);
var decrypted = bytes.toString(CryptoJS.enc.Utf8);
console.log('Decrypted Data ', decrypted);

} }

【问题讨论】:

  • 请发布您的 React Native / JavaScript 代码。 CryptoJS 隐式支持填充。
  • 我已经在上面添加了我的反应代码..请检查这个..

标签: php react-native encryption cryptojs zero-padding


【解决方案1】:

你的 PHP 代码的结果是:

n4gIdzwY5UsOpzGtslpRlyNjLwLla7sJWfGkfH0GHadPFjtsOxNGJgqRe9WnjYkbNjCgwvvAvQtYV1kFHTpCIS4zDJa3h/2ADHrDgC7ym3HUyMeVIWgFKRCZYeVKz8SEHmullNxWG6dCjsWEbK6yqVmpNfwJSeh0XHHDFe0/Sak=

以下 CryptoJS 代码给出了相同的结果:

// IV
var iv_real = "ahc/2u6F0Yvww12fyQiZWA==";
var decoded_iv = CryptoJS.enc.Base64.parse(iv_real);

// Key
var hash = CryptoJS.SHA256("s@keypact.appa62f1bed41166b2c455d82337222723b0287d920");
var hashHex32 = hash.toString(CryptoJS.enc.Hex).substring(0,32);
var aes_key = CryptoJS.enc.Utf8.parse(hashHex32);

// Plaintext
var plaintext_shared_secret = "9b8a3e600073de05e5d095b5d909043e50f5047ffcd0048c01c65ca690b7b4e981e51b59641d4ffd5a140c27f25a761ab0f99e601b59c5ae3427c751bfae9331";

var encrypted = CryptoJS.AES.encrypt(
    plaintext_shared_secret, 
    aes_key, 
    {
        iv: decoded_iv,
        padding: CryptoJS.pad.NoPadding 
    });

console.log(encrypted.toString().replace(/(.{56})/g,'$1\n'));
<script src="https://cdnjs.cloudflare.com/ajax/libs/crypto-js/4.0.0/crypto-js.min.js"></script>

在 PHP 代码中,SHA256 哈希以十六进制编码返回,因此由 64 个字符或 64 个字节组成。 openssl_encrypt 仅用于 AES-256 的前 32 个字节,因此在 CryptoJS 代码中,密钥必须相应缩短。将哈希作为二进制数据返回会更有意义,因此它将是 32 字节长。此外,如果十六进制编码的数据在一种环境中为大写,而在另一种环境中为小写,则使用十六进制编码的数据可能会导致跨平台问题。
另一点是在 PHP 代码中禁用了填充(因为OPENSSL_ZERO_PADDING 标志),因此也必须在 CryptoJS 代码中禁用它。这意味着只有长度是块大小的整数倍(AES 为 16 字节)的明文才能被加密,对于发布的明文(长度为 128 字节)也是如此。
由于明文在 PHP 代码中似乎是十六进制编码的,因此优化方法是在加密之前对明文进行十六进制解码,这样可以将数据量减半。
请注意,静态 IV 是不安全的。相反,应为每次加密使用随机生成的 IV。

【讨论】:

  • 感谢您的加密密钥绝对正确。我完全理解您的 SHA256 哈希部分,填充和随机 IV。非常感谢你分享这些细节,我真的很感激。但是由于我在 ReactNative 中使用它,所以我无法在 ReactNative 中使用 CryptoJS.SHA256,所以我使用另一种方法来执行 SHA256。你能分享一下hashHex32的输出是什么吗?是 074bf4849734a4c3a653fc213f2734d2 吗?
  • @MaitreyiSharma,是的。
  • @MaitreyiSharma - hashHex32 确实是 074bf4849734a4c3a653fc213f2734d2。我不太确定为什么 SHA256 功能不可用,请参阅例如this ReactNative/CryptoJS online example.
  • @Topco 感谢分享 React 示例链接,很高兴知道。我是 ReactNative 的新手,以及我们从 Expo 中弹出代码的方式,它总是像您所做的那样在导入 crypto-js 时出错,“错误:错误:无法从 node_modules/crypto-js/core.js 解析模块 crypto:加密无法可以在项目中找到。”尽管在 nodemodules 中安装了 crypto-js。所以我们使用 react-native-crypto-js 模块。我可能可以检查这个,因为填充也是我当前实现无法使用的字段之一。但是再次感谢您。
  • 为了解密,我在你的snacking.expo的doIt函数中更新了3行 var cipherText = CryptoJS.enc.Base64.parse(encrypted.toString()); var decrypted = CryptoJS.AES.decrypt(cipherText, aes_key, {padding: CryptoJS.pad.NoPadding, iv: decoded_iv}); return "AES-key:" + hashHex32 + "\nPlaintext:" + decrypted.toString();但它打印为空。你也可以看看这个吗?
猜你喜欢
  • 1970-01-01
  • 2011-10-20
  • 2014-12-16
  • 2021-10-24
  • 2012-06-10
  • 1970-01-01
  • 2011-11-20
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多