Jak mogę zaszyfrować hasło w Javie?


176

Muszę haszować hasła do przechowywania w bazie danych. Jak mogę to zrobić w Javie?

Miałem nadzieję, że wezmę hasło w postaci zwykłego tekstu, dodam losową sól, a następnie przechowam sól i zaszyfrowane hasło w bazie danych.

Następnie, gdy użytkownik chciał się zalogować, mogłem wziąć przesłane przez niego hasło, dodać losową sól z informacji o jego koncie, zaszyfrować ją i sprawdzić, czy jest równa zapisanemu hasłu z informacjami o koncie.


11
@YGL w dzisiejszych czasach nie jest to rekombinacja, ponieważ ataki GPU są tak tanie, rodzina SHA jest w rzeczywistości bardzo złym wyborem do haszowania haseł (zbyt szybko), nawet z solą. Użyj bcrypt, scrypt lub PBKDF2
Eran Medan

11
Dlaczego to pytanie zostało zamknięte? To jest pytanie dotyczące prawdziwego problemu inżynieryjnego, a odpowiedzi są nieocenione. OP nie prosi o bibliotekę, ale pyta, jak rozwiązać problem inżynierski.
stackoverflowuser2010,

12
Po prostu niesamowite. To pytanie ma 52 głosy za i ktoś decyduje się zamknąć je jako „nie na temat”.
stackoverflowuser2010,

1
Tak, już wcześniej publikowałem na Meta ten problem z zamykaniem, ale zostałem dość mocno pobity.
Chris Dutrow

8
To pytanie powinno zostać ponownie otwarte. Chodzi o to, jak napisać program rozwiązujący opisany problem (uwierzytelnianie hasłem) za pomocą krótkiego kodu. Widzenie słowa wywołującego „biblioteka” nie usprawiedliwia odruchowego zamykania pytania; nie prosi o rekomendację biblioteki, pyta, jak haszować hasła. Edycja: Tam, naprawiłem to.
erickson

Odpowiedzi:


157

Aby to zrobić, możesz użyć funkcji wbudowanej w środowisko wykonawcze Java. SunJCE w Javie 6 obsługuje PBKDF2, który jest dobrym algorytmem do haszowania haseł.

byte[] salt = new byte[16];
random.nextBytes(salt);
KeySpec spec = new PBEKeySpec("password".toCharArray(), salt, 65536, 128);
SecretKeyFactory f = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA1");
byte[] hash = f.generateSecret(spec).getEncoded();
Base64.Encoder enc = Base64.getEncoder();
System.out.printf("salt: %s%n", enc.encodeToString(salt));
System.out.printf("hash: %s%n", enc.encodeToString(hash));

Oto klasa narzędzi, której możesz użyć do uwierzytelnienia hasła PBKDF2:

import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.KeySpec;
import java.util.Arrays;
import java.util.Base64;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.PBEKeySpec;

/**
 * Hash passwords for storage, and test passwords against password tokens.
 * 
 * Instances of this class can be used concurrently by multiple threads.
 *  
 * @author erickson
 * @see <a href="http://stackoverflow.com/a/2861125/3474">StackOverflow</a>
 */
public final class PasswordAuthentication
{

  /**
   * Each token produced by this class uses this identifier as a prefix.
   */
  public static final String ID = "$31$";

  /**
   * The minimum recommended cost, used by default
   */
  public static final int DEFAULT_COST = 16;

  private static final String ALGORITHM = "PBKDF2WithHmacSHA1";

  private static final int SIZE = 128;

  private static final Pattern layout = Pattern.compile("\\$31\\$(\\d\\d?)\\$(.{43})");

  private final SecureRandom random;

  private final int cost;

  public PasswordAuthentication()
  {
    this(DEFAULT_COST);
  }

  /**
   * Create a password manager with a specified cost
   * 
   * @param cost the exponential computational cost of hashing a password, 0 to 30
   */
  public PasswordAuthentication(int cost)
  {
    iterations(cost); /* Validate cost */
    this.cost = cost;
    this.random = new SecureRandom();
  }

  private static int iterations(int cost)
  {
    if ((cost < 0) || (cost > 30))
      throw new IllegalArgumentException("cost: " + cost);
    return 1 << cost;
  }

  /**
   * Hash a password for storage.
   * 
   * @return a secure authentication token to be stored for later authentication 
   */
  public String hash(char[] password)
  {
    byte[] salt = new byte[SIZE / 8];
    random.nextBytes(salt);
    byte[] dk = pbkdf2(password, salt, 1 << cost);
    byte[] hash = new byte[salt.length + dk.length];
    System.arraycopy(salt, 0, hash, 0, salt.length);
    System.arraycopy(dk, 0, hash, salt.length, dk.length);
    Base64.Encoder enc = Base64.getUrlEncoder().withoutPadding();
    return ID + cost + '$' + enc.encodeToString(hash);
  }

  /**
   * Authenticate with a password and a stored password token.
   * 
   * @return true if the password and token match
   */
  public boolean authenticate(char[] password, String token)
  {
    Matcher m = layout.matcher(token);
    if (!m.matches())
      throw new IllegalArgumentException("Invalid token format");
    int iterations = iterations(Integer.parseInt(m.group(1)));
    byte[] hash = Base64.getUrlDecoder().decode(m.group(2));
    byte[] salt = Arrays.copyOfRange(hash, 0, SIZE / 8);
    byte[] check = pbkdf2(password, salt, iterations);
    int zero = 0;
    for (int idx = 0; idx < check.length; ++idx)
      zero |= hash[salt.length + idx] ^ check[idx];
    return zero == 0;
  }

  private static byte[] pbkdf2(char[] password, byte[] salt, int iterations)
  {
    KeySpec spec = new PBEKeySpec(password, salt, iterations, SIZE);
    try {
      SecretKeyFactory f = SecretKeyFactory.getInstance(ALGORITHM);
      return f.generateSecret(spec).getEncoded();
    }
    catch (NoSuchAlgorithmException ex) {
      throw new IllegalStateException("Missing algorithm: " + ALGORITHM, ex);
    }
    catch (InvalidKeySpecException ex) {
      throw new IllegalStateException("Invalid SecretKeyFactory", ex);
    }
  }

  /**
   * Hash a password in an immutable {@code String}. 
   * 
   * <p>Passwords should be stored in a {@code char[]} so that it can be filled 
   * with zeros after use instead of lingering on the heap and elsewhere.
   * 
   * @deprecated Use {@link #hash(char[])} instead
   */
  @Deprecated
  public String hash(String password)
  {
    return hash(password.toCharArray());
  }

  /**
   * Authenticate with a password in an immutable {@code String} and a stored 
   * password token. 
   * 
   * @deprecated Use {@link #authenticate(char[],String)} instead.
   * @see #hash(String)
   */
  @Deprecated
  public boolean authenticate(String password, String token)
  {
    return authenticate(password.toCharArray(), token);
  }

}

11
Możesz być nieco ostrożny w przypadku konwersji bajtów na szesnastkowe z BigInteger: zera wiodące są usuwane. To jest ok do szybkiego debugowania, ale widziałem błędy w kodzie produkcyjnym z powodu tego efektu.
Thomas Pornin

24
@ thomas-pornin podkreśla, dlaczego potrzebujemy biblioteki , a nie bloku kodu, który jest prawie gotowy . Straszne, że przyjęta odpowiedź nie odpowiada na pytanie na tak ważny temat.
Nilzor

9
Użyj algorytmu PBKDF2WithHmacSHA512 zaczynającego się od Java 8. Jest nieco silniejszy.
iwan.z

1
Uwaga, istniejące ALG nie zostaną usunięte w późniejszych wersjach: java_4: PBEWithMD5AndDES, DESede DES java_5 / 6/7: PBKDF2WithHmacSHA1, PBE (tylko w Javie 5), PBEWithSHA1AndRC2_40, PBEWithSHA1And, PBEWithMD5AndTriple java_8: PBEWithHmacSHA224AndAES_128, PBEWithHmacSHA384AndAES_128, PBEWithHmacSHA512AndAES_128, RC4_40, PBKDF2WithHmacSHA256 , PBEWithHmacSHA1AndAES_128, RC4_128, PBKDF2WithHmacSHA224, PBEWithHmacSHA256AndAES_256, RC2_128, PBEWithHmacSHA224AndAES_256, PBEWithHmacSHA384AndAES_256, PBEWithHmacSHA512AndAES_256, PBKDF2WithHmacSHA512, PBEWithHmacSHA256AndAES_128, PBKDF2WithHmacSHA384, PBEWithHmacSHA1AndAES_256
iwan.z

4
@TheTosters Tak, czas wykonania będzie dłuższy w przypadku nieprawidłowych haseł; a dokładniej, błędne hasło zajmie tyle samo czasu co prawidłowe hasło. Zapobiega atakom czasowym, chociaż przyznaję, że nie mogę wymyślić praktycznego sposobu wykorzystania takiej luki w tym przypadku. Ale nie idziesz na skróty. To, że tego nie widzę, nie oznacza, że ​​bardziej przebiegły umysł tego nie zrobi.
erickson

97

Tutaj jest pełna implementacja z dwiema metodami, które robią dokładnie to, co chcesz:

String getSaltedHash(String password)
boolean checkPassword(String password, String stored)

Chodzi o to, że nawet jeśli atakujący uzyska dostęp zarówno do bazy danych, jak i kodu źródłowego, hasła są nadal bezpieczne.

import javax.crypto.SecretKey;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.PBEKeySpec;
import java.security.SecureRandom;
import org.apache.commons.codec.binary.Base64;

public class Password {
    // The higher the number of iterations the more 
    // expensive computing the hash is for us and
    // also for an attacker.
    private static final int iterations = 20*1000;
    private static final int saltLen = 32;
    private static final int desiredKeyLen = 256;

    /** Computes a salted PBKDF2 hash of given plaintext password
        suitable for storing in a database. 
        Empty passwords are not supported. */
    public static String getSaltedHash(String password) throws Exception {
        byte[] salt = SecureRandom.getInstance("SHA1PRNG").generateSeed(saltLen);
        // store the salt with the password
        return Base64.encodeBase64String(salt) + "$" + hash(password, salt);
    }

    /** Checks whether given plaintext password corresponds 
        to a stored salted hash of the password. */
    public static boolean check(String password, String stored) throws Exception{
        String[] saltAndHash = stored.split("\\$");
        if (saltAndHash.length != 2) {
            throw new IllegalStateException(
                "The stored password must have the form 'salt$hash'");
        }
        String hashOfInput = hash(password, Base64.decodeBase64(saltAndHash[0]));
        return hashOfInput.equals(saltAndHash[1]);
    }

    // using PBKDF2 from Sun, an alternative is https://github.com/wg/scrypt
    // cf. http://www.unlimitednovelty.com/2012/03/dont-use-bcrypt.html
    private static String hash(String password, byte[] salt) throws Exception {
        if (password == null || password.length() == 0)
            throw new IllegalArgumentException("Empty passwords are not supported.");
        SecretKeyFactory f = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA1");
        SecretKey key = f.generateSecret(new PBEKeySpec(
            password.toCharArray(), salt, iterations, desiredKeyLen));
        return Base64.encodeBase64String(key.getEncoded());
    }
}

Przechowujemy 'salt$iterated_hash(password, salt)' . Sól to 32 losowe bajty, a jej celem jest to, że jeśli dwie różne osoby wybiorą to samo hasło, przechowywane hasła będą nadal wyglądać inaczej.

To iterated_hash, co jest w zasadzie hash(hash(hash(... hash(password, salt) ...)))bardzo kosztowne dla potencjalnego napastnika, który ma dostęp do Twojej bazy danych, aby odgadnąć hasła, haszować je i wyszukiwać skróty w bazie danych. Musisz to obliczać za iterated_hashkażdym razem, gdy loguje się użytkownik, ale nie kosztuje to dużo w porównaniu z atakującym, który spędza prawie 100% swojego czasu na obliczaniu skrótów.


14
Przepraszam, że się zrzędzę, ale dlaczego powinienem wybrać to zamiast istniejącej biblioteki? Prawdopodobnie biblioteka ma większe szanse na dokładny przegląd. Wątpię, czy każdy z 14 głosów pozytywnych przeanalizował kod pod kątem jakichkolwiek problemów.
Joachim Sauer

2
@JoachimSauer Zasadniczo jest to po prostu użycie biblioteki (javax.crypto), ale masz rację - puste hasła nie są obsługiwane. Dodano wyjątek, aby było to wyraźne. Dzięki!
Martin Konicek

3
Prawdopodobnie powinieneś zmienić sygnatury metod na char[] passwordzamiast String password.
assylias

2
Chociaż wydaje się, że odniesienie nie uzyskało jednomyślnej zgody. Zobacz także: security.stackexchange.com/a/20369/12614
assylias

