加密与Node.js的加密模块,并与Java解密(在Android应用程序)并与、应用程序、模块、js

2023-09-06 00:14:12 作者:山海藏深意

寻找一种方式来加密节点数据(主要是字符串)和解密在一个Android应用程序(JAVA)。

已经成功在每一个这样做的(加密/解密的节点,加密/解密在Java),但似乎无法得到它的他们之间的合作。

也许我不是加密/解密以同样的方式,但在每种语言的每个库有不同的名称,同样的事情...

任何帮助AP preciated。

这里的一些code: Node.js的

  VAR密码=需要('密码')
变种密= crypto.createCipher('AES-128-CBC','somepass')
VAR文本=叔叔有一个小农场
VAR加密的= cipher.u​​pdate(文字,UTF8,十六进制)
加密的+ = cipher.final(十六进制)
//现在加密的包含密文的六角重新presentation
 

和java

 私有静态字符串解密(byte []的原料,byte []的加密)抛出异常{
    SecretKeySpec skeySpec =新SecretKeySpec(原AES);
    密密码= Cipher.getInstance(AES);
    cipher.init(Cipher.DECRYPT_MODE,skeySpec);
    byte []的解密= cipher.doFinal(加密);
    返回新的String(解密);
}
 

原始密钥是这样生成

 私有静态的byte [] getRawKey(字符串种子)抛出异常{
    的KeyGenerator kgen = KeyGenerator.getInstance(AES);
    SecureRandom的SR = SecureRandom.getInstance(SHA1PRNG);
    byte []的seedBytes = seed.getBytes()
    sr.setSeed(seedBytes);
    kgen.init(128,SR); // 192和256位可能无法使用
    SecretKey的SKEY = kgen.generateKey();
    byte []的原料= skey.getEn codeD();
    回归原始;
}
 
Node.js应用中常用安全保护机制和加密算法实现

而加密的十六进制字符串转换为字节像这样

 公共静态的byte [] toByte(字符串十六进制串){
    INT的len = hexString.length()/ 2;
    byte []的结果=新的字节[长度];
    的for(int i = 0; I< LEN;我++)
        结果[I] = Integer.valueOf(hexString.substring(2 * I,2 * I + 2),16).byteValue();
    返回结果;
}
 

解决方案

显然,如果你通过一个密码来 crypto.createCipher()它使用OpenSSL的 EVP_BytesToKey()派生密钥。您可以通过一个原始字节的缓冲区,并使用相同的初始化Java的 SecretKey的,或模仿 EVP_BytesToKey()在你的Java的code。使用 $男子EVP_BytesToKey 了解更多的细节,但本质上它散列密码多次使用MD5和并置的盐。

作为使用原始密钥,这样的事情应该让你使用原始密钥:

变种C = crypto.createCipheriv(AES-128-ECB,新的缓冲区(00010203050607080a0b0c0d0f101112,六角)的toString(二进制),);

请注意,由于您使用的是CBC,则需要使用相同IV加密和解密(你可能想将其追加到你的邮件,等等。)

强制性警告:实施加密协议,自己很少是一个好主意。即使你得到这个工作,你要使用相同的密钥的所有邮件?多长时间?如果您决定转动钥匙,怎么给你管理这个。等,.etc。

Looking for a way to encrypt data (mainly strings) in node and decrypt in an android app (java).

Have successfully done so in each one (encrypt/decrypt in node, and encrypt/decrypt in java) but can't seem to get it to work between them.

Possibly I'm not encrypting/decrypting in the same way, but each library in each language has different names for same things...

Any help appreciated.

here's some code: Node.js

var crypto = require('crypto')
var cipher = crypto.createCipher('aes-128-cbc','somepass')
var text = "uncle had a little farm"
var crypted = cipher.update(text,'utf8','hex')
crypted += cipher.final('hex')
//now crypted contains the hex representation of the ciphertext

and java

private static String decrypt(byte[] raw, byte[] encrypted) throws Exception {
    SecretKeySpec skeySpec = new SecretKeySpec(raw, "AES");
    Cipher cipher = Cipher.getInstance("AES");
    cipher.init(Cipher.DECRYPT_MODE, skeySpec );
    byte[] decrypted = cipher.doFinal(encrypted);
    return new String(decrypted);
}

the raw key is created like this

private static byte[] getRawKey(String seed) throws Exception {
    KeyGenerator kgen = KeyGenerator.getInstance("AES");
    SecureRandom sr = SecureRandom.getInstance("SHA1PRNG");
    byte[] seedBytes = seed.getBytes()
    sr.setSeed(seedBytes);
    kgen.init(128, sr); // 192 and 256 bits may not be available
    SecretKey skey = kgen.generateKey();
    byte[] raw = skey.getEncoded();
    return raw;
}

while the encrypted hex string is converted to bytes like this

public static byte[] toByte(String hexString) {
    int len = hexString.length()/2;
    byte[] result = new byte[len];
    for (int i = 0; i < len; i++)
        result[i] = Integer.valueOf(hexString.substring(2*i, 2*i+2), 16).byteValue();
    return result;
}

解决方案

Apparently if you pass a passphrase to crypto.createCipher() it uses OpenSSL's EVP_BytesToKey() to derive the key. You can either pass a raw byte buffer and use the same to initialize Java's SecretKey, or emulate EVP_BytesToKey() in your Java code. Use $ man EVP_BytesToKey for more details, but essentially it hashes the passphrase multiple times with MD5 and concatenates a salt.

As for using a raw key, something like this should let you use a raw key:

var c = crypto.createCipheriv("aes-128-ecb", new Buffer("00010203050607080a0b0c0d0f101112", "hex").toString("binary"), "");

Note that since you are using CBC, you need to use the same IV for encryption and decryption (you might want to append it to your message, etc.)

Mandatory warning: implementing a crypto protocol yourself is rarely a good idea. Even if you get this to work, are you going to use the same key for all messages? For how long? If you decide to rotate the key, how to you manage this. Etc, .etc.