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

保护密码的一种方法是进行加密,并使用一种慢速哈希方法,如PBKDF2。我们会发现PBKDF2是用来保护wi-fi系统密码的方法。所以让我们使用Node.js来进行一系列加密算法使其最终实现加密,然后根据密码、盐值和给定的哈希方法来生成加密密钥:

1.jpg

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

2.jpg

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

3.jpg

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

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

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

4.jpg

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

5.jpg

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

...}

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

6.jpg

因此,对于密码为“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,但还有很多选择:

7.jpg

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

本文首发于:https://mp.weixin.qq.com/s/TAVT0NHBW2QucbKMkbz3CA

点赞 0
收藏 0
分享
本文参与登链社区写作激励计划 ,好文好收益,欢迎正在阅读的你也加入。

0 条评论

请先 登录 后评论
ChinaDeFi 去中心化金融社区
ChinaDeFi 去中心化金融社区
ChinaDeFi.com 是一个研究驱动的DeFi创新组织,同时我们也是区块链开发团队。每天从全球超过500个优质信息源的近900篇内容中,寻找思考更具深度、梳理更为系统的内容,以最快的速度同步到中国市场提供决策辅助材料。