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

AES 256 生成秘钥的时候 可以不使用 SecureRandom 的生成的写法吗

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

    查到一般的写法是 利用了 SecureRandom

    private static SecretKeySpec getSecretKey(final String key) { //返回生成指定算法密钥生成器的 KeyGenerator 对象 KeyGenerator kg = null;

        try {
            kg = KeyGenerator.getInstance(KEY_ALGORITHM);
    
            SecureRandom secureRandom = SecureRandom.getInstance("SHA1PRNG");
            secureRandom.setSeed(key.getBytes("utf-8"));
            kg.init(256, secureRandom);
    
            //生成一个密钥
            SecretKey secretKey = kg.generateKey();
            // 转换为 AES 专用密钥
            return new SecretKeySpec(secretKey.getEncoded(), KEY_ALGORITHM);
        } catch (NoSuchAlgorithmException | UnsupportedEncodingException ex) {
            Logger.getLogger(AESUtil.class.getName()).log(Level.SEVERE, null, ex);
        }
    
        return null;
    }
    

    不使用 SecureRandom 也能一句话默认生成 128 长度的

            return new SecretKeySpec(key.getBytes("ASCII"), KEY_ALGORITHM);
    
    11 条回复    2020-11-10 14:51:35 +08:00
    BrettD
        1
    BrettD  
       2020-11-09 14:50:49 +08:00 via iPhone   ❤️ 1
    用安全随机数生成器生成的随机密钥好一些
    rqxiao
        2
    rqxiao  
    OP
       2020-11-09 14:54:24 +08:00
    就是想请问下
    AES 256 生成秘钥的时候 不使用 SecureRandom 可以吗,写法是什么样的

    还有 SecureRandom 这种写法其实用过 ,但是也不知道为什么每次加密解密都是都是利用 SecureRandom 生成的 key,但是实际上这个 key 并不是“随机的”,加密解密其实都是用同一个 key
    wakzz
        3
    wakzz  
       2020-11-09 15:11:26 +08:00   ❤️ 1
    @rqxiao
    ```
    SecureRandom secureRandom = SecureRandom.getInstance("SHA1PRNG");
    secureRandom.setSeed(key.getBytes("utf-8"));
    ```
    这两行的含义是通过用户指定的种子生成一个安全秘钥,同一个种子多次调用当然生成的都是同一个安全秘钥。你也可以自己随机生成一个加密秘钥,只需要秘钥的比特长度没错就行。
    GM
        4
    GM  
       2020-11-09 15:25:40 +08:00   ❤️ 1
    当然可以,秘钥就是一串随机 byte[]数组而已,用任何方法都可以生成。但是用这个很明显安全性更好啊。
    jim9606
        5
    jim9606  
       2020-11-09 15:49:49 +08:00   ❤️ 1
    之所以要用 SecureRandom 是因为你需要避免你使用的密钥被预测出来。
    常规的伪随机数生成器( PRNG ),例如线性同余 PRNG,生成的内容是可以被预测的(就是说,攻击者可以根据生成器已经生成的随机数推测之后的随机数),而你可能在其他非保密应用中使用过 PRNG 导致攻击者可以获悉以前产生的随机数。因此,密码系统生成随机数应该使用这种不可被预测的密码学安全伪随机数生成器( CSPRNG )
    LLaMA2
        6
    LLaMA2  
       2020-11-09 16:03:30 +08:00
    可以工作,但不合规,上次有个对接的,由于他的代码和 Android 不兼容,结果没得办法,直接 secretKey.getEncoded()写死
    imdong
        7
    imdong  
       2020-11-09 16:24:12 +08:00
    记得 Win 下 Putty 的 Keygen 是在生成时要求用户随机移动鼠标或按键来获取随机数种子。
    sunxiansong
        8
    sunxiansong  
       2020-11-09 18:10:28 +08:00
    补充个例子:生成登陆 token,一般来说主要的需求是 token 唯一,那么是不是可以用 uuid,答案是不行,因为容易被预测,降低碰撞难度。你先用正常账号登陆,拿到 token,从这个 uuid 往后碰,难度不大,碰对了就能登上其他人的账号。
    Jrue0011
        9
    Jrue0011  
       2020-11-10 10:20:34 +08:00
    @rqxiao 第一个方法最终生成的 SecretKeySpec 相同的原因是传入了相同的参数 key(String)并使用这个 key.getBytes("utf-8")得到的相同 byte[]作为随机数种子。
    直接调用 kg.init(256)的话内部会使用一个没有传入随机数种子的 SecureRandom 。
    kahlkn
        10
    kahlkn  
       2020-11-10 13:54:01 +08:00
    话说每次生成密钥时都要调用 “SecureRandom.getInstance("SHA1PRNG");” 来创建一个 SecureRandom 对象真的好吗?据我所知 SecureRandom 的创建应该是 比较耗费性能的,所以一般的用途也是 创建完之后静态化持有,然后 init 的时候传进去( JDK 底层就是用一个类来静态持有)。

    所以由此解决了你的问题,可以不使用 SecureRandom 生成,不使用会有一个默认的 SecureRandom 来替代的。
    rqxiao
        11
    rqxiao  
    OP
       2020-11-10 14:51:35 +08:00
    @Jrue0011 KeyGenerator.init ( 256 )的确是有个默认的 SecureRandom 的,我百度出的一些 aes 加密网站 ,验证下来 128 的时候他们是没有用 SecureRandom,所以就想试下 256 的写法 。不过大家都说 SecureRandom 的确更安全,256 这个也没必要试了。
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   3158 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 33ms · UTC 13:27 · PVG 21:27 · LAX 05:27 · JFK 08:27
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.