目前 RSA 算法相关的教程和文章都有一个根本性缺陷

2020-02-24 09:43:46 +08:00
 itskingname

注意我是说这些教程和文章有缺陷,不是说 RSA 算法有缺陷。

我们知道,在 RSA 算法里面,需要选定两个足够大的质数 p 和 q 相乘得到 N,由于对 N 进行分解非常困难,所以能保证 RSA 算法的安全性。网上的文章也是这样说的。

但是,我在网上看了四十多篇 RSA 相关的文章,所有的文章对于如何选定 p 和 q,全都没有讲。都只是轻描淡写地说一句:

选定两个足够大的质数 p 和 q

我现在就问你,你给我找两个质数,每个质数要超过 100 位数。你能在短时间找出来吗?

所以我很好奇,现在的 RSA 库里面,他们是怎么选定这个 p 和 q 的呢?难道是现场 2,3,5,7,11,13...这样一个一个数直到找到足够大的为止?还是提前算好并存在了某个地方,要用的时候直接随机取出来用?

目前 python-rsa 库确实是一个一个数出来的:

3965 次点击
所在节点    分享发现
42 条回复
shintendo
2020-02-24 09:55:34 +08:00
应该是生成足够位数的随机数,判定是不是质数,不是就再取一个
itskingname
2020-02-24 09:59:21 +08:00
@shintendo 看了源代码才知道,找 p 和 q 的算法太简单粗暴了。运气不好的话,算一天都遇不上。
Citrus
2020-02-24 10:00:06 +08:00
1. 个人并不认为这是教程的缺陷,因为如何选大素数可以单独拎出来说一整篇文章,完全没必要在 RSA 的文章里详细说。就像我告诉你如何检测牛奶的成分,会告诉你取一杯牛奶,但是不会把《奶牛的产后护理》一并附上
2. 请看仔细,Python 并不是从 2 3 5 7 这样一个个的数到足够大。我不知道你是怎么把这段源码理解成这样的。。。这样数每次生成密钥还不到天荒地老。而且一个个数上去只要稍微会一点算法的人都知道是没必要的。因为素数都是各自独立的,找一个大素数完全没必要从 2 数上来
3. 关键函数:rsa.randnum.read_random_odd_int(nbits)
Citrus
2020-02-24 10:01:30 +08:00
@itskingname 一天都遇不到的结论是如何得出的?请给出你的计算。RSA 的素数获取是有数学论证的,请不要不给证据的直接猜想。
coderluan
2020-02-24 10:02:52 +08:00
@shintendo 我记得应该是从足够位数的最小数开始递增,直到找到一个质数。

PS:生成质数算是和正经问题,但是说这个是别人文章的缺陷就太扯了,我感觉看 RSA 文章的人,是有能力搜索解决这个问题的,写文章不可能所有东西都说清楚的。
shintendo
2020-02-24 10:07:34 +08:00
@coderluan 印象中第一个数是随机取的,往后开始递增
@itskingname 不会遇不到,素数的密度有数学论证的
itskingname
2020-02-24 10:09:08 +08:00
@Citrus 2,3,5 是我还没有看源代码的时候猜的,发了这篇帖子我去看了一下源代码,然后截图贴过来。因为怕过了 6 分钟改不了了,所以贴了图又直接发。导致前面的文字没有修改
est
2020-02-24 10:11:08 +08:00
这就是为啥喊不要自己造加密库轮子的原因
itskingname
2020-02-24 10:11:25 +08:00
@Citrus #4,因为它的 randomnum 这个模块里面,获取随机计数是没有去重的。运气不好的情况下,始终获取的都是非质数的奇数。而且会重复获得。
itskingname
2020-02-24 10:13:04 +08:00
@shintendo 它不是递增计算的。它就是不停获取这么多位的随机奇数,然后反复验证是不是质数。
swulling
2020-02-24 10:14:01 +08:00
@itskingname #2 一天都找不到?你可以自己跑下 benchmark 看看
mxT52CRuqR6o5
2020-02-24 10:18:24 +08:00
在数学上去验证一个数是不是素数确实是很慢的,所以你会想不通,但实际操作是现在有快速验证一个数是否是素数的方法,可以快速判断一个数是否是工程实践中可用的素数(验出来的数大概率是素数)
itskingname
2020-02-24 10:24:12 +08:00
@swulling 我都说了在运气不好的情况下。现实中不容易出现这样的极端情况。
falsemask
2020-02-24 10:31:03 +08:00
Miller-Rabin 素数检测,可以了解一下,java BigInteger 类用的是这个算法
Mohanson
2020-02-24 10:36:32 +08:00
素数除了产设随机数再判断是否素数, 没有其它方法了吧?

如果有的话, 等于"找到了素数通项公式"...
itskingname
2020-02-24 10:44:21 +08:00
@Mohanson 产生随机数再判断,在大多数情况下效果不错,但极端情况下就很慢,因为 python-rsa 库里面没有做去重处理,可能运气不好多次产生同一个非质数奇数。

而从最小的 nbit 奇数开始逐渐增加 2,一个一个遍历,不会重复。效率平庸,但不容易出现极端情况。
ETiV
2020-02-24 10:49:21 +08:00
#14 +1

but 那个算法并不能保证被检测的数 100%是质数
但是够快
swulling
2020-02-24 10:50:36 +08:00
@itskingname
1. 统计学就是避免运气的影响,根据素数密度分布能够得到 getprime 耗时的数学期望
2. 验证是否为素数非常快,参考 https://en.wikipedia.org/wiki/Miller%E2%80%93Rabin_primality_test
3. 性能多做 benchmark,随手做一个 1000 loop 的 128 位素数

In [4]: timeit.timeit("rsa.prime.getprime(128)", setup="import rsa", number=1000)
Out[4]: 4.098196368999993

如果仅仅说,运气不好就 XXX,那么基本上对统计学没有实际的逻辑概念
mxT52CRuqR6o5
2020-02-24 10:52:53 +08:00
@itskingname 你这样就不够安全了,生成素数是一次性操作,慢一点也没关系,安全才是第一目的,慢不慢什么的无所谓的,不要本末倒置了
swulling
2020-02-24 11:04:02 +08:00
@itskingname #16

1. 如果顺序遍历,那么你的 p 和 q 不是都被人知道了么?这个还有什么安全性可言?

2. #17 我记得 Miller Rabin 通过一些方法可以在特定的范围内,比如 2 的 32 次方内,确定 100%是否为素数。不太懂,有懂的可以补充

3. 其实工程上并不需要 100%的准确,因为验证素数足够快,所以随机选了极大次,都不是素数的概率应该非常的低。具体多少我算不出来,但是应该有人能够算出来。如果这个概率低到了和宇宙射线把你的 bit 反转的概率都还要低,真的要从工程上讨论它么?

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/646975

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX