【问题标题】:Java SecureRandom as saltJava SecureRandom 作为盐
【发布时间】:2015-02-23 22:28:16
【问题描述】:

这是为密码生成盐的正确方法吗?

        SecureRandom random = new SecureRandom();
        byte[] salt = random.generateSeed(64);

        String decoded = new String(salt, "Cp1252");
        System.out.println(decoded);

我正在尝试生成新密码 (SHA-512),所以我还需要一个盐。
散列密码将是 = 用户密码 + salt ...这是正确的吗?
这些奇怪的字符不会“破坏”数据库(MySQL)吗? (更新:不,因为盐应该被加密/编码/散列,结果不应该使用奇怪的字符)

很少输出:

ã2}wÑ»-ÄKÇæê®ƒzR4qÉÖÙÚ!ž0ÉW9;*Vß4x»)
àöˆ˜£¿{,J¼…HþTù#+Bv(Fp´G~Aò`^e_ElpíÜžS  A!­ñÛz‹y@`ý‡)‡ª€
5a£Æ.¥sgöfÈB:4-�y$Óx%Óâyý¾N¨…áq

这些盐是否也应该被加密为 SHA-512? (更新:使用来自 apache commons encode 的 base64 库进行编码,见下文)

更新

        SecureRandom random = new SecureRandom();
        byte[] saltArr = new byte[64];
        random.nextBytes(saltArr);

        String salt = new String(saltArr, "Cp1252");
        System.out.println("SALT:"+salt);


        byte[] encodedBytes = Base64.encodeBase64(saltArr);
        System.out.println("Encoded SALT:" + new String(encodedBytes));

        byte[] decodedBytes = Base64.decodeBase64(encodedBytes);
        System.out.println("Decoded SALT:" + new String(decodedBytes, "Cp1252"));


        //SHA
        String target = "Test";
        MessageDigest sh = MessageDigest.getInstance("SHA-512");
        sh.update(target.getBytes());
        StringBuffer sb = new StringBuffer();
        for (byte b : sh.digest()) sb.append(Integer.toHexString(0xff & b));
        System.out.println("Hashed PWD:"+sb);

        //And then joining them together... 

【问题讨论】:

标签: java mysql security


【解决方案1】:

首先,使用nextBytes(实际上调用PRNG)代替generateSeed就足够了。后者使用种子生成算法,这是一个更复杂的操作,因为它需要一个熵源(800-90A p19-23

盐的主要功能是防御字典攻击 与密码哈希列表和预先计算的彩虹相比 表攻击。 (Wikipedia)

换句话说,you need a different salt for each password,但盐不是秘密(您将把它与摘要输出一起存储),并且您 PRNG 的输出应该没问题。

此外,由于盐(可能包含完整范围 0x00-0xFF 中的字节)将作为字符串保存,因此应将其编码*为 Base64(或其他字符集安全编码,例如 base 85,但 base64 更常见)。

*SHA is not an encryption function.

SecureRandom random = new SecureRandom();
byte[] salt = new byte[64];
random.nextBytes(salt);

String password="god";
MessageDigest md = MessageDigest.getInstance("SHA-512");
md.update(password.getBytes(Charset.forName("UTF-8")));
md.update(salt);

byte[] digest = md.digest();

【讨论】:

  • 哦,是的,抱歉,有时我将散列与加密混淆了...更新,您能检查一下它是否正确吗?
  • 是的。但请注意,getBytes() 使用平台的默认字符集将字符串编码为字节序列。如果您将应用程序迁移到具有不同默认字符集的另一个平台,则相同的密码和盐值可能会散列为不同的值;所以我使用了getBytes(Charset)。另请注意,Integer.toHexString(0xff & b) 并不总是返回两个字符。
猜你喜欢
  • 2023-03-13
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-02-22
  • 1970-01-01
  • 2012-08-28
  • 1970-01-01
  • 2017-03-15
相关资源
最近更新 更多