RSA 算法从原理上说, 可以使用 private key 加密, public key 解密, 但为什么各个语言的实现都只允许 public key 加密, private key 解密? private key 加密可以保障数据不被篡改, 但无法保证数据无法被读取, 但部分场景我只需要数据不被篡改, 内容可以是透明的, 但各个库都只允许对原内容的 HASH 进行加密(就是签名), 而不允许对原内容加密(库的实现就只允许使用 Public Key 加密), 这是处于什么安全方面的考虑呢? 我理解 public key 是公开的, 谁都可以解密内容, 因此签名就可以保证数据不被篡改, 但我很疑惑为什么不能通过 public key 能否解密和解密后的内容来预防篡改?

不是不能,是一般不这么做。因为 RSA 的在计算机上的运算速度远比 HASH 要慢得多。

但部分场景我只需要数据不被篡改, 内容可以是透明的

实现这个需求的话,hash 更适合

私钥加密,公钥解密需求场景不明确,公钥是公开的,又能解密,还不如不加密了

私钥一般用来加密哈希值,做数字签名

签名就是 private key 加密, public key 解密啊
为什么签名是对原内容的 HASH 加密而不是对原内容加密,是因为加密慢啊,对原内容用 private key 加密来实现签名工程设计上不合理

而且 rsa 的加解密性能很感人,所以实际中都是用 rsa 加密对称加密的密钥和哈希值,不过非对称加密算法 rsa 用的也很少,现在基本都用 ecc 的变种算法

你自己都说明白了啊

  1. private key 加密等于没有加密,所有人都可以看到。只是『无法伪造』。
  2. 实现『无法伪造』只需要签名算法就可以了(签名=private 加密 hash ),计算速度快。比如你有 10G 的文件要签名,算 hash 秒出,RSA 加密一遍可能好几分钟。你选哪个?

可以啊,谁说不可以,随便找了个, stackoverflow.com/questions/10332022/rsa-decryption-with-a-public-key

不过不建议自己瞎用,性能是一方面,密码误用脑壳痛,一般团队也不可能有那么多精力搞这个

用私钥加密,那个叫签名

这个问题要从两方面来看,RSA 是基于欧拉定理的非对称加密算法,从算法的数学原理来看,两个秘钥都可以用于加密和解密。
但是,我们平时使用的 RSA 库,是基于 RSA 算法的原理上做了很多工业化的封装,让它更容易使用,就拿 https 的实现技术来举例,封装之后私钥和公钥的内容是不一样的,
以下是公钥内容:
Subject Public Key Info:
Public Key Algorithm: rsaEncryption
Public-Key: (2048 bit)
Modulus:
00:9f:54:6e:12:db:07:35:85:40:92:20:4f:aa:16:
d9:b8:37:4c:8d:bd:0c:2d:dc:a8:ac:c9:14:23:00:
31:02:41:10:ea:67:bf:b4:f1:01:8c:c3:fe:0d:3e:
64:6e:cd:c8:a7:e4:ec:ba:82:e6:61:e1:6f:55:8a:
48:69:ab:35:d3:d3:b3:85:44:de:24:d6:b1:3b:bd:
af:98:6c:17:fd:21:9f:71:3a:08:e3:84:ef:ec:84:
d7:cd:ef:e3:ec:d4:04:8c:19:55:c1:d9:6e:92:7d:
8f:80:68:b8:e0:78:58:25:72:e0:2f:bd:22:7c:88:
22:25:27:b1:a1:42:e6:8e:9a:51:86:2f:fd:16:83:
ce:46:60:32:e0:41:47:c3:c2:40:dd:44:55:42:c5:
8c:e7:24:19:85:0e:65:e8:56:c9:06:95:80:b3:8e:
84:b9:5d:5c:6f:24:9b:30:d1:16:50:2a:39:ab:b2:
36:67:4d:b1:1f:95:7a:ec:5d:3e:49:bc:d2:3d:f5:
90:dd:1a:1b:fc:23:b5:79:c4:52:de:e1:d3:1d:1a:
f2:5a:37:a6:3c:52:bd:81:28:e9:46:8c:f4:f7:6e:
03:53:ed:09:1d:47:67:e4:2f:97:51:64:22:75:a8:
0e:9f:29:12:15:17:5a:a3:23:69:97:32:9c:74:7f:
1f:53
Exponent: 65537 (0x10001)

