repetir - password en java
Genere una contraseña aleatoria segura en Java con requisitos mínimos de caracteres especiales (2)
¿Cómo creo una contraseña aleatoria que cumpla con los requisitos de longitud y conjunto de caracteres del sistema en Java?
Tengo que crear una contraseña aleatoria de entre 10 y 14 caracteres y que tenga al menos una mayúscula, una minúscula y un carácter especial. Lamentablemente, algunos caracteres especiales son demasiado especiales y no se pueden usar, por lo que no puedo usar solo ASCII impreso.
Muchos de los ejemplos en este sitio generan una contraseña aleatoria o una clave de sesión sin suficiente entropía en los caracteres o sin requisitos realistas en un entorno empresarial como los que se mencionan anteriormente, por lo que estoy preguntando más para obtener una mejor respuesta.
Mi conjunto de caracteres, cada carácter especial en un teclado estándar de EE. UU., Excepto un espacio:
A-Z
a-z
0-9
~`!@#$%^&*()-_=+[{]}/|;:''",<.>/?
Recientemente aprendí sobre Passay . Proporciona la funcionalidad requerida necesaria en su clase PasswordGenerator . Genera aleatoriamente contraseñas que cumplen los requisitos similares a lo que se describe a continuación utilizando CharacterRules en lugar de PasswordCharacterSets como he hecho a continuación. En lugar de mantener una lista de índices no utilizados para la inserción aleatoria de caracteres, simplemente mezcla el búfer de caracteres después de insertar caracteres que cumplan con los requisitos.
A continuación queda de antes, recomiendo usar Passay si su licencia lo permite, este código debería funcionar de otra manera y proporciona detalles de por qué las contraseñas generadas son criográficamente fuertes.
Terminé escribiendo este código dos veces. Una vez para obtener un resultado de carácter aleatorio, pero resultó que la distribución de caracteres dependía del tamaño del juego de caracteres (¡gritos!). Lo reescribí y ahora solo debes copiar / pegar el código y cambiar Main.java a los juegos de caracteres que quieras. Aunque se podría haber hecho de forma diferente, creo que este es un enfoque relativamente directo para obtener el resultado correcto y recomiendo la reutilización, los comentarios, las críticas y las ediciones bien pensadas.
Los controles del código PasswordGenerator son los siguientes:
- Longitud mín. / Máx . : Establecer utilizando un número aleatorio
- PasswordCharacterSet : se supone que todos los PasswordCharacterSets pasados a PasswordGenerator consisten en conjuntos de caracteres únicos; si no, los caracteres aleatorios tendrán un sesgo hacia los duplicados.
- PasswordCharacterSet Min Characters : los caracteres mínimos que se usarán para este juego de caracteres.
Los bits principales para la generación de contraseña real:
- Aleatoriedad de Random : estamos utilizando SecureRandom, que está respaldado por un PRNG criptográficamente fuerte, en lugar de la clase Random que no lo es.
- Orden aleatorio de caracteres para la contraseña : todos los índices de la matriz pw char se agregan a la matriz remainingIndexes. Como llamamos addRandomCharacters, elimina un índice al azar y usamos el índice eliminado para poblar la matriz.
- Caracteres aleatorios : en addRandomCharacters, se elige un índice aleatorio del índice de caracteres que estamos usando y se agrega a la matriz pw.
- Se establecen los caracteres mínimos de cada tipo : simplemente hacemos una excavación de la cantidad mínima de caracteres primero. Elegimos la cantidad mínima de valores aleatorios de cada juego de caracteres y seguimos adelante.
- Distribución aleatoria para los caracteres restantes : después de establecer los valores mínimos, queremos hacer que el resto de los caracteres sea aleatorio en todos los conjuntos de caracteres. Todos los personajes se agregan a una única matriz. Las ranuras restantes se llenan usando la misma estrategia para los juegos de caracteres anteriores.
Descripción de la complejidad de la contraseña: la complejidad de la contraseña generalmente se menciona en bits de entropía. Aquí está la cantidad de posibilidades para su espacio de claves:
Hay al menos un carácter alfabético en mayúscula (de 26), un carácter alfabético en minúscula (de 26), un dígito (de 10) y un carácter especial (de un total de 32), la forma en que calcula el número de posibilidades es el número de posibilidades para cada personaje multiplicado por el número de caracteres, ya que se colocan aleatoriamente en la cadena. Entonces sabemos que las posibilidades para cuatro de los personajes son:
Required Characters = 26*26*10*32=216,320
Todos los personajes restantes tienen 94 (26 + 26 + 10 + 32) posibilidades cada uno
Nuestro cálculo es:
Characters Possibilities Bits of Entropy
10 chars 216,320*94^6 = 149,232,631,038,033,920 ~2^57
11 chars 216,320*94^7 = 14,027,867,317,575,188,480 ~2^63
12 chars 216,320*94^8 = 1,318,619,527,852,067,717,120 ~2^70
13 chars 216,320*94^9 = 123,950,235,618,094,365,409,280 ~2^76
14 chars 216,320*94^10 = 11,651,322,148,100,870,348,472,320 ~2^83
Con esto está claro, si quiere las contraseñas más seguras, siempre debe elegir la mayor cantidad de caracteres posible, que es 14 en este caso.
Main.java
package org.redtown.pw;
import java.util.EnumSet;
import java.util.HashSet;
import java.util.Set;
import org.redtown.pw.PasswordGenerator.PasswordCharacterSet;
public class Main {
public static void main(String[] args) {
Set<PasswordCharacterSet> values = new HashSet<PasswordCharacterSet>(EnumSet.allOf(SummerCharacterSets.class));
PasswordGenerator pwGenerator = new PasswordGenerator(values, 10, 14);
for(int i=0; i < 10; ++i) {
System.out.println(pwGenerator.generatePassword());
}
}
private static final char[] ALPHA_UPPER_CHARACTERS = { ''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'' };
private static final char[] ALPHA_LOWER_CHARACTERS = { ''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'' };
private static final char[] NUMERIC_CHARACTERS = { ''0'', ''1'', ''2'', ''3'', ''4'',
''5'', ''6'', ''7'', ''8'', ''9'' };
private static final char[] SPECIAL_CHARACTERS = { ''~'', ''`'', ''!'', ''@'', ''#'',
''$'', ''%'', ''^'', ''&'', ''*'', ''('', '')'', ''-'', ''_'', ''='', ''+'', ''['', ''{'',
'']'', ''}'', ''//', ''|'', '';'', '':'', ''/''', ''"'', '','', ''<'', ''.'', ''>'', ''/'',
''?'' };
private enum SummerCharacterSets implements PasswordCharacterSet {
ALPHA_UPPER(ALPHA_UPPER_CHARACTERS, 1),
ALPHA_LOWER(ALPHA_LOWER_CHARACTERS, 1),
NUMERIC(NUMERIC_CHARACTERS, 1),
SPECIAL(SPECIAL_CHARACTERS, 1);
private final char[] chars;
private final int minUsage;
private SummerCharacterSets(char[] chars, int minUsage) {
this.chars = chars;
this.minUsage = minUsage;
}
@Override
public char[] getCharacters() {
return chars;
}
@Override
public int getMinCharacters() {
return minUsage;
}
}
}
PasswordGenerator.java
package org.redtown.pw;
import java.security.SecureRandom;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Random;
public class PasswordGenerator {
private final List<PasswordCharacterSet> pwSets;
private final char[] allCharacters;
private final int minLength;
private final int maxLength;
private final int presetCharacterCount;
public PasswordGenerator(Collection<PasswordCharacterSet> origPwSets, int minLength, int maxLength) {
this.minLength = minLength;
this.maxLength = maxLength;
// Make a copy of the character arrays and min-values so they cannot be changed after initialization
int pwCharacters = 0;
int preallocatedCharacters = 0;
List<PasswordCharacterSet> pwSets = new ArrayList<PasswordCharacterSet>(origPwSets.size());
for(PasswordCharacterSet origpwSet : origPwSets) {
PasswordCharacterSet newPwSet = new PwSet(origpwSet);
pwSets.add(newPwSet);
pwCharacters += newPwSet.getCharacters().length;
preallocatedCharacters += newPwSet.getMinCharacters();
}
this.presetCharacterCount = preallocatedCharacters;
this.pwSets = Collections.unmodifiableList(pwSets);
if (minLength < presetCharacterCount) {
throw new IllegalArgumentException("Combined minimum lengths "
+ presetCharacterCount
+ " are greater than the minLength of " + minLength);
}
// Copy all characters into single array so we can evenly access all members when accessing this array
char[] allChars = new char[pwCharacters];
int currentIndex = 0;
for(PasswordCharacterSet pwSet : pwSets) {
char[] chars = pwSet.getCharacters();
System.arraycopy(chars, 0, allChars, currentIndex, chars.length);
currentIndex += chars.length;
}
this.allCharacters = allChars;
}
public char[] generatePassword() {
SecureRandom rand = new SecureRandom();
// Set pw length to minLength <= pwLength <= maxLength
int pwLength = minLength + rand.nextInt(maxLength - minLength + 1);
int randomCharacterCount = pwLength - presetCharacterCount;
// Place each index in an array then remove them randomly to assign positions in the pw array
List<Integer> remainingIndexes = new ArrayList<Integer>(pwLength);
for(int i=0; i < pwLength; ++i) {
remainingIndexes.add(i);
}
// Fill pw array
char[] pw = new char[pwLength];
for(PasswordCharacterSet pwSet : pwSets) {
addRandomCharacters(pw, pwSet.getCharacters(), pwSet.getMinCharacters(), remainingIndexes, rand);
}
addRandomCharacters(pw, allCharacters, randomCharacterCount, remainingIndexes, rand);
return pw;
}
private static void addRandomCharacters(char[] pw, char[] characterSet,
int numCharacters, List<Integer> remainingIndexes, Random rand) {
for(int i=0; i < numCharacters; ++i) {
// Get and remove random index from the remaining indexes
int pwIndex = remainingIndexes.remove(rand.nextInt(remainingIndexes.size()));
// Set random character from character index to pwIndex
int randCharIndex = rand.nextInt(characterSet.length);
pw[pwIndex] = characterSet[randCharIndex];
}
}
public static interface PasswordCharacterSet {
char[] getCharacters();
int getMinCharacters();
}
/**
* Defensive copy of a passed-in PasswordCharacterSet
*/
private static final class PwSet implements PasswordCharacterSet {
private final char[] chars;
private final int minChars;
public PwSet(PasswordCharacterSet pwSet) {
this.minChars = pwSet.getMinCharacters();
char[] pwSetChars = pwSet.getCharacters();
// Defensive copy
this.chars = Arrays.copyOf(pwSetChars, pwSetChars.length);
}
@Override
public char[] getCharacters() {
return chars;
}
@Override
public int getMinCharacters() {
return minChars;
}
}
}
Sugiero usar Apache commons RandomStringUtils. Usa algo que ya está hecho.
String characters = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789~`!@#$%^&*()-_=+[{]}//|;:/'/",<.>/?";
String pwd = RandomStringUtils.random( 15, characters );
System.out.println( pwd );
Si estás usando maven
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
<version>3.4</version>
</dependency>
de lo contrario descargar
Versión ACTUALIZADA con seguro aleatorio. Así que la materia de los caracteres requeridos se deja y se puede resolver como en el comentario, genera las partes requeridas por separado y las normales. Entonces únete a ellos al azar.
char[] possibleCharacters = (new String("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789~`!@#$%^&*()-_=+[{]}//|;:/'/",<.>/?")).toCharArray();
String randomStr = RandomStringUtils.random( randomStrLength, 0, possibleCharacters.length-1, false, false, possibleCharacters, new SecureRandom() );
System.out.println( randomStr );