2015-05-13 178 views
0

我想通过java.security.SecureRandom生成一个只包含字母和数字的字符串(我称之为“盐”,但它可能不是正确的术语) 。使用只包含字母和数字的java.security.SecureRandom生成一个字符串

Random ran = new SecureRandom(); 
byte [] salt = new byte[32]; 
ran.nextBytes(salt); 
String str = new String(salt,"utf-8"); 
System.out.println(str); 

结果不好,因为它包含了我不想要的“?#.....”之类的东西。

如何生成一个像9c021ac3d11381d9fb2a56b59495f66e一样的随机字符串?

+0

可能重复的[如何生成一个随机的字母数字字符串?](http://stackoverflow.com/questions/41107/how-to-generate-a-random-alpha-numeric-string) – ceekay

+0

作者想要生成一个由字母和数字组成的随机字符串。这不是盐,所以我主要删除了这个词(留下一个解释性说明)。这使得问题可以回答,但可能过于宽泛,因为OP在他的代码中没有努力将随机字符串限制为字母和数字,所以结果不会限制为字母和数字并不奇怪。 –

回答

0

“9c021ac3d11381d9fb2a56b59495f66e”看起来像盐的十六进制表示。

盐转换可以使用:

String str = bytesToHex(salt); 

final protected static char[] hexArray = "abcdef".toCharArray(); 
public static String bytesToHex(byte[] bytes) { 
    char[] hexChars = new char[bytes.length * 2]; 
    for (int j = 0; j < bytes.length; j++) { 
     int v = bytes[j] & 0xFF; 
     hexChars[j * 2] = hexArray[v >>> 4]; 
     hexChars[j * 2 + 1] = hexArray[v & 0x0F]; 
    } 
    return new String(hexChars); 
} 

如果速度并不重要,你也可以使用:从javax.xml.bind.DataTypeConverter

0

下面类

字符串printHexBinary(字节[])将产生盐。你也可以选择你的盐的字母和数字。

public class SaltGenerator { 
      private static SecureRandom prng; 
      private static final Logger LOG = LoggerFactory 
        .getLogger(AuthTokenGenerator.class); 
      static { 
       try { 
        // Initialize SecureRandom 
        prng = SecureRandom.getInstance("SHA1PRNG"); 
       } catch (NoSuchAlgorithmException e) { 
        LOG.info("ERROR while intantiating Secure Random: " + prng); 
      } 
     } 
     /** 
     * @return 
     */ 
     public static String getToken() { 
      try { 
       LOG.info("About to Generate Token in getToken()"); 
       String token; 
       // generate a random number 
       String randomNum = Integer.toString(prng.nextInt()); 
       // get its digest 
       MessageDigest sha = MessageDigest.getInstance("SHA-1"); 
       byte[] result = sha.digest(randomNum.getBytes()); 
       token = hexEncode(result); 
       LOG.info("Token in getToken(): " + token); 
       return token; 
      } catch (NoSuchAlgorithmException ex) { 
       return null; 
      } 
     } 
     /** 
     * @param aInput 
     * @return 
     */ 
     private static String hexEncode(byte[] aInput) { 
      StringBuilder result = new StringBuilder(); 
      char[] digits = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 
        'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z' }; 
      for (byte b : aInput) { 
       result.append(digits[(b & 0xf0) >> 4]); 
       result.append(digits[b & 0x0f]); 
      } 
      return result.toString(); 
     } 
} 
1

为什么不使用Base64编码转换盐?寻找Apache Commons Codec,Base64类。

然后,可以将字节数组转换为使用

Base64.encodeBase64String(salt); 
+0

是的,Base64 = 10个数字+26个小写字母+26个大写字母+2个特殊字符。所以几乎适合。这两个特殊字符也可以是URL安全的。 Java 8在最终的Base64类中整合了BASE64编码。 –

+0

@JoopEggen是除了特殊字符(+ /和=)...也许不完全是OP想要的。如果OP使用SO重复链接,可能是最好的... –

1

可以打开在一个BigInteger字节字符串,做一个基座62(= 10 + 26 + 26)在其上的转换。

// Digits listed, so maybe look-alike chars (zero and oh) can be handled. 
private static final String digits = "0123...ABC...abc...z"; 

String humanReadable(byte[] bytes) { 

    // Ensure that we have a byte array which is a positive big-endian. 
    if (bytes.length != 0 && bytes[0] < 0) { 
     byte[] ubytes = new byte[bytes.length + 1]; 
     System.arraycopy(bytes, 0, ubytes, 1, bytes.length); 
     bytes = ubytes; 
    } 

    BigInteger n = new BigInteger(bytes); 
    StringBuilder sb = new StringBuilder(48); 
    final BigInteger DIGIT_COUNT = BigInteger.valueOf(digits.length()); 
    while (n.signum() != 0) { 
     int index = n.mod(DIGITS).intValue(); 
     sb.append(digits.charAt(index)); 
     n = n.div(DIGITS); 
    } 
    return sb.toString(); 
} 
相关问题