問題描述
為了編寫一個(gè)簡單的 nodejs 應(yīng)用程序與用 java 編寫的服務(wù)器通信,我必須為 nodejs 實(shí)現(xiàn)以下功能.
In order to write an simple nodejs app talking to an server written in java I have to implement the following functionality for nodejs.
public class Crypto {
Cipher decipher;
byte[] salt = {
(byte) 0x01, (byte) 0x02, (byte) 0x03, (byte) 0x04,
(byte) 0x0A, (byte) 0x0B, (byte) 0x0C, (byte) 0x0D
};
int iterationCount = 10;
public Crypto(String pass) {
try {
KeySpec keySpec = new PBEKeySpec(pass.toCharArray(), salt, iterationCount);
SecretKey key = SecretKeyFactory.getInstance(
"PBEWithMD5AndTripleDES").generateSecret(keySpec);
ecipher = Cipher.getInstance("PBEWithMD5AndTripleDES/CBC/PKCS5Padding");
AlgorithmParameterSpec paramSpec = new PBEParameterSpec(salt, iterationCount);
decipher.init(Cipher.DECRYPT_MODE, key, paramSpec);
} catch (Exception ex) {
}
}
}
我使用 crypto
nodejs 的模塊
var crypto = require('crypto'),
pass = new Buffer(wek),
salt = new Buffer([0x01, 0x02, 0x03, 0x04, 0x0A, 0x0B, 0x0C, 0x0D])
password = 'mySecretPassword'
key = crypto.pbkdf2(pass, salt, 10, 256)
cipher,
encrypted;
cipher = crypto.createCipher('des-ede-cbc', key);
encrypted = cipher.update(new Buffer('the very secred information'));
將加密信息發(fā)送到服務(wù)器后,我無法使用上面 java 代碼示例中列出的 decipher
對象解密消息.我認(rèn)為主要問題是 md5
部分.我不知道如何使用 crypto
nodejs
模塊來實(shí)現(xiàn)它.有誰知道如何解決這個(gè)問題?或者是否有任何其他模塊或庫來實(shí)現(xiàn)這一點(diǎn)?
After sending the encrypted information to the server, I can't decrypt the message with the decipher
Object as listed in the java code sample above. I think the main problem is the md5
part. I can't figure out how to implement that with the crypto
nodejs
module. Has anyone an idea how to solve this problem? Or is ther any other module or library to achieve that?
我為 nodejs 嘗試了另一個(gè)模塊:node-forge
I tried another module for nodejs: node-forge
forge = require('node-forge')
var numIterations = 10,
keyLength = 24,
password = forge.util.createBuffer('mySecretPassword'),
salt = new forge.util.ByteBuffer(new Uint8Array([0x01, 0x02, 0x03, 0x04, 0x0A, 0x0B, 0x0C, 0x0D])),
derivedKey = forge.pkcs5.pbkdf2(password, salt.getBytes(), numIterations, keyLength, forge.md.md5.create())
iv = {}; // TODO... ???
var cipher = forge.des.createEncryptionCipher(derivedKey);
cipher.start(iv);
cipher.update('the very secred information');
cipher.finish();
var encrypted = cipher.output;
但我有幾個(gè)問題/疑問:
But I have several problems/questions:
- 我是否在 javascript 中使用了正確的算法?
salt
計(jì)算是否與java實(shí)現(xiàn)匹配?- 如何確定在 java 實(shí)現(xiàn)中使用了哪個(gè)
keyLength
? 初始化向量
在java實(shí)現(xiàn)中是如何產(chǎn)生的?在node-forge
的最后一個(gè)代碼示例中,我必須在cipher.start(iv)
上提供iv
.在 java 代碼中,我看不到這是如何完成的.我認(rèn)為客戶端和服務(wù)器上的iv
必須相同還是不正確?
- Do I use the correct algorithm in javascript?
- Is the
salt
calculation match with the java implementation? - How can I determine which
keyLength
is used in the java implementation? - How is the
initialization vector
generated in the java implementation? In the last code sample withnode-forge
I have to provide theiv
oncipher.start(iv)
. In the java code I can't see how this is done. In my opinion theiv
must be the same on client and server or is this incorrect?
推薦答案
我對 com.sun.crypto.provider.PBES1Core#deriveCipherKey() 處的密鑰派生函數(shù)的 DESede 部分進(jìn)行了逆向工程;
I reverse engineered the DESede part of the key derivation function found at com.sun.crypto.provider.PBES1Core#deriveCipherKey();
我們在 Java 服務(wù)器中使用 Jasypt 作為加密庫,我們的 node.js 服務(wù)器能夠使用它進(jìn)行加密和解密.我希望它有所幫助(用 ES2015 編寫,在 node v4.0.0 及更高版本中運(yùn)行):
We use Jasypt as encryption library in a Java server and our node.js server is able to encrypt and decrypt with this. I hope it helps (Written in ES2015, runs in node v4.0.0 and up):
'use strict';
var crypto = require('crypto');
class Encryption {
constructor() {
this.privateKey = new Buffer('<your password>', 'utf-8');
}
encrypt(message) {
var salt = crypto.randomBytes(8);
var key = this._generateKey(this.privateKey, salt);
var cipher = crypto.createCipheriv('des-ede3-cbc', this._subBuf(key, 0, 24), this._subBuf(key, 24));
var result = cipher.update(message, 'utf-8', 'hex');
return salt.toString('hex') + result + cipher.final('hex');
}
decrypt(message) {
var salt = new Buffer(message.substr(0, 16), 'hex');
var key = this._generateKey(this.privateKey, salt);
message = message.substr(16);
var decipher = crypto.createDecipheriv('des-ede3-cbc', this._subBuf(key, 0, 24), this._subBuf(key, 24));
var result = decipher.update(message, 'hex', 'utf-8');
return result + decipher.final('utf-8');
}
_generateKey(password, salt) {
if (!(password instanceof Buffer)) {
throw new Error('Password needs to be a buffer');
}
if (!(salt instanceof Buffer) || salt.length != 8) {
throw new Error('Salt needs to be an 8 byte buffer');
}
var iterations;
for(iterations = 0; iterations < 4 && salt[iterations] == salt[iterations + 4]; ++iterations) {}
if(iterations == 4) {
for(iterations = 0; iterations < 2; ++iterations) {
var tmp = salt[iterations];
salt[iterations] = salt[3 - iterations];
salt[2] = tmp; // Seems like an error that we have to live with now
}
}
var result = new Buffer(32);
for(iterations = 0; iterations < 2; ++iterations) {
var intermediate = new Buffer(salt.length / 2);
for (let i = 0; i < salt.length / 2; i++) {
intermediate[i] = salt[iterations * (salt.length / 2) + i];
}
for(let i = 0; i < 1000; ++i) {
var hash = crypto.createHash('md5');
hash.update(intermediate);
hash.update(password);
intermediate = hash.digest();
}
for (let i = 0; i<intermediate.length; i++) {
result[i + (iterations * 16)] = intermediate[i];
}
}
return result;
}
_subBuf(buffer, start, length) {
if (!length) {
length = buffer.length - start;
}
var result = new Buffer(length, 'hex');
for (let i = 0; i < length; i++) {
result[i] = buffer[i + start]
}
return result;
}
}
解釋一下發(fā)生了什么:
- 加密消息以十六進(jìn)制格式返回,其他內(nèi)容可能更適合您的實(shí)現(xiàn).
- _generateKey() 是來自 java 源代碼的直接副本.
- 使用的密鑰長度為 32 字節(jié),并假設(shè)前 24 個(gè)字節(jié)是 TripleDES 的密鑰,后 8 個(gè)字節(jié)是鹽
- 生成的消息以用于加密消息的隨機(jī)生成的鹽為前綴.
- 根據(jù) JVM 的安全設(shè)置,您可能實(shí)際上并未使用 des-ede3(cbc 似乎是一個(gè)固定設(shè)置).您絕對應(yīng)該仔細(xì)檢查這是否適用于您的設(shè)置.
這里可能需要清理一些代碼,但它至少應(yīng)該讓您朝著正確的方向開始.
Some code clean up might be necessary here, but it should at least get you started in the right direction.
這篇關(guān)于PBEWithMD5AndTripleDES/CBC/PKCS5Padding的Nodejs javascript實(shí)現(xiàn)的文章就介紹到這了,希望我們推薦的答案對大家有所幫助,也希望大家多多支持html5模板網(wǎng)!