当前位置: 首页 > 知识库问答 >
问题:

Android中的AES加密和nodejs中的解密

龙默
2023-03-14

我尝试在android中加密,在nodejs服务器中解密。我生成了一个AES 128位密钥,并使用AES算法对其进行加密,然后使用RSA算法对生成的密钥进行加密。然后将两者都发送到服务器。但是在服务器端解密时,我认为RSA解密工作正常,但在AES解密中有一个问题。我在服务器端没有收到我在客户端加密的字符串。

这是android端加密的代码:

String encryptedSecretKey;
String cipherTextString;

// 1. generate secret key using AES
KeyGenerator keyGenerator = null;
keyGenerator = KeyGenerator.getInstance("AES");
keyGenerator.init(128);

// 2. get string which needs to be encrypted
String text = "This is the message to be encrypted";

// 3. encrypt string using secret key
byte[] raw = secretKey.getEncoded();
SecretKeySpec skeySpec = new SecretKeySpec(raw, "AES");
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
cipher.init(Cipher.ENCRYPT_MODE, skeySpec);
cipherTextString = Base64.encodeToString(cipher.doFinal(text.getBytes(Charset.forName("UTF-8"))), Base64.DEFAULT);

// 4. get public key
X509EncodedKeySpec publicSpec = new X509EncodedKeySpec(Base64.decode(publicKeyString, Base64.DEFAULT));
KeyFactory keyFactory = KeyFactory.getInstance("RSA");
PublicKey publicKey = keyFactory.generatePublic(publicSpec);

// 5. encrypt secret key using public key
Cipher cipher2 = Cipher.getInstance("RSA/ECB/OAEPWithSHA1AndMGF1Padding");
cipher2.init(Cipher.ENCRYPT_MODE, publicKey);
encryptedSecretKey = Base64.encodeToString(cipher2.doFinal(secretKey.getEncoded()), Base64.DEFAULT);

然后把这个发到服务器端

服务器端的代码如下所示:

var encryptedMessage = req.body.cipherText;
var encryptedAesKey = req.body.secretKey;

//printing those values
console.log("\nEncryptedMessage: \n" + encryptedMessage);
console.log("\nEncrypted key: \n" + encryptedAesKey);

var privateKey = fs.readFileSync('././Keys/privkey_server.pem', "utf8");
var bufferForAesKey = new Buffer(encryptedAesKey, "base64");
var obj = {
        key: privateKey
        // , padding: constants.RSA_PKCS1_PADDING
        // , padding: constants.RSA/ECB/OAEPWithSHA-1
};
var decryptedAes = crypto.privateDecrypt(obj, bufferForAesKey);

console.log("Decrypted AES: " + decryptedAes);

var decryptedAesKeyString = decryptedAes.toString("base64");
console.log("Decrypted AES Key: " + decryptedAesKeyString);
var bufferForAES = new Buffer(decryptedAes, "base64");

//decrypting using AES
var bufferForEncryptedMsg = new Buffer(encryptedMessage, "base64");

var decipher = crypto.createDecipher('aes-128-cbc',bufferForAES);
decipher.setAutoPadding(false);
var dec = decipher.update(bufferForEncryptedMsg,"base64", "utf8");
dec += decipher.final("utf8");
console.log(dec);

这里的最终结果“dec”没有给出正确的结果,但客户端和服务器的中间结果是相同的。这意味着,RSA工作良好,但在AES中存在问题。

输出如下:

EncryptedMessage: 
SfosHg+cTrQXYUdF0FuqCJMHgfcP13ckp2L0B9QqOcl8UtWnnl8fLi5lxgR2SKOj


Encrypted key: 
C/pa52PZda3xShrPXkHZx8OL6sW4JBEhG/ggNAoHhSVXIGt+iDq/B1ByG5yStBGF3GFJRQT0aGsG
+bZJydP7j9gTivmt99H/bxiZan4CHZnqfGKG1dJCI7ILAYZMCw7JhIcRC8qHMM4LMdF+rxRhENDe
alUfnsLWpcrX9J6fKejJ7EWnWQ1VadKqCDmrJ5xw0lBbsOpwN/vY09+VhF4WkOz8Y3cQGk+FVdz5
tr4L9/jgXlTZdOC2KVBLSH+9pvtHwMWFKKoDSAzvkil4htBjbWTqlBuEINC4I/J/4P3RX2riT5Pv
xHQi/Dv7vdBlo9AEdvWe3Ek8oBleIpmIQHXwQWknPOYghhBAVmACG/tbEQcAtbcmRLruT/XzjPJt
HNBt2HeG9JHYKNoHC3kOuJdnlGe8mv8k0Nzwj04RhEGKSmPIiu/oDgYwS0l96KIlS2ELqBlS5O0L
AJ+RBG7m0WwC9dfrufsuwu0+SPUmg5/ElXRmA3T81lXtQqQbGg8G6r/bAVFGduy4a49s/VWoylx+
/sI079IwyY0IOfwQTVGZRyDC5O1ZBjoYv2+TRo3bjG8GXNQoybkmWkhgotcqVD9mXO67D2NBsFPT
EJnw+1ApSqR7ggIAF+qsMxejFKBICBL/4J8FP4+obA07J1pWiciTRKX+G130qzIBKM08Zdaf/50=