3
Czy jesteś pewien, że .equals () na łańcuchach nie powoduje zwarcia (tj .: zatrzymaj pętlę, gdy znajdzie dwa bajty, które nie są równe)? Jeśli tak, istnieje ryzyko, że atak czasowy wycieknie informacje o skrócie hasła.
bobpoekert


7

Możesz użyć implementacji biblioteki Shiro (dawniej JSecurity ) tego, co zostało opisane przez OWASP .

Wygląda również na to, że biblioteka JASYPT ma podobne narzędzie .


Właśnie tego używałem. Ale ponieważ zdecydowaliśmy się nie używać Shiro, pojawiły się obawy dotyczące nieefektywności konieczności włączenia całej biblioteki Shiro tylko do tego jednego pakietu.
Chris Dutrow

Nie znam biblioteki składającej się tylko z narzędzia do mieszania haseł. Prawdopodobnie lepiej zrezygnować z własnego, jeśli problemem są zależności. Odpowiedź Ericksona wygląda dla mnie całkiem nieźle. Lub po prostu skopiuj kod z odsyłacza OWASP, do którego się odwołałem, jeśli wolisz używać SHA w bezpieczny sposób.
laz

7

Możesz obliczać skróty za pomocą MessageDigest, ale jest to złe z punktu widzenia bezpieczeństwa. Hashe nie mogą być używane do przechowywania haseł, ponieważ można je łatwo złamać.

Do przechowywania haseł należy użyć innego algorytmu, takiego jak bcrypt, PBKDF2 i scrypt. Zobacz tutaj .


3
Jak zaszyfrowałbyś hasło podczas logowania bez przechowywania soli w bazie danych?
ZZ Coder

9
Używanie nazwy użytkownika jako soli nie jest fatalnym błędem, ale nie jest tak dobre, jak użycie soli z kryptograficznego RNG. I nie ma absolutnie żadnego problemu z przechowywaniem soli w bazie danych. Sól nie jest tajemnicą.
erickson

1
Czy nazwa użytkownika i adres e-mail nie byłyby również przechowywane w bazie danych?
Chris Dutrow

@ZZ Coder, @erickson poprawne, jakoś założyłem, że będzie to jedna sól dla wszystkich haseł, co doprowadziłoby do łatwo obliczalnej tęczowej tablicy.
Bozho

13
Jednym z problemów związanych z używaniem nazwy użytkownika (lub innego identyfikatora, takiego jak adres e-mail) jako soli, jest to, że nie można zmienić identyfikatora bez konieczności ustawiania przez użytkownika nowego hasła.
Lawrence Dol

6

Oprócz bcrypt i PBKDF2 wspomnianych w innych odpowiedziach, poleciłbym przyjrzeć się scrypt

MD5 i SHA-1 nie są zalecane, ponieważ są stosunkowo szybkie, dlatego przy użyciu obliczeń rozproszonych typu „rent per hour” (np. EC2) lub nowoczesnej wysokiej klasy GPU można „złamać” hasła za pomocą ataków brutalnych / słownikowych przy stosunkowo niskich kosztach i rozsądnych czas.

Jeśli musisz ich użyć, to przynajmniej powtórz algorytm określoną wcześniej znaczną liczbę razy (1000+).


6

W pełni zgadzam się z Ericksonem, że PBKDF2 jest .

Jeśli nie masz tej opcji lub potrzebujesz tylko użyć skrótu, Apache Commons DigestUtils jest znacznie łatwiejsze niż poprawienie kodu JCE: https://commons.apache.org/proper/commons-codec/apidocs/org/apache /commons/codec/digest/DigestUtils.html

Jeśli używasz hasha, idź z sha256 lub sha512. Ta strona zawiera dobre zalecenia dotyczące obsługi haseł i haszowania (pamiętaj, że nie zaleca haszowania do obsługi haseł): http://www.daemonology.net/blog/2009-06-11-cryptographic-right-answers.html


Warto zauważyć, że SHA512 nie jest lepszy niż SHA256 (w tym celu) tylko dlatego, że liczba jest większa.
Azsgy

5

Możesz użyć Spring Security Crypto (ma tylko 2 opcjonalne zależności kompilacji ), który obsługuje szyfrowanie haseł PBKDF2 , BCrypt , SCrypt i Argon2 .

