java key iv,Node.js加密密钥和IV匹配Java SecretKeySpec / IvParameterSpec

I'm trying to to port a Java (simple) encryption algorythm to Node JS. I will need to be able to decrypt/encrypt stuff encrypted/decrypted from the Java side.

I'm stuck at the very beginning, the initialization of the cipher.

In Java, I get the key with SecretKeySpec, and the Initialization Vector with IvParameterSpec:

public CryptStuff(String password) throws zillion_exceptions {

if (password==null) throw new InvalidKeyException("No encryption password is set!");

key = new SecretKeySpec(password.getBytes("UTF-8"), "AES");

cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");

ivSpec=new IvParameterSpec(new byte[cipher.getBlockSize()]);

cipher.init(Cipher.ENCRYPT_MODE, key, ivSpec);

}

NodeJS requires a Key Buffer and an IV buffer, however, I don't know how to calculate them from scratch:

var mCrypto = require('crypto'),

key=[0,0,0,0,0,0,.......],

iv=[0,0,0,0,0,.........];

function init (password) {

// generate key from password

// generate IV from blocksize?

var aesCipher = mCrypto.createCipheriv("aes-????????", (new Buffer(key)), (new Buffer(iv)));

.

.

.

}

Also, what's the matching algorithm string for AES/CBC/PKCS5Padding?

解决方案

Assuming you have the same password string as in the Java code, you can create a key buffer like this in node:

var key = new Buffer(password, "utf8");

Since you're using a zero filled IV (bad!) in Java, this is the equivalent code in node:

var iv = new Buffer(16); // 16 byte buffer with random data

iv.fill(0); // fill with zeros

Since you're using CBC mode in Java, you have to do the same in node. Note that you have to select the correct key size when selecting the cipher string depending on your "password" length:

var aesCipher = mCrypto.createCipheriv("aes-128-cbc", key, iv);

// or

var aesCipher = mCrypto.createCipheriv("aes-192-cbc", key, iv);

// or

var aesCipher = mCrypto.createCipheriv("aes-256-cbc", key, iv);

Node will automatically apply PKCS#7 padding which is the same as PKCS#5 padding for AES.

A password is not a key!

A password has usually not the appropriate length to be used as a key (valid lengths are 16 byte, 24 byte and 32 byte for AES) and it is comprised of only printable characters which might make it easier for an attacker to brute force the key.

What you would need to create a key from a password is key derivation function. Popular ones are PBKDF2, bcrypt and scrypt (with increasing cost).

Random IV!

You really should be generating a new random IV for every ciphertext that you produce. If you use a static IV, an attacker that observes your ciphertexts can determine that you sent the same or even similar messages. If you use a random IV, then the ciphertexts differ so much that an attacker cannot determine whether two different ciphertexts where created from the same plaintext or not. This is called semantic security.

The random IV itself doesn't have to be secret, so you can easily prepend it to the ciphertext and slice it off before decryption.

You can even combine this with the key derivation function (KDF). Simply generate a random salt for the KDF. A KDF is usually able to derive a variable amount of output bytes, so simply let it derive key || IV (concatenation) and then split them. Now, you only need to prepend the salt to the ciphertext.

Authentication!

Depending on your system, you might be vulnerable to attacks such as the padding oracle attack. The best defense against this is to authenticate the ciphertext. So you can either use an encrypt-then-MAC scheme with a strong MAC such as HMAC-SHA256 or an authenticated mode of operation such as GCM or EAX. Java and node both support GCM, but there is a little more work involved.

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
您好!关于Java AES加解密,需要使用到密钥和初始化向量(IV)。下面是一个简单的示例代码: ```java import javax.crypto.Cipher; import javax.crypto.spec.IvParameterSpec; import javax.crypto.spec.SecretKeySpec; public class AesUtil { private static final String ALGORITHM = "AES/CBC/PKCS5Padding"; // 加密算法 private static final String CHARSET = "UTF-8"; // 编码方式 /** * 加密方法 * * @param content 待加密字符串 * @param key 密钥 * @param iv 初始化向量 * @return 加密后的字符串 * @throws Exception */ public static String aesEncrypt(String content, String key, String iv) throws Exception { Cipher cipher = Cipher.getInstance(ALGORITHM); SecretKeySpec keySpec = new SecretKeySpec(key.getBytes(CHARSET), "AES"); IvParameterSpec ivSpec = new IvParameterSpec(iv.getBytes(CHARSET)); cipher.init(Cipher.ENCRYPT_MODE, keySpec, ivSpec); byte[] encrypted = cipher.doFinal(content.getBytes(CHARSET)); return Base64.getEncoder().encodeToString(encrypted); } /** * 解密方法 * * @param content 待解密字符串 * @param key 密钥 * @param iv 初始化向量 * @return 解密后的字符串 * @throws Exception */ public static String aesDecrypt(String content, String key, String iv) throws Exception { Cipher cipher = Cipher.getInstance(ALGORITHM); SecretKeySpec keySpec = new SecretKeySpec(key.getBytes(CHARSET), "AES"); IvParameterSpec ivSpec = new IvParameterSpec(iv.getBytes(CHARSET)); cipher.init(Cipher.DECRYPT_MODE, keySpec, ivSpec); byte[] decrypted = cipher.doFinal(Base64.getDecoder().decode(content)); return new String(decrypted, CHARSET); } } ``` 其中,`aesEncrypt` 方法用于加密,`aesDecrypt` 方法用于解密。`key` 和 `iv` 参数分别为密钥和初始化向量,需要使用相同的 `key` 和 `iv` 才能成功解密。 使用示例: ```java public static void main(String[] args) throws Exception { String content = "Hello, AES!"; String key = "1234567890123456"; // 密钥长度必须为16/24/32位 String iv = "1234567890123456"; // 初始化向量长度必须为16位 String encrypted = AesUtil.aesEncrypt(content, key, iv); System.out.println("加密后:" + encrypted); String decrypted = AesUtil.aesDecrypt(encrypted, key, iv); System.out.println("解密后:" + decrypted); } ``` 输出结果: ``` 加密后:dS7U2yvJg3GRVTzB+TcHAA== 解密后:Hello, AES! ``` 注意,密钥长度必须为16/24/32位,初始化向量长度必须为16位。此外,加密算法使用的是`AES/CBC/PKCS5Padding`,这是一种安全可靠的加密方式,能够保证数据的机密性和完整性。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值