以下是私钥内容:
Private-Key: (2048 bit)
modulus:
00:9f:54:6e:12:db:07:35:85:40:92:20:4f:aa:16:
d9:b8:37:4c:8d:bd:0c:2d:dc:a8:ac:c9:14:23:00:
31:02:41:10:ea:67:bf:b4:f1:01:8c:c3:fe:0d:3e:
64:6e:cd:c8:a7:e4:ec:ba:82:e6:61:e1:6f:55:8a:
48:69:ab:35:d3:d3:b3:85:44:de:24:d6:b1:3b:bd:
af:98:6c:17:fd:21:9f:71:3a:08:e3:84:ef:ec:84:
d7:cd:ef:e3:ec:d4:04:8c:19:55:c1:d9:6e:92:7d:
8f:80:68:b8:e0:78:58:25:72:e0:2f:bd:22:7c:88:
22:25:27:b1:a1:42:e6:8e:9a:51:86:2f:fd:16:83:
ce:46:60:32:e0:41:47:c3:c2:40:dd:44:55:42:c5:
8c:e7:24:19:85:0e:65:e8:56:c9:06:95:80:b3:8e:
84:b9:5d:5c:6f:24:9b:30:d1:16:50:2a:39:ab:b2:
36:67:4d:b1:1f:95:7a:ec:5d:3e:49:bc:d2:3d:f5:
90:dd:1a:1b:fc:23:b5:79:c4:52:de:e1:d3:1d:1a:
f2:5a:37:a6:3c:52:bd:81:28:e9:46:8c:f4:f7:6e:
03:53:ed:09:1d:47:67:e4:2f:97:51:64:22:75:a8:
0e:9f:29:12:15:17:5a:a3:23:69:97:32:9c:74:7f:
1f:53
publicExponent: 65537 (0x10001)
privateExponent:
6b:1b:de:17:8c:e8:ae:c1:12:a4:69:56:44:b8:b1:
ca:56:5a:7f:5a:5c:4a:a4:71:3c:1e:bd:0b:be:80:
33:cc:bb:eb:68:ad:86:9d:11:f6:a8:77:2c:3e:0a:
54:36:c0:b2:a5:81:c2:ec:66:a5:dc:5f:f4:f8:4e:
2f:c3:2a:1f:69:cc:e0:45:68:b5:09:23:02:4f:45:
31:49:51:63:18:ec:4f:b8:bc:ea:fe:9e:2f:b9:2a:
3e:46:0b:4a:55:49:6d:49:46:ce:57:36:2f:02:7b:
aa:ce:3b:a2:a3:24:56:a0:80:37:77:85:2c:84:73:
b7:d8:94:60:1d:52:53:00:39:20:44:16:66:62:fe:
0c:5d:46:f1:90:c1:2a:c8:b0:2b:cd:5e:18:a5:ea:
15:ca:2e:6c:f3:3e:c7:8f:11:93:e3:81:85:20:ba:
a5:77:cf:d3:5e:27:8c:74:ca:7a:f9:e6:99:04:9c:
0b:61:d8:b7:2e:3d:2a:be:ba:bc:69:50:64:a2:fe:
c6:32:f8:f0:36:d0:b9:86:4c:72:53:57:78:17:8b:
67:e8:e2:14:82:67:00:e1:77:f0:08:e4:6d:be:e8:
12:8c:70:5e:56:be:e3:6b:20:2f:1d:bd:96:99:07:
36:4f:9c:43:2d:2c:8c:98:d3:41:69:70:6d:81:b3:
f9
prime1:
00:c2:ca:27:6b:67:fa:7e:9b:c8:38:9a:3f:3f:9c:
a4:65:0c:e0:c7:66:b9:21:61:9f:b2:85:6c:a7:72:
3e:76:ac:13:df:06:39:97:63:da:fa:ef:62:86:ed:
e1:7b:05:23:20:ac:87:37:17:9b:24:e1:92:38:25:
66:e1:d0:06:d9:a2:86:03:26:c0:e9:cc:f9:0b:40:
44:ba:54:5f:2e:ab:c7:cc:a5:20:e8:63:14:e9:d1:
ee:35:76:40:df:12:72:46:9b:30:4a:af:a9:b5:5c:
04:b0:87:fc:b7:58:8b:44:1e:8b:07:fc:6e:f3:2e:
4a:8d:e0:06:8c:8f:a4:4d:67
prime2:
00:d1:65:b5:8a:e5:e2:ea:2e:65:14:8f:d1:0e:2e:
5e:82:1c:b2:73:a8:c3:7c:79:13:35:a4:60:9d:2a:
da:8d:bb:9d:11:2c:8d:f8:ba:41:f0:61:ca:ed:e3:
e2:20:52:d4:47:b7:02:92:7d:4b:56:a2:0b:1d:65:
b8:be:04:a0:37:98:4e:af:a5:38:57:7f:ca:79:c8:
f6:9d:9c:31:80:e9:ef:bc:58:90:69:33:d8:20:37:
08:7e:5b:c8:6f:c8:15:c3:a0:bb:01:c7:e0:c7:b2:
fc:78:8b:ac:09:c4:0f:83:c8:e7:25:50:8d:c5:09:
d1:88:29:a9:45:60:23:7f:35
exponent1:
21:02:64:ff:bc:95:24:93:7d:b0:a9:e3:02:02:a7:
91:40:47:6f:43:27:28:53:04:df:19:e1:39:d7:10:
62:c7:f2:6e:1e:fd:ef:7b:ca:86:2f:bf:00:a2:9b:
4d:5f:a7:7e:47:fe:7a:05:94:13:01:ee:e7:78:df:
20:71:42:57:eb:44:ce:8f:e8:ad:36:41:15:f9:04:
2c:97:53:b1:f3:06:5e:d5:b4:e7:ec:b2:84:95:40:
ca:ea:89:3f:c4:3e:7d:5c:9b:28:6c:f0:53:7d:8e:
85:e3:e5:9d:a4:71:a5:4f:8f:bc:00:b9:44:98:99:
a5:c5:4b:16:d2:d8:c3:0d
exponent2:
16:db:95:6f:ae:1c:91:17:b3:6d:05:2d:fa:f0:50:
dc:bf:29:33:ba:ee:6b:fe:03:7c:cd:8e:c6:59:51:
36:3b:8e:af:bb:3f:5c:31:68:d5:46:b7:92:34:58:
10:d3:39:dd:02:3b:43:a6:6d:bc:ed:3f:6d:5c:17:
48:96:d4:ae:7c:ef:c9:f8:ad:27:d0:09:58:35:f9:
c5:c6:b1:18:b3:70:ba:0c:a8:e6:f3:03:da:b0:67:
3a:f3:e5:f3:5d:d2:12:62:cf:47:28:7c:7f:10:28:
c3:37:eb:f5:bc:f3:3c:9d:87:ad:e9:17:30:b5:1b:
ac:53:6f:e8:e4:cf:bb:29
coefficient:
00:ba:5d:2f:f3:08:be:93:3e:09:45:45:66:2a:ce:
2f:cc:bf:4d:c5:8a:7a:e8:86:1b:6e:22:00:52:47:
65:ee:b8:80:22:b3:b3:aa:ec:d5:a2:21:d8:28:b9:
bc:e8:f5:34:9a:5b:66:60:25:03:b3:01:90:c6:9c:
2e:a2:36:d6:84:cf:12:af:b1:a3:1c:b3:42:77:16:
a5:3d:e4:34:8a:8e:4f:d5:ed:69:43:c0:cc:86:eb:
13:51:45:d1:42:68:09:b4:ad:d1:57:8e:58:b7:d6:
b5:d5:08:13:dc:86:13:94:45:e1:e2:cf:bf:e8:44:
c3:09:b6:a5:1e:dc:5a:ed:2d


