java - password - randomstringutils




如何生成一個隨機的字母數字字符串? (20)

算法

要生成一個隨機字符串,將從可接受符號集合中隨機抽取的字符連接起來,直到字符串達到所需的長度。

履行

這裡有一些相當簡單和非常靈活的代碼來生成隨機標識符。 閱讀重要應用筆記後面的信息

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);

用作會話標識符

生成可能是唯一的會話標識符不夠好,或者您可以使用簡單的計數器。 當使用可預測的標識符時,攻擊者劫持會話。

長度和安全之間存在緊張關係。 較短的標識符更容易被猜出,因為可能性較少。 但更長的標識符消耗更多的存儲和帶寬。 更大的符號集有助於實現,但如果標識符包含在URL中或手動重新輸入,可能會導致編碼問題。

會話標識符的隨機性或熵的基本來源應來自為密碼學設計的隨機數生成器。 然而,初始化這些生成器有時可能在計算上很昂貴或很慢,所以應該盡可能地重複使用它們。

用作對象標識符

並非每個應用程序都需要安全性 隨機分配可以是多個實體在共享空間中生成標識符的有效方式,無需任何協調或分區。 協調可能會很慢,特別是在集群或分佈式環境中,當實體最終分配太小或太大的份額時,分割空間會導致問題。

如果攻擊者可能能夠查看並操縱它們,那麼在沒有採取措施使其不可預知的情況下生成的標識符應該受到其他方式的保護,正如大多數Web應用程序中所發生的那樣。 應該有一個單獨的授權系統,用於保護沒有訪問權限的攻擊者可以猜出標識符的對象。

考慮到預期的標識符總數,還必須注意使用足夠長的標識符以使碰撞不太可能。 這被稱為“生日悖論”。 碰撞概率 p約為n 2 /(2q x ),其中n是實際生成的標識符的數量, q是字母表中不同符號的數量, x是標識符的長度。 這應該是一個非常小的數字,例如2 -50或更少。

解決這個問題表明,500k個15個字符的標識符之間相互碰撞的機會大約是2 -52 ,這可能比從宇宙射線中未發現的錯誤更少。

與UUID進行比較

根據它們的規範,UUID的設計不是不可預知的, 應該用作會話標識符。

標準格式的UUID佔用大量空間:只有122位熵的36個字符。 (並非隨機選擇“隨機”UUID的所有位)隨機選擇的字母數字字符串僅包含21個字符的熵。

UUID不靈活; 他們有一個標準化的結構和佈局。 這是他們的主要美德,也是他們的主要弱點。 與外部團隊合作時,UUID提供的標準化可能會有幫助。 純粹為了內部使用,它們可能效率低下。

我一直在尋找一種簡單的 Java算法來生成一個偽隨機字母數字字符串。 在我的情況下,它將被用作一個獨特的會話/密鑰標識符,“很可能”在500K +一代中是唯一的(我的需求並不需要任何更複雜的東西)。 理想情況下,我可以根據我的獨特需要指定長度。 例如,生成的長度為12的字符串可能看起來像"AEYGF7K0DM1X"


  1. 按照您的要求更改字符串字符。

  2. 字符串是不可變的。 這裡StringBuilder.append比字符串連接更高效。


public static String getRandomString(int length) {
       final String characters = "[email protected]#$%^&*()_+";
       StringBuilder result = new StringBuilder();
       while(length > 0) {
           Random rand = new Random();
           result.append(characters.charAt(rand.nextInt(characters.length())));
           length--;
       }
       return result.toString();
    }

Java提供了一種直接執行此操作的方法。 如果你不想破折號,他們很容易剝離。 只需使用uuid.replace("-", "")

import java.util.UUID;

public class randomStringGenerator {
    public static void main(String[] args) {
        System.out.println(generateString());
    }

    public static String generateString() {
        String uuid = UUID.randomUUID().toString();
        return "uuid = " + uuid;
    }
}

輸出:

uuid = 2d7428a6-b58c-4008-8575-f05549f16316

Best Random String Generator Method

public class RandomStringGenerator{

    private static int randomStringLength = 25 ;
    private static boolean allowSpecialCharacters = true ;
    private static String specialCharacters = "[email protected]$%*-_+:";
    private static boolean allowDuplicates = false ;