Decrypted AES: %Kp[ϪS�/�W l��9ӊ˽��~��
B�A�
Decrypted AES Key: JUtwW8+qU6Mv/FcgbMbkOdOKy72pun4B490KQrRB4QQ=
T�Ϝ��u��q�
          ���w�p���u`�̗r[`H0[tW��=��~i-�W

这里解密的AES密钥与我们在android中生成的密钥相同。但最终的结果并没有达到预期的效果。我的代码中有错误吗??

共有1个答案

吕自明
2023-03-14

Neardupe用Java解密node.js中的字符串?这是相反方向的同一个东西。

[在爪哇]我生成了一个 AES 128 位密钥,并使用 AES 算法对其进行加密,然后使用 RSA 算法对此生成的密钥进行加密。

不,你没有。您的 Java 代码实例化 AES-128 的密钥生成器,但不使用它来生成任何密钥。您实际使用的密钥(正如您所说的服务器从RSA-OAEP正确解密的)是32字节,对应于AES-256。

但您的主要问题是createDecipher使用密码而不是密钥。根据文件

crypto.createDecipher(算法,密码[,选项])

加密的实现。createDecipher()使用OpenSSL函数EVP_BytesToKey派生密钥,摘要算法设置为MD5,一次迭代,没有salt。

你把实际上是一把钥匙的东西当成了密码;这会导致nodejs使用与Java中完全不同的密钥,从而得到完全错误的结果。您应该使用< code>createDecipheriv,它接受密钥和iv(初始化向量)。

这是你的另一个问题。要解密,您必须使用与加密相同的IV,通常是通过将IV包含在从发送方发送到接收方的密文中,但您没有。因此,以下(简化的)代码无法解密数据的前 16 个字节,但会解密其余部分。

const crypto = require('crypto');
msg = Buffer.from('SfosHg+cTrQXYUdF0FuqCJMHgfcP13ckp2L0B9QqOcl8UtWnnl8fLi5lxgR2SKOj','base64');
aeskey = Buffer.from('JUtwW8+qU6Mv/FcgbMbkOdOKy72pun4B490KQrRB4QQ=','base64');
dec = crypto.createDecipheriv('aes-256-cbc',aeskey,Buffer.alloc(16)/*this should be the IV*/);
console.log(dec.update(msg,'','latin1')+dec.final('latin1'));
// I used latin1 instead of utf8 because the garbaged first block 
// isn't valid UTF-8, and the rest is ASCII which works as either.
->
Y;øï«*M2WÚâeage to be encrypted
// some garbaged chars are control chars and Stack (or browser?) 
// may not display them but there really are 16 in total

顺便说一句,文档中的“初始化向量[必须]不可预测和唯一…[但不是秘密]”对于CBC模式是正确的,但对于OpenSSL(因此是nodejs)和Java支持的其他一些模式不是正确的。然而,这不是一个编程问题,因此这里离题了;它属于crypto.SX或可能security.SX,在那里它已经被回答了很多次。

 类似资料:
  • 这是一个错误: 1.JS

  • 问题内容: 我有一个现有的网络服务,可以使用AES进行加密和解密,现在我必须以与Java相同的方式进行加密,但是要使用javascript。我已经阅读了有关在javascript中执行此操作的所有主题,但尚未找到任何有用的解决方案。Javascript总是以不同的方式加密,我找不到原因。 这是现有的java代码: 这是我倾向于使用的javascript代码,但是提供了不同的加密(CryptoJS)

  • 问题内容: 我在使用CryptoJS解密在Go lang中加密的文本时遇到问题。 这是Go代码:https : //play.golang.org/p/xCbl48T_iN 这是JS代码:http: //jsfiddle.net/Ltkxm64n/ 两者都可以很好地进行加密和解密,但是当我将base64密文从GO复制到JS(反之亦然)时,它不起作用。我还注意到js输出的第一部分与Go输出相同,但是

  • 我试图在Android和PHP端使用AES加密/解密数据,并累犯空答案。 首先,我在Android中生成了对称密钥: 在服务器端,我试图解密数据。我可以解密(从RSA)秘密的AES密钥,并得到它的字符串表示。在客户端(Android)和服务器端(PHP)上是一样的。但是如何使用这个字符串AES密钥来解密数据呢?我尝试了这个(PHP): PHP中的结果: 怎么啦?

  • 我已经看过了AES-Encryption with Crypto(node js)/decryption with Pycrypto(python)的文章,因为我正试图做完全相反的事情,但我似乎做得不对。这是我到目前为止试过的。。。 Python加密 节点。js解密 每次我尝试运行节点时。js解密,我最终得到错误消息:

  • 就像我说的,一切都很好,除了这个小的decypt...我搜索了谷歌和所有的东西,尝试了示例代码,但似乎我的代码有些东西不对。