使用 PBKDF2(和 Node.js)的对称密钥加密
波恩大学研究人员最近发表的一篇论文表明,许多开发者都在努力解决如何正确保护密码。
这项研究要求Freelance.com的260名Java开发人员编写能够安全存储密码的代码。最后,他们中的43人开始了这项工作。给定的任务是为一个虚假的社交媒体网站设置一个用户注册系统。其中39个是男性,1个是女性,其他人没有明确性别。37人有大学学历,平均有6.4年的Java编程经验:
为了评估在任务中获得更多报酬是否会提高安全性,小组中大约一半的人得到了100欧元,其余的人得到了200欧元。然后把他们按照是否提示他们使用给定的方法的分类方式进行分类:
使用定义密码存储方法(P100),支付100欧元。
使用定义密码存储方法(P200),支付200欧元。
未定义密码存储方式(N200),支付200欧元。
未定义密码存储方式(P200),支付200欧元。
通常情况下,开发人员需要3天左右的时间提交他们的工作,其中18人不得不重新提交他们的代码,因为他们使用的是明文密码。其中15个给出的理由是,规范中没有对安全密码存储提出要求,而其他3个只是重新提交了相同的明文密码。
最后,从安全性的角度来看,结果很糟糕,许多开发人员使用编码格式(Base64)、弱哈希(MD5和SHA-1)和弱密码加密(AES和3DES):
令人担忧的是,将近五分之一的人选择了一个甚至不是哈希方法的方法:Base64。Base64的安全性是零,因为它是一种编码方法。密码的哈希和以加扰形式的编码之间经常被混淆。对于那些使用Base64的人,说辞是:
对其进行加密,使清晰的密码不可见
很难解密
总的来说,研究人员发现,开发人员通常不知道哈希和加密之间的区别。当要对密码进行“盐化”时,43人中只有15人选择了“盐化”,而这43人中有17人从其他网站复制了代码。研究人员还发现,给开发人员更多的报酬并不能产生更好的代码。该研究还强调出,对加密和哈希的知识掌握普遍还不是很好,许多人无法区分这两者。
所以让我们自己保护密码。
保护密码的一种方法是进行加密,并使用一种慢速哈希方法,如PBKDF2。我们会发现PBKDF2是用来保护wi-fi系统密码的方法。所以让我们使用Node.js来进行一系列加密算法使其最终实现加密,然后根据密码、盐值和给定的哈希方法来生成加密密钥:
const crypto = require("crypto");
var message="Hello";
var algorithm="aes-128-cbc";
var password="qwerty";
var hash="sha256";
var salt="salt";
var args = process.argv;
if (args.length>2) message=args[2];
if (args.length>3) algorithm=args[3];
if (args.length>4) password=args[4];
if (args.length>5) hash=args[5];
if (args.length>6) salt=args[6];
var key=crypto.randomBytes(16);
var iv = crypto.randomBytes(16);
var err=null;
keysize=16;
if (algorithm.indexOf("256")>-1) {
keysize=32;
}
if (algorithm.indexOf("cha")>-1) {
keysize=32;
}
if (algorithm.indexOf("bf")>-1) {
iv = crypto.randomBytes(8);
}
if (algorithm.indexOf("cast")>-1) {
iv = crypto.randomBytes(8);
}
if (algorithm.indexOf("des-")>-1) {
iv = crypto.randomBytes(8);
keysize=8;
}
if (algorithm.indexOf("ecb")>-1) {
iv = null;
}
crypto.pbkdf2(password, salt, 100, keysize, hash, (err, key) => {
const cipher = crypto.createCipheriv(algorithm, Buffer.from(key),iv);
let encrypted = cipher.update(message);
encrypted = Buffer.concat([encrypted, cipher.final()]);
const decipher = crypto.createDecipheriv(algorithm, Buffer.from(key),iv);
let decrypted = decipher.update(encrypted);
decrypted = Buffer.concat([decrypted, decipher.final()]);
console.log("Message: ",message);
console.log("\nEncryption Algorithm: ",algorithm);
if (iv!=null) console.log(" IV:\t",iv.toString('hex'));
console.log("\nPassword:\t",password);
console.log(" Hashing:\t",hash);
console.log(" Salt:\t\t",salt);
console.log("\nDerived Key:\t",key.toString('hex'));
console.log("\nEncrypted:\t",encrypted.toString('hex'));
console.log("Encrypted:\t",encrypted.toString('base64'));
console.log("\nDecrypted:\t",decrypted.toString());
});
在这种情况下,为了生成密钥,我们使用回调函数,调用PBKDF2函数,然后当它完成时,回调括号中定义的代码:
crypto.pbkdf2(password, salt, 100, keysize, hash, (err, key) => {
...}
在本例中,我们传递了一个密码、一个盐值和一个哈希方法。我们可以使用的一些典型哈希方法包括:
因此,对于密码为“qwerty”,哈希方法为“SHA-1”,盐值为“salt123”,我们得到以下16字节的键:
Password: qwerty
Hashing: sha1
Salt: salt123Derived
Key: 8b8c9613f705303540f4f52cd4393b0f
密钥的大小显然取决于我们想要使用的加密方法,因此128位密钥需要16个字节,256位密钥需要32个字节。keysize的值被传递给函数:
crypto.pbkdf2(password, salt, 100, keysize, hash, (err, key) => {
...}
现在我们需要选择加密方法。在大多数情况下,我们将使用AES或ChaCha20,但还有很多选择:
为此,在Node.js中,我们的每个方法都有一个标签,例如“AES -256- CBC”,用于CBC模式的256位AES。让我们试一试:
https://asecuritysite.com/node/node_encrypt2
对于128位AES-CTR:
Message: TestEncryption Algorithm: aes-128-ctr
IV: d8e6e5de3d11ab945595c2297a406ee4Password: qwerty
Hashing: sha1
Salt: salt123Derived
Key: 8b8c9613f705303540f4f52cd4393b0fEncrypted: 74247bc0
Encrypted: dCR7wA==Decrypted: Test
对于256位AES OFB:
Message: TestEncryption Algorithm: aria-256-ofb
IV: 4f7f8ccd91279504377745fa10cbdfc9Password: qwerty
Hashing: sha1
Salt: salt123Derived Key: 8b8c9613f705303540f4f52cd4393b0f9298aee6eadc3c41960b0301b019aca3Encrypted: a4be0b31
Encrypted: pL4LMQ==Decrypted: Test
加密和解密部分,我们基本上是先加密一个字符串(消息),然后用以下方法解密密文:
const cipher = crypto.createCipheriv(algorithm, Buffer.from(key),iv);
let encrypted = cipher.update(message);
encrypted = Buffer.concat([encrypted, cipher.final()]);
const decipher = crypto.createDecipheriv(algorithm, Buffer.from(key),iv);
请注意,加密密钥的大小是 256 位版本的两倍,是 128 位密钥大小的两倍。
Source:https://medium.com/@billatnapier/symmetric-key-encryption-with-pbkdf2-and-node-js-846ac57901c1
关于
ChinaDeFi - ChinaDeFi.com 是一个研究驱动的DeFi创新组织,同时我们也是区块链开发团队。每天从全球超过500个优质信息源的近900篇内容中,寻找思考更具深度、梳理更为系统的内容,以最快的速度同步到中国市场提供决策辅助材料。