    private static boolean isAlphanum = false;
    private static boolean isNumeric = false;
    private static boolean isAlpha = false;
    private static final String alphabet = "abcdefghijklmnopqrstuvwxyz";
    private static boolean mixCase = false;
    private static final String capAlpha = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
    private static final String num = "0123456789";

    public static String getRandomString() {
        String returnVal = "";
        int specialCharactersCount = 0;
        int maxspecialCharacters = randomStringLength/4;

        try {
            StringBuffer values = buildList();
            for (int inx = 0; inx < randomStringLength; inx++) {
                int selChar = (int) (Math.random() * (values.length() - 1));
                if (allowSpecialCharacters)
                {
                    if (specialCharacters.indexOf("" + values.charAt(selChar)) > -1)
                    {
                        specialCharactersCount ++;
                        if (specialCharactersCount > maxspecialCharacters)
                        {
                            while (specialCharacters.indexOf("" + values.charAt(selChar)) != -1)
                            {
                                selChar = (int) (Math.random() * (values.length() - 1));
                            }
                        }
                    }
                }
                returnVal += values.charAt(selChar);
                if (!allowDuplicates) {
                    values.deleteCharAt(selChar);
                }
            }
        } catch (Exception e) {
            returnVal = "Error While Processing Values";
        }
        return returnVal;
    }

    private static StringBuffer buildList() {
        StringBuffer list = new StringBuffer(0);
        if (isNumeric || isAlphanum) {
            list.append(num);
        }
        if (isAlpha || isAlphanum) {
            list.append(alphabet);
            if (mixCase) {
                list.append(capAlpha);
            }
        }
        if (allowSpecialCharacters)
        {
            list.append(specialCharacters);
        }
        int currLen = list.length();
        String returnVal = "";
        for (int inx = 0; inx < currLen; inx++) {
            int selChar = (int) (Math.random() * (list.length() - 1));
            returnVal += list.charAt(selChar);
            list.deleteCharAt(selChar);
        }
        list = new StringBuffer(returnVal);
        return list;
    }   

}

Here is the one line code by AbacusUtil

String.valueOf(CharStream.random('0', 'z').filter(c -> N.isLetterOrDigit(c)).limit(12).toArray())

Random doesn't mean it must be unique. to get unique strings, using:

N.uuid() // e.g.: "e812e749-cf4c-4959-8ee1-57829a69a80f". length is 36.
N.guid() // e.g.: "0678ce04e18945559ba82ddeccaabfcd". length is 32 without '-'

Here it is a Scala solution:

(for (i <- 0 until rnd.nextInt(64)) yield { 
  ('0' + rnd.nextInt(64)).asInstanceOf[Char] 
}) mkString("")

You can use following code , if your password mandatory contains numbers alphabetic special characters:

private static final String NUMBERS = "0123456789";
private static final String UPPER_ALPHABETS = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
private static final String LOWER_ALPHABETS = "abcdefghijklmnopqrstuvwxyz";
private static final String SPECIALCHARACTERS = "@#$%&*";
private static final int MINLENGTHOFPASSWORD = 8;

public static String getRandomPassword() {
    StringBuilder password = new StringBuilder();
    int j = 0;
    for (int i = 0; i < MINLENGTHOFPASSWORD; i++) {
        password.append(getRandomPasswordCharacters(j));
        j++;
        if (j == 3) {
            j = 0;
        }
    }
    return password.toString();
}

private static String getRandomPasswordCharacters(int pos) {
    Random randomNum = new Random();
    StringBuilder randomChar = new StringBuilder();
    switch (pos) {
        case 0:
            randomChar.append(NUMBERS.charAt(randomNum.nextInt(NUMBERS.length() - 1)));
            break;
        case 1:
            randomChar.append(UPPER_ALPHABETS.charAt(randomNum.nextInt(UPPER_ALPHABETS.length() - 1)));
            break;
        case 2:
            randomChar.append(SPECIALCHARACTERS.charAt(randomNum.nextInt(SPECIALCHARACTERS.length() - 1)));
            break;
        case 3:
            randomChar.append(LOWER_ALPHABETS.charAt(randomNum.nextInt(LOWER_ALPHABETS.length() - 1)));
            break;
    }
    return randomChar.toString();

}

