/** * sets a password * * This method sets the password of the user in this * {@link AuthenticationManager}. The password is hashed with BCrypt using * the format in OpenBSD with a cost factor of 16. The final output will be * written to the password file as an ASCII string. This method will ready * this authenticator for {@link OpenBSDBCryptAuthManager#verify(String)} * and {@link OpenBSDBCryptAuthManager#getPassword()}. * * @param pass * the password to set * * @throws FailToStoreCredentialException * if failed to write the hashed password to the password file */ @Override public synchronized void setPassword(String pass) throws FailToStoreCredentialException { byte[] salt = new byte[16]; rand.nextBytes(salt); current = OpenBSDBCrypt.generate(pass.toCharArray(), salt, 16); try { passwdFile.write(current, StandardCharsets.US_ASCII); } catch (IOException e) { FailToStoreCredentialException fc = new FailToStoreCredentialException( "Cannot store the hashed password:" + e.getMessage()); fc.initCause(e); current = null; throw fc; } this.password = pass; }
public boolean testAnswer( final String testResponse ) { if ( testResponse == null ) { return false; } final String casedAnswer = caseInsensitive ? testResponse.toLowerCase() : testResponse; switch ( formatType ) { case BCRYPT: return OpenBSDBCrypt.checkPassword( answerHash, casedAnswer.toCharArray() ); case SCRYPT: return SCryptUtil.check( casedAnswer, answerHash ); default: throw new IllegalArgumentException( "can't test answer for unknown format " + formatType.toString() ); } }
public static String BCryptHash(String p, int cost) throws NoSuchAlgorithmException { String salt = KeyGenerators.string().generateKey(); String res = OpenBSDBCrypt.generate(p.toCharArray(), salt.getBytes(), cost); return res; }
private PasswordCryptAnswer( final AnswerFactory.AnswerConfiguration answerConfiguration, final String answer ) { if ( answer == null || answer.length() < 1 ) { throw new IllegalArgumentException( "missing answerHash text" ); } this.caseInsensitive = answerConfiguration.isCaseInsensitive(); this.formatType = answerConfiguration.formatType; final String casedAnswer = caseInsensitive ? answer.toLowerCase() : answer; switch ( formatType ) { case BCRYPT: final int bcryptRounds = 10; final byte[] salt = new byte[16]; ( new SecureRandom() ).nextBytes( salt ); answerHash = OpenBSDBCrypt.generate( casedAnswer.toCharArray(), salt, bcryptRounds ); break; case SCRYPT: answerHash = SCryptUtil.scrypt( casedAnswer ); break; default: throw new IllegalArgumentException( "can't test answer for unknown format " + formatType.toString() ); } }
protected boolean comparePasswords(String plainText, String hashed) { int lastIndex = passwordTypes.size() - 1; if (passwordTypes.get(lastIndex) == PasswordType.bcrypt) { for (int i = 0; i < lastIndex; i++) { plainText = hashPassword(plainText, passwordTypes.get(i)); } return OpenBSDBCrypt.checkPassword(hashed, plainText.toCharArray()); } return hashPassword(plainText).equals(hashed); }
protected String hashPassword(String password, PasswordType type) { switch (type) { case md5: return StringUtils.hash(password, "MD5"); case sha1: return StringUtils.hash(password, "SHA-1"); case sha256: return StringUtils.hash(password, "SHA-256"); case sha512: return StringUtils.hash(password, "SHA-512"); case bcrypt: byte[] salt = new byte[16]; new SecureRandom().nextBytes(salt); int cost = (bcryptCost < 4 || bcryptCost > 31) ? DEFAULT_BCRYPT_COST : bcryptCost; return OpenBSDBCrypt.generate(password.toCharArray(), salt, cost); case nt: byte[] digestBytes; byte[] utf16leBytes = null; try { MessageDigest md = MessageDigest.getInstance("MD4"); utf16leBytes = password.getBytes("UTF-16LE"); digestBytes = md.digest(utf16leBytes); return new String(new String(Hex.encode(digestBytes))); } catch (Exception e) { return null; } case plain: default: return password; } }
@Test public void hashPassword() throws Exception { assertTrue(MD5_PASSWORD.equals(jdbcAuthProvider.hashPassword(PASSWORD, JDBCAuthProvider.PasswordType.md5))); assertTrue(SHA1_PASSWORD.equals(jdbcAuthProvider.hashPassword(PASSWORD, JDBCAuthProvider.PasswordType.sha1))); assertTrue(SHA256_PASSWORD.equals(jdbcAuthProvider.hashPassword(PASSWORD, JDBCAuthProvider.PasswordType.sha256))); assertTrue(SHA512_PASSWORD.equals(jdbcAuthProvider.hashPassword(PASSWORD, JDBCAuthProvider.PasswordType.sha512))); assertFalse(BCRYPTED_PASSWORD.equals(jdbcAuthProvider.hashPassword(PASSWORD, JDBCAuthProvider.PasswordType.bcrypt))); assertTrue(OpenBSDBCrypt.checkPassword(BCRYPTED_PASSWORD, PASSWORD.toCharArray())); }
@Override public String encryptPassword(char[] plainPassword) { if (plainPassword == null) { return null; } final char[] normalizedChars = TextNormalizer.getInstance().normalizeToNfc(plainPassword); final String bcryptString = OpenBSDBCrypt.generate(normalizedChars, gensalt(), costFactor /* log rounds */); return passwordEncoderDecoder.encode(bcryptString); }
@Override public boolean checkPassword(char[] plainPassword, String storedPassword) { if (plainPassword == null) { return (storedPassword == null); } else if (storedPassword == null) { return false; } final String bcryptString = passwordEncoderDecoder.decode(storedPassword); final char[] normalizedChars = TextNormalizer.getInstance().normalizeToNfc(plainPassword); return OpenBSDBCrypt.checkPassword(bcryptString, normalizedChars); }
@Override public boolean check(String passwordHash, String password) { return OpenBSDBCrypt.checkPassword(passwordHash, password.toCharArray()); }
@Override public String generate(String password) { // bcrypt needs exactly 128 bits of salt byte[] salt = EncryptionUtils.generateSalt(16); return OpenBSDBCrypt.generate(password.toCharArray(), salt, getCostFactor()); }
@Override public User authenticate(final AuthCredentials credentials) { final Settings cfg = getConfigSettings(); if (cfg == null) { throw new ElasticsearchSecurityException("Internal authentication backend not configured. May be Search Guard is not initialized. See http://docs.search-guard.com/v6/sgadmin"); } String hashed = cfg.get(credentials.getUsername() + ".hash"); if (hashed == null) { for(String username:cfg.names()) { String u = cfg.get(username + ".username"); if(credentials.getUsername().equals(u)) { hashed = cfg.get(username+ ".hash"); break; } } if(hashed == null) { throw new ElasticsearchSecurityException(credentials.getUsername() + " not found"); } } final byte[] password = credentials.getPassword(); if(password == null || password.length == 0) { throw new ElasticsearchSecurityException("empty passwords not supported"); } ByteBuffer wrap = ByteBuffer.wrap(password); CharBuffer buf = StandardCharsets.UTF_8.decode(wrap); char[] array = new char[buf.limit()]; buf.get(array); Arrays.fill(password, (byte)0); try { if (OpenBSDBCrypt.checkPassword(hashed, array)) { final List<String> roles = cfg.getAsList(credentials.getUsername() + ".roles", Collections.emptyList()); return new User(credentials.getUsername(), roles, credentials); } else { throw new ElasticsearchSecurityException("password does not match"); } } finally { Arrays.fill(wrap.array(), (byte)0); Arrays.fill(buf.array(), '\0'); Arrays.fill(array, '\0'); } }
/** * verifies a password * * This method verifies a password input. It can only be called after a * successful {@link OpenBSDBCryptAuthManager#setPassword(String)} or a * {@link OpenBSDBCryptAuthManager#load()} with valid password file. If the * password is valid, the plain text password will be stored, which can be * accessed by {@link OpenBSDBCryptAuthManager#getPassword()}. * * @param pass * the password to verify * @return true if valid, false otherwise * * @throws NullPointerException * if no hash is in the buffer */ @Override public synchronized boolean verify(String pass) { boolean result = OpenBSDBCrypt.checkPassword(current, pass.toCharArray()); if (result) { this.password = pass; } return result; }