vlambda博客
学习文章列表

使用 PBKDF2(和 Node.js)的对称密钥加密


使用 PBKDF2(和 Node.js)的对称密钥加密


波恩大学研究人员最近发表的一篇论文表明,许多开发者都在努力解决如何正确保护密码。


使用 PBKDF2(和 Node.js)的对称密钥加密


这项研究要求Freelance.com的260名Java开发人员编写能够安全存储密码的代码。最后,他们中的43人开始了这项工作。给定的任务是为一个虚假的社交媒体网站设置一个用户注册系统。其中39个是男性,1个是女性,其他人没有明确性别。37人有大学学历,平均有6.4年的Java编程经验:


使用 PBKDF2(和 Node.js)的对称密钥加密


为了评估在任务中获得更多报酬是否会提高安全性,小组中大约一半的人得到了100欧元,其余的人得到了200欧元。然后把他们按照是否提示他们使用给定的方法的分类方式进行分类:


  • 使用定义密码存储方法(P100),支付100欧元。

  • 使用定义密码存储方法(P200),支付200欧元。

  • 未定义密码存储方式(N200),支付200欧元。

  • 未定义密码存储方式(P200),支付200欧元。


通常情况下,开发人员需要3天左右的时间提交他们的工作,其中18人不得不重新提交他们的代码,因为他们使用的是明文密码。其中15个给出的理由是,规范中没有对安全密码存储提出要求,而其他3个只是重新提交了相同的明文密码。


使用 PBKDF2(和 Node.js)的对称密钥加密


最后,从安全性的角度来看,结果很糟糕,许多开发人员使用编码格式(Base64)、弱哈希(MD5和SHA-1)和弱密码加密(AES和3DES):


使用 PBKDF2(和 Node.js)的对称密钥加密


令人担忧的是,将近五分之一的人选择了一个甚至不是哈希方法的方法: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) => {
...}

在本例中,我们传递了一个密码、一个盐值和一个哈希方法。我们可以使用的一些典型哈希方法包括:


使用 PBKDF2(和 Node.js)的对称密钥加密


因此,对于密码为“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篇内容中,寻找思考更具深度、梳理更为系统的内容,以最快的速度同步到中国市场提供决策辅助材料。