从以上公私钥的内容能了解到 2 点信息:
1 、私钥文件包含了公钥文件的内容( modulus ,publicExponent )。
2 、私钥文件中的 privateExponent 就是私钥的核心内容(用于解密数学运算的大数)。
3 、私钥文件还包含了额外的内容(prime1 ,prime2 ,exponent1 ,exponent2 ,coefficient)。

之所以私钥文件要包含额外的内容,是因为 RSA 算法本身的解密运算量太大,机器资源消耗很高,所以在实际应用中,解密时不会直接使用原算法,而是用了<中国剩余定理>,根据公钥和私钥两个文件所包含的内容计算出一些中间结果,然后中国剩余定理根据这些中间结果可以快速解密,节省机器资源。


回答楼主的问题:
1 、可以公钥解密,但是性能会差很多。 私钥解密公钥加密,内容透明防篡改,这个场景在 RSA 里的应用叫做<数字签名>。

另外,根据公私钥文件内容,我们在使用非对称加密时,一定不要泄露私钥文件,因为私钥文件包含了公钥内容,这样相当于密钥对全被泄露了。


参考文档:
RSA 算法原理: www.ruanyifeng.com/blog/2013/06/rsa_algorithm_part_one.html
欧拉定理: zh.wikipedia.org/wiki/%E6%AC%A7%E6%8B%89%E5%AE%9A%E7%90%86_(%E6%95%B0%E8%AE%BA)
中国剩余定理: zh.wikipedia.org/wiki/%E4%B8%AD%E5%9B%BD%E5%89%A9%E4%BD%99%E5%AE%9A%E7%90%86

