PBEKeySpecCrypt.java

  1. /*
  2.  * GovWay - A customizable API Gateway
  3.  * https://govway.org
  4.  *
  5.  * Copyright (c) 2005-2025 Link.it srl (https://link.it).
  6.  *
  7.  * This program is free software: you can redistribute it and/or modify
  8.  * it under the terms of the GNU General Public License version 3, as published by
  9.  * the Free Software Foundation.
  10.  *
  11.  * This program is distributed in the hope that it will be useful,
  12.  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  14.  * GNU General Public License for more details.
  15.  *
  16.  * You should have received a copy of the GNU General Public License
  17.  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
  18.  *
  19.  */

  20. package org.openspcoop2.utils.crypt;

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

  23. import org.openspcoop2.utils.UtilsException;
  24. import org.openspcoop2.utils.io.Base64Utilities;
  25. import org.openspcoop2.utils.io.HexBinaryUtilities;
  26. import org.openspcoop2.utils.random.RandomGenerator;
  27. import org.slf4j.Logger;

  28. /**
  29.  * PBEKeySpecCrypt
  30.  *
  31.  * @author Poli Andrea (apoli@link.it)
  32.  * @author $Author$
  33.  * @version $Rev$, $Date$
  34.  */
  35. public class PBEKeySpecCrypt implements ICrypt {

  36.     private static final String PBE_ALGORITHM = "PBKDF2WithHmacSHA1";
  37.    
  38.     private Logger log;
  39.     private CryptConfig config;
  40.     private RandomGenerator randomGenerator;

  41.     public PBEKeySpecCrypt(){
  42.        
  43.     }
  44.    
  45.     @Override
  46.     public void init(Logger log, CryptConfig config) {
  47.         this.log = log;
  48.        
  49.         this.config = config;
  50.         if(this.config == null) {
  51.             this.config = new CryptConfig();
  52.         }
  53.        
  54.         this.randomGenerator = new RandomGenerator(this.config.isUseSecureRandom(), this.config.getAlgorithmSecureRandom());
  55.     }
  56.    
  57.     @Override
  58.     public String crypt(String password) throws UtilsException {
  59.        
  60.         int iterations = 1000;
  61.         if(this.config.getIteration()!=null && this.config.getIteration()>0) {
  62.             iterations = this.config.getIteration().intValue();
  63.         }
  64.        
  65.         char[] chars = password.toCharArray();
  66.        
  67.         int saltLength = 16;
  68.         if(this.config.getSaltLength()!=null && this.config.getSaltLength()>0) {
  69.             saltLength = this.config.getSaltLength().intValue();
  70.         }
  71.         byte[] salt = this.randomGenerator.nextRandomBytes(saltLength);
  72.        
  73.         try {
  74.             PBEKeySpec spec = new PBEKeySpec(chars, salt, iterations, 64 * 8);
  75.             String algo = PBE_ALGORITHM;
  76.             if(this.config.getDigestAlgorithm()!=null) {
  77.                 algo = this.config.getDigestAlgorithm();
  78.             }
  79.             SecretKeyFactory skf = SecretKeyFactory.getInstance(algo);
  80.             byte[] hash = skf.generateSecret(spec).getEncoded();
  81.             String prefix = iterations + ":";
  82.             if(this.config.isUseBase64Encoding()) {
  83.                 return prefix +  Base64Utilities.encodeAsString(salt) + ":" + Base64Utilities.encodeAsString(hash);
  84.             }
  85.             else {
  86.                 return prefix +  HexBinaryUtilities.encodeAsString(salt) + ":" + HexBinaryUtilities.encodeAsString(hash);
  87.             }
  88.         }catch(Exception e) {
  89.             throw new UtilsException(e.getMessage(),e);
  90.         }
  91.        
  92.     }
  93.    
  94.     @Override
  95.     public boolean check(String password, String pwcrypt) {
  96.         try {
  97.             String[] parts = pwcrypt.split(":");
  98.             if(parts.length!=3) {
  99.                 throw new Exception("Wrong format");
  100.             }
  101.             int iterations = Integer.parseInt(parts[0]);
  102.             byte[] salt = null;
  103.             byte[] hash = null;
  104.             if(this.config.isUseBase64Encoding()) {
  105.                 salt = Base64Utilities.decode(parts[1]);
  106.                 hash = Base64Utilities.decode(parts[2]);
  107.             }
  108.             else {
  109.                 salt = HexBinaryUtilities.decode(parts[1]);
  110.                 hash = HexBinaryUtilities.decode(parts[2]);
  111.             }
  112.            
  113.             PBEKeySpec spec = new PBEKeySpec(password.toCharArray(), salt, iterations, hash.length * 8);
  114.            
  115.             String algo = PBE_ALGORITHM;
  116.             if(this.config.getDigestAlgorithm()!=null) {
  117.                 algo = this.config.getDigestAlgorithm();
  118.             }
  119.             SecretKeyFactory skf = SecretKeyFactory.getInstance(algo);
  120.            
  121.             byte[] testHash = skf.generateSecret(spec).getEncoded();
  122.            
  123.             int diff = hash.length ^ testHash.length;
  124.            
  125.             for(int i = 0; i < hash.length && i < testHash.length; i++)
  126.             {
  127.                 diff |= hash[i] ^ testHash[i];
  128.             }
  129.            
  130.             return diff == 0;
  131.         }catch(Throwable e){
  132.             if(this.log!=null) {
  133.                 this.log.error("Verifica password '"+pwcrypt+"' fallita: "+e.getMessage(),e);
  134.             }
  135.             return false;
  136.         }
  137.     }
  138.    
  139. }