理清弄透:加密&解密、签名&验签_Bob

标签: | 发表时间:2021-07-18 09:40 | 作者:
出处:https://www.sohu.com

加密&解密、签名&验签,在区块链、钱包等领域应用甚广,背后的原理或细节是什么?这里通过图文并茂的故事,外加撸代码的方式,一起理清弄透这4个概念。

一、故事角色和人设

正式开始之前,先介绍一下本文的主人翁Bob。他有2把秘钥:公钥、私钥;生活中,他会遇到3种类型的人:朋友Alice、骗子Doug、可信任的公证人CA。Bob的公钥是公开的,所有人都可见,私钥仅Bob自己可见。

  • Bob有2把秘钥:公钥BobPub、私钥BobPri

  • Bob会遇到3类人:Alice、CA、Doug是每类的代表

二、对称加密&解密

故事角色和人设交代清楚后,主人翁Bob遇到了第一个棘手难题:平时通过一款聊天App与朋友Alice联系,某一天收到一份神秘邮件,里面明文写满了历史聊天内容。吓一大跳,还好没聊隐私的事情。惊吓之后,Bob想到了第一个办法:

  • 棘手难题1:明文聊天,网络传输过程中被劫持,有窃听风险;
  • 解决办法1:与Alice约定一个暗号串,对聊天消息加密后再发送;

→ 具体操作步骤如下:

  1. Alice 与 Bob 两人事先约定一个共用密钥key;
  2. Alice 将消息用key加密,将密文邮递给 Bob;
  3. Bob 收到密文后,用key解密,看到明文;

→ 这个过程用到的其实是密码学中的对称加密,实现代码如下:

var crypto = require('crypto');
// Encrypt
function encrypt(str, key) {
    var cipher = crypto.createCipher('aes192', key);
    var enc = cipher.update(str, 'utf8', 'hex');
    enc += cipher.final('hex');
    return enc;
    }

// Decrypt
function decrypt(str, key) {
    var decipher = crypto.createDecipher('aes192', key);
    var dec = decipher.update(str, 'hex', 'utf8');
    dec += decipher.final('utf8');
    return dec;
    }

var msg = 'Hey Bob, how about lunch at Taco Bell.';

// Both Bob and Alice have the same keyvarkey = 'aceport';

// Aliceen
crypted_msg = encrypt(msg, key);
console.log(encrypted_msg);

// Bob 
decrypted_msg = decrypt(encrypted_msg, key);
console.log(decrypted_msg);

三、非对称加密&解密

Alice是个开朗的姑娘,朋友很多,很快把Bob发明的加密聊天传播给了其它朋友。同时,Alice又是个粗心的姑娘,与所有朋友聊天都用了同一个暗号串。美好的日子没过多久,Bob又收到一份神秘邮件,里面除了满写满了明文聊天内容之外,还多了一串👻👻👻。大惊之后,Bob找极客朋友请教,找到了克服暗号串误漏的方法:

  • 棘手难题2:共用秘钥key极易泄漏,最终导致消息内容泄漏;
  • 解决办法2:使用基于公钥+私钥的非对称加密算法;

→ 具体操作步骤如下:

  1. Alice 将消息用Bob公钥BobPub加密,将密文邮递给 Bob;
  2. Bob 收到密文后,用自己的私钥BobPri解密,看到明文;

→ 非对称加密算法,实现代码如下:

const ursa = require('ursa');
const fs = require('fs');
msg = "Hey Bob, how about lunch at Taco Bell.";

// Alice has Bob's public key 
var BobPub = ursa.createPublicKey(fs.readFileSync('./key/BobPub'));
console.log('Encrypt with Bob Public Key');
encrypted_msg = BobPub.encrypt(msg, 'utf8', 'base64');
console.log('encrypted:', encrypted_msg, 'n');

// Bob has his private key
var BobPri = ursa.createPrivateKey(fs.readFileSync('./key/BobPri'));
decrypted_msg = BobPri.decrypt(encrypted_msg, 'base64', 'utf8');
console.log('decrypted:', decrypted_msg, 'n');

四、签名&验签

自从用了非对称加密消息,由于其它人没有Bob的私钥,无法解密,再没收到神秘邮件。为解被调戏之辱,Bob决定向神秘人回了一封38个👻表情符号的邮件。

对抗与反对抗的博弈总是在进行,静好舒畅一段时间后,Bob发现收到朋友Alice的消息,解密后全是38个👻表情符号。很明显,Alice发的消息,在传输过程中被篡改了。大惊之后,Bob再次找极客朋友请教,再次找到防篡改的方法:

  • 棘手难题3:消息被篡改,完整性有问题,有篡改风险;
  • 解决办法3:使用签名+验签算法;

→ 具体操作步骤如下,Bob和Alice分别做如下操作:

Bob做如下操作:

  1. Bob对消息内容做hash,得到指纹Message Digest;
  2. Bob用私钥对Message Digest签名,得到Signature;
  3. Bob将签名Signature,附到消息尾部,一并发给Alice;

Alice收到消息后,做如下操作:

  1. 取出消息的正文,做hash得到Message Digest;
  2. 从消息底部取出Signature;
  3. 调用验证函数Verify(Message Digest, Signature)计算得到key;
  4. 将key与本地保存的Bob公钥进行比较:若key==BobPub,则验证成功;否则,验证失败,消息被篡改过,或消息来源不是Bob;

→ 签名和验签算法,实现代码如下:

const ursa = require('ursa');
const fs = require('fs');
msg = "IT’S A SECRET TO Alice.";

// 1. Bob// Bob has his private key and Alice's public key
var BobPri = ursa.createPrivateKey(fs.readFileSync('./key/BobPri'));
var AlicePub = ursa.createPublicKey(fs.readFileSync('./key/AlicePub'));
console.log('1. Encrypt with Alice Public; Sign with Bob Private');
var encrypted_msg = AlicePub.encrypt(msg, 'utf8', 'base64');
var signiture = BobPri.hashAndSign('sha256', msg, 'utf8', 'base64');
console.log('encrypted: ', encrypted_msg);
console.log('signed: ', signiture, 'n');

// 2. Alice// Alice has her private key and Bob's public key
var AlicePri = ursa.createPrivateKey(fs.readFileSync('./key/AlicePri'));
var BobPub = ursa.createPublicKey(fs.readFileSync('./key/BobPub'));
console.log('2. Decrypt with Alice Private; Verify with Bob Public');
var decrypted_msg = AlicePri.decrypt(encrypted_msg, 'base64', 'utf8');
if(msg !== decrypted_msg) {
    throw new Error("invalid decrypt");
} else{
    console.log('decrypted: ', decrypted_msg);
}

decrypted_msg = new Buffer(decrypted_msg).toString('base64');
if(!BobPub.hashAndVerify('sha256', decrypted_msg, signiture, 'base64')) {
    throw new Error("invalid signature");
} else{
    console.log('Bob Signature?', true, 'n');
}

五、数字证书

在一些列对抗中,神秘人Doug发现Bob是个硬茬,而Alice是只小白鼠。于是在一个月黑风高的夜晚,入侵了Alice的电脑,用自己的公钥替换了Bob的公钥文件。第二天,Alice打开电脑,收到Doug伪装成Bob发来的签过名的消息,聊天App调用本地的假Bob公钥验签,通过。从此,Doug可顺利冒充Bob了:

  • Doug用自己的私钥做成"数字签名",发消息给Alice,让她做转账等操作;
  • 收到消息后,Alice用假的Bob公钥进行验签通过,从而被骗;

人终究比机器聪明智慧,Alice被骗几次后,从蛛丝马迹中觉察到了:自己电脑中的Bob公钥有问题,可能是假的。于是,她找Bob,一起找到了德高望重的公证人CA,给出来解决方法:

  • 棘手难题4:用户电脑被入侵,公钥被替换,有冒充风险;
  • 解决办法4:使用数字证书,防止公钥被篡改;

→ 具体操作步骤如下:

  • 证书中心CA用自己的私钥,对Bob的公钥和一些相关信息一并签名,生成"数字证书Digital Certificate"给Bob;
  • Bob拿到Digital Certificate后:每次发送消息时,除了给消息附上签名,还附上数字证书;

  • Alice收到信息后:先用CA的公钥验证数字证书,进而取到Bob的真实公钥,最后就能验证Signature及消息;

六、拓展:Https协议

Bob、Alice、Doug、CA四种角色,几乎可以拓展到绝大多数的安全场景。比如Bob为服务方,Doug为钓鱼网站,Alice为普通用户,CA为SSL证书颁发中心,就可以拓展出Https协议的雏形:

  • 服务端Bob,将域名xxxxxx.com(相当于Bob的公钥),拿去向SSL证书中心购买数字证书: crt private、crt public, 并将所购证书配置到官网的nginx服务;
  • 客户端用户Alice访问网站xxxxxx.com时,服务端将数字证书附在报文一并返回。浏览器调用预置的SSL证书中心的根证书对数字证书验签,算出服务端的公钥。若算出的公钥,与浏览器当前访问域名不同,则给用户发出“当前访问网站不安全”的警告,如下图1~4步骤所示;
  • 钓鱼网站由于没有xxxxxx.com的数字证书,所以无法伪装成服务端Bob;

Https协议非常复杂,这里不深入讲述,感兴趣的朋友可带着如下问题,深入研究:

  • 数字证书,保存在哪里?
  • CA的公钥,与根证书是什么关系?保存在哪里?
  • 证书颁发机构、网站nginx配置、浏览器,如何运作?

七、结论

阅读完本文后,您可以开始着手检查自己设计的系统是否存在窃听或劫持风险、篡改风险、冒充风险,相信您也能coding出相应的解决方案。

最后,重要事说三遍,请记住下面两点:

  • 公钥加密,私钥解密;
  • 私钥签名,公钥验签;

