public static String getRandomString(int length) {
char[] chars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRST".toCharArray();
StringBuilder sb = new StringBuilder();
Random random = new Random();
for (int i = 0; i < chars.length; i++) {
char c = chars[random.nextInt(chars.length)];
sb.append(c);
}
String randomStr = sb.toString();
return randomStr;
}
public static String randomSeriesForThreeCharacter() {
Random r = new Random();
String value="";
char random_Char ;
for(int i=0; i<10;i++)
{
random_Char = (char) (48 + r.nextInt(74));
value=value+random_char;
}
return value;
}
31
算法
要生成随机字符串,请连接从可接受符号集中随机绘制的字符,直到字符串达到所需长度 .
实施
这是一些用于生成随机标识符的相当简单且非常灵活的代码 . 阅读以下重要应用说明的信息 .
import java.security.SecureRandom;
import java.util.Locale;
import java.util.Objects;
import java.util.Random;
public class RandomString {
/**
* Generate a random string.
*/
public String nextString() {
for (int idx = 0; idx < buf.length; ++idx)
buf[idx] = symbols[random.nextInt(symbols.length)];
return new String(buf);
}
public static final String upper = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
public static final String lower = upper.toLowerCase(Locale.ROOT);
public static final String digits = "0123456789";
public static final String alphanum = upper + lower + digits;
private final Random random;
private final char[] symbols;
private final char[] buf;
public RandomString(int length, Random random, String symbols) {
if (length < 1) throw new IllegalArgumentException();
if (symbols.length() < 2) throw new IllegalArgumentException();
this.random = Objects.requireNonNull(random);
this.symbols = symbols.toCharArray();
this.buf = new char[length];
}
/**
* Create an alphanumeric string generator.
*/
public RandomString(int length, Random random) {
this(length, random, alphanum);
}
/**
* Create an alphanumeric strings from a secure generator.
*/
public RandomString(int length) {
this(length, new SecureRandom());
}
/**
* Create session identifiers.
*/
public RandomString() {
this(21);
}
}
用法示例
为8个字符的标识符创建一个不安全的生成器:
RandomString gen = new RandomString(8, ThreadLocalRandom.current());
为会话标识符创建安全的生成器:
RandomString session = new RandomString();
创建一个带有易于阅读的打印代码的生成器 . 字符串比完整的字母数字字符串长,以补偿使用更少的符号:
String easy = RandomString.digits + "ACEFGHJKLMNPQRUVWXYabcdefhijkprstuvwx";
RandomString tickets = new RandomString(23, new SecureRandom(), easy);
还必须注意使用足够长的标识符,以便在给定预期的标识符总数的情况下不太可能发生冲突 . 这被称为"the birthday paradox." The probability of a collision,p,大约是n2 /(2qx),其中n是实际生成的标识符的数量,q是字母表中不同符号的数量,x是标识符的长度 . 这应该是一个非常小的数字,如2-50或更少 .
package password.generater;
import java.util.Random;
/**
*
* @author dell
*/
public class PasswordGenerater {
/**
* @param args the command line arguments
*/
public static void main(String[] args) {
int length= 11;
System.out.println(generatePswd(length));
// TODO code application logic here
}
static char[] generatePswd(int len){
System.out.println("Your Password ");
String charsCaps="ABCDEFGHIJKLMNOPQRSTUVWXYZ";
String Chars="abcdefghijklmnopqrstuvwxyz";
String nums="0123456789";
String symbols="!@#$%^&*()_+-=.,/';:?><~*/-+";
String passSymbols=charsCaps + Chars + nums +symbols;
Random rnd=new Random();
char[] password=new char[len];
for(int i=0; i<len;i++){
password[i]=passSymbols.charAt(rnd.nextInt(passSymbols.length()));
}
return password;
}
}
2
import java.util.Date;
import java.util.Random;
public class RandomGenerator {
private static Random random = new Random((new Date()).getTime());
public static String generateRandomString(int length) {
char[] values = {'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','0','1','2','3',
'4','5','6','7','8','9'};
String out = "";
for (int i=0;i<length;i++) {
int idx=random.nextInt(values.length);
out += values[idx];
}
return out;
}
}
3
static final String AB = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
static SecureRandom rnd = new SecureRandom();
String randomString( int len ){
StringBuilder sb = new StringBuilder( len );
for( int i = 0; i < len; i++ )
sb.append( AB.charAt( rnd.nextInt(AB.length()) ) );
return sb.toString();
}
import java.util.Random;
public class passGen{
//Verison 1.0
private static final String dCase = "abcdefghijklmnopqrstuvwxyz";
private static final String uCase = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
private static final String sChar = "!@#$%^&*";
private static final String intChar = "0123456789";
private static Random r = new Random();
private static String pass = "";
public static void main (String[] args) {
System.out.println ("Generating pass...");
while (pass.length () != 16){
int rPick = r.nextInt(4);
if (rPick == 0){
int spot = r.nextInt(25);
pass += dCase.charAt(spot);
} else if (rPick == 1) {
int spot = r.nextInt (25);
pass += uCase.charAt(spot);
} else if (rPick == 2) {
int spot = r.nextInt (7);
pass += sChar.charAt(spot);
} else if (rPick == 3){
int spot = r.nextInt (9);
pass += intChar.charAt (spot);
}
}
System.out.println ("Generated Pass: " + pass);
}
}
所以这样做只是将密码添加到字符串中......并且工作得很好看看...非常简单 . 我写的
6
public static String generateSessionKey(int length){
String alphabet =
new String("0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"); //9
int n = alphabet.length(); //10
String result = new String();
Random r = new Random(); //11
for (int i=0; i<length; i++) //12
result = result + alphabet.charAt(r.nextInt(n)); //13
return result;
}
/*
* The random generator used by this class to create random keys.
* In a holder class to defer initialization until needed.
*/
private static class RandomHolder {
static final Random random = new SecureRandom();
public static String randomKey(int length) {
return String.format("%"+length+"s", new BigInteger(length*5/*base 32,2^5*/, random)
.toString(32)).replace('\u0020', '0');
}
}
public static String getRandomString(int length) {
final String characters = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJLMNOPQRSTUVWXYZ1234567890!@#$%^&*()_+";
StringBuilder result = new StringBuilder();
while(length > 0) {
Random rand = new Random();
result.append(characters.charAt(rand.nextInt(characters.length())));
length--;
}
return result.toString();
}
6
对于“简单”的解决方案,我真的不喜欢这个答案:S
我会去一个简单的;),纯java,一个班轮(熵基于随机字符串长度和给定的字符集):
public String randomString(int length, String characterSet) {
return IntStream.range(0, length).map(i -> new SecureRandom().nextInt(characterSet.length())).mapToObj(randomInt -> characterSet.substring(randomInt, randomInt + 1)).collect(Collectors.joining());
}
@Test
public void buildFiveRandomStrings() {
for (int q = 0; q < 5; q++) {
System.out.println(randomString(10, "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"));//charachterSet can basically be anything
}
}
或者(有点可读的旧方式)
public String randomString(int length, String characterSet) {
StringBuilder sb = new StringBuilder(); //consider using StringBuffer if needed
for (int i = 0; i < length; i++) {
int randomInt = new SecureRandom().nextInt(characterSet.length());
sb.append(characterSet.substring(randomInt, randomInt + 1));
}
return sb.toString();
}
@Test
public void buildFiveRandomStrings() {
for (int q = 0; q < 5; q++) {
System.out.println(randomString(10, "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789")); //charachterSet can basically be anything
}
}
(for (i <- 0 until rnd.nextInt(64)) yield {
('0' + rnd.nextInt(64)).asInstanceOf[Char]
}) mkString("")
41
Java 8中的另一种选择是:
static final Random random = new Random(); // Or SecureRandom
static final int startChar = (int) '!';
static final int endChar = (int) '~';
static String randomString(final int maxLength) {
final int length = random.nextInt(maxLength + 1);
return random.ints(length, startChar, endChar + 1)
.collect(StringBuilder::new, StringBuilder::appendCodePoint, StringBuilder::append)
.toString();
}
30 回答
您可以使用Apache库:RandomStringUtils
Java提供了一种直接执行此操作的方法 . 如果你不想要破折号,它们很容易脱落 . 只需使用
uuid.replace("-", "")
Output:
没有任何外部库,这很容易实现 .
1.加密伪随机数据生成
首先,您需要加密PRNG . Java具有SecureRandom,因为它通常使用机器上的最佳熵源(例如
/dev/random
) . Read more here.Note:
SecureRandom
是Java中生成随机字节的最慢但最安全的方式 . 但我建议不考虑这里的性能,因为它通常对您的应用程序没有实际影响,除非您必须每秒生成数百万个令牌 .2.可能值的必需空间
接下来,你必须决定你的令牌需要"how unique" . 考虑熵的唯一要点是确保系统能够抵抗暴力攻击:可能值的空间必须非常大,以至于任何攻击者只能在非荒谬的时间内尝试可忽略不计的值 . 诸如random UUID之类的唯一标识符具有122bit的熵(即2 ^ 122 = 5.3x10 ^ 36) - 碰撞的机会是“*(...),因为有十亿分之一的重复,103万亿版本4 UUID必须生成2“ . We will choose 128 bit since it fits exactly into 16 bytes 并被视为highly sufficient,因为它基本上是唯一的,但最极端的用例,你不必考虑重复 . 这是一个简单的熵比较表,包括birthday problem的简单分析 .
对于简单的要求,8或12字节长度可能就足够了,但是有16个字节,您就处于“安全方面” .
这基本上就是这样 . 最后一件事是考虑编码,因此它可以表示为可打印的文本(读取,
String
) .3.二进制到文本编码
典型编码包括:
Base64每个字符编码6bit,产生33%的开销 . 遗憾的是,JDK中没有标准实现(7及以下 - 有Android和Java 8+) . 但numerous libraries exist加上这个 . 缺点是,标准
Base64
对于例如安全性并不安全 . urls和大多数文件系统中的文件名需要额外的编码(例如url encoding)或URL safe version of Base64 is used . 使用填充编码16个字节的示例:XfJhfv3C0P6ag7y9VQxSbw==
Base32每个字符编码5bit,产生40%的开销 . 这将使用
A-Z
和2-7
,使其具有合理的空间效率,同时不区分大小写的字母数字 . 没有standard implementation in the JDK . 示例编码16个字节而不填充:WUPIL5DQTZGMF4D3NX5L7LNFOY
Base16(hex)每个字符编码4bit,每个字节需要2个字符(即16字节创建一个长度为32的字符串) . 因此,hex比
Base32
的空间效率更低,但在大多数情况下(url)使用是安全的,因为它只使用0-9
和A
来F
. 编码16个字节的示例:4fa3dd0f57cb3bf331441ed285b27735
. See a SO discussion about converting to hex here.其他编码如Base85和异国情调Base122存在空间效率更好/更差 . 你可以创建自己的编码(基本上这个线程中的大多数答案都可以),但如果你没有非常具体的要求,我会反对它 . 见more encoding schemes in the Wikipedia article.
4.摘要和示例
使用SecureRandom
使用至少16个字节(2 ^ 128)的可能值
根据您的要求进行编码(如果您需要字母数字,通常为
hex
或base32
)Don't
...使用你的家庭酿造编码:如果他们看到你使用的标准编码而不是奇怪的一次创建字符的循环,那么对其他人来说更好的可维护性和可读性 .
...使用UUID:你浪费了6比特的熵,并且有冗长的字符串表示
示例:十六进制令牌生成器
示例:工具
如果你想要一个随时可用的cli工具,你可以使用骰子:https://github.com/patrickfav/dice
这是一行代码AbacusUtil
随机并不意味着它必须是唯一的 . 使用以下方法获取唯一字符串:
如果您的密码必须包含数字字母特殊字符,您可以使用以下代码:
令人惊讶的是没有人建议它但是:
简单 .
这样做的好处是UUID很好而且很长并且保证几乎不可能碰撞 .
维基百科有一个很好的解释:
http://en.wikipedia.org/wiki/Universally_unique_identifier#Random_UUID_probability_of_duplicates
该前4位是版本类型,2是变体,所以你得到122位随机 . 因此,如果你想,你可以从最后截断,以减少UUID的大小 . 不建议这样做,但你仍然有很多随机性,足以让你的500k记录容易 .
算法
要生成随机字符串,请连接从可接受符号集中随机绘制的字符,直到字符串达到所需长度 .
实施
这是一些用于生成随机标识符的相当简单且非常灵活的代码 . 阅读以下重要应用说明的信息 .
用法示例
为8个字符的标识符创建一个不安全的生成器:
为会话标识符创建安全的生成器:
创建一个带有易于阅读的打印代码的生成器 . 字符串比完整的字母数字字符串长,以补偿使用更少的符号:
用作会话标识符
生成可能唯一的会话标识符不够好,或者您可以使用简单的计数器 . 当使用可预测的标识符时,攻击者劫持会话 .
长度和安全之间存在紧张关系 . 较短的标识符更容易猜测,因为可能性较小 . 但是更长的标识符会消耗更多的存储空间较大的符号集会有所帮助,但如果标识符包含在URL中或手动重新输入,则可能会导致编码问题 .
会话标识符的随机性或熵的基础源应来自为加密设计的随机数生成器 . 但是,初始化这些生成器有时可能在计算上很昂贵或很慢,因此应尽可能地重新使用它们 .
用作对象标识符
并非每个应用程序都需要安随机分配可以是多个实体在没有任何协调或分区的情况下在共享空间中生成标识符的有效方式 . 协调可能很慢,特别是在集群或分布式环境中,当实体最终使用太小或太大的共享时,拆分空间会导致问题 .
如果攻击者可能能够查看和操纵它们,那么在不采取措施使其不可预测的情况下生成的标识符应该受到其他方式的保护,就像在大多数Web应用程序中一样 . 应该有一个单独的授权系统来保护攻击者可以在没有访问权限的情况下猜出其标识符的对象 .
还必须注意使用足够长的标识符,以便在给定预期的标识符总数的情况下不太可能发生冲突 . 这被称为"the birthday paradox." The probability of a collision,p,大约是n2 /(2qx),其中n是实际生成的标识符的数量,q是字母表中不同符号的数量,x是标识符的长度 . 这应该是一个非常小的数字,如2-50或更少 .
解决这个问题表明,500k 15个字符标识符之间碰撞的可能性大约为2-52,这可能不如宇宙射线未检测到的错误等 .
与UUID的比较
根据他们的规范,UUID不是不可预测的,不应该用作会话标识符 .
标准格式的UUID需要占用大量空间:36个字符,仅有122位熵 . (并非随机选择“随机”UUID的所有位 . )随机选择的字母数字字符串仅包含21个字符的更多熵 .
UUID不灵活;他们有一个标准化的结构和布局 . 这是他们的主要优点,也是他们的主要弱点 . 与外部团队合作时,UUID提供的标准化可能会有所帮助 . 对于纯粹的内部使用,它们可能效率低下 .
也许这很有帮助
我找到了这个生成随机十六进制编码字符串的解决方案提供的单元测试似乎符合我的主要用例 . 虽然,它比其他一些答案稍微复杂一些 .
您可以使用UUID类及其getLeastSignificantBits()消息来获取64位随机数据,然后将其转换为基数为36的数字(即由0-9,A-Z组成的字符串):
这会产生一个长达13个字符的String . 我们使用Math.abs()来确保没有减号潜入 .
所以这样做只是将密码添加到字符串中......并且工作得很好看看...非常简单 . 我写的
如果您乐意使用Apache类,可以使用org.apache.commons.text.RandomStringGenerator(commons-text) .
例:
由于commons-lang 3.6,
RandomStringUtils
已被弃用 .你提到"simple",但是为了防止其他人正在寻找满足更严格的安全要求的东西,你可能想看看jpwgen . jpwgen是建模的在Unix中的pwgen之后,它是非常可配置的 .
一个简单易用的解决方案,但只使用小写和数字:
大小约为12位数到36位,并且无法进一步改善 . 当然,您可以追加多个实例 .
使用UUID是不安全的,因为UUID的某些部分根本不是随机的 . @erickson的过程非常简洁,但不会创建相同长度的字符串 . 以下代码段应该足够了:
为什么选择
length*5
. 让我们假设一个长度为1的随机字符串的简单情况,因此是一个随机字符 . 要获得包含所有数字0-9和字符a-z的随机字符,我们需要一个0到35之间的随机数来获得每个字符中的一个 .BigInteger
提供了一个构造函数来生成一个随机数,均匀分布在0 to (2^numBits - 1)
范围内 . 不幸的是35不是2 ^ numBits可以接收的数字 - 1.所以我们有两个选择:要么使用2^5-1=31
,要么2^6-1=63
. 如果我们选择2^6
,我们会得到很多"unnecesarry" / "longer"数字 . 因此2^5
是更好的选择,即使我们松散4个字符(w-z) . 要生成一定长度的字符串,我们可以简单地使用2^(length*numBits)-1
数字 . 最后一个问题,如果我们想要一个具有一定长度的字符串,随机可以生成一个小数字,因此不满足长度,所以我们必须将字符串填充到它所需的长度前置零 .根据您的要求更改字符串字符 .
字符串是不可变的 . 这里
StringBuilder.append
比字符串连接更有效 .对于“简单”的解决方案,我真的不喜欢这个答案:S
我会去一个简单的;),纯java,一个班轮(熵基于随机字符串长度和给定的字符集):
或者(有点可读的旧方式)
但另一方面,你也可以使用具有相当好的熵的UUID(https://en.wikipedia.org/wiki/Universally_unique_identifier#Collisions):
希望有所帮助 .
这是一个Scala解决方案:
Java 8中的另一种选择是:
使用Dollar应该简单如下:
它输出类似的东西:
在一行中:
使用apache库可以在一行中完成
这是doc http://commons.apache.org/lang/api-2.3/org/apache/commons/lang/RandomStringUtils.html
在Java中:
这是一个示例运行: