需要安全密码生成器推荐

任何人都可以推荐使用Apache或LGPL许可证下的Java安全密码生成器吗?

我不会担心产生令人难以置信的强大的一次性密码。 将密码设置得很长,并且在强制密码有效期限的情况下使用暴力不应该是一个问题。 如果密码仅在1小时内有效,那么如果密码仍未使用则不会有问题。 在那段时间内,有人不可能用蛮力破解它。

同样重要的是,您只需让一次性密码工作一次。 这样,如果密码被截获,用户将注意到一次性密码何时到期并且可以采取适当的操作。

我会去Apache Commons RandomStringUtils ,密码是10-15个字母和数字。

……虽然这总是一个你想成为多么偏执的问题。 这个解决方案适用于常规Web应用程序,但对银行来说还不够好……

它在.net中,但转换应该是微不足道的。 对于大多数人来说可能有点过分,但这是我在我的应用程序中总是使用的实现。 这是我前段时间发现的一个实现,并做了一些修改,我不记得原作者,但我会快速搜索一下,看看我是否可以给他适当的信用。

 public static string GenerateRandomString(int minLength, int maxLength, int minLCaseCount, int minUCaseCount, int minNumCount, int minSpecialCount) { char[] randomString; const string LCaseChars = "abcdefgijkmnopqrstwxyz"; const string UCaseChars = "ABCDEFGHJKLMNPQRSTWXYZ"; const string NumericChars = "23456789"; const string SpecialChars = "*$-+?_&=!%{}/"; Hashtable charGroupsUsed = new Hashtable(); charGroupsUsed.Add("lcase", minLCaseCount); charGroupsUsed.Add("ucase", minUCaseCount); charGroupsUsed.Add("num", minNumCount); charGroupsUsed.Add("special", minSpecialCount); // Because we cannot use the default randomizer, which is based on the // current time (it will produce the same "random" number within a // second), we will use a random number generator to seed the // randomizer. // Use a 4-byte array to fill it with random bytes and convert it then // to an integer value. byte[] randomBytes = new byte[4]; // Generate 4 random bytes. RNGCryptoServiceProvider rng = new RNGCryptoServiceProvider(); rng.GetBytes(randomBytes); // Convert 4 bytes into a 32-bit integer value. int seed = (randomBytes[0] & 0x7f) << 24 | randomBytes[1] << 16 | randomBytes[2] << 8 | randomBytes[3]; // Create a randomizer from the seed. Random random = new Random(seed); // Allocate appropriate memory for the password. if (minLength < maxLength) { randomString = new char[random.Next(minLength, maxLength + 1)]; } else { randomString = new char[minLength]; } int requiredCharactersLeft = minLCaseCount + minUCaseCount + minNumCount + minSpecialCount; // Build the password. for (int i = 0; i < randomString.Length; i++) { string selectableChars = ""; // if we still have plenty of characters left to acheive our minimum requirements. if (requiredCharactersLeft < randomString.Length - i) { // choose from any group at random selectableChars = LCaseChars + UCaseChars + NumericChars + SpecialChars; } else // we are out of wiggle room, choose from a random group that still needs to have a minimum required. { // choose only from a group that we need to satisfy a minimum for. foreach (DictionaryEntry charGroup in charGroupsUsed) { if ((int)charGroup.Value > 0) { switch (charGroup.Key.ToString()) { case "lcase": selectableChars += LCaseChars; break; case "ucase": selectableChars += UCaseChars; break; case "num": selectableChars += NumericChars; break; case "special": selectableChars += SpecialChars; break; } } } } // Now that the string is built, get the next random character. char nextChar = selectableChars[random.Next(0, selectableChars.Length - 1)]; // Tac it onto our password. randomString[i] = nextChar; // Now figure out where it came from, and decrement the appropriate minimum value. if (LCaseChars.Contains(nextChar)) { charGroupsUsed["lcase"] = (int)charGroupsUsed["lcase"] - 1; if ((int)charGroupsUsed["lcase"] >= 0) { requiredCharactersLeft--; } } else if (UCaseChars.Contains(nextChar)) { charGroupsUsed["ucase"] = (int)charGroupsUsed["ucase"] - 1; if ((int)charGroupsUsed["ucase"] >= 0) { requiredCharactersLeft--; } } else if (NumericChars.Contains(nextChar)) { charGroupsUsed["num"] = (int)charGroupsUsed["num"] - 1; if ((int)charGroupsUsed["num"] >= 0) { requiredCharactersLeft--; } } else if (SpecialChars.Contains(nextChar)) { charGroupsUsed["special"] = (int)charGroupsUsed["special"] - 1; if ((int)charGroupsUsed["special"] >= 0) { requiredCharactersLeft--; } } } return new string(randomString); } 

编辑

我相信我开始使用http://www.obviex.com/Samples/Password.aspx上发布的代码。 虽然代码现在还有一些function。

这是一个使用Commons的例子。 它会创建一个长度为8到20个字符的字母数字密码。

 public String getRandomPassword() { StringBuffer password = new StringBuffer(20); int next = RandomUtils.nextInt(13) + 8; password.append(RandomStringUtils.randomAlphanumeric(next)); return password.toString(); } 

UPDATE RandomUtils.nextInt返回0(包括)和指定值(不包括)之间的数字,以便获得8到20个字符(包括8和20个字符)之间的值,参数值应为13.我已经更正了上面的代码。

更新如下面的评论中所述,这可以在不使用StringBuffer的情况下编写。 这是一个修改过的一行版本:

 return RandomStringUtils.randomAlphanumeric(RandomUtils.nextInt(13) + 8); 

对于那些感兴趣的人,这是Matthew的代码,转换为Java

 import java.util.HashMap; import java.util.Map; import java.util.Random; public class PasswordGenerator { public static String GenerateRandomString(int minLength, int maxLength, int minLCaseCount, int minUCaseCount, int minNumCount, int minSpecialCount) { char[] randomString; String LCaseChars = "abcdefgijkmnopqrstwxyz"; String UCaseChars = "ABCDEFGHJKLMNPQRSTWXYZ"; String NumericChars = "23456789"; String SpecialChars = "*$-+?_&=!%{}/"; Map charGroupsUsed = new HashMap(); charGroupsUsed.put("lcase", minLCaseCount); charGroupsUsed.put("ucase", minUCaseCount); charGroupsUsed.put("num", minNumCount); charGroupsUsed.put("special", minSpecialCount); // Because we cannot use the default randomizer, which is based on the // current time (it will produce the same "random" number within a // second), we will use a random number generator to seed the // randomizer. // Use a 4-byte array to fill it with random bytes and convert it then // to an integer value. byte[] randomBytes = new byte[4]; // Generate 4 random bytes. new Random().nextBytes(randomBytes); // Convert 4 bytes into a 32-bit integer value. int seed = (randomBytes[0] & 0x7f) << 24 | randomBytes[1] << 16 | randomBytes[2] << 8 | randomBytes[3]; // Create a randomizer from the seed. Random random = new Random(seed); // Allocate appropriate memory for the password. int randomIndex = -1; if (minLength < maxLength) { randomIndex = random.nextInt((maxLength-minLength)+1)+minLength; randomString = new char[randomIndex]; } else { randomString = new char[minLength]; } int requiredCharactersLeft = minLCaseCount + minUCaseCount + minNumCount + minSpecialCount; // Build the password. for (int i = 0; i < randomString.length; i++) { String selectableChars = ""; // if we still have plenty of characters left to acheive our minimum requirements. if (requiredCharactersLeft < randomString.length - i) { // choose from any group at random selectableChars = LCaseChars + UCaseChars + NumericChars + SpecialChars; } else // we are out of wiggle room, choose from a random group that still needs to have a minimum required. { // choose only from a group that we need to satisfy a minimum for. for(Map.Entry charGroup : charGroupsUsed.entrySet()) { if ((int)charGroup.getValue() > 0) { if("lcase".equals(charGroup.getKey()) ){ selectableChars += LCaseChars; } else if("ucase".equals(charGroup.getKey())){ selectableChars += UCaseChars; } else if("num".equals(charGroup.getKey())){ selectableChars += NumericChars; } else if("special".equals(charGroup.getKey())){ selectableChars += SpecialChars; } } } } // Now that the string is built, get the next random character. randomIndex = random.nextInt((selectableChars.length())-1); char nextChar = selectableChars.charAt(randomIndex); // Tac it onto our password. randomString[i] = nextChar; // Now figure out where it came from, and decrement the appropriate minimum value. if (LCaseChars.indexOf(nextChar) > -1) { charGroupsUsed.put("lcase",charGroupsUsed.get("lcase") - 1); if (charGroupsUsed.get("lcase") >= 0) { requiredCharactersLeft--; } } else if (UCaseChars.indexOf(nextChar) > -1) { charGroupsUsed.put("ucase",charGroupsUsed.get("ucase") - 1); if (charGroupsUsed.get("ucase") >= 0) { requiredCharactersLeft--; } } else if (NumericChars.indexOf(nextChar) > -1) { charGroupsUsed.put("num", charGroupsUsed.get("num") - 1); if (charGroupsUsed.get("num") >= 0) { requiredCharactersLeft--; } } else if (SpecialChars.indexOf(nextChar) > -1) { charGroupsUsed.put("special",charGroupsUsed.get("special") - 1); if (charGroupsUsed.get("special") >= 0) { requiredCharactersLeft--; } } } return new String(randomString); } } 

并进行unit testing

 import org.junit.Test; public class PasswordGeneratorTest { @Test public void testPasswordCreation(){ System.out.println(PasswordGenerator.GenerateRandomString(8,25,3,1,1,1)); } } 

Password Safe是开源的(在Artistic License下),包括密码生成代码。

您可以使用Random和内置的MessageDigest实现轻松实现它。

 import java.util.Random; import java.security.*; import java.math.*; public class RandPassGen { public static String genPass( int chars ) { Random r = new Random(); MessageDigest md = null; try { md = MessageDigest.getInstance("MD5"); } catch ( NoSuchAlgorithmException e ) { System.out.println( "Unsupported Algorithm!" ); return null; } byte[] entropy = new byte[1024]; r.nextBytes(entropy); md.update( entropy , 0, 1024 ); return new BigInteger(1, md.digest()).toString(16).substring(0, chars); } public static void main( String[] av ) { Integer chars = Integer.valueOf(av[0]); if ((chars < 0) || (chars > 32)) { System.out.println( "Generate between 0 and 32 characters." ); return; } System.out.println( genPass( chars ) ); } } 

我添加了一个类似于C#/ Java版本的Golang实现。 它在Apache 2.0下可用。 来源位于:

https://github.com/deftlabs/dlshared/blob/master/password_utils.go