V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
V2EX 提问指南
szvone
V2EX  ›  问与答

安卓上一个奇怪的 rsa,每次加密结果都一样

  •  2
     
  •   szvone · 2020-01-09 00:00:11 +08:00 · 5701 次点击
    这是一个创建于 1541 天前的主题,其中的信息可能已经有所发展或是发生改变。

    排版乱了,请看一楼

    38 条回复    2020-01-09 15:33:18 +08:00
    szvone
        1
    szvone  
    OP
       2020-01-09 00:00:54 +08:00
    有这么一个函数:

    public static String a(String str, String str2) throws Exception {
    Cipher v1 = Cipher.getInstance("RSA");
    v1.init(1, KeyFactory.getInstance("RSA").generatePublic(new X509EncodedKeySpec(Base64.decode(str2,Base64.DEFAULT))));
    return Base64.encodeToString(v1.doFinal(str.getBytes()),Base64.DEFAULT);
    }

    用下面的代码调用:

    String key = "MFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBAI6Nnwc6Doyk6sFvN/oVbsjS+EhV661qfVrgfJ/PTNev\n" +
    "uDjQQvI8pjooKreTab2sbSUuv2otPxfLC+IyN58ye7UCAwEAAQ==";

    String res = null;

    try {

    res = a("13888888888",key);

    } catch (Exception e) {

    e.printStackTrace();

    }


    得到的 res 始终会是:LTaf1+LNtbI0NHMISTHuiY10rYKQK0BhqkgHqcrM1N8nYWZXUR0WuKMvU4ZzCZD1D0hdO9ZhcXuM1NdL0mOSyg==


    且这个 res 永远都是这个值,RSA 加密的话不是每次都会变动吗,为啥这个就不会变动呢?

    这个用 javascript 怎么实现呢?
    momocraft
        2
    momocraft  
       2020-01-09 00:14:49 +08:00
    为什么你会期待变动啊
    CEBBCAT
        3
    CEBBCAT  
       2020-01-09 00:57:59 +08:00 via Android
    可能是你选的版本的事儿。发代码可以用 gist

    麻烦您发帖前不要忘记先 Google,我一搜就有 https://blog.csdn.net/guyongqiangx/article/details/74930951
    bkmi
        4
    bkmi  
       2020-01-09 01:02:52 +08:00
    因为你 Cipher.getInstance() 传错参数了,看一下文档。
    szvone
        5
    szvone  
    OP
       2020-01-09 01:26:11 +08:00 via iPhone
    @CEBBCAT 大佬,我问的是为啥不会变动
    szvone
        6
    szvone  
    OP
       2020-01-09 01:26:53 +08:00 via iPhone
    @momocraft 因为 rsa 是非对称加密 每次的加密结果不是应该要变动才对吗
    szvone
        7
    szvone  
    OP
       2020-01-09 01:27:52 +08:00 via iPhone
    @bkmi 有个问题就是如果不用安卓的话,用 Java 跑,他会变动
    CEBBCAT
        8
    CEBBCAT  
       2020-01-09 01:30:50 +08:00 via Android
    @szvone 大哥,我给你提供了两个信息:

    1. Google 就有
    2. 有人详细调查了为什么他那边回回不同

    拿出你的主观能动性来啊!
    CEBBCAT
        9
    CEBBCAT  
       2020-01-09 01:32:00 +08:00 via Android
    @szvone 我吊,谁说非对称就要回回不一样了?
    webshe11
        10
    webshe11  
       2020-01-09 01:39:42 +08:00
    把 a() 改成 random() 保证回回都不一样(滑稽
    crab
        11
    crab  
       2020-01-09 01:40:34 +08:00
    填充用的全 0 或者 F 不是随机数吧
    yicong135
        12
    yicong135  
       2020-01-09 01:51:52 +08:00 via Android
    👏
    nvkou
        13
    nvkou  
       2020-01-09 02:00:23 +08:00 via Android
    输入不变输出还变?还是不是一一映射了?非对称是不能推导出私钥而保证加密方安全。
    xiri
        14
    xiri  
       2020-01-09 04:17:28 +08:00 via Android
    你对非对称加密貌似有什么误解
    geelaw
        15
    geelaw  
       2020-01-09 04:42:59 +08:00 via iPhone   ❤️ 3
    @momocraft #2
    @CEBBCAT #9
    @nvkou #13
    @xiri #14

    一个定理:一个具有最基本安全性(具体来说是语义安全)的非对称加密算法必须满足,正常生成的密钥,加密同一消息两次,密文相同的概率必须非常小。

    回到题主的问题,我个人并不是很懂 Java 的 API,根据文档字符串是 RSA 的时候使用 PKCS#1 定义的 RSA 变换,我个人也不是很懂 PKCS#1,一个可能的理解是 Android 上该算法的实现是 RSA 陷门函数,并不是一个安全的加密算法。
    isnullstring
        16
    isnullstring  
       2020-01-09 08:28:39 +08:00
    私钥 解密
    公钥 加密
    那你的公钥变了没?
    mxT52CRuqR6o5
        17
    mxT52CRuqR6o5  
       2020-01-09 08:30:08 +08:00 via Android
    @geelaw 是密码体制而不是非对称加密算法吧
    geelaw
        18
    geelaw  
       2020-01-09 08:41:08 +08:00 via iPhone   ❤️ 1
    @mxT52CRuqR6o5 #17 和非对称密码学紧密相关的算法可以总称为“非对称密码(学)算法”,而“非对称加密算法”是指非对称加密方案 (public-key encryption scheme) 的加密算法 (encryption algorithm)。
    baicheng10
        19
    baicheng10  
       2020-01-09 08:43:15 +08:00
    @geelaw #14 正常生成的密钥,加密同一消息两次,密文相同的概率必须非常小 ---> 相同的密钥,加密同一消息数次,密文各不相? 你这是“量子加密”么 ……
    ThirdFlame
        20
    ThirdFlame  
       2020-01-09 08:50:32 +08:00
    非对称加密 没有说在明文 和 秘钥不改变的情况下,密文会变的说法。

    但是有些加密函数自带了填充,比如 最优非对称加密填充(OAEP),那么每次加密时会对明文进行了填充(每次填充都不一样),就导致了密文每次都会发生变化。
    bagel
        21
    bagel  
       2020-01-09 08:52:12 +08:00   ❤️ 1
    Padding 导致的。说白了就是没有真正理解 RSA 加密算法。

    上面 geelaw 已经指出来了,还一堆人在那不懂装懂。另外,geelaw 你最后“可能的理解”是错的,Android 上的 API 是正确的,只是有些人不会用又不愿意读文档而已。
    ThirdFlame
        22
    ThirdFlame  
       2020-01-09 08:53:35 +08:00
    @geelaw
    @baicheng10
    在没有填充的情况下,明文 秘钥不变的情况下,密文不变。
    在最优非对称加密填充(OAEP) 下 明文 秘钥不变的情况下,密文会变。根本原因是明文被填充了一些东西(每次还不一样),其实也就是明文变化了,所以导致了密文变化。
    有些填充方式是固定的,不会导致每次填充后的明文变化,也就不会产生密文的变化。
    CEBBCAT
        23
    CEBBCAT  
       2020-01-09 08:54:45 +08:00 via Android   ❤️ 2
    @baicheng10 他这个还真没说错,你去搜索一下 语义安全 就明白了,或者去看这个链接: https://www.zhihu.com/question/305995210
    mxT52CRuqR6o5
        24
    mxT52CRuqR6o5  
       2020-01-09 09:01:31 +08:00 via Android
    @geelaw 能说一下 [一个具有最基本安全性(具体来说是语义安全)的非对称加密算法必须满足,正常生成的密钥,加密同一消息两次,密文相同的概率必须非常小] 这个说法是从哪来的吗?查了半天没查到
    KingPL
        25
    KingPL  
       2020-01-09 09:09:53 +08:00
    sm2 每次加密后不一样,但依旧可以重放攻击,正常后端解密后也需要验签,防重放攻击
    baicheng10
        26
    baicheng10  
       2020-01-09 09:22:20 +08:00
    @CEBBCAT #22 明白了,谢谢。
    geelaw
        27
    geelaw  
       2020-01-09 09:25:35 +08:00   ❤️ 2
    @bagel #21 根据 #7 的说法,另一个 Java runtime 的实现是不同的,我猜另一个实现是 Sun 或者 Oracle 的,这个实现出现如此严重错误的可能感觉也不大。

    @baicheng10 #19 如果你加密同一条消息多项式次,密文以极高的概率各不相同。
    @ThirdFlame #20 确定性加密并不安全。
    @mxT52CRuqR6o5 #24 你可以参考 #23 的链接。
    ThirdFlame
        28
    ThirdFlame  
       2020-01-09 09:45:12 +08:00
    @geelaw 安全不安全 不是我所说的那段话所要讨论的。 我只是想说明 为啥非对称加密 其实是不会变的。 而有些函数,为啥会变。

    你的问题 其实就是要去看 那个函数实现里面有没有填充。 而不是问 “RSA 加密的话不是每次都会变动吗,为啥这个就不会变动呢?”
    xiri
        29
    xiri  
       2020-01-09 10:11:11 +08:00 via Android
    @geelaw
    我姑且是学过密码学的。
    根据我学到的原理,rsa 加密时所取的参数都是确定值,在明文不变的情况下计算出来的结果不可能会发生变化。
    你说的“每次加密结果不同”貌似是同属于非对称密码体制下的椭圆曲线加密算法才有的性质。
    椭圆曲线加密除了明文和一些必要参数,还用到了一个随机选取的 k 值。这个 k 值不需要让解密者知道,不会影响解密,但 k 值的变化会影响密文的结果。
    xiri
        30
    xiri  
       2020-01-09 10:14:20 +08:00 via Android
    @xiri 我这里只是从纯理论层面说明,不考虑实际应用时存在的填充之类的行为
    geelaw
        31
    geelaw  
       2020-01-09 10:23:25 +08:00 via iPhone
    @ThirdFlame #28 楼主觉得自己选择了 RSA 加密算法,应该同一明文得到很多不同的密文,回复中问为什么非对称加密都要明文有不同的密文。一个不安全的非对称加密算法(仅符合语法和正确性)当然没有必要有随机化的加密算法。显然讨论不安全的加密算法是否非要随机并不是楼上一些回复的疑惑。

    另外,那个问题不是“我的问题”。

    @xiri #29

    之前我一直是说结论,懒得提症结,觉得还是需要点明一下:很多回复混淆了 RSA 陷门函数和(安全的) RSA 加密。
    szvone
        32
    szvone  
    OP
       2020-01-09 10:36:48 +08:00
    @bagel
    @geelaw
    @xiri
    @ThirdFlame
    @CEBBCAT

    感谢各位大佬的回复,我遇到的问题是,如果在电脑上面跑 main 函数,那么这个加密结果是会变动,如果在安卓上用按钮事件触发,这个加密结果始终不变,在无法改动安卓代码的情况下,服务端应该如何编写这个加密过程
    Delon
        33
    Delon  
       2020-01-09 10:41:54 +08:00
    楼上就 @geelaw 一个明白人,楼主要查问题也要从 padding 上面查
    Delon
        34
    Delon  
       2020-01-09 10:44:07 +08:00
    收回第一句,楼上还是挺多明白人的,我眼瞎
    jacklin96
        35
    jacklin96  
       2020-01-09 10:51:10 +08:00
    @geelaw 看你的头像好像很眼熟 然后去 fb 看了一眼 发现你躺在我的推荐好友列表里
    3dwelcome
        36
    3dwelcome  
       2020-01-09 11:04:57 +08:00
    RSA 有两种填充。
    第一种叫签名报文(PKCS#1 Type 01),保证每次签名后,结果都不变,好知道谁签名的(比如 TLS 里的 RSA)。
    第二种才叫加密((PKCS#1 Type 02),保证每次加密后,结果都变化,增加安全性。
    bagel
        37
    bagel  
       2020-01-09 11:30:33 +08:00
    我再详细说下吧

    @szvone #32 你在 Android 上面调用 init 方式没有指定 iv,这是为啥每次结果都一样的原因。安全的做法是像下面这样调用
    cipher.init(Cipher.ENCRYPT_MODE, keySpec, new IvParameterSpec(ivBytes));

    @geelaw #27 Android 和 Java 上面实现不同,Android 默认没有用随机 iv 填充。这是实现的差异,两者都是符合规范的。spec 里原文是
    If this cipher requires any algorithm parameters that cannot be derived from the given key, the underlying cipher implementation is supposed to generate the required parameters itself (using provider-specific default or random values)

    参考: https://stackoverflow.com/questions/31036780/android-cryptography-api-not-generating-safe-iv-for-aes#31037133
    szvone
        38
    szvone  
    OP
       2020-01-09 15:33:18 +08:00 via iPhone
    ^_^已经完全理解,感谢各位大佬不吝赐教
    @bagel
    @3dwelcome
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   我们的愿景   ·   实用小工具   ·   2802 人在线   最高记录 6543   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 37ms · UTC 14:47 · PVG 22:47 · LAX 07:47 · JFK 10:47
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.