参考文献:

  1. What is a Digital Signature? http://www.youdzone.com/signature.html
  2. 数字签名是什么?http://www.ruanyifeng.com/blog/2011/08/what_is_a_digital_signature.html

相关 [加密 解密 签名] 推荐:

理清弄透:加密&解密、签名&验签_Bob

- -
加密&解密、签名&验签,在区块链、钱包等领域应用甚广,背后的原理或细节是什么. 这里通过图文并茂的故事,外加撸代码的方式,一起理清弄透这4个概念. 正式开始之前,先介绍一下本文的主人翁Bob. 他有2把秘钥:公钥、私钥;生活中,他会遇到3种类型的人:朋友Alice、骗子Doug、可信任的公证人CA.

公钥私钥加密解密数字证书数字签名详解

- - 忘我的追寻
决心花一些时间,将这些概念和使用的过程彻底弄清楚. 最先找到的文章是: 数字签名是什么. (阮一峰博客),读了一遍,又找了一些资料,终于把这些概念弄清楚了,这里整理记录一下. 1、密钥对,在非对称加密技术中,有两种密钥,分为私钥和公钥,私钥是密钥对所有者持有,不可公布,公钥是密钥对持有者公布给他人的.

RSA加密、解密、签名、验签的原理及方法 - PC君 - 博客园

- -
  RSA加密是一种非对称加密. 可以在不直接传递密钥的情况下,完成解密. 这能够确保信息的安全性,避免了直接传递密钥所造成的被破解的风险. 是由一对密钥来进行加解密的过程,分别称为公钥和私钥. 两者之间有数学相关,该加密算法的原理就是对一极大整数做因数分解的困难性来保证安全性. 通常个人保存私钥,公钥是公开的(可能同时多人持有).

JAVA实现RSA加密解密

- - CSDN博客推荐文章
提供加密,解密,生成密钥对等方法. RSA加密原理概述   :. RSA的安全性依赖于大数的分解,公钥和私钥都是两个大素数(大于100的十进制位)的函数. 据猜测,从一个密钥和密文推断出明文的难度等同于分解两个大素数的积   .  1.选择两个大素数 p,q ,计算 n=p*q;   .  2.随机选择加密密钥 e ,要求 e 和 (p-1)*(q-1)互质   .

使用GnuPG(PGP)加密信息及数字签名教程

- - 月光博客
   PGP (Pretty Good Privacy) 是由 Phil Zimmermann 于 1991 开发的一个用于数据加密和数字签名的程序,由于被广泛应用以至于后来形成一个开放的标准 OpenPGP,而 GnuPG 则是实现了该标准的一个开源免费程序,本文将会简单介绍如何使用 GnuPG 管理钥匙、加密解密文件和电子邮件、数字签名文件和电子邮件等内容.

SOAP WebService以CXF实现WS-Security之xml签名及加密

- - 编程语言 - ITeye博客
接上篇,记录一下使用apache cxf和spring使用自签名数字证书实现WebService服务端及客户端的xml签名、加密以及解密和签名验证;. 这里仅针对客户端加密和签名并在服务端实现解密及签名验证的单向认证的情形,双向认证可以参照官方sample改进;. 客户端使用客户端私钥进行消息签名、客户端使用服务端公钥消息加密;.

Java加解密艺术之DES对称加密算法

- - CSDN博客推荐文章
加密的时候使用密钥对数据进行加密,解密的时候使用同样的密钥对数据进行解密 * @see DES是美国国家标准研究所提出的算法. 由于加解密的数据安全性和密钥长度成正比,故DES的56位密钥已经形成安全隐患 * @see 后来针对DES算法进行了改进,有了三重DES算法(也称DESede或Triple-DES).

iOS中使用RSA对数据进行加密解密

- - ITeye博客
RSA算法是一种非对称加密算法,常被用于加密数据传输.如果配合上数字摘要算法, 也可以用于文件签名.. 本文将讨论如何在iOS中使用RSA传输加密数据.. openssl-1.0.1j, openssl需要使用1.x版本, 推荐使用[homebrew](http://brew.sh/)安装.. RSA使用"秘匙对"对数据进行加密解密.在加密解密数据前,需要先生成公钥(public key)和私钥(private key)..

java 实现文件内容的加密和解密

- - 编程语言 - ITeye博客
转载: http://xiaoxiaokuang.iteye.com/blog/1440031. getKey(str);//生成密匙. * 文件file进行加密并保存目标文件destFile中. * @param file 要加密的文件 如c:/test/srcFile.txt. * @param destFile 加密后存放的文件名 如c:/加密后文件.txt.

对文件压缩加密/解密解压缩的例子,DES/RSA [转]

- - 行业应用 - ITeye博客
RSA压缩加密/解压缩解密. * 对文件压缩加密/解密解压缩 对象类.   // 如果传入的是目录.    // 创建压缩的子目录.    // 把压缩文件加入rar中.   * 对directory目录下的文件压缩,保存为指定的文件zipFile.   * 解压缩文件zipFile保存在directory目录下.