为了编写一个简单的nodejs app与用java编写的服务器交谈,我必须为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
module of 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'));
在将加密信息发送到服务器之后,我无法使用上面java代码示例中列出的decipher
对象解密消息。我认为主要问题是md5
部分。我无法弄清楚如何使用crypto
nodejs
模块实现该功能。有谁知道如何解决这个问题?或者是其他任何模块或库来实现这一目标吗?
编辑:我为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;
但我有几个问题/问题:
salt
计算是否与java实现匹配?keyLength
? initialization vector
?在使用node-forge
的最后一个代码示例中,我必须在iv
上提供cipher.start(iv)
。在java代码中,我无法看到这是如何完成的。在我看来,iv
在客户端和服务器上必须是相同的,或者这是不正确的?答案 0 :(得分:2)
我反向设计了com.sun.crypto.provider.PBES1Core#derivedveCipherKey();
中的密钥派生函数的DESede部分。我们在Java服务器中使用Jasypt作为加密库,我们的node.js服务器可以使用它加密和解密。我希望它有所帮助(在ES2015中编写,在节点v4.0.0及更高版本中运行):
'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;
}
}
要解释一下发生了什么:
这里可能需要清理一些代码,但至少应该让你从正确的方向开始。
答案 1 :(得分:0)
我5年前的最终解决方案是:
var forge = require('node-forge');
var crypto = require('crypto');
var base64Coder = require('./utils/tac-base64coder');
var ByteBuffer = forge.util.ByteBuffer;
var DES_EDE_KEY_LEN = 24;
var DES_BLOCK_SIZE = 8;
var SALT_BYTES = [0x45, 0xC4, 0x31, 0x72, 0x8A, 0x62, 0xB3, 0x9A];
var KEY_BUFFER_LENGTH = 24;
var IV_BUFFER_LENGTH = 8;
module.exports = {
/**
* Generates the derived key. The 16 bytes of the first digest and the 1st 8 bytes of the 2nd digest
* form the triple DES key, and the last 8 bytes of the 2nd digest form the IV.
*
* @method _deriveCipherKey
* @param {String} key The key phrase
* @param {Int8Array} salt The salt
* @param {Number} iCount The iteration count
* @returns {Buffer}
* @private
*/
_deriveCipherKey: function _deriveCipherKey (key, salt, iCount) {
var md;
var passwdBytes = new Buffer(key);
var i;
var toBeHashed;
var result = new Buffer(DES_EDE_KEY_LEN + DES_BLOCK_SIZE);
result.fill(0);
// if the 2 salt halves are the same, invert one of them
for (i = 0; i < 4; i++) {
if (salt[i] !== salt[i + 4]) {
break;
}
}
if (i === 4) { // same, invert 1st half
for (i = 0; i < 2; i++) {
var tmp = salt[i];
salt[i] = salt[3 - i];
salt[3 - 1] = tmp;
}
}
for (i = 0; i < 2; i++) {
toBeHashed = new Buffer(salt.length / 2);
toBeHashed.fill(0);
salt.copy(toBeHashed, 0, i * (salt.length / 2));
for (var j = 0; j < iCount; j++) {
md = crypto.createHash('md5');
md.update(toBeHashed);
md.update(passwdBytes);
toBeHashed = md.digest();
}
toBeHashed.copy(result, i * 16);
}
return result;
},
/**
* Encrypts the given string with the given key
*
* @method encrypt
* @param {String} encryptionKey The encryption key
* @param {String} toEncrypt The string to encrypt
* @returns {String}
*/
encrypt: function encrypt (encryptionKey, toEncrypt) {
var encodedStr = forge.util.encodeUtf8(toEncrypt);
var salt = new Buffer(SALT_BYTES);
var key = new Buffer(KEY_BUFFER_LENGTH);
var iv = new Buffer(IV_BUFFER_LENGTH);
var key2 = new ByteBuffer();
var iv2 = new ByteBuffer();
var derivedKey = this._deriveCipherKey(encryptionKey, salt, 12);
var cipher;
var i = 0;
derivedKey.copy(key, 0, 0, 24);
derivedKey.copy(iv, 0, 24);
for (; i < KEY_BUFFER_LENGTH; i++) {
key2.putByte(key[i]);
}
for (i = 0; i < IV_BUFFER_LENGTH; i++) {
iv2.putByte(iv[i]);
}
cipher = forge.des.createEncryptionCipher(key2);
cipher.start(iv2);
cipher.update(forge.util.createBuffer(encodedStr));
cipher.finish();
return base64Coder.encode(cipher.output.getBytes().toString());
},
/**
* Decrypts the given base64 string with the given key
*
* @method decrypt
* @param {String} encryptionKey The decryption key
* @param {String} toDecrypt The encrypted base64 string
* @returns {String}
*/
decrypt: function decrypt (encryptionKey, toDecrypt) {
var decr = forge.util.decode64(toDecrypt);
var salt = new Buffer(SALT_BYTES);
var key = new Buffer(KEY_BUFFER_LENGTH);
var iv = new Buffer(IV_BUFFER_LENGTH);
var derivedKey = this._deriveCipherKey(encryptionKey, salt, 12);
var key2 = new forge.util.ByteBuffer();
var iv2 = new forge.util.ByteBuffer();
var i = 0;
var cipher;
derivedKey.copy(key, 0, 0, 24);
derivedKey.copy(iv, 0, 24);
for (; i < KEY_BUFFER_LENGTH; i++) {
key2.putByte(key[i]);
}
for (i = 0; i < IV_BUFFER_LENGTH; i++) {
iv2.putByte(iv[i]);
}
cipher = forge.des.createDecryptionCipher(key2);
cipher.start(iv2);
cipher.update(forge.util.createBuffer(decr));
cipher.finish();
return cipher.output.getBytes().toString('utf8');
}
};