CryptoJs AES Decryption Error: Malformed UTF-8 data in Nativescript-Angular
CryptoJs AES Decryption Error: Malformed UTF-8 data in Nativescript-Angular
解密加密数据时出错。我的目标是在 PHP 中加密 pdf 文件并在 nativescript 中解密以在应用程序中本地显示 pdf。我将此作为最后的手段发布,因为我已经阅读过关于我的问题的类似帖子,但 none 对我有用。数据在 PHP 中使用 openssl and will be decrypted in nativescript using cryptoJs for AES decryption and jsrsasign 进行加密,用于密钥和 IV 的 RSA 解密。我非常感谢任何能帮助我的东西。我的做法可能有问题,但我不确定是什么。这是我目前的进度。
PHP 中的加密 (RSA+AES)。
Already tested in decrypting the data successfully in PHP. So it's safe to assume that it can be decrypted.
$data = // Is a pdf file
//get public key
$publicKey = // API CALL to get the public key
// get mime type of file
$dataFormat['docMimeType'] = "application/json";
// compute the hash of the file before encryption
$dataFormat['hash'] = hash('sha256', $data);
// generate random two 16 bytes long encryption key
$secretKey1 = openssl_random_pseudo_bytes(16);
$secretKey2 = openssl_random_pseudo_bytes(16);
// concatenate the two key to make the 32 bytes long AES encryption key
$secretKey = $secretKey1.$secretKey2;
// RSA Encryption of the keys and IV
// encrypt the aes encryption key with the public key
openssl_public_encrypt($secretKey1, $dataFormat['key1'], $publicKey, OPENSSL_PKCS1_OAEP_PADDING);
openssl_public_encrypt($secretKey2, $dataFormat['key2'], $publicKey, OPENSSL_PKCS1_OAEP_PADDING);
// Encoding the encrypted keys to base64
$dataFormat['key1'] = base64_encode($dataFormat['key1']);
$dataFormat['key2'] = base64_encode($dataFormat['key2']);
// AES Encryption
// generate random iv
$iv = openssl_random_pseudo_bytes(16);
// encrypt iv with the public key
openssl_public_encrypt($iv, $dataFormat['iv'], $publicKey, OPENSSL_PKCS1_OAEP_PADDING);
$dataFormat['iv'] = base64_encode($dataFormat['iv']);
// Manually doing the padding - Zero padding
$pad = 32 - (strlen($data) % 32);
$clear = $data . str_repeat(chr(0), $pad);
// encrypt the data with the aes encryption key
$dataFormat['doc'] = openssl_encrypt($clear, 'AES-256-CBC', $secretKey, OPENSSL_RAW_DATA|OPENSSL_ZERO_PADDING, $iv);
$dataFormat['doc'] = base64_encode($dataFormat['doc']);
// save file to the cloud which will then be fetch by the app in nativescript for decryption
// save cipher
file_put_contents($cipherfile, json_encode($dataFormat));
// $cipherfile is the .enc file that will be uploaded to the cloud
pm 格式的 pkcs#8 私钥示例
-----BEGIN PRIVATE KEY-----
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
LFzA9Qx4EmEK73S8UTxk/9eDLFMhfA==
-----END PRIVATE KEY-----
示例输出(用于处理):文件内容如下所示。
{
"docMimeType": "application/json",
"hash": "253cd9d4f849084f276c649a5155512c5b0bb68c8f7cbde33cc529f68c672168",
"key1": "dxUYOfiIEchLeha/Hu3dUd6MzucwABf8/Q9eUPgJAhEhmjrsf1MXnXOtcPCNGE/8bXEU6Iv3XIcLjImhaFBF8aYoDbS6GjnhPMeGpRQN8+raXrfm/5J9rlRjUImSyZUUnwgJ7vkHP22F9I8rrZywA5QgHiK97vyp7y2cv1H9y2tT5kukrDxhvWWBHoii+V0pA0SCEviPrlWjopyL/SpiaUfoG/L97Rdg7k181c1pHR5S+dWRAy190aU/IFo7VZXQ6FuqWd0TyoOEeBoAwrxTXG+03OXs7qqZwlFdHtCZ6ehrUl8Kkcbbv7O2PBOFsHnla5c+7aSDQ69xCHXmzoxB+dTbu5OY0E8TFWLD6V8QVe2Y5q79Nybf9r56YZDX6sqKK5uZqJDQB9wQUWHhM5hE7mzP7Ll1IVC4sAml+k2qrwJqOaDDN0eUidR+X31LXDEO9+y3g6NrlsNTROttiF0jC1oKyN5y+OOwxx0OEntXYUsM1Z8iQ9QQBHL418EF/FoEwmTVcg/7Lg20Qdgp21mv0ihMmYssB0EmopzH9yQ6d4eEp4Wh5krO2Ph73zJx6RvjVu1JfkoMmZ8fxwlHs+Xe09WE828NCWTW2WheP63V+fQZ07nm9c/BcITCmiQ9376wYh3+Hj+o6/N+et1nf0vO9zbooUI+V3Hd/m0wUnBxm+s=",
"key2": "stkiCTyRmKfU7OhGfsqQyvi2UZ2syRjAdD4Sk0N/x+JMYX2Dr5rlwV+EH5TG388uvoPH7NSalPrprF+Nlm+YEVhYS0E5SBXJiIEFixT5AIQ9rhAHD/WFfxjvHainhiHhoLcX5rQ6C0zGCNUZaH0X4I4v8r575rbklTqSgCs3ueGDX9mAQKj2q5eJMIfRh+mAwQq7lhTk4TbGxL6LAyWxYL+Zw4R5ljUl6uK0o5Vwpn7I2xdAIQs6J7jW6jDfMT+5mbk06nrba09ysKdJILe8je97SyBRR5y+OHfJF5EArTSKwnLrAp/DXE40DP8BHOheL/PNxoKzIEkOX0Cu3aAXmHR6SLJxtwKGEHn5tzUvBzx54h2K5iEh2C8Wvkqqi7m+DcmxnrjYKEjmP7jzUvSMIob7EBcJ+wHvE9s5aPCK1MbKqK1UbHHkHRHsk8tgZsv/PC8A0+wdlMKI30GL1B9wcck7Fottgnc1eGzdFjbnEirLHeihaJPJOjkjiz1RtkOQHgd6l9bzUTMUnCq0melgSlut68akgvGM7kTtHhEY27sHj8UGF5zjTS+KPYzpi17Wp/9TgWpETxXsewvtBP9oCl/L+ZhhUrRihZOctSgTzFTZpIyrlx9ZDg0A0MU/Q2AyhBU0r9dzowyApDUu/TWPdj2Z9p/DX7c0i5y4IK7TOX0=",
"iv": "Y2RdcAtnid52Ueu2MDdh2bY1aJBysk2UTstPdCAILU+RqcZCtgp+f5kLlRweG7Kgst88oZrJy6B/33F2WMqQ1qx1AqK+WthG+gVg15YC50OGaKGNuBAFSdFCJli2MLIE4s8ItXH2VmgxkGGE3ETuz3b7fheUJOUpUKcc3Kz0HmZiyo5eXsB4lNSXsaTP5Z8kaQcHDfacu9UORF9RUM2tfUH4IzAkU3ENPEM4cTP27HFRsFAeuXAcNAAYUQws9HVQFtg9pXAyuN0GUzD4GksL/3M0Y8CvITewLQDRHSBSljspPtF+lFqS3ZQTxAbtqxjEf6/Q1dCP1CIeiXEi2it8GEKZzWhH7385qW383JIBk1b9HjT7+26w2s7AqpLSevK5iOis+4sHzqEix9MHsOUp4OEcQ+BAYFkYiFlmPeo4tNgg9sRuIrgQwaEvCgHG2IoboURqCRs6iRnS4j8dHyvG5acavSEm0ozouqt4KBVoZt/chq8hpxH123kRIeuZH1qTsmzfSInAJLKpW2ky+nLifjOrSCA1D7ZDpfykACa1PpP+I6LgjMkWoQ/zkd70hz28fD+tpDWBJPngDcxnCz8UbZRma9psVEsw/4IOWQr3yy+V4Y9+xllLzZLy1YbEcdewsh/FXjLkhWqic3uPPyNlLWqzpHqBqTvgpPwU31zyJks=",
"doc": // data is too large to be included in the post. If you want to see the full version of the sample output I created a gist in github https://gist.github.com/ketuvin/cba7e7215dbdd67ea8b10050ecbbcd3f
}
在 nativescript 中,此文件将被提取并从 JSON 处理到数组。然后会被解密。
在 Nativescript 中解密
import * as cryptoJs from "crypto-js"
import { KJUR, KEYUTIL } from "jsrsasign"
/**
@params encryptedFile - the file to be decrypted
@params pem - the pkcs#8 private key (cipher=aes-256-cbc)
*/
decryptFile(encryptedFile, pem) {
// load key
let privateKey = KEYUTIL.getKey(pem);
// Base64 Decode using cryptoJs
let key1 = cryptoJs.enc.Base64.parse(encryptedFile['key1']).toString();
let key2 = cryptoJs.enc.Base64.parse(encryptedFile['key2']).toString();
let iv = cryptoJs.enc.Base64.parse(encryptedFile['iv']).toString();
let doc = cryptoJs.enc.Base64.parse(encryptedFile['doc']).toString();
console.log("Base64 Decoded Key1: "+key1);
console.log("Base64 Decoded Key2: "+key2);
console.log("Base64 Decoded IV: "+iv);
// RSA Decryption of the keys and IV using jsrsasign
let decryptedKey1 = KJUR.crypto.Cipher.decrypt(key1, privateKey, "RSAOAEP");
let decryptedKey2 = KJUR.crypto.Cipher.decrypt(key2, privateKey, "RSAOAEP");
let decryptedIV = KJUR.crypto.Cipher.decrypt(iv, privateKey, "RSAOAEP");
console.log("RSA Decrypted Key1: "+decryptedKey1);
console.log("RSA Decrypted Key2: "+decryptedKey2);
console.log("RSA Decrypted IV: "+decryptedIV);
// Concatenate the keys to make up the AES key
let decryptedKey = decryptedKey1 + decryptedKey2;
console.log("AES KEY (Key1+Key2): "+decryptedKey);
// Convert to wordarray
let parsedkey = cryptoJs.enc.Utf8.parse(decryptedKey);
let parsedIV = cryptoJs.enc.Utf8.parse(decryptedIV);
// AES Decryption using crypto-js
let decrypted = cryptoJs.AES.decrypt(doc, parsedkey, {
iv: parsedIV,
mode: cryptoJs.mode.CBC,
padding: cryptoJs.pad.ZeroPadding
}).toString(cryptoJs.enc.Utf8); // Error: Malformed Utf-8 data
return decrypted;
}
在控制台中,
See actual log here
Base64 Decoded Key1: 0a5b90147517916c338fb8aa359d3f53a542eed1d482e42dd93eea0735a5d5a64dc219cdc703ba0a88cbf10b7feae82d2d4fe5a389f296cba8452b5e3371166c903aae2f64223f561821bb61f7be1ea41d96ac64d0e47da601041aef88ab9ded35c40240f7615e001f624b22966107539f98c499607e4b2760a162a963a854dffbfe955afec959b069101a49d1f765e729ff7035f0beb8ce06a1b3776a62f8c7db5b3efcfb1b0c1231f654e6aa075667621e99abbb6ba78a6fd81061c59de1024da81d2a8cc42dc84fa5af61c3d5b1a009cca2b4543e66974dce60f6631c490564be8494d0324fb1d7a8e7067feba5dd38653c936895247557e380e31e118af7a1886063e867acf58a3f63ab98bfa619b6a18518be68675a072d5a5217bc7ca4c5dba601ab7560e42dce1aadeca5a7fe0eba50f5d1c997eaf25d8dbbfded2cbea6402b121df8691f1673c243d1a8195e0af2a3b938fa271ecda93984ba9eef24912169ccabfd7a8f9fd2c4aa710e174f10d04914d7107c2a4fa54b463d002cc2347d4429604b2e1bb536a74f754f1f931362c90168e841ee05717e23323d627a938b582af62fb64c2d55442932517194eedf89d265523fe6f6ccdcd9c90fe5c76f9b3220c4a4fecfb4e84075167092b3971d52cfafba904f5b00ea14878df6b47bfbae29a97d1a4fa7caa995baddb6280f4939091fe2531d39b80759971d55ee
VM38 bundle.ad8287f8f3cbaa7f8ee5.hot-update.js:109 Base64 Decoded Key2: 2ba192411fb0a2ceeca359d389b4cacfa0f87f7a3a0c7168ad1e2e92d4952b4ab6465b7ad8975e2b735bd6c9489d4c34462df636ef3b4d7fdc6ed56cdb9cd3bab96539a420ca630721cb378df95371f1f7b10cf2dc9f7f149816b920be2a2dd0006052176ec10fee093672526e0b3eb8488a5ad1dee25a34e754c5c4b0a99478173501609bcb35dd5e99355b660485eee8f3fed8b3fcbc4873e760a303682ccd0f0aceea1c9da419bfec5d78619cbe5d22bfd34cc055e3ce7c3c596029b9c393b2039823e29b465ca4581e80015052c4ac4c63d9ffdafa995c0b1c2bc0cb10f194a99989467a7958956d29cea1efa271a6239110316fa9ea9f4bfe2f8a509db86e68245ae930f27b327e49f799757fc868985cfb93a24e7686b2d55966365ba506acd9e63e64b63ccf98024fcd472b2d69cee7a20904ba07556ac8ba6f05d8ec60c18e958dfb100b29d6409efb164caec3d35dfaf39f83ef59c3db1fa21fe684c6c13a403c52cec4b593b153e6ad79607f7f5e4dbfcb4c64ec058846278e06d0cdf72afee431a10bb12a2955ca78ea105da0607942d8af226e64fd2803310090f7e69c96fd634b82e946213bf073952bef8dcbdab11be4b197c144bacd10f6231c043795f855fd2042e2370bc64cdbefdbc9180e48b3d8aff957e8c998b92b8c5c2e8a2cc25f79c40f7633842b839313dbf6547b34d4d8f7974c09f54f9a20d8
VM38 bundle.ad8287f8f3cbaa7f8ee5.hot-update.js:110 Base64 Decoded IV: 4bba6438c3360e5d18080afc3edde5f3bcb81f3690cb152758b15ebf5377b6f4fe6b8008fce35fb7f966251b7405916626c3fe2caa61c9e183f87ced6b3f5cee8e336c32d23f0646c18c38aa2ce98dcfb9bfb3f32a02bdf9f3d16e36ef501d564316300203dc42b416c512530161952ddeef7d016b7af9b5c757ed6a43646efe34615db7674ec9446d1bf3aa8e8832a81b601bde8b2281c6fbe441d7bb2e8c3a7f26204e51078857b13d31b117df82850e20c6bf38110b7a52d62f78fd571204a50ae9ac3c11300eef05b48d43d7bd64532e50e9b03add4c826f9bb2804f8c5362f5f6ec5526219c2519f9e04742b92b52db45d7d717fd0fe43a2c31f59634a958811e07e095c3f9e4f8562ae999ef0761411d7de71751a80e0332d6aaa298d090c23790ee1439e8f5b2b9d8d80bf5834306a9be47a476f31dd9ec71c9e254eb48dce2139cc4170ca42f385ef408a2e8425a60b443ef41d8725a0399a81cfa53117c931c7c066f25614182117b18b9a1e5302a0bcc866560f2309d5c9d2dedcbed2782b1a3535d0b2532d0d7f7ff9d89296054fa12a00b54401fc4b098f2011506f25165618eae95bfcd83d097f1ca897e83528a22dfaa11c7978daa9fbca33b246f395417376162967275ecbdad7007c93b9b3e40377814c632926a01ff93b62dd583cb9ae4b5e5cb2fa338de4e3acaeb22be7622bfb6bbfbbf56dafb07e093
VM38 bundle.ad8287f8f3cbaa7f8ee5.hot-update.js:115 RSA Decrypted Key1: g.œ'Æ‹wvüXã2¸¶
VM38 bundle.ad8287f8f3cbaa7f8ee5.hot-update.js:116 RSA Decrypted Key2: lÖÑCò®|f.üØÁ}]
VM38 bundle.ad8287f8f3cbaa7f8ee5.hot-update.js:117 RSA Decrypted IV: KN¿N8ª1Ê°YëLr”e
VM38 bundle.ad8287f8f3cbaa7f8ee5.hot-update.js:119 AES KEY (Key1+Key2): g.œ'Æ‹wvüXã2¸¶lÖÑCò®|f.üØÁ}]
VM9 vendor.js:20948 ERROR Error: Malformed UTF-8 data
我解决了问题! (从技术上讲,虽然我问错了问题)。我意识到这是因为我使用 UTF-8 编码解析密钥和 IV,而实际上我应该使用 Latin1。我检查了数据的编码,它是我最近了解到的ISO-8859-1,也称为Latin1。所以我更改了这段代码
let parsedkey = cryptoJs.enc.Utf8.parse(decryptedKey);
let parsedIV = cryptoJs.enc.Utf8.parse(decryptedIV);
到
let parsedkey = cryptoJs.enc.Latin1.parse(decryptedKey);
let parsedIV = cryptoJs.enc.Latin1.parse(decryptedIV);
我的aes解密现在是这样的
let decrypted = cryptoJs.AES.decrypt(doc, parsedkey, {
iv: parsedIV,
mode: cryptoJs.mode.CBC,
padding: cryptoJs.pad.ZeroPadding
}).toString(cryptoJs.enc.Latin1);
现在我可以处理 pdf 并将其本地显示在我的应用程序中。希望这对和我有类似情况的其他人有所帮助。
解密加密数据时出错。我的目标是在 PHP 中加密 pdf 文件并在 nativescript 中解密以在应用程序中本地显示 pdf。我将此作为最后的手段发布,因为我已经阅读过关于我的问题的类似帖子,但 none 对我有用。数据在 PHP 中使用 openssl and will be decrypted in nativescript using cryptoJs for AES decryption and jsrsasign 进行加密,用于密钥和 IV 的 RSA 解密。我非常感谢任何能帮助我的东西。我的做法可能有问题,但我不确定是什么。这是我目前的进度。
PHP 中的加密 (RSA+AES)。
Already tested in decrypting the data successfully in PHP. So it's safe to assume that it can be decrypted.
$data = // Is a pdf file
//get public key
$publicKey = // API CALL to get the public key
// get mime type of file
$dataFormat['docMimeType'] = "application/json";
// compute the hash of the file before encryption
$dataFormat['hash'] = hash('sha256', $data);
// generate random two 16 bytes long encryption key
$secretKey1 = openssl_random_pseudo_bytes(16);
$secretKey2 = openssl_random_pseudo_bytes(16);
// concatenate the two key to make the 32 bytes long AES encryption key
$secretKey = $secretKey1.$secretKey2;
// RSA Encryption of the keys and IV
// encrypt the aes encryption key with the public key
openssl_public_encrypt($secretKey1, $dataFormat['key1'], $publicKey, OPENSSL_PKCS1_OAEP_PADDING);
openssl_public_encrypt($secretKey2, $dataFormat['key2'], $publicKey, OPENSSL_PKCS1_OAEP_PADDING);
// Encoding the encrypted keys to base64
$dataFormat['key1'] = base64_encode($dataFormat['key1']);
$dataFormat['key2'] = base64_encode($dataFormat['key2']);
// AES Encryption
// generate random iv
$iv = openssl_random_pseudo_bytes(16);
// encrypt iv with the public key
openssl_public_encrypt($iv, $dataFormat['iv'], $publicKey, OPENSSL_PKCS1_OAEP_PADDING);
$dataFormat['iv'] = base64_encode($dataFormat['iv']);
// Manually doing the padding - Zero padding
$pad = 32 - (strlen($data) % 32);
$clear = $data . str_repeat(chr(0), $pad);
// encrypt the data with the aes encryption key
$dataFormat['doc'] = openssl_encrypt($clear, 'AES-256-CBC', $secretKey, OPENSSL_RAW_DATA|OPENSSL_ZERO_PADDING, $iv);
$dataFormat['doc'] = base64_encode($dataFormat['doc']);
// save file to the cloud which will then be fetch by the app in nativescript for decryption
// save cipher
file_put_contents($cipherfile, json_encode($dataFormat));
// $cipherfile is the .enc file that will be uploaded to the cloud
pm 格式的 pkcs#8 私钥示例
-----BEGIN PRIVATE KEY-----
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
LFzA9Qx4EmEK73S8UTxk/9eDLFMhfA==
-----END PRIVATE KEY-----
示例输出(用于处理):文件内容如下所示。
{
"docMimeType": "application/json",
"hash": "253cd9d4f849084f276c649a5155512c5b0bb68c8f7cbde33cc529f68c672168",
"key1": "dxUYOfiIEchLeha/Hu3dUd6MzucwABf8/Q9eUPgJAhEhmjrsf1MXnXOtcPCNGE/8bXEU6Iv3XIcLjImhaFBF8aYoDbS6GjnhPMeGpRQN8+raXrfm/5J9rlRjUImSyZUUnwgJ7vkHP22F9I8rrZywA5QgHiK97vyp7y2cv1H9y2tT5kukrDxhvWWBHoii+V0pA0SCEviPrlWjopyL/SpiaUfoG/L97Rdg7k181c1pHR5S+dWRAy190aU/IFo7VZXQ6FuqWd0TyoOEeBoAwrxTXG+03OXs7qqZwlFdHtCZ6ehrUl8Kkcbbv7O2PBOFsHnla5c+7aSDQ69xCHXmzoxB+dTbu5OY0E8TFWLD6V8QVe2Y5q79Nybf9r56YZDX6sqKK5uZqJDQB9wQUWHhM5hE7mzP7Ll1IVC4sAml+k2qrwJqOaDDN0eUidR+X31LXDEO9+y3g6NrlsNTROttiF0jC1oKyN5y+OOwxx0OEntXYUsM1Z8iQ9QQBHL418EF/FoEwmTVcg/7Lg20Qdgp21mv0ihMmYssB0EmopzH9yQ6d4eEp4Wh5krO2Ph73zJx6RvjVu1JfkoMmZ8fxwlHs+Xe09WE828NCWTW2WheP63V+fQZ07nm9c/BcITCmiQ9376wYh3+Hj+o6/N+et1nf0vO9zbooUI+V3Hd/m0wUnBxm+s=",
"key2": "stkiCTyRmKfU7OhGfsqQyvi2UZ2syRjAdD4Sk0N/x+JMYX2Dr5rlwV+EH5TG388uvoPH7NSalPrprF+Nlm+YEVhYS0E5SBXJiIEFixT5AIQ9rhAHD/WFfxjvHainhiHhoLcX5rQ6C0zGCNUZaH0X4I4v8r575rbklTqSgCs3ueGDX9mAQKj2q5eJMIfRh+mAwQq7lhTk4TbGxL6LAyWxYL+Zw4R5ljUl6uK0o5Vwpn7I2xdAIQs6J7jW6jDfMT+5mbk06nrba09ysKdJILe8je97SyBRR5y+OHfJF5EArTSKwnLrAp/DXE40DP8BHOheL/PNxoKzIEkOX0Cu3aAXmHR6SLJxtwKGEHn5tzUvBzx54h2K5iEh2C8Wvkqqi7m+DcmxnrjYKEjmP7jzUvSMIob7EBcJ+wHvE9s5aPCK1MbKqK1UbHHkHRHsk8tgZsv/PC8A0+wdlMKI30GL1B9wcck7Fottgnc1eGzdFjbnEirLHeihaJPJOjkjiz1RtkOQHgd6l9bzUTMUnCq0melgSlut68akgvGM7kTtHhEY27sHj8UGF5zjTS+KPYzpi17Wp/9TgWpETxXsewvtBP9oCl/L+ZhhUrRihZOctSgTzFTZpIyrlx9ZDg0A0MU/Q2AyhBU0r9dzowyApDUu/TWPdj2Z9p/DX7c0i5y4IK7TOX0=",
"iv": "Y2RdcAtnid52Ueu2MDdh2bY1aJBysk2UTstPdCAILU+RqcZCtgp+f5kLlRweG7Kgst88oZrJy6B/33F2WMqQ1qx1AqK+WthG+gVg15YC50OGaKGNuBAFSdFCJli2MLIE4s8ItXH2VmgxkGGE3ETuz3b7fheUJOUpUKcc3Kz0HmZiyo5eXsB4lNSXsaTP5Z8kaQcHDfacu9UORF9RUM2tfUH4IzAkU3ENPEM4cTP27HFRsFAeuXAcNAAYUQws9HVQFtg9pXAyuN0GUzD4GksL/3M0Y8CvITewLQDRHSBSljspPtF+lFqS3ZQTxAbtqxjEf6/Q1dCP1CIeiXEi2it8GEKZzWhH7385qW383JIBk1b9HjT7+26w2s7AqpLSevK5iOis+4sHzqEix9MHsOUp4OEcQ+BAYFkYiFlmPeo4tNgg9sRuIrgQwaEvCgHG2IoboURqCRs6iRnS4j8dHyvG5acavSEm0ozouqt4KBVoZt/chq8hpxH123kRIeuZH1qTsmzfSInAJLKpW2ky+nLifjOrSCA1D7ZDpfykACa1PpP+I6LgjMkWoQ/zkd70hz28fD+tpDWBJPngDcxnCz8UbZRma9psVEsw/4IOWQr3yy+V4Y9+xllLzZLy1YbEcdewsh/FXjLkhWqic3uPPyNlLWqzpHqBqTvgpPwU31zyJks=",
"doc": // data is too large to be included in the post. If you want to see the full version of the sample output I created a gist in github https://gist.github.com/ketuvin/cba7e7215dbdd67ea8b10050ecbbcd3f
}
在 nativescript 中,此文件将被提取并从 JSON 处理到数组。然后会被解密。
在 Nativescript 中解密
import * as cryptoJs from "crypto-js"
import { KJUR, KEYUTIL } from "jsrsasign"
/**
@params encryptedFile - the file to be decrypted
@params pem - the pkcs#8 private key (cipher=aes-256-cbc)
*/
decryptFile(encryptedFile, pem) {
// load key
let privateKey = KEYUTIL.getKey(pem);
// Base64 Decode using cryptoJs
let key1 = cryptoJs.enc.Base64.parse(encryptedFile['key1']).toString();
let key2 = cryptoJs.enc.Base64.parse(encryptedFile['key2']).toString();
let iv = cryptoJs.enc.Base64.parse(encryptedFile['iv']).toString();
let doc = cryptoJs.enc.Base64.parse(encryptedFile['doc']).toString();
console.log("Base64 Decoded Key1: "+key1);
console.log("Base64 Decoded Key2: "+key2);
console.log("Base64 Decoded IV: "+iv);
// RSA Decryption of the keys and IV using jsrsasign
let decryptedKey1 = KJUR.crypto.Cipher.decrypt(key1, privateKey, "RSAOAEP");
let decryptedKey2 = KJUR.crypto.Cipher.decrypt(key2, privateKey, "RSAOAEP");
let decryptedIV = KJUR.crypto.Cipher.decrypt(iv, privateKey, "RSAOAEP");
console.log("RSA Decrypted Key1: "+decryptedKey1);
console.log("RSA Decrypted Key2: "+decryptedKey2);
console.log("RSA Decrypted IV: "+decryptedIV);
// Concatenate the keys to make up the AES key
let decryptedKey = decryptedKey1 + decryptedKey2;
console.log("AES KEY (Key1+Key2): "+decryptedKey);
// Convert to wordarray
let parsedkey = cryptoJs.enc.Utf8.parse(decryptedKey);
let parsedIV = cryptoJs.enc.Utf8.parse(decryptedIV);
// AES Decryption using crypto-js
let decrypted = cryptoJs.AES.decrypt(doc, parsedkey, {
iv: parsedIV,
mode: cryptoJs.mode.CBC,
padding: cryptoJs.pad.ZeroPadding
}).toString(cryptoJs.enc.Utf8); // Error: Malformed Utf-8 data
return decrypted;
}
在控制台中, See actual log here
Base64 Decoded Key1: 0a5b90147517916c338fb8aa359d3f53a542eed1d482e42dd93eea0735a5d5a64dc219cdc703ba0a88cbf10b7feae82d2d4fe5a389f296cba8452b5e3371166c903aae2f64223f561821bb61f7be1ea41d96ac64d0e47da601041aef88ab9ded35c40240f7615e001f624b22966107539f98c499607e4b2760a162a963a854dffbfe955afec959b069101a49d1f765e729ff7035f0beb8ce06a1b3776a62f8c7db5b3efcfb1b0c1231f654e6aa075667621e99abbb6ba78a6fd81061c59de1024da81d2a8cc42dc84fa5af61c3d5b1a009cca2b4543e66974dce60f6631c490564be8494d0324fb1d7a8e7067feba5dd38653c936895247557e380e31e118af7a1886063e867acf58a3f63ab98bfa619b6a18518be68675a072d5a5217bc7ca4c5dba601ab7560e42dce1aadeca5a7fe0eba50f5d1c997eaf25d8dbbfded2cbea6402b121df8691f1673c243d1a8195e0af2a3b938fa271ecda93984ba9eef24912169ccabfd7a8f9fd2c4aa710e174f10d04914d7107c2a4fa54b463d002cc2347d4429604b2e1bb536a74f754f1f931362c90168e841ee05717e23323d627a938b582af62fb64c2d55442932517194eedf89d265523fe6f6ccdcd9c90fe5c76f9b3220c4a4fecfb4e84075167092b3971d52cfafba904f5b00ea14878df6b47bfbae29a97d1a4fa7caa995baddb6280f4939091fe2531d39b80759971d55ee
VM38 bundle.ad8287f8f3cbaa7f8ee5.hot-update.js:109 Base64 Decoded Key2: 2ba192411fb0a2ceeca359d389b4cacfa0f87f7a3a0c7168ad1e2e92d4952b4ab6465b7ad8975e2b735bd6c9489d4c34462df636ef3b4d7fdc6ed56cdb9cd3bab96539a420ca630721cb378df95371f1f7b10cf2dc9f7f149816b920be2a2dd0006052176ec10fee093672526e0b3eb8488a5ad1dee25a34e754c5c4b0a99478173501609bcb35dd5e99355b660485eee8f3fed8b3fcbc4873e760a303682ccd0f0aceea1c9da419bfec5d78619cbe5d22bfd34cc055e3ce7c3c596029b9c393b2039823e29b465ca4581e80015052c4ac4c63d9ffdafa995c0b1c2bc0cb10f194a99989467a7958956d29cea1efa271a6239110316fa9ea9f4bfe2f8a509db86e68245ae930f27b327e49f799757fc868985cfb93a24e7686b2d55966365ba506acd9e63e64b63ccf98024fcd472b2d69cee7a20904ba07556ac8ba6f05d8ec60c18e958dfb100b29d6409efb164caec3d35dfaf39f83ef59c3db1fa21fe684c6c13a403c52cec4b593b153e6ad79607f7f5e4dbfcb4c64ec058846278e06d0cdf72afee431a10bb12a2955ca78ea105da0607942d8af226e64fd2803310090f7e69c96fd634b82e946213bf073952bef8dcbdab11be4b197c144bacd10f6231c043795f855fd2042e2370bc64cdbefdbc9180e48b3d8aff957e8c998b92b8c5c2e8a2cc25f79c40f7633842b839313dbf6547b34d4d8f7974c09f54f9a20d8
VM38 bundle.ad8287f8f3cbaa7f8ee5.hot-update.js:110 Base64 Decoded IV: 4bba6438c3360e5d18080afc3edde5f3bcb81f3690cb152758b15ebf5377b6f4fe6b8008fce35fb7f966251b7405916626c3fe2caa61c9e183f87ced6b3f5cee8e336c32d23f0646c18c38aa2ce98dcfb9bfb3f32a02bdf9f3d16e36ef501d564316300203dc42b416c512530161952ddeef7d016b7af9b5c757ed6a43646efe34615db7674ec9446d1bf3aa8e8832a81b601bde8b2281c6fbe441d7bb2e8c3a7f26204e51078857b13d31b117df82850e20c6bf38110b7a52d62f78fd571204a50ae9ac3c11300eef05b48d43d7bd64532e50e9b03add4c826f9bb2804f8c5362f5f6ec5526219c2519f9e04742b92b52db45d7d717fd0fe43a2c31f59634a958811e07e095c3f9e4f8562ae999ef0761411d7de71751a80e0332d6aaa298d090c23790ee1439e8f5b2b9d8d80bf5834306a9be47a476f31dd9ec71c9e254eb48dce2139cc4170ca42f385ef408a2e8425a60b443ef41d8725a0399a81cfa53117c931c7c066f25614182117b18b9a1e5302a0bcc866560f2309d5c9d2dedcbed2782b1a3535d0b2532d0d7f7ff9d89296054fa12a00b54401fc4b098f2011506f25165618eae95bfcd83d097f1ca897e83528a22dfaa11c7978daa9fbca33b246f395417376162967275ecbdad7007c93b9b3e40377814c632926a01ff93b62dd583cb9ae4b5e5cb2fa338de4e3acaeb22be7622bfb6bbfbbf56dafb07e093
VM38 bundle.ad8287f8f3cbaa7f8ee5.hot-update.js:115 RSA Decrypted Key1: g.œ'Æ‹wvüXã2¸¶
VM38 bundle.ad8287f8f3cbaa7f8ee5.hot-update.js:116 RSA Decrypted Key2: lÖÑCò®|f.üØÁ}]
VM38 bundle.ad8287f8f3cbaa7f8ee5.hot-update.js:117 RSA Decrypted IV: KN¿N8ª1Ê°YëLr”e
VM38 bundle.ad8287f8f3cbaa7f8ee5.hot-update.js:119 AES KEY (Key1+Key2): g.œ'Æ‹wvüXã2¸¶lÖÑCò®|f.üØÁ}]
VM9 vendor.js:20948 ERROR Error: Malformed UTF-8 data
我解决了问题! (从技术上讲,虽然我问错了问题)。我意识到这是因为我使用 UTF-8 编码解析密钥和 IV,而实际上我应该使用 Latin1。我检查了数据的编码,它是我最近了解到的ISO-8859-1,也称为Latin1。所以我更改了这段代码
let parsedkey = cryptoJs.enc.Utf8.parse(decryptedKey);
let parsedIV = cryptoJs.enc.Utf8.parse(decryptedIV);
到
let parsedkey = cryptoJs.enc.Latin1.parse(decryptedKey);
let parsedIV = cryptoJs.enc.Latin1.parse(decryptedIV);
我的aes解密现在是这样的
let decrypted = cryptoJs.AES.decrypt(doc, parsedkey, {
iv: parsedIV,
mode: cryptoJs.mode.CBC,
padding: cryptoJs.pad.ZeroPadding
}).toString(cryptoJs.enc.Latin1);
现在我可以处理 pdf 并将其本地显示在我的应用程序中。希望这对和我有类似情况的其他人有所帮助。