由 RSA 可以生成一对密钥(私钥和公钥)

明文消息用公钥进行加密后,可以得到密文消息。

密文消息必须用私钥进行解密后,才能得到明文消息。

公钥是公布出去的,任何人都可以知道。

密钥自己藏着,只有自己知道。

只要有公钥的人,就可以将消息进行加密。

只有公钥没有私钥的人,无法对密文进行解密,无法知道密文表达什么信息。


加密场景:

======================================================
(友情提醒,以下场景既不符合日常逻辑,也不符合真实应用,仅仅为了说明基本的加密流程,请自行甄别)

自从潘金莲放窗帘时不小心打到西门庆的头之后,他们两就开始秘密交往,潘金莲的丈夫武大郎总是怀疑他们俩在偷情,苦于没有证据,总是在暗地里偷偷观察着。

一天,潘金莲想写情书撩西门庆,但是情书内容又不想被武大郎知道,于是潘金莲就告诉西门庆,采用 RSA 加密的方式来传递书信。

于是,西门庆就用 RSA 生成了一对密钥(一个公钥,一个私钥),将公钥的内容写成一封信,然后寄出去送给潘金莲。

不料,武大郎观察到了西门庆发出的信件,中途偷偷地将这封信件拦截了下来并复制了一份自己藏着,然后又将信件继续原路寄给潘金莲,以免打草惊蛇,以为这样就可以神不知鬼不觉地拿到他们之间偷情的证据了。当武大郎打开信封一看,发现里面写的只是公钥内容,完全看不懂。

信封(公钥)传达到潘金莲手上后,潘金莲就开始写情书了:“巴拉巴拉各种虎狼之词,以下省略 5000 字,…”(明文)。写好后立刻装入信封就想直接寄回给西门庆,但是马上就停住了,心想,太冲动了,这封信如果这样直接寄出去的话,中途被武大郎拦截下来的话,不就什么都被看到了吗。于是潘金莲拿着西门庆刚刚发过来的公钥对自己写的情书进行加密,生成了一份完全看不懂的信息“eSYJztu3RqGZBcRPvINyg2Hpmu…”(密文)。然后这封信可以放心的寄给西门庆了。

果然,武大郎偷偷观察到了潘金莲发出的信件,于是又进行同样的操作,拦截,复制,原路寄回给西门庆。当武大郎打开复制回来的信件(密文)后,发现又是一堆看不懂的信息,突然想起之前西门庆曾经发过一封公钥,于是尝试用之前第一封从西门庆那封信复制下来的公钥进行各种 RSA 操作(用公钥加密,解密)。结果发现无论怎么操作,得到的都是看不懂的信息。单凭这封全是乱码的信件并不能坐实潘金莲与西门庆偷情。

信封(密文)最终传达到西门庆手上,西门庆拿着自己手上的密钥(密钥只有自己知道,其他人都不知道),对信封进行解密,于是看到了信封原来的内容:“巴拉巴拉各种虎狼之词,…”西门庆被撩得心花怒放。

======================================================

以上就是使用 RSA 进行加密解密的一个虚拟场景。可以看出,加密后消息的传递是单向的,只有潘金莲发加密消息给西门庆是可以避免被武大郎偷看,西门庆没法直接发有效的加密消息给潘金莲(因为潘金莲没有私钥)。除非双方都各自生成自己得 RSA 公钥私钥,并且互相发送各自的公钥给对方,这样双方就可以加密通讯了。

整个通讯流程(单向)就是:

  1. A 明文告诉 B,我现在要发送消息给你,请使用 RSA 进行加解密(这条消息会被 C 截获,C 知道了 AB 之间要通讯并使用 RSA 加密)
  2. B 生成一对密钥(公钥,私钥),然后将公钥发送给 A(这个公钥会被 C 截获,但是 C 拿不到私钥)
  3. A 把需要发送的消息和收到的公钥进行 RSA 加密,得到密文,然后发送给 B(这个密文会被 C 截获,但 C 无法知道密文所对应的明文的内容,因为 C 只截获到公钥,没有私钥,用公钥对密文怎么操作都得不到明文)
  4. B 拿到密文后,使用自己的私钥解密,得到明文。

B如果想发加密的消息给A,则将以上流程反着来走一遍就行了,只不过就需要由A来生成密钥(公钥,私钥)。
A想给B发加密消息,由B来生成密钥对(公钥B,私钥B),对外公布公钥B。
B想给A发加密消息,由A来生成密钥对(公钥A,私钥A),对外公布公钥A。