You can use the UUID class with its getLeastSignificantBits() message to get 64bit of Random data, then convert it to a radix 36 number (ie a string consisting of 0-9,AZ):

Long.toString(Math.abs( UUID.randomUUID().getLeastSignificantBits(), 36));

This yields a String up to 13 characters long. We use Math.abs() to make sure there isn't a minus sign sneaking in.



令人驚訝的是,這裡沒有人建議它,但是:

import java.util.UUID

UUID.randomUUID().toString();

簡單。

這樣做的好處是UUID非常好,而且保證幾乎不可能發生碰撞。

維基百科有一個很好的解釋:

“......只有在接下來的100年內每秒產生10億個UUID之後,創建一個副本的可能性將大約為50%。”

http://en.wikipedia.org/wiki/Universally_unique_identifier#Random_UUID_probability_of_duplicates

前4位是版本類型,2是變體,因此您可以獲得122位隨機數。 所以如果你想要從最後截斷來減少UUID的大小。 這不是推薦的,但你仍然有大量的隨機性,足以讓你的500k記錄變得容易。


使用UUID是不安全的,因為部分UUID不是隨機的。 @erickson的過程非常整潔,但不會創建長度相同的字符串。 以下片段應該足夠了:

/*
 * 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');
    }
}

為什麼選擇length*5 。 假設一個長度為1的隨機字符串的簡單情況,那麼一個隨機字符。 要獲得一個包含所有數字0-9和字符az的隨機字符,我們需要一個0到35之間的隨機數來獲取每個字符中的一個。 BigInteger提供了一個構造函數來生成一個隨機數,均勻分佈在0 to (2^numBits - 1)的範圍內。 不幸的是,35沒有可以通過2 ^ numBits - 1接收的數字。所以我們有兩個選擇:或者用2^5-1=31或者2^6-1=63 。 如果我們選擇2^6我們會得到很多“不必要的”/“更長的”數字。 因此2^5是更好的選擇,即使我們鬆動4個字符(wz)。 現在要生成一定長度的字符串,我們可以簡單地使用2^(length*numBits)-1數字。 最後一個問題是,如果我們想要一個具有一定長度的字符串,隨機可以生成一個小數字,所以長度不符合,所以我們必須將字符串填充到它所需的長度前置零。



它在Java中:

import static java.lang.Math.round;
import static java.lang.Math.random;
import static java.lang.Math.pow;
import static java.lang.Math.abs;
import static java.lang.Math.min;
import static org.apache.commons.lang.StringUtils.leftPad

public class RandomAlphaNum {
  public static String gen(int length) {
    StringBuffer sb = new StringBuffer();
    for (int i = length; i > 0; i -= 12) {
      int n = min(12, abs(i));
      sb.append(leftPad(Long.toString(round(random() * pow(36, n)), 36), n, '0'));
    }
    return sb.toString();
  }
}

這是一個示例運行:

scala> RandomAlphaNum.gen(42)
res3: java.lang.String = uja6snx21bswf9t89s00bxssu8g6qlu16ffzqaxxoy

您可以為此使用Apache庫: RandomStringUtils

RandomStringUtils.randomAlphanumeric(20).toUpperCase();

沒有任何外部庫,這很容易實現。

1.加密偽隨機數據生成

首先你需要一個加密PRNG。 Java的SecureRandom通常使用機器上最好的熵源(例如/dev/random )。 在這裡閱讀更多。

SecureRandom rnd = new SecureRandom();
byte[] token = new byte[byteLength];
rnd.nextBytes(token);

注意: SecureRandom是Java中生成隨機字節的最慢但最安全的方式。 不過我建議不要在這裡考慮性能,因為它通常不會對應用程序產生真正的影響,除非您必須每秒生成數百萬個令牌。

2.可能值的必需空間

接下來,你必須決定你的代幣需要的“獨特性”。 考慮熵的唯一要點是確保系統能夠抵抗暴力攻擊:可能值的空間必須非常大,以至於任何攻擊者只能在非滑稽時間1嘗試微不足道的比例值1 。 唯一標識符如隨機UUID具有122位熵(即2 ^ 122 = 5.3x10 ^ 36) - 碰撞的可能性為“*(...),因為存在十億分之一的重複機會,103萬億版本4 UUID必須生成2 “。 我們將選擇128位,因為它恰好適合於16個字節,並且對於基本上每一個都是獨一無二的,但卻是最極端的用例,您不必考慮重複。 這裡是一個簡單的熵比較表,包括生日問題的簡單分析。

對於簡單的要求8或12字節長度可能就足夠了,但是對於16字節,您處於“安全的一面”。

基本上就是這樣。 最後一點是考慮編碼,以便它可以表示為可打印的文本(讀取, String )。

3.二進製文本編碼

典型的編碼包括:

  • Base64每個字符編碼6bit,產生33%的開銷。 不幸的是,在JDK中沒有標準的實現(在Android )。 但是有大量的圖書館增加了這一點。 缺點是, Base64對於例如。 在大多數需要額外編碼的文件系統(例如url編碼 )中作為文件名。 用padding編碼16個字節的示例: XfJhfv3C0P6ag7y9VQxSbw==

  • Base32每個字符編碼5bit,產生40%的開銷。 這將使用AZ2-7 ,這使得空間效率合理,而不區分大小寫的字母數字。 和Base64一樣, JDK中沒有標準的實現 。 編碼16個字節而沒有填充的示例: WUPIL5DQTZGMF4D3NX5L7LNFOY

  • Base16 (十六進制)每個字符編碼4位,每個字節需要2個字符(即16個字節創建一個長度為32的字符串)。 因此,十六進制的空間效率低於Base32但在大多數情況下(url)可以安全使用,因為它只使用0-9AF 編碼16個字節的示例: 4fa3dd0f57cb3bf331441ed285b27735請參閱關於轉換為十六進制的SO討論。

Base85和異國情調的Base122等其他編碼存在更好/更差的空間效率。 你可以創建自己的編碼(基本上這個線程中的大多數答案都可以),但如果你沒有特別的要求,我會建議你不要這樣做。 請參閱Wikipedia文章中的更多編碼方案。

4.總結和例子

  • 使用SecureRandom
  • 至少使用16個字節(2 ^ 128)的可能值
  • 根據您的要求進行編碼(如果您需要它是字母數字,通常是hexbase32

  • ...使用家庭編碼編碼: 如果他們看到您使用的是什麼標準編碼,而不是奇怪的一次創建字符,則可以更好地維護和讀取其他編碼。
  • ...使用UUID: 你正在浪費6比特的熵並且有詳細的字符串表示

示例:十六進制令牌生成器

public static String generateRandomHexToken(int byteLength) {
    SecureRandom secureRandom = new SecureRandom();
    byte[] token = new byte[byteLength];
    secureRandom.nextBytes(token);
    return new BigInteger(1, token).toString(16); //hex encoding
}

//generateRandomHexToken(16) -> 2189df7475e96aa3982dbeab266497cd

示例:工具

如果你想要一個隨時可用的cli工具,你可以使用骰子: https://github.com/patrickfav/dicehttps://github.com/patrickfav/dice


簡單而簡單的解決方案,但只使用小寫和數字:

Random r = new java.util.Random ();
String s = Long.toString (r.nextLong () & Long.MAX_VALUE, 36);

這個尺寸大約是12位數字,以36為基數,並且不能進一步改進。 當然你可以附加多個實例。


import java.util.*;
import javax.swing.*;
public class alphanumeric{
    public static void main(String args[]){
        String nval,lenval;
        int n,len;

        nval=JOptionPane.showInputDialog("Enter number of codes you require : ");
        n=Integer.parseInt(nval);

        lenval=JOptionPane.showInputDialog("Enter code length you require : ");
        len=Integer.parseInt(lenval);

        find(n,len);

    }
    public static void find(int n,int length) {
        String str1="0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
        StringBuilder sb=new StringBuilder(length);
        Random r = new Random();

        System.out.println("\n\t Unique codes are \n\n");
        for(int i=0;i<n;i++){
            for(int j=0;j<length;j++){
                sb.append(str1.charAt(r.nextInt(str1.length())));
            }
            System.out.println("  "+sb.toString());
            sb.delete(0,length);
        }
    }
}

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;
    }
}

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;
}

public static String getRandomString(int length) 
{
   String randomStr = UUID.randomUUID().toString();
   while(randomStr.length() < length) {
       randomStr += UUID.randomUUID().toString();
   }
   return randomStr.substring(0, length);
}




alphanumeric