Coverage Summary for Class: BCryptPasswordEncryptor (com.acciente.oacc.encryptor.bcrypt)

Class Class, % Method, % Line, %
BCryptPasswordEncryptor 100% (1/ 1) 100% (8/ 8) 100% (26/ 26)


1 /* 2  * Copyright 2009-2018, Acciente LLC 3  * 4  * Acciente LLC licenses this file to you under the 5  * Apache License, Version 2.0 (the "License"); you 6  * may not use this file except in compliance with the 7  * License. You may obtain a copy of the License at 8  * 9  * http://www.apache.org/licenses/LICENSE-2.0 10  * 11  * Unless required by applicable law or agreed to in 12  * writing, software distributed under the License is 13  * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES 14  * OR CONDITIONS OF ANY KIND, either express or implied. 15  * See the License for the specific language governing 16  * permissions and limitations under the License. 17  */ 18 package com.acciente.oacc.encryptor.bcrypt; 19  20 import com.acciente.oacc.encryptor.PasswordEncryptor; 21 import com.acciente.oacc.normalizer.TextNormalizer; 22 import org.bouncycastle.crypto.generators.OpenBSDBCrypt; 23  24 import java.io.Serializable; 25 import java.security.SecureRandom; 26  27 /** 28  * Password encryptor implementation that uses the OpenBSD BCrypt algorithm for creating password hashes. 29  */ 30 public class BCryptPasswordEncryptor implements PasswordEncryptor, Serializable { 31  private static final long serialVersionUID = 1L; 32  33  public static final String NAME = "bcrypt"; 34  35  private static final int BCRYPT_COST_FACTOR_MIN = 4; 36  private static final int BCRYPT_COST_FACTOR_MAX = 31; 37  private static final int BCRYPT_SALT_SIZE = 16; 38  39  private static final PasswordEncoderDecoder passwordEncoderDecoder = new PasswordEncoderDecoder(); 40  private static final SecureRandom secureRandom = new SecureRandom(); 41  42  private final int costFactor; 43  44  /** 45  * Returns a password encryptor that uses the BCrypt algorithm with the specified cost factor. 46  * 47  * @param costFactor the BCrypt cost factor, must be between 4 and 31 (inclusive). 48  * @return a BCryptPasswordEncryptor instance configured as described above. 49  * @throws IllegalArgumentException if the specified BCrypt cost factor is not between 4 and 31 (inclusive). 50  */ 51  public static BCryptPasswordEncryptor newInstance(int costFactor) { 52  assertCostFactorValid(costFactor); 53  return new BCryptPasswordEncryptor(costFactor); 54  } 55  56  private BCryptPasswordEncryptor(int costFactor) { 57  this.costFactor = costFactor; 58  } 59  60  @Override 61  public String encryptPassword(char[] plainPassword) { 62  if (plainPassword == null) { 63  return null; 64  } 65  final char[] normalizedChars = TextNormalizer.getInstance().normalizeToNfc(plainPassword); 66  67  final String bcryptString = OpenBSDBCrypt.generate(normalizedChars, gensalt(), costFactor /* log rounds */); 68  69  return passwordEncoderDecoder.encode(bcryptString); 70  } 71  72  @Override 73  public boolean checkPassword(char[] plainPassword, String storedPassword) { 74  if (plainPassword == null) { 75  return (storedPassword == null); 76  } 77  else if (storedPassword == null) { 78  return false; 79  } 80  81  final String bcryptString = passwordEncoderDecoder.decode(storedPassword); 82  final char[] normalizedChars = TextNormalizer.getInstance().normalizeToNfc(plainPassword); 83  84  return OpenBSDBCrypt.checkPassword(bcryptString, normalizedChars); 85  } 86  87  /** 88  * Returns the cost factor in use by this instance. 89  * 90  * @return the integer cost factor used by this instance. 91  */ 92  public int getCostFactor() { 93  return costFactor; 94  } 95  96  private static byte[] gensalt() { 97  final byte[] saltBytes = new byte[BCRYPT_SALT_SIZE]; 98  secureRandom.nextBytes(saltBytes); 99  return saltBytes; 100  } 101  102  private static void assertCostFactorValid(int computedCostFactorMin) { 103  if (computedCostFactorMin < BCRYPT_COST_FACTOR_MIN || computedCostFactorMin > BCRYPT_COST_FACTOR_MAX) { 104  throw new IllegalArgumentException("The cost factor must be between " + BCRYPT_COST_FACTOR_MIN + " and " + 105  BCRYPT_COST_FACTOR_MAX + " (inclusive)"); 106  } 107  } 108 }