[英]how to show error when wrong password is given NodeJS crypto - createDecipheriv and pbkdf2
創建了一個加密文本的簡單應用程序,但是當給出錯誤的密碼或鹽時,我如何顯示錯誤。 在repli上托管它。 但是當我輸入錯誤的密碼或鹽時,它只會解密它。 crypto.createDecipheriv()在加密中沒有回調或函數
const app = {
encrypt(text, password, salt) {
password = password.repeat(32).substr(0, 32);
salt = salt.repeat(16).substr(0, 16);
crypto.pbkdf2(password, salt, 10, 16, 'sha512', (err, key) => {
if (err) {
console.log(err);
} else {
key = key.toString('hex');
const cipher = crypto.createCipheriv('aes-256-gcm', key, salt);
let encrypted = cipher.update(text, 'utf8', 'hex');
console.log(encrypted);
}
});
},
decrypt(text, password, salt) {
password = password.repeat(32).substr(0, 32);
salt = salt.repeat(16).substr(0, 16);
crypto.pbkdf2(password, salt, 10, 16, 'sha512', (err, key) => {
if (err) {
console.log(err);
} else {
key = key.toString('hex');
const cipher = crypto.createDecipheriv('aes-256-gcm', key, salt);
let decrypted = cipher.update(text, 'hex', 'utf8');
console.log(decrypted);
}
});
}
}
const message = 'Hello World';
app.encrypt(message, 'password', 'salt');
const cipherText = 'a0a4e0ad97133494856502';
app.decrypt(cipherText, 'password', 'salt');
GCM在加密時會生成一個認證標簽(默認為16字節),用於解密時的認證。
一些庫(例如Java)在加密期間隱式連接密文和標簽(ciphertext|tag),並在解密期間隱式分離兩者(這並不重要,因為標簽不是秘密的)。
另一方面,NodeJS 的加密模塊獨立處理密文和標簽,因此必須明確考慮標簽。 它可以在使用getAuthTag()
加密期間確定,並且必須在使用setAuthTag()
解密期間設置。 發布的代碼中都缺少兩者。
同樣缺少的是在加密時生成標簽並在解密時執行身份驗證的final()
調用。
為了在此示例中將標簽傳遞給解密,以下修復在加密期間將標簽與密文連接起來,並在解密期間將其分開(遵循 Java 模式)。
如果這些問題得到解決,則解密適用於正確的數據,並為不正確的數據顯示相應的消息: Error: Unsupported state or unable to authenticate data.
修復代碼,詳情見評論:
const crypto = require('crypto');
const app = {
encrypt(text, password, salt) {
password = password.repeat(32).substr(0, 32);
salt = salt.repeat(16).substr(0, 16);
crypto.pbkdf2(password, salt, 10, 16, 'sha512', (err, key) => {
if (err) {
console.log(err);
} else {
key = key.toString('hex');
const cipher = crypto.createCipheriv('aes-256-gcm', key, salt);
let encrypted = cipher.update(text, 'utf8', 'hex') + cipher.final('hex'); // Fix 1a: call final(): create tag
let tag = cipher.getAuthTag(); // Fix 2a: get tag
console.log(encrypted + tag.toString('hex')); // Fix 3a: concat ciphertext and tag
}
});
},
decrypt(text, password, salt) {
var tag = Buffer.from(text.substr(-32, 32), 'hex'); // Fix 3b: Separate ciphertext and tag
var ciphertext = text.substr(0, text.length - 32);
password = password.repeat(32).substr(0, 32);
salt = salt.repeat(16).substr(0, 16);
crypto.pbkdf2(password, salt, 10, 16, 'sha512', (err, key) => {
if (err) {
console.log(err);
} else {
key = key.toString('hex');
const cipher = crypto.createDecipheriv('aes-256-gcm', key, salt);
cipher.setAuthTag(tag); // Fix 2b: set tag
try {
let decrypted = cipher.update(ciphertext, 'hex', 'utf8') + cipher.final('utf8'); // Fix 1b: call final(): authenticate
console.log(decrypted);
} catch (e) {
console.log("Authentication failed!");
}
}
});
}
}
const message = 'Hello World';
app.encrypt(message, 'password', 'salt');
const cipherText = 'a0a4e0ad971334948565023568ae285d45b9cefc80abe3afcf9155';
app.decrypt(cipherText, 'password', 'salt');
app.decrypt(cipherText, 'password123', 'salt');
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.