Argon2PasswordEncoder argon2PasswordEncoder = new Argon2PasswordEncoder();
String aCryptedPassword = argon2PasswordEncoder.encode("password");
boolean passwordIsValid = argon2PasswordEncoder.matches("password", aCryptedPassword);
SCryptPasswordEncoder sCryptPasswordEncoder = new SCryptPasswordEncoder();
String sCryptedPassword = sCryptPasswordEncoder.encode("password");
boolean passwordIsValid = sCryptPasswordEncoder.matches("password", sCryptedPassword);
BCryptPasswordEncoder bCryptPasswordEncoder = new BCryptPasswordEncoder();
String bCryptedPassword = bCryptPasswordEncoder.encode("password");
boolean passwordIsValid = bCryptPasswordEncoder.matches("password", bCryptedPassword);
Pbkdf2PasswordEncoder pbkdf2PasswordEncoder = new Pbkdf2PasswordEncoder();
String pbkdf2CryptedPassword = pbkdf2PasswordEncoder.encode("password");
boolean passwordIsValid = pbkdf2PasswordEncoder.matches("password", pbkdf2CryptedPassword);

4

Choć PBKDF2 rekomendacja NIST już wspomniano, chciałbym podkreślić, że nie było publicznego hasło mieszania konkurencja , która trwała od 2013 do 2015. W końcu Argon2 została wybrana jako zalecana funkcji haszowania hasła.

Istnieje dość dobrze przyjęte powiązanie Java dla oryginalnej (natywnej biblioteki C), której możesz użyć.

W przeciętnym przypadku użycia nie sądzę, aby z punktu widzenia bezpieczeństwa miało to znaczenie, jeśli wybierzesz PBKDF2 zamiast Argon2 lub odwrotnie. Jeśli masz silne wymagania dotyczące bezpieczeństwa, polecam wziąć pod uwagę Argon2 w Twojej ocenie.

Więcej informacji na temat bezpieczeństwa funkcji mieszania haseł można znaleźć na stronie security.se .


@zaph Zmieniłem odpowiedź, aby była bardziej obiektywna. Należy pamiętać, że zalecenie NIST może nie zawsze być najlepszym wyborem (zobacz tutaj przykład) - oczywiście dotyczy to wszystkiego, co jest zalecane również gdzie indziej. Dlatego uważam, że ta odpowiedź nadaje wartość temu pytaniu.
Qw3ry,

2

Tutaj masz dwa linki do haszowania MD5 i innych metod haszowania:

Javadoc API: https://docs.oracle.com/javase/1.5.0/docs/api/java/security/MessageDigest.html

Samouczek: http://www.twmacinta.com/myjava/fast_md5.php


3
Pamiętaj tylko, że w przypadku mieszania haseł wolniejsze oznacza lepsze. Powinieneś używać tysięcy iteracji funkcji skrótu jako techniki „wzmacniania klucza”. Konieczna jest również sól.
erickson

Miałem wrażenie, że wielokrotne iteracje algorytmu haszującego jakości dałyby mniej więcej takie samo bezpieczeństwo jak jedna iteracja, ponieważ długość bajtów byłaby nadal taka sama?
Chris Dutrow

@erickson Lepiej byłoby wyraźnie spowolnić napastników.
demon

6
O wzmocnieniu klucza: istnieją sole, które sprawiają, że wstępnie obliczone skróty są bezużyteczne. Ale atakujący nie muszą wcześniej obliczać. Atakujący mogą po prostu mieszać ciągi znaków + sól „w locie”, dopóki nie znajdą właściwego. Ale jeśli będziesz iterować tysiące razy dla swoich skrótów, będą musieli zrobić to samo. 10k iteracji nie będzie miało większego wpływu na Twój serwer, ponieważ nie zdarza się to często. Atakujący będą potrzebować 10k razy większej mocy obliczeniowej.
zockman

2
@Simon obecnie MD5 jest uważane za bezużyteczne do haszowania haseł, ponieważ można je złamać w ciągu kilku sekund za pomocą ataków brutalnych / słownikowych na GPU. Zobacz tutaj: codahale.com/how-to-safely-store-a-password
Eran Medan

1

Spośród wszystkich standardowych schematów mieszania, ssha LDAP jest najbezpieczniejszym w użyciu,

http://www.openldap.org/faq/data/cache/347.html