补充一下,数字签名这个场景,在 rsa 库一般会提供独立的方法(加密:signature, 解密:verify),跟加密,解密方法区分开。

以前数学推导过这个整套系统:
leimao.github.io/blog/Public-Key-Cryptosystem-and-Digital-Signature/
leimao.github.io/article/RSA-Algorithm/
但是现在有些忘了。希望这整个数学过程对你的理解有所帮助。

“但我很疑惑为什么不能通过 public key 能否解密和解密后的内容来预防篡改?”

为了避免被暴力破解,真正的 RSA 加密,都是不验证结果是否正确的。

openssl 这些库是支持这种操作的,所以原理上是能的;很多语言的 crypto 库不支持,那是因为不推荐这种做法。

只对 hash 加密没啥安全上的考虑,纯粹是对比整体加密,安全性不会降低的情况下效率上更优

  1. 相比对全文加密,对 hash 加密效率更高
  2. 验证签名可以放在异步逻辑进行,不影响内容的读取

jwt 不就是私钥加密

私钥加密,公钥解密,就可以用来做授权。
我们就是这么用的,客户把它们机器的特征码发给我们,我们用私钥加密。当然前提是客户给的特征码不可伪造。或者说伪造成本比较高。

我了解原理, 我使用的场景和你一样, 但我发现.NET 的各种加密库都不支持此操作, 我在 Stackoverflow 也找了一些类似的提问, 没有搞明白很多库直接不支持的原因, 我要加密的内容非常短, 因此速度不是问题

可能是因为大部分库帮你封装好了 sign verify 接口吧。
另外,这个疑问也不是第一天看到了。。。
/t/704756
/t/809833
/t/826703
/t/542814
等等等等。。。

RSA-1024 理论上每次最大能加密 1024 位,也就是 128 个字节不到,RSA 加密又慢,你觉得 RSA 加密 10G 的文件要多久。。。正常的做法是加密文件的 HASH ,达到签名的目的。

