nodejs AES/GCM/NoPadding 加密
nodejs AES/GCM/NoPadding encryption
我参考了 中提到的 nodejs 加密,我可以加密并在解密时收到错误“错误:不支持的状态或无法验证数据”
var crypto = require('crypto');
console.log('AES GCMC 256 String encryption with PBKDF2 derived key');
var plaintext = 'The quick brown fox jumps over the lazy dog';
console.log('plaintext: ', plaintext);
const cryptoConfig = {
cipherAlgorithm: 'aes-256-gcm',
masterKey: 'somekey',
iterations: 65535,
keyLength: 32,
saltLength: 16,
ivLength: 12,
tagLength: 16,
digest: 'sha512'
}
var ciphertext = encrypt(plaintext);
console.log('ciphertext: ', ciphertext);
decrypt(ciphertext)
function encrypt(content) {
const salt = crypto.randomBytes(cryptoConfig.saltLength);
console.log("salt : ", salt)
const iv = crypto.randomBytes(cryptoConfig.ivLength);
console.log("iv : ", iv)
const key = crypto.pbkdf2Sync(cryptoConfig.masterKey, salt, cryptoConfig.iterations,
cryptoConfig.keyLength, cryptoConfig.digest);
const cipher = crypto.createCipheriv(cryptoConfig.cipherAlgorithm, key, iv);
const encrypted = Buffer.concat([cipher.update(content, 'utf8'), cipher.final()]);
const tag = cipher.getAuthTag();
console.log("tag : ", tag)
// ### put the auth tag at the end of encrypted
//const encdata = Buffer.concat([salt, iv, tag, encrypted]).toString('base64');
const encdata = Buffer.concat([salt, iv, encrypted, tag]).toString('base64');
return encdata;
}
function decrypt(encdata){
///decrypt
// base64 decoding
const bData = Buffer.from(encdata, 'base64');
// convert data to buffers
const salt1 = bData.slice(0, 16);
const iv1 = bData.slice(16, 32);
const tag1 = bData.slice(32, 48);
const text1 = bData.slice(48);
// derive key using; 32 byte key length
// const key = crypto.pbkdf2Sync(cryptoConfig.masterkey, salt , 2145, 32, 'sha512');
const key1 = crypto.pbkdf2Sync(cryptoConfig.masterKey, salt1, cryptoConfig.iterations,
cryptoConfig.keyLength, cryptoConfig.digest)
// AES 256 GCM Mode
const decipher = crypto.createDecipheriv('aes-256-gcm', key1, iv1);
decipher.setAuthTag(tag1);
// encrypt the given text
const decrypted = decipher.update(text1, 'binary', 'utf8') + decipher.final('utf8');
console.log(decrypted)
}
从错误来看,我在从加密数据中分离 IV、salt 时搞砸了,因此与加密时使用的内容不匹配。
这是我为我的跨平台加密博客编写的示例程序 - 这应该可以帮助您分离和传送 salt、iv 和 gcm 标签。
可在此处找到实时 运行 版本:https://replit.com/@javacrypto/CpcNodeJsCryptoAesGcm256Pbkdf2StringEncryption#index.js/
var crypto = require('crypto');
console.log('AES GCM 256 String encryption with PBKDF2 derived key');
var plaintext = 'The quick brown fox jumps over the lazy dog';
console.log('plaintext: ', plaintext);
var password = "secret password";
console.log('\n* * * Encryption * * *');
var ciphertextBase64 = aesGcmPbkdf2EncryptToBase64(password, plaintext);
console.log('ciphertext (Base64): ' + ciphertextBase64);
console.log('output is (Base64) salt : (Base64) nonce : (Base64) ciphertext : (Base64) gcmTag');
console.log('\n* * * Decryption * * *');
var ciphertextDecryptionBase64 = ciphertextBase64;
console.log('ciphertext (Base64): ', ciphertextDecryptionBase64);
console.log('input is (Base64) salt : (Base64) nonce : (Base64) ciphertext : (Base64) gcmTag');
var decryptedtext = aesGcmPbkdf2DecryptFromBase64(password, ciphertextBase64);
console.log('plaintext: ', decryptedtext);
function aesGcmPbkdf2EncryptToBase64(password, data) {
var PBKDF2_ITERATIONS = 15000;
var salt = generateSalt32Byte();
var key = crypto.pbkdf2Sync(password, salt, PBKDF2_ITERATIONS, 32, 'sha256');
var nonce = generateRandomNonce();
const cipher = crypto.createCipheriv('aes-256-gcm', key, nonce);
let encryptedBase64 = '';
cipher.setEncoding('base64');
cipher.on('data', (chunk) => encryptedBase64 += chunk);
cipher.on('end', () => {
// do nothing console.log(encryptedBase64);
// Prints: some clear text data
});
cipher.write(data);
cipher.end();
var saltBase64 = base64Encoding(salt);
var nonceBase64 = base64Encoding(nonce);
var gcmTagBase64 = base64Encoding(cipher.getAuthTag());
return saltBase64 + ':' + nonceBase64 + ':' + encryptedBase64 + ':' + gcmTagBase64;
}
function aesGcmPbkdf2DecryptFromBase64(password, data) {
var PBKDF2_ITERATIONS = 15000;
var dataSplit = data.split(":");
var salt = base64Decoding(dataSplit[0]);
var gcmTag = base64Decoding(dataSplit[3]);
var key = crypto.pbkdf2Sync(password, salt, PBKDF2_ITERATIONS, 32, 'sha256');
var nonce = base64Decoding(dataSplit[1]);
var ciphertext = dataSplit[2];
const decipher = crypto.createDecipheriv('aes-256-gcm', key, nonce);
decipher.setAuthTag(gcmTag);
let decrypted = '';
decipher.on('readable', () => {
while (null !== (chunk = decipher.read())) {
decrypted += chunk.toString('utf8');
}
});
decipher.on('end', () => {
// do nothing console.log(decrypted);
});
decipher.write(ciphertext, 'base64');
decipher.end();
return decrypted;
}
function generateSalt32Byte() {
return crypto.randomBytes(32);
}
function generateRandomNonce() {
return crypto.randomBytes(12);
}
function base64Encoding(input) {
return input.toString('base64');
}
function base64Decoding(input) {
return Buffer.from(input, 'base64')
}
我参考了
var crypto = require('crypto');
console.log('AES GCMC 256 String encryption with PBKDF2 derived key');
var plaintext = 'The quick brown fox jumps over the lazy dog';
console.log('plaintext: ', plaintext);
const cryptoConfig = {
cipherAlgorithm: 'aes-256-gcm',
masterKey: 'somekey',
iterations: 65535,
keyLength: 32,
saltLength: 16,
ivLength: 12,
tagLength: 16,
digest: 'sha512'
}
var ciphertext = encrypt(plaintext);
console.log('ciphertext: ', ciphertext);
decrypt(ciphertext)
function encrypt(content) {
const salt = crypto.randomBytes(cryptoConfig.saltLength);
console.log("salt : ", salt)
const iv = crypto.randomBytes(cryptoConfig.ivLength);
console.log("iv : ", iv)
const key = crypto.pbkdf2Sync(cryptoConfig.masterKey, salt, cryptoConfig.iterations,
cryptoConfig.keyLength, cryptoConfig.digest);
const cipher = crypto.createCipheriv(cryptoConfig.cipherAlgorithm, key, iv);
const encrypted = Buffer.concat([cipher.update(content, 'utf8'), cipher.final()]);
const tag = cipher.getAuthTag();
console.log("tag : ", tag)
// ### put the auth tag at the end of encrypted
//const encdata = Buffer.concat([salt, iv, tag, encrypted]).toString('base64');
const encdata = Buffer.concat([salt, iv, encrypted, tag]).toString('base64');
return encdata;
}
function decrypt(encdata){
///decrypt
// base64 decoding
const bData = Buffer.from(encdata, 'base64');
// convert data to buffers
const salt1 = bData.slice(0, 16);
const iv1 = bData.slice(16, 32);
const tag1 = bData.slice(32, 48);
const text1 = bData.slice(48);
// derive key using; 32 byte key length
// const key = crypto.pbkdf2Sync(cryptoConfig.masterkey, salt , 2145, 32, 'sha512');
const key1 = crypto.pbkdf2Sync(cryptoConfig.masterKey, salt1, cryptoConfig.iterations,
cryptoConfig.keyLength, cryptoConfig.digest)
// AES 256 GCM Mode
const decipher = crypto.createDecipheriv('aes-256-gcm', key1, iv1);
decipher.setAuthTag(tag1);
// encrypt the given text
const decrypted = decipher.update(text1, 'binary', 'utf8') + decipher.final('utf8');
console.log(decrypted)
}
从错误来看,我在从加密数据中分离 IV、salt 时搞砸了,因此与加密时使用的内容不匹配。
这是我为我的跨平台加密博客编写的示例程序 - 这应该可以帮助您分离和传送 salt、iv 和 gcm 标签。
可在此处找到实时 运行 版本:https://replit.com/@javacrypto/CpcNodeJsCryptoAesGcm256Pbkdf2StringEncryption#index.js/
var crypto = require('crypto');
console.log('AES GCM 256 String encryption with PBKDF2 derived key');
var plaintext = 'The quick brown fox jumps over the lazy dog';
console.log('plaintext: ', plaintext);
var password = "secret password";
console.log('\n* * * Encryption * * *');
var ciphertextBase64 = aesGcmPbkdf2EncryptToBase64(password, plaintext);
console.log('ciphertext (Base64): ' + ciphertextBase64);
console.log('output is (Base64) salt : (Base64) nonce : (Base64) ciphertext : (Base64) gcmTag');
console.log('\n* * * Decryption * * *');
var ciphertextDecryptionBase64 = ciphertextBase64;
console.log('ciphertext (Base64): ', ciphertextDecryptionBase64);
console.log('input is (Base64) salt : (Base64) nonce : (Base64) ciphertext : (Base64) gcmTag');
var decryptedtext = aesGcmPbkdf2DecryptFromBase64(password, ciphertextBase64);
console.log('plaintext: ', decryptedtext);
function aesGcmPbkdf2EncryptToBase64(password, data) {
var PBKDF2_ITERATIONS = 15000;
var salt = generateSalt32Byte();
var key = crypto.pbkdf2Sync(password, salt, PBKDF2_ITERATIONS, 32, 'sha256');
var nonce = generateRandomNonce();
const cipher = crypto.createCipheriv('aes-256-gcm', key, nonce);
let encryptedBase64 = '';
cipher.setEncoding('base64');
cipher.on('data', (chunk) => encryptedBase64 += chunk);
cipher.on('end', () => {
// do nothing console.log(encryptedBase64);
// Prints: some clear text data
});
cipher.write(data);
cipher.end();
var saltBase64 = base64Encoding(salt);
var nonceBase64 = base64Encoding(nonce);
var gcmTagBase64 = base64Encoding(cipher.getAuthTag());
return saltBase64 + ':' + nonceBase64 + ':' + encryptedBase64 + ':' + gcmTagBase64;
}
function aesGcmPbkdf2DecryptFromBase64(password, data) {
var PBKDF2_ITERATIONS = 15000;
var dataSplit = data.split(":");
var salt = base64Decoding(dataSplit[0]);
var gcmTag = base64Decoding(dataSplit[3]);
var key = crypto.pbkdf2Sync(password, salt, PBKDF2_ITERATIONS, 32, 'sha256');
var nonce = base64Decoding(dataSplit[1]);
var ciphertext = dataSplit[2];
const decipher = crypto.createDecipheriv('aes-256-gcm', key, nonce);
decipher.setAuthTag(gcmTag);
let decrypted = '';
decipher.on('readable', () => {
while (null !== (chunk = decipher.read())) {
decrypted += chunk.toString('utf8');
}
});
decipher.on('end', () => {
// do nothing console.log(decrypted);
});
decipher.write(ciphertext, 'base64');
decipher.end();
return decrypted;
}
function generateSalt32Byte() {
return crypto.randomBytes(32);
}
function generateRandomNonce() {
return crypto.randomBytes(12);
}
function base64Encoding(input) {
return input.toString('base64');
}
function base64Decoding(input) {
return Buffer.from(input, 'base64')
}