Po prostu postępowałbym zgodnie z określonymi tam algorytmami i używał MessageDigest do wykonania skrótu.

Musisz przechowywać sól w swojej bazie danych, zgodnie z sugestią.


1
Ponieważ SSHA nie iteruje funkcji skrótu, jest za szybki. Pozwala to atakującym na szybsze wypróbowywanie haseł. Lepsze algorytmy, takie jak Bcrypt, PBBKDF1 i PBKDF2, wykorzystują techniki „wzmacniania klucza”, aby spowolnić atakujących do punktu, w którym hasło powinno wygasać, zanim będą mogli brutalnie wymusić nawet 8-literową przestrzeń hasła.
erickson

Problem z tymi wszystkimi mechanizmami polega na tym, że nie otrzymujesz wsparcia klienta. Problem z zaszyfrowanymi hasłami polega na tym, że nie można ich obsługiwać za pomocą innych algorytmów. W przypadku ssha obsługują go przynajmniej wszyscy klienci LDAP.
ZZ Coder

Nie jest „najbezpieczniejszy”, jest po prostu „całkiem kompatybilny”. bcrypt / scrypt są znacznie bardziej intensywne dla zasobów.
eckes

1

Od 2020 roku najbardziej wiarygodny i elastyczny algorytm w użyciu,

najbardziej prawdopodobny optymalizujący swoją wytrzymałość na jakimkolwiek sprzęcie,

jest Argon2id lub Argon2i .

Zapewnia niezbędne narzędzie kalibracyjne do znalezienia zoptymalizowanych parametrów wytrzymałościowych, biorąc pod uwagę docelowy czas mieszania i używany sprzęt.

  • Argon2i specjalizuje się w chciwym haszowaniu pamięci
  • Argon2d specjalizuje się w chciwym haszowaniu procesora
  • Argon2id używa obu metod.

Chciwe mieszanie pamięci pomogłoby w zapobieganiu używaniu GPU do łamania.

Wiosenna implementacja zabezpieczeń / Bouncy Castle nie jest zoptymalizowana i jest stosunkowo słaba, biorąc pod uwagę to, czego może użyć atakujący. cf: Spring Documentation

Obecna implementacja wykorzystuje zamek Bouncy, który nie wykorzystuje paralelizmu / optymalizacji, które wykorzystują łamacze haseł, więc występuje niepotrzebna asymetria między atakującym a obrońcą.

Najbardziej wiarygodną implementacją używaną w javie jest mkammerer ,

jar opakowujący / biblioteka oficjalnej natywnej implementacji napisanej w Rust.

Jest dobrze napisany i prosty w użyciu.

Wersja wbudowana zapewnia natywne kompilacje dla systemów Linux, Windows i OSX.

Na przykład jest używany przez jpmorganchase w swoim projekcie bezpieczeństwa tessera używanym do zabezpieczenia Quorum , jego implementacji kryptowaluty Ethereum.

Oto przykładowy kod z tessera.

Kalibrację można przeprowadzić za pomocą de.mkammerer.argon2.Argon2Helper # findIterations

Algorytmy SCRYPT i Pbkdf2 można również skalibrować, pisząc kilka prostych testów porównawczych, ale obecne minimalne bezpieczne wartości iteracji będą wymagały dłuższych czasów mieszania.


0

Oparłem to na filmie na Udemy i zredagowałem, aby było silniejsze, losowe hasło

}

private String pass() {
        String passswet="1234567890zxcvbbnmasdfghjklop[iuytrtewq@#$%^&*" ;

        char icon1;
        char[] t=new char[20];

         int rand1=(int)(Math.random()*6)+38;//to make a random within the range of special characters

            icon1=passswet.charAt(rand1);//will produce char with a special character

        int i=0;
        while( i <11) {

             int rand=(int)(Math.random()*passswet.length());
             //notice (int) as the original value of Math>random() is double

             t[i] =passswet.charAt(rand);

             i++;
                t[10]=icon1;
//to replace the specified item with icon1
         }
        return new String(t);
}






}

Jestem otwarty na poprawki, ale myślę, że nie powinieneś używać liczb losowych podczas haszowania. Dzieje się tak, aby funkcja skrótu pozostała deterministyczna; oznacza to, że jeśli haszujesz ciąg wiele razy, zawsze otrzymasz z powrotem tę samą wartość skrótu dla tego ciągu.
duldi
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.