先看个公钥和私钥的公式
第一步,随机选择两个不相等的质数 p 和 q 。
第二步,计算 p 和 q 的乘积 n 。
第三步,计算 n 的欧拉函数φ(n)。
第四步,随机选择一个整数 e ,条件是 1< e < φ(n),且 e 与φ(n) 互质。(常常选择 65537 )
第五步,计算 e 对于φ(n)的模反元素 d 。
第六步,将 n 和 e 封装成公钥,n 和 d 封装成私钥。

在实际使用中 e 是常量也就是 65537 因此有了私钥也就推导出了公钥 不支持私钥加密应该是为了安全考虑

内容加密场景是 我发出去的消息 只有对方能解 所以用公钥加密
签名的场景是 我发出的消息并且把公钥发给对方 对方要用公钥认证是我发出去的消息 如果发送的是私钥的话 公钥也就暴露了

总结 Q&A:

但部分场景我只需要数据不被篡改, 内容可以是透明的, 但各个库都只允许对原内容的 HASH 进行加密(就是签名), 而不允许对原内容加密(库的实现就只允许使用 Public Key 加密), 这是处于什么安全方面的考虑呢
答:并不出于安全方面的考虑,而是效率和通用性

但我很疑惑为什么不能通过 public key 能否解密和解密后的内容来预防篡改

答: 原文是否被篡改过并不影响解密过程,在没有附带摘要( hash )的情况下是无法得知解密结果是否「正确」或者「能否解密」的。hash 的作用就是告诉你原文写了什么,解密后的原文 rehash 比对加密过的「真·原 hash 」一致,这才是签名防篡改的关键逻辑。你的设想是否漏掉了什么?

嗯, 你说到了关键, 就是在不知道私钥的情况下, 能否对私钥加密的内容定向篡改? 否则随意篡改的内容解密后结果就是未知的,攻击者没法定向伪造, 这样解密后的内容, 将无法按照预定义的格式还原. 嗯, 加密的确不能当作签名使用, 是我想错了. 我原本以为内容被修改后解密会失败😅

加密通信 等于 我把我家信箱全部打开,任何一个人都可以过来 选择其中一个信箱扔进去一封信 一摔门锁上,这封信只有我自己可以打开,投信人可以确保 不被其他人截取;

数字签名 等于 我做了一幅字画,加上了我自己的签名和私章,所有人都能看到,且能够判断是我的原作 还是仿品

这是两个不同场景

假设你有条消息,m 。要生成他们的密文,c 。你没有用 HASH ,也没有添加随机数。使用了原始的 RSA 做了 “加密”。

c = m ^ d

然后你把这东西,通过中间路由,发给了公钥方。
这时候,通信中间,有个路由算了个 s ,把消息改了,传给了公钥方

c' = c ^ 123 = (m ^ d) ^ 123 = m ^ (d * 123) = m ^ (123 * d) = (m ^ 123) ^ d [mod n]

公钥方做解密过程

m' = c' ^ e = (m ^ 123) ^ d ^ e = (m ^ 123) ^ (d * e) = (m ^ 123) [mod n]

m ^ 123 对你的业务有没有影响呢。。说不准。万一有影响呢?有影响不就被中间这货坑了么。

那 RSA 签名咋能用的呢?签名主要把 m 换成了 HASH(m) 。(实际应用时还有 padding 等更多运算)。最后验签方也是计算消息的 HASH 值,对比 HASH 值是不是相等。

即便中间这货给换了签名,那公钥方最后做解密得到的 也是 HASH(m) ^ 123 。

中间这货需要构造一个 123 ,使得 HASH(?) = HASH(m) ^ 123 里的 ? 有意义是很困难的。

这里唯一好找的就俩解,一个 把 123 换成 0 ,一个 把 123 换成 1 。

换成 0 的话,整个 HASH 值就是 0 ,然后 就看 HASH 0 为 0 的消息对业务有没有影响。(实际应用时,会通过加入随机数等操作避免这种情况。)

换成 1 的话,那就是原消息。中间人无害转发,也挺好。