V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
thinkershare
V2EX  ›  信息安全

关于 RSA 加密解密的疑惑

  •  
  •   thinkershare · 2022-02-15 11:37:17 +08:00 · 4082 次点击
    这是一个创建于 1011 天前的主题,其中的信息可能已经有所发展或是发生改变。

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

    26 条回复    2022-03-04 16:54:03 +08:00
    abersheeran
        1
    abersheeran  
       2022-02-15 11:41:58 +08:00
    不是不能,是一般不这么做。因为 RSA 的在计算机上的运算速度远比 HASH 要慢得多。
    rimutuyuan
        2
    rimutuyuan  
       2022-02-15 11:48:52 +08:00
    但部分场景我只需要数据不被篡改, 内容可以是透明的

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


    私钥加密,公钥解密需求场景不明确,公钥是公开的,又能解密,还不如不加密了
    newmlp
        3
    newmlp  
       2022-02-15 11:49:35 +08:00
    私钥一般用来加密哈希值,做数字签名
    mxT52CRuqR6o5
        4
    mxT52CRuqR6o5  
       2022-02-15 11:53:12 +08:00
    签名就是 private key 加密, public key 解密啊
    为什么签名是对原内容的 HASH 加密而不是对原内容加密,是因为加密慢啊,对原内容用 private key 加密来实现签名工程设计上不合理
    newmlp
        5
    newmlp  
       2022-02-15 11:53:27 +08:00
    而且 rsa 的加解密性能很感人,所以实际中都是用 rsa 加密对称加密的密钥和哈希值,不过非对称加密算法 rsa 用的也很少,现在基本都用 ecc 的变种算法
    rrfeng
        6
    rrfeng  
       2022-02-15 11:54:35 +08:00
    你自己都说明白了啊
    1. private key 加密等于没有加密,所有人都可以看到。只是『无法伪造』。
    2. 实现『无法伪造』只需要签名算法就可以了(签名=private 加密 hash ),计算速度快。比如你有 10G 的文件要签名,算 hash 秒出,RSA 加密一遍可能好几分钟。你选哪个?
    thevita
        7
    thevita  
       2022-02-15 11:57:26 +08:00
    可以啊,谁说不可以,随便找了个,https://stackoverflow.com/questions/10332022/rsa-decryption-with-a-public-key
    ----
    不过不建议自己瞎用,性能是一方面,密码误用脑壳痛,一般团队也不可能有那么多精力搞这个
    Reficul
        8
    Reficul  
       2022-02-15 12:00:44 +08:00 via iPhone
    用私钥加密,那个叫签名
    eivenchan
        9
    eivenchan  
       2022-02-15 12:36:59 +08:00   ❤️ 8
    这个问题要从两方面来看,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 算法原理: https://www.ruanyifeng.com/blog/2013/06/rsa_algorithm_part_one.html
    欧拉定理: https://zh.wikipedia.org/wiki/%E6%AC%A7%E6%8B%89%E5%AE%9A%E7%90%86_(%E6%95%B0%E8%AE%BA)
    中国剩余定理: https://zh.wikipedia.org/wiki/%E4%B8%AD%E5%9B%BD%E5%89%A9%E4%BD%99%E5%AE%9A%E7%90%86
    eivenchan
        10
    eivenchan  
       2022-02-15 12:40:31 +08:00
    @eivenchan 补充一下,数字签名这个场景,在 rsa 库一般会提供独立的方法(加密:signature, 解密:verify),跟加密,解密方法区分开。
    leimao
        11
    leimao  
       2022-02-15 12:47:07 +08:00   ❤️ 1
    以前数学推导过这个整套系统:
    https://leimao.github.io/blog/Public-Key-Cryptosystem-and-Digital-Signature/
    https://leimao.github.io/article/RSA-Algorithm/
    但是现在有些忘了。希望这整个数学过程对你的理解有所帮助。
    3dwelcome
        12
    3dwelcome  
       2022-02-15 12:47:31 +08:00   ❤️ 1
    “但我很疑惑为什么不能通过 public key 能否解密和解密后的内容来预防篡改?”

    为了避免被暴力破解,真正的 RSA 加密,都是不验证结果是否正确的。
    0o0O0o0O0o
        13
    0o0O0o0O0o  
       2022-02-15 12:48:01 +08:00 via iPhone   ❤️ 1
    openssl 这些库是支持这种操作的,所以原理上是能的;很多语言的 crypto 库不支持,那是因为不推荐这种做法。
    Bromine0x23
        14
    Bromine0x23  
       2022-02-15 12:51:07 +08:00
    只对 hash 加密没啥安全上的考虑,纯粹是对比整体加密,安全性不会降低的情况下效率上更优
    liliclinton
        15
    liliclinton  
       2022-02-15 13:09:14 +08:00
    1. 相比对全文加密,对 hash 加密效率更高
    2. 验证签名可以放在异步逻辑进行,不影响内容的读取
    leeyuzhe
        16
    leeyuzhe  
       2022-02-15 13:23:34 +08:00
    jwt 不就是私钥加密
    cjw1115
        17
    cjw1115  
       2022-02-15 13:48:04 +08:00   ❤️ 1
    私钥加密,公钥解密,就可以用来做授权。
    我们就是这么用的,客户把它们机器的特征码发给我们,我们用私钥加密。当然前提是客户给的特征码不可伪造。或者说伪造成本比较高。
    thinkershare
        18
    thinkershare  
    OP
       2022-02-15 14:13:06 +08:00
    @cjw1115 我了解原理, 我使用的场景和你一样, 但我发现.NET 的各种加密库都不支持此操作, 我在 Stackoverflow 也找了一些类似的提问, 没有搞明白很多库直接不支持的原因, 我要加密的内容非常短, 因此速度不是问题
    Citrus
        19
    Citrus  
       2022-02-15 14:21:42 +08:00   ❤️ 1
    @thinkershare 可能是因为大部分库帮你封装好了 sign verify 接口吧。
    另外,这个疑问也不是第一天看到了。。。
    /t/704756
    /t/809833
    /t/826703
    /t/542814
    等等等等。。。
    lakehylia
        20
    lakehylia  
       2022-02-15 14:33:56 +08:00
    RSA-1024 理论上每次最大能加密 1024 位,也就是 128 个字节不到,RSA 加密又慢,你觉得 RSA 加密 10G 的文件要多久。。。正常的做法是加密文件的 HASH ,达到签名的目的。
    datoujiejie221
        21
    datoujiejie221  
       2022-02-15 14:45:19 +08:00
    先看个公钥和私钥的公式
    第一步,随机选择两个不相等的质数 p 和 q 。
    第二步,计算 p 和 q 的乘积 n 。
    第三步,计算 n 的欧拉函数φ(n)。
    第四步,随机选择一个整数 e ,条件是 1< e < φ(n),且 e 与φ(n) 互质。(常常选择 65537 )
    第五步,计算 e 对于φ(n)的模反元素 d 。
    第六步,将 n 和 e 封装成公钥,n 和 d 封装成私钥。

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

    内容加密场景是 我发出去的消息 只有对方能解 所以用公钥加密
    签名的场景是 我发出的消息并且把公钥发给对方 对方要用公钥认证是我发出去的消息 如果发送的是私钥的话 公钥也就暴露了
    GeruzoniAnsasu
        22
    GeruzoniAnsasu  
       2022-02-15 15:41:57 +08:00
    总结 Q&A:

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

    答:并不出于安全方面的考虑,而是效率和通用性

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

    答: 原文是否被篡改过并不影响解密过程,在没有附带摘要( hash )的情况下是无法得知解密结果是否「正确」或者「能否解密」的。hash 的作用就是告诉你原文写了什么,解密后的原文 rehash 比对加密过的「真·原 hash 」一致,这才是签名防篡改的关键逻辑。你的设想是否漏掉了什么?
    thinkershare
        23
    thinkershare  
    OP
       2022-02-15 16:22:10 +08:00
    @GeruzoniAnsasu 嗯, 你说到了关键, 就是在不知道私钥的情况下, 能否对私钥加密的内容定向篡改? 否则随意篡改的内容解密后结果就是未知的,攻击者没法定向伪造, 这样解密后的内容, 将无法按照预定义的格式还原. 嗯, 加密的确不能当作签名使用, 是我想错了. 我原本以为内容被修改后解密会失败😅
    lucybenz
        24
    lucybenz  
       2022-02-15 16:25:46 +08:00
    加密通信 等于 我把我家信箱全部打开,任何一个人都可以过来 选择其中一个信箱扔进去一封信 一摔门锁上,这封信只有我自己可以打开,投信人可以确保 不被其他人截取;

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

    这是两个不同场景
    kxuanobj
        25
    kxuanobj  
       2022-02-15 16:32:31 +08:00   ❤️ 1
    假设你有条消息,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 的话,那就是原消息。中间人无害转发,也挺好。
    youngbug
        26
    youngbug  
       2022-03-04 16:54:03 +08:00   ❤️ 1
    rsa 签名方案,是先对待签名数据进行 hash ,再进行私钥运算是,因为待签名数据长度不确定,如果长度大于 rsa 的模长,那么一次 RSA 运算,如果是 1024bit 密钥,理论上只能对 128 字节待签名数据进行签名,如果你对一个很大的数据进行签名,要执行多次 RSA 私钥运算,会产生一堆签名结果数据,很不合理。

    对待签名数据进行 hash ,保证了最后只用做一次 rsa 私钥运算,也保证签名结果数据长度是固定的。

    你的要防止篡改的内容长度是固定的么?如果固定且长度小于 rsa 密钥的模长,那你可以直接对原文进行私钥运算。如果你要签名的数据很长,你自己设计的 rsa 签名,那你就把代签名的数据分组,一组一组的做私钥运算,生成一组一组的签名数据,验签的时候一组一组验签,也没问题。。
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   3765 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 22ms · UTC 05:11 · PVG 13:11 · LAX 21:11 · JFK 00:11
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.