以上就是加密的场景

加密是为了防止信息被泄露,而签名是为了防止信息被篡改

签名场景:

======================================================

西门庆被潘金莲撩了一段时间后,已经不满足于书信的情话,想进一步和潘金莲为爱鼓掌,于是想告诉她"午时去王婆家做衣服"。由于事关重大,潘金莲要如何才能确信这条消息真的是西门庆发给她的呢?潘金莲心想,万一这条消息是哪个泼皮乱发的,那岂不是白跑一趟?

在RSA 算法里有一组对称操作,用公钥加密的密文,用私钥进行解密可以得到明文;反过来,用私钥加密密文,用公钥解密也可以得到明文。

潘金莲手上是有西门庆的公钥的(延续上一场景的公钥),如果西门庆用自己的私钥对做衣服这条消息进行加密,密文发给潘金莲后,潘金莲用公钥进行解密,如果解密后能得到明文,那不就能够说明,发送者确实是西门庆本人。因为假设除了西门庆外,没有人拥有私钥。能用之前公钥解密的密文一定是密钥的持有者(即西门庆)所发出的

于是,潘金莲让西门庆重新发消息,并用私钥加密。西门庆立马重新写了一条消息“午时去王婆家做衣服”,然后用自己手上有私钥将这条消息加密生成了“PvINeSYJuZBcRygztu3Gpm2HRq…”一共两条消息(一条明文一条密文)合并写在一封信里寄给了潘金莲。

潘金莲收到信封后,用手上的公钥对信件后面的密文部分“PvINeSYJuZBcRygztu3Gpm2HRq…”进行 RSA 解密,得到“午时去王婆家做衣服”。然后和信件前面部分里对比,发现内容一模一样,这就确认了,这条消息确实是西门庆发的。

======================================================

这里,西门庆用私钥对前面明文内容加密,然后追加到明文后面的这种做法,就是签名。

潘金莲用公钥对签名解密,并与前面明文部分进行比对,这个做法就叫做验签。

为什么可以这么做?不怕被武大郎中途截获修改吗?不怕。因为如果武大郎中途截获了这封信,并修改成“申时去王婆家喝茶”但由于武大郎没有私钥,无法对明文加密,因此无法修改后面的签名部分。当潘金莲收到信件后,用公钥解密签名部分得到的内容,跟被篡改的明文内容一对比,发现不一致,就说明消息被篡改了,发送者并不是西门庆。

又或者武大郎用自己的私钥对篡改后的明文进行加密签名,再发送给潘金莲,潘金莲用手上西门庆的公钥根本无法解密武大郎篡改后的加密部分,所以出现这种情况也可以确定发送者不是西门庆。

从这里可以看出,加密和签名,这两种场景是不一样的。

加密,是为了确保通讯内容不被第三方知道。

签名,是为了确保发送者确实是本人,并且消息没有被篡改过。

加密场景下,并不关心消息是否被篡改过。可能武大郎第一次截获西门庆公钥时,偷偷换成了自己生成的公钥,并发给潘金莲。潘金莲用公钥加密后发出的情书被武大郎截获之后,武大郎用自己的私钥也是可以解密出来那些虎狼之词的(中间人攻击),但是加密场景并没有解决这些问题,加密场景仅仅是为了说明如何不让私钥持有者以外的第三方知道消息的内容。

而在签名场景下,只关心消息没有被篡改,并不关心内容是否保密。比如“午时去王婆家做衣服”就是明文传输,任何人都知道这个信息。签名场景并不负责保密内容,仅仅是为了说明这条消息是西门庆本人发出的,并且没有被篡改过。(场景只是为了说明验签的流程,在实际应用中,并不会用明文进行验签,而是使用明文的哈希值)

总结:

公钥公开,所有人都能拿到公钥

加密场景:发送者用公钥加密、自己用私钥解密

签名场景:自己用私钥签名、接收方用公钥验签


综合应用

这两个场景可以取长补短,同时应用加密和签名,实现传递消息的保密性与可靠性

  1. A 和 B 都使用RSA生成了一套自己的密钥对(公钥 A 私钥 A,公钥 B 私钥 B)

  2. A 和 B 都对外公布了自己的公钥,然后,A 拿到了公钥 B,B 拿到了公钥 A

  3. A 想要给 B 发送消息:
    3.1 在发送前,先用 对方的公钥B对要发送的消息进行RSA加密,得到密文 A
    3.2 然后再对密文 A 使用 自己的私钥A进行加密,得到密文 AA
    3.3 将得到密文 AA作为签名,追加到密文 A 后面(这里可以使用特定的标志符用来识别,比如彼此约定标识符为连续2个空行,那么在出现连续2个空行之前的内容就是密文 A,后面的就是密文 AA。虽然这样做有可能出现冲突的情况,即密文里一部分和约定的标识符有重合,导致提前或者延后认错标识符,这里暂时不展开说了,以后有机会再补上具体如何识别),将整体(密文 A+标识符+密文 AA)作为消息发送给B

  4. B 收到(密文 A+标识符+密文 AA)后,
    4.1 根据约定的标识符找到后面的密文 AA,先用 对方的公钥A进行验签(即用公钥A密文 AA进行RSA解密),与标识符前的密文 A 进行对比,如果跟密文A对得上,那就可以确信这份密文是 A 发出的,没有被篡改过。(反之,如果对不上,那就有可能被篡改过,应该丢弃掉,然后明文通知A本次通信出现错误,需要重新对接。)
    4.2 再用自己的私钥B密文 A 进行解密,得到A发出的原始的明文。

这样,既实现保密,又能确保消息的完整和可靠。

第三方C即使截获了公钥 A和公钥 B,和(密文 A+标识符+密文 AA)这段密文消息,那么他也只能用公钥进行验签,却无法得知通信的内容。(不过这样依然无法避免受到中间人攻击)

题外话1:TLS通信过程

既然说了RSA(非对称加密)的综合应用,那额外再简单说一下互联网中https所使用的TLS通信大致是如何进行的,因为TLS就是使用了RSA(非对称加密)并结合对称加密来实现的。

所谓非对称加密,就是像RSA那样,用公钥加密,用私钥解密(或者用私钥加密,用公钥解密)的方式
加密与解密不是同一把密钥的,这种就叫做非对称加密
与之相对的对称加密,就是指加密与解密都使用统一把密钥的方式,不分公私。

由于非对称加密和解密都比较慢,直接用来正常通信的话,效率不高,效果不理想。而使用对称加密的话,速度就很快,可以用来正常通信。
但是如果使用对称加密的话,首先第一件事就是通信双方要达成一致意见,使用同一个会话密钥,然后接下来双方都使用这个会话密钥将通信内容进行加密和解密。

可问题就在于,如何安全的达成一致意见,使用同一会话密钥?

如果A明文告诉B,我们使用“XXYYZZ”作为密钥进行对称加密吧。而这句话被第三方C截获的话,那AB间的加密就没什么意义了,因为C也知道加密解密都是使用“XXYYZZ”,AB之间的任何通信,C都知道。
所以,A只能用密文告诉B:“我们接下来的会话使用XXYYZZ作为密钥进行对称加密”
怎么做到用密文告诉B呢?

答案就是:使用前面所说的RSA加密解密流程。

虽然使用RSA加密很慢,但是如果只用来对第一次会话密钥进行加密的话,还是可以接受的。
即:使用RSA加密会话密钥,确保这个会话密钥无法被第三方知道,然后双方再使用对称加密进行会话

大致流程如下:

  1. 客户端(浏览器)明文发送3个信息(自己支持的TLS版本,加密套件【各种加密算法】,生成一个随机数【第一个随机数】)给服务器。
  2. 服务器收到客户端的信息后,将(自己支持的TLS版本,加密套件【各种加密算法】,生成一个随机数【第二个随机数】)这3个信息也明文返回给客户端,同时使用RSA生成一对密钥,将公钥发送给客户端(其实还包括服务器网站的证书等,这个省略不讲了)。
  3. 客户端收到服务器的公钥后,再次生成一个随机数(第三个随机数,又叫预主密钥),并用服务器发过来的公钥进行加密,然后将加密后的预主密钥发送给服务器。
  4. 服务器用自己的私钥解密,得到与客户端一模一样的预主密钥。这时候只有客户端与服务器知道这个预主密钥,其他人即使中途截获了前面的全部信息,但也无法知道这个预主密钥的值。然后客户端与服务器都使用第一个随机数+第二个随机数+预主密钥计算生成出会话密钥。这个会话密钥就是对称加密算法所使用的密钥了。
  5. 接下来,双方均使用同一个会话密钥,使用对称加密进行相互通话。

题外话2:三次握手,四次分手

既然说了客户端服务端之间的TSL来回通信了3次,就顺便说一下TCP通信中经典的三次握手四次分手,客户端与服务端的使用TCP建立连接时,要经历三次握手过程,结束连接时需要四次。
这是为了确保通信的有效性与可靠性。

打个比方,比如说在微信上,西门庆想约潘金莲,于是先试探性的问“是潘金莲吗?”,然后潘金莲回复“是的,有事?”,西门庆说“有事”,然后就说“周六晚上景阳冈酒店相见”。
前面的一问一答再一答的过程就是三次握手。

为什么不能一次?想想,若西门庆一开口就直接说“周六晚上景阳冈酒店相见”,万一对面武大郎刚好拿了潘金莲的手机看呢,又或者潘金莲没看信息,直到周日才看到呢,这不耽误事情么。所以要等到对方确认后,然后再说具体内容。

那么为什么不能是两次?因为网络存在延迟丢包等的可能性。当西门庆第一次发送“是潘金莲吗”时,如果出现网络阻塞,这时候西门庆迟迟等不到潘金莲的回复,会以为消息发送失败了,于是重发一次“是潘金莲吗”。这条信息很顺利地到达了潘金莲那,潘金莲回复“是的,有事?”。西门庆如果不回复“有事”,而是直接说“周六晚上景阳冈酒店相见”的话,这样会出现一个问题。假如说当最开始那条消息所处的网络突然好了,消息送达到潘金莲那里,那么潘金莲会认为这是西门庆又来找她了,于是她又回复一次“是的,有事?”。这时候西门庆会觉得这肯定是刚才最开始发起的那次延迟的邀约的回应,而刚刚已经正式邀约过了一次了,于是就不再回复了。而潘金莲却认为这是两次邀约,一直等待着西门庆回复,是否还有事,又或者是否改期了,等等,一直在那里傻傻地等待着,浪费资源。而如果是三次的话,那么潘金莲等收到西门庆说“有事”之后才开始认真听具体的事。如果收不到最后那次回复“有事”的话,那就当西门庆从来没发过消息给她,那就不用在那里傻傻地等待了。

那么为什么不是四次或更多次?因为就建立通信而言,三次已经足够可靠了,四次不是不可以,而是没必要。

三次握手

类似的,TCP通讯的简单流程如下:

  1. 客户端发起请求报文,发送SYN(synchronization)+客户端自己的序号(sequence)给服务端。
  2. 服务端收到请求后,发送SYN+ACK(acknowledgement)+服务端自己的序号+确认号(接收到的客户端序号的值+1)给客户端。(这样客户端收到确认号之后,用确认号-1就知道这个应答是不是自己发送的那条TCP报文了。)
  3. 客户端收到服务端发回来的报文后,再发送ACK+序号(这时候使用服务端发过来的确认号)+确认号(使用服务端生成的序号+1)

然后,双方就可以开始通讯了。

四次分手

当需要终止TCP连接的时候:

  1. 客户端发起报文,发送FIN(finish)+ACK+序号+确认号 给服务端。
  2. 服务端收到后,先发送一个ACK+序号(使用客户端的确认号)+确认号(使用客户端的序号+1)给客户端。(虽然发送了ACK,但此并没有正式关闭连接,因为可能还有要处理的数据。发送ACK回去,仅仅只是告诉客户端“我已经知道了你想分手”,但不代表“可以马上分手”)
  3. 等服务端处理完数据后,会再发送一个报文:FIN+ACK+序号+确认号(此时序号和确认号都直接使用刚刚第二步时用的序号和确认号,这时候就代表“可以关闭连接了”)
  4. 客户端收到报文后,再发送ACK+序号(使用服务端发过来的确认号)+确认号(使用服务端的序号+1)
  5. 服务端收到ACK后即关闭连接。
  6. 客户端等待超时后关闭连接(如果最后一次ACK发生丢包,那么首先服务端会等待超时,然后根据状态重新发一次FIN+ACK+序号+确认号给客户端,客户端此时即使之前发送过ACK了,还是会继续发ACK给服务端,并重置自己的超时时间,这样就能保证服务端正常关闭了。)

至此,客户端与服务端完成了关闭连接的步骤。
实际中,握手与分手的请求不一定非得是客户端发起给服务端的,也可以反过来,服务端发起给客户端,将以上流程反过来就是了。

推荐阅读:https://blog.csdn.net/weixin_37989267/article/details/119143683

RSA加密解密和签名的应用场景相关推荐

  1. python加密解密 sha256_Python下实现的RSA加密/解密及签名/验证功能示例

    本文实例讲述了Python下实现的RSA加密/解密及签名/验证功能.分享给大家供大家参考,具体如下: 原文是py2环境,而我的环境是py3,所以对原代码做了修改:decode(), encode() ...

  2. python实现RSA加密解密 及 签名验签功能

    本篇写一下python实现RSA的加密解密功能.私钥签名 公钥验签功能. 主要分三部分来介绍 生成私钥和公钥 脚本如下,运行后会生成public.pem(公钥) 和 private.pem(私钥) d ...

  3. Java使用RSA加密解密及签名校验

    该工具类中用到了BASE64,需要借助第三方类库:javabase64-1.3.1.jar 注意: RSA加密明文最大长度117字节,解密要求密文最大长度为128字节,所以在加密和解密的过程中需要分块 ...

  4. C# Java间进行RSA加密解密交互

    C# Java间进行RSA加密解密交互 原文:C# Java间进行RSA加密解密交互 这里,讲一下RSA算法加解密在C#和Java之间交互的问题,这两天纠结了很久,也看了很多其他人写的文章,颇受裨益, ...

  5. iOS使用Security.framework进行RSA 加密解密签名和验证签名

    iOS 上 Security.framework为我们提供了安全方面相关的api: Security框架提供的RSA在iOS上使用的一些小结 支持的RSA keySize 大小有:512,768,10 ...

  6. [crypto]-53-openssl命令行的使用(aes/rsa签名校验/rsa加密解密/hmac)

    常用技巧 如何编写一个二进制规律性的文件, 比如你可以编写一个"0123456789abcdef"的文本文件,记得删除换行符然后用ultraedit打开,ctrl+H就可以看到二进 ...

  7. Java使用RSA加密解密签名及校验

    RSA加密解密类: import java.io.BufferedReader; import java.io.BufferedWriter; import java.io.FileReader; i ...

  8. C#的RSA加密解密签名,就为了支持PEM PKCS#8格式密钥对的导入导出

    差点造了一整个轮子 .Net Framework 4.5 里面的RSA功能,并未提供简单对PEM密钥格式的支持(.Net Core有咩?),差点(还远着)造了一整个轮子,就为了支持PEM PKCS#8 ...

  9. java rsa 验_Java使用RSA加密解密签名及校验

    RSA加密解密类: package com.ihep; import java.io.BufferedReader; import java.io.BufferedWriter; import jav ...

最新文章

  1. linux valgrind memCheck ---内存检查工具的可视化方法valkyrie
  2. Oracle树查询总结
  3. 在Matlab中调用Mathematica的函数
  4. java 判断语句 性能_前端性能优化:js中优化条件判断语句
  5. [codevs 1916] 负载平衡问题
  6. python查询sql_Python处理SQL语句(提供SQL查询平台使用)
  7. easyui(一) 初始easyui
  8. Linux学习:Linux基础命令集(2)
  9. 博客园随笔添加自己的版权信息 [转]
  10. SQL HAVING Clause
  11. rz/sz:工作原理
  12. 计算机c盘满了怎么搬家,c盘占满了,怎么清理
  13. 测试PHP连接MYSQL成功与否的代码
  14. 登陆服务器显示guest,登录界面如何隐藏guest账号
  15. 【区块链 | Compound】4.剖析DeFi借贷产品之Compound:清算篇
  16. WuThreat身份安全云-TVD每日漏洞情报-2022-12-22
  17. C语言编程——高斯消元法
  18. Windows 7 桌面便签使用小技巧
  19. 内存或者 cpu 占用率过高如何排查
  20. 使用邮箱地址标识用户

热门文章

  1. QQ、MSN、淘包旺旺、Skype常设对话的html链接代码
  2. MONTARA酒店集团呈献布吉岛最新奢华宅邸别墅推广综合式养生社区概念
  3. 技嘉B85M-D3V主板鼠标失灵的解决办法
  4. linux进程管理工具supervisor安装卸载、子配置文件详解、遇到的问题、supervisor group群组管理、启动一个springboot项目示例、update命令注意点
  5. 淘宝/天猫API:item_search_shop-获得店铺的所有商品
  6. “打印机故障”,我的解决方案
  7. JSDoc3的简单使用
  8. 彻底删除PCTOOLS.DLL文件的方法
  9. 对设备的控制和远程控制方式
  10. c语言中终止线程的方法,终止线程优雅不使用TerminateThread()