X-Git-Url: http://git.argeo.org/?a=blobdiff_plain;f=security%2Fruntime%2Forg.argeo.security.core%2Fsrc%2Fmain%2Fjava%2Forg%2Fargeo%2Fsecurity%2Fcrypto%2FPasswordBasedEncryption.java;h=aec25ac1728225367fefe9b0a3110f00191ca36f;hb=4c1cdecd3d3de9ff6a70b875a72bfd29a85b0227;hp=63cdc6c0c8c11e7e260e2db76212779c89670b0e;hpb=9884b3225a86b831917b10376925eebcbf99e513;p=lgpl%2Fargeo-commons.git diff --git a/security/runtime/org.argeo.security.core/src/main/java/org/argeo/security/crypto/PasswordBasedEncryption.java b/security/runtime/org.argeo.security.core/src/main/java/org/argeo/security/crypto/PasswordBasedEncryption.java index 63cdc6c0c..aec25ac17 100644 --- a/security/runtime/org.argeo.security.core/src/main/java/org/argeo/security/crypto/PasswordBasedEncryption.java +++ b/security/runtime/org.argeo.security.core/src/main/java/org/argeo/security/crypto/PasswordBasedEncryption.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2007-2012 Mathieu Baudier + * Copyright (C) 2007-2012 Argeo GmbH * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -20,6 +20,8 @@ import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; +import java.security.GeneralSecurityException; +import java.security.InvalidKeyException; import java.security.Key; import java.security.Security; @@ -32,23 +34,36 @@ import javax.crypto.spec.IvParameterSpec; import javax.crypto.spec.PBEKeySpec; import javax.crypto.spec.SecretKeySpec; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; import org.argeo.ArgeoException; import org.argeo.StreamUtils; import org.bouncycastle.jce.provider.BouncyCastleProvider; /** Simple password based encryption / decryption */ public class PasswordBasedEncryption { + private final static Log log = LogFactory + .getLog(PasswordBasedEncryption.class); + static { Security.addProvider(new BouncyCastleProvider()); } public final static Integer DEFAULT_ITERATION_COUNT = 1024; - public final static Integer DEFAULT_KEY_LENGTH = 256; + /** Stronger with 256, but causes problem with Oracle JVM */ + public final static Integer DEFAULT_SECRETE_KEY_LENGTH = 256; + public final static Integer DEFAULT_SECRETE_KEY_LENGTH_RESTRICTED = 128; public final static String DEFAULT_SECRETE_KEY_FACTORY = "PBKDF2WithHmacSHA1"; public final static String DEFAULT_SECRETE_KEY_ENCRYPTION = "AES"; - public final static String DEFAULT_CIPHER = "AES/CBC/PKCS5Padding"; + public final static String DEFAULT_CIPHER_NAME = "AES/CBC/PKCS5Padding"; public final static String DEFAULT_CHARSET = "UTF-8"; + private Integer iterationCount = DEFAULT_ITERATION_COUNT; + private Integer secreteKeyLength = DEFAULT_SECRETE_KEY_LENGTH; + private String secreteKeyFactoryName = DEFAULT_SECRETE_KEY_FACTORY; + private String secreteKeyEncryption = DEFAULT_SECRETE_KEY_ENCRYPTION; + private String cipherName = DEFAULT_CIPHER_NAME; + private static byte[] DEFAULT_SALT_8 = { (byte) 0xA9, (byte) 0x9B, (byte) 0xC8, (byte) 0x32, (byte) 0x56, (byte) 0x35, (byte) 0xE3, (byte) 0x03 }; @@ -57,9 +72,9 @@ public class PasswordBasedEncryption { (byte) 0x03, (byte) 0xA9, (byte) 0x9B, (byte) 0xC8, (byte) 0x32, (byte) 0x56, (byte) 0x35, (byte) 0xE3, (byte) 0x03 }; - private final Key key; - private final Cipher ecipher; - private final Cipher dcipher; + private Key key; + private Cipher ecipher; + private Cipher dcipher; /** * Default provider is bouncy castle, in order to have consistent behaviour @@ -82,39 +97,50 @@ public class PasswordBasedEncryption { public PasswordBasedEncryption(char[] password, byte[] passwordSalt, byte[] initializationVector) { try { - byte[] salt = new byte[8]; - System.arraycopy(passwordSalt, 0, salt, 0, salt.length); - // for (int i = 0; i < password.length && i < salt.length; i++) - // salt[i] = (byte) password[i]; - byte[] iv = new byte[16]; - System.arraycopy(initializationVector, 0, iv, 0, iv.length); - // for (int i = 0; i < password.length && i < iv.length; i++) - // iv[i] = (byte) password[i]; - - SecretKeyFactory keyFac = SecretKeyFactory - .getInstance(getSecretKeyFactoryName()); - PBEKeySpec keySpec = new PBEKeySpec(password, salt, - getIterationCount(), getKeyLength()); - String secKeyEncryption = getSecretKeyEncryption(); - if (secKeyEncryption != null) { - SecretKey tmp = keyFac.generateSecret(keySpec); - key = new SecretKeySpec(tmp.getEncoded(), - getSecretKeyEncryption()); - } else { - key = keyFac.generateSecret(keySpec); + initKeyAndCiphers(password, passwordSalt, initializationVector); + } catch (InvalidKeyException e) { + Integer previousSecreteKeyLength = secreteKeyLength; + secreteKeyLength = DEFAULT_SECRETE_KEY_LENGTH_RESTRICTED; + log.warn("'" + e.getMessage() + "', will use " + secreteKeyLength + + " secrete key length instead of " + + previousSecreteKeyLength); + try { + initKeyAndCiphers(password, passwordSalt, initializationVector); + } catch (Exception e1) { + throw new ArgeoException( + "Cannot get secret key (with restricted length)", e1); } - ecipher = Cipher.getInstance(getCipherName(), securityProviderName); - ecipher.init(Cipher.ENCRYPT_MODE, key, new IvParameterSpec(iv)); - // AlgorithmParameters params = ecipher.getParameters(); - // byte[] iv = - // params.getParameterSpec(IvParameterSpec.class).getIV(); - dcipher = Cipher.getInstance(getCipherName()); - dcipher.init(Cipher.DECRYPT_MODE, key, new IvParameterSpec(iv)); } catch (Exception e) { throw new ArgeoException("Cannot get secret key", e); } } + protected void initKeyAndCiphers(char[] password, byte[] passwordSalt, + byte[] initializationVector) throws GeneralSecurityException { + byte[] salt = new byte[8]; + System.arraycopy(passwordSalt, 0, salt, 0, salt.length); + // for (int i = 0; i < password.length && i < salt.length; i++) + // salt[i] = (byte) password[i]; + byte[] iv = new byte[16]; + System.arraycopy(initializationVector, 0, iv, 0, iv.length); + + SecretKeyFactory keyFac = SecretKeyFactory + .getInstance(getSecretKeyFactoryName()); + PBEKeySpec keySpec = new PBEKeySpec(password, salt, + getIterationCount(), getKeyLength()); + String secKeyEncryption = getSecretKeyEncryption(); + if (secKeyEncryption != null) { + SecretKey tmp = keyFac.generateSecret(keySpec); + key = new SecretKeySpec(tmp.getEncoded(), getSecretKeyEncryption()); + } else { + key = keyFac.generateSecret(keySpec); + } + ecipher = Cipher.getInstance(getCipherName(), securityProviderName); + ecipher.init(Cipher.ENCRYPT_MODE, key, new IvParameterSpec(iv)); + dcipher = Cipher.getInstance(getCipherName()); + dcipher.init(Cipher.DECRYPT_MODE, key, new IvParameterSpec(iv)); + } + public void encrypt(InputStream decryptedIn, OutputStream encryptedOut) throws IOException { try { @@ -188,23 +214,43 @@ public class PasswordBasedEncryption { } protected Integer getIterationCount() { - return DEFAULT_ITERATION_COUNT; + return iterationCount; } protected Integer getKeyLength() { - return DEFAULT_KEY_LENGTH; + return secreteKeyLength; } protected String getSecretKeyFactoryName() { - return DEFAULT_SECRETE_KEY_FACTORY; + return secreteKeyFactoryName; } protected String getSecretKeyEncryption() { - return DEFAULT_SECRETE_KEY_ENCRYPTION; + return secreteKeyEncryption; } protected String getCipherName() { - return DEFAULT_CIPHER; + return cipherName; + } + + public void setIterationCount(Integer iterationCount) { + this.iterationCount = iterationCount; + } + + public void setSecreteKeyLength(Integer keyLength) { + this.secreteKeyLength = keyLength; + } + + public void setSecreteKeyFactoryName(String secreteKeyFactoryName) { + this.secreteKeyFactoryName = secreteKeyFactoryName; + } + + public void setSecreteKeyEncryption(String secreteKeyEncryption) { + this.secreteKeyEncryption = secreteKeyEncryption; + } + + public void setCipherName(String cipherName) { + this.cipherName = cipherName; } public void setSecurityProviderName(String securityProviderName) {