You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@ofbiz.apache.org by Jacques Le Roux <ja...@les7arts.com> on 2015/06/10 12:05:04 UTC

Re: svn commit: r1684608 - in /ofbiz/trunk: ./ framework/base/lib/ framework/base/src/org/ofbiz/base/crypto/ framework/entity/src/org/ofbiz/entity/ framework/entity/src/org/ofbiz/entity/jdbc/ framework/entity/src/org/ofbiz/entity/test/ framework/entity/src...

Hi Jacopo,

Very happy about that, I don't have time to review in details yet, but I'm already impressed by the comment and a 1st cursory review :)

Just a question, since I have no experience with Moqui code, is there a relation or ideas coming from there?

Jacques

Le 10/06/2015 11:01, jacopoc@apache.org a écrit :
> Author: jacopoc
> Date: Wed Jun 10 09:01:30 2015
> New Revision: 1684608
>
> URL: http://svn.apache.org/r1684608
> Log:
> New implementation of the two-way cryptographic services of OFBiz based on Apache Shiro:
> * two-way encryption is now delegated to Apache Shiro, with stronger initialization vectors
> * the mechanism is backward compatible
> * new tools to update the encryption of private keys, useful to upgrade older versions of OFBiz and most of all to replace old keys with new ones (this is critical to implement stronger security practices as requested by PCI)
> * unit tests
>
>
> Added:
>      ofbiz/trunk/framework/base/lib/shiro-core-1.2.3.jar   (with props)
> Modified:
>      ofbiz/trunk/LICENSE
>      ofbiz/trunk/build.xml
>      ofbiz/trunk/framework/base/src/org/ofbiz/base/crypto/DesCrypt.java
>      ofbiz/trunk/framework/base/src/org/ofbiz/base/crypto/Main.java
>      ofbiz/trunk/framework/entity/src/org/ofbiz/entity/Delegator.java
>      ofbiz/trunk/framework/entity/src/org/ofbiz/entity/GenericDelegator.java
>      ofbiz/trunk/framework/entity/src/org/ofbiz/entity/jdbc/SqlJdbcUtil.java
>      ofbiz/trunk/framework/entity/src/org/ofbiz/entity/test/EntityCryptoTestSuite.java
>      ofbiz/trunk/framework/entity/src/org/ofbiz/entity/util/EntityCrypto.java
>      ofbiz/trunk/framework/entityext/build.xml
>      ofbiz/trunk/framework/entityext/servicedef/services.xml
>      ofbiz/trunk/framework/entityext/src/org/ofbiz/entityext/data/EntityDataServices.java
>
> Modified: ofbiz/trunk/LICENSE
> URL: http://svn.apache.org/viewvc/ofbiz/trunk/LICENSE?rev=1684608&r1=1684607&r2=1684608&view=diff
> ==============================================================================
> --- ofbiz/trunk/LICENSE (original)
> +++ ofbiz/trunk/LICENSE Wed Jun 10 09:01:30 2015
> @@ -38,6 +38,7 @@ framework/base/lib/log4j-slf4j-impl-2.3.
>   framework/base/lib/nekohtml-1.9.16.jar
>   framework/base/lib/resolver-2.9.1.jar
>   framework/base/lib/serializer-2.9.1.jar
> +framework/base/lib/shiro-core-1.2.3.jar
>   framework/base/lib/ws-commons-java5-1.0.1.jar
>   framework/base/lib/ws-commons-util-1.0.2.jar
>   framework/base/lib/xercesImpl-2.9.1.jar
>
> Modified: ofbiz/trunk/build.xml
> URL: http://svn.apache.org/viewvc/ofbiz/trunk/build.xml?rev=1684608&r1=1684607&r2=1684608&view=diff
> ==============================================================================
> --- ofbiz/trunk/build.xml (original)
> +++ ofbiz/trunk/build.xml Wed Jun 10 09:01:30 2015
> @@ -1536,6 +1536,8 @@ under the License.
>               <classpath>
>                   <path location="framework/base/build/lib/ofbiz-base.jar"/>
>                   <path location="framework/base/lib/commons/commons-codec-1.10.jar"/>
> +                <path location="framework/base/lib/shiro-core-1.2.3.jar"/>
> +                <path location="framework/base/lib/slf4j-api-1.6.4.jar"/>
>               </classpath>
>           </java>
>       </target>
>
> Added: ofbiz/trunk/framework/base/lib/shiro-core-1.2.3.jar
> URL: http://svn.apache.org/viewvc/ofbiz/trunk/framework/base/lib/shiro-core-1.2.3.jar?rev=1684608&view=auto
> ==============================================================================
> Binary file - no diff available.
>
> Propchange: ofbiz/trunk/framework/base/lib/shiro-core-1.2.3.jar
> ------------------------------------------------------------------------------
>      svn:mime-type = application/octet-stream
>
> Modified: ofbiz/trunk/framework/base/src/org/ofbiz/base/crypto/DesCrypt.java
> URL: http://svn.apache.org/viewvc/ofbiz/trunk/framework/base/src/org/ofbiz/base/crypto/DesCrypt.java?rev=1684608&r1=1684607&r2=1684608&view=diff
> ==============================================================================
> --- ofbiz/trunk/framework/base/src/org/ofbiz/base/crypto/DesCrypt.java (original)
> +++ ofbiz/trunk/framework/base/src/org/ofbiz/base/crypto/DesCrypt.java Wed Jun 10 09:01:30 2015
> @@ -21,11 +21,11 @@ package org.ofbiz.base.crypto;
>   import java.security.NoSuchAlgorithmException;
>   import java.security.InvalidKeyException;
>   import java.security.InvalidAlgorithmParameterException;
> +import java.security.Key;
>   import java.security.spec.InvalidKeySpecException;
>   import javax.crypto.Cipher;
>   import javax.crypto.IllegalBlockSizeException;
>   import javax.crypto.BadPaddingException;
> -import javax.crypto.SecretKey;
>   import javax.crypto.NoSuchPaddingException;
>   import javax.crypto.KeyGenerator;
>   import javax.crypto.SecretKeyFactory;
> @@ -42,14 +42,14 @@ public class DesCrypt {
>   
>       public static final String module = DesCrypt.class.getName();
>   
> -    public static SecretKey generateKey() throws NoSuchAlgorithmException {
> +    public static Key generateKey() throws NoSuchAlgorithmException {
>           KeyGenerator keyGen = KeyGenerator.getInstance("DESede");
>   
>           // generate the DES3 key
>           return keyGen.generateKey();
>       }
>   
> -    public static byte[] encrypt(SecretKey key, byte[] bytes) throws GeneralException {
> +    public static byte[] encrypt(Key key, byte[] bytes) throws GeneralException {
>           Cipher cipher = DesCrypt.getCipher(key, Cipher.ENCRYPT_MODE);
>           byte[] encBytes = null;
>           try {
> @@ -64,7 +64,7 @@ public class DesCrypt {
>           return encBytes;
>       }
>   
> -    public static byte[] decrypt(SecretKey key, byte[] bytes) throws GeneralException {
> +    public static byte[] decrypt(Key key, byte[] bytes) throws GeneralException {
>           Cipher cipher = DesCrypt.getCipher(key, Cipher.DECRYPT_MODE);
>           byte[] decBytes = null;
>           try {
> @@ -79,7 +79,7 @@ public class DesCrypt {
>           return decBytes;
>       }
>   
> -    public static SecretKey getDesKey(byte[] rawKey) throws GeneralException {
> +    public static Key getDesKey(byte[] rawKey) throws GeneralException {
>           SecretKeyFactory skf = null;
>           try {
>               skf = SecretKeyFactory.getInstance("DESede");
> @@ -97,7 +97,7 @@ public class DesCrypt {
>               }
>   
>               // create the SecretKey Object
> -            SecretKey key = null;
> +            Key key = null;
>               try {
>                   key = skf.generateSecret(desedeSpec1);
>               } catch (InvalidKeySpecException e) {
> @@ -110,7 +110,7 @@ public class DesCrypt {
>       }
>   
>       // return a cipher for a key - DESede/CBC/PKCS5Padding IV = 0
> -    protected static Cipher getCipher(SecretKey key, int mode) throws GeneralException {
> +    protected static Cipher getCipher(Key key, int mode) throws GeneralException {
>           byte[] zeros = { 0, 0, 0, 0, 0, 0, 0, 0 };
>           IvParameterSpec iv = new IvParameterSpec(zeros);
>   
>
> Modified: ofbiz/trunk/framework/base/src/org/ofbiz/base/crypto/Main.java
> URL: http://svn.apache.org/viewvc/ofbiz/trunk/framework/base/src/org/ofbiz/base/crypto/Main.java?rev=1684608&r1=1684607&r2=1684608&view=diff
> ==============================================================================
> --- ofbiz/trunk/framework/base/src/org/ofbiz/base/crypto/Main.java (original)
> +++ ofbiz/trunk/framework/base/src/org/ofbiz/base/crypto/Main.java Wed Jun 10 09:01:30 2015
> @@ -19,6 +19,7 @@
>   package org.ofbiz.base.crypto;
>   
>   import org.apache.commons.codec.binary.Base64;
> +import org.apache.shiro.crypto.AesCipherService;
>   
>   public class Main {
>       public static void main(String[] args) throws Exception {
> @@ -29,6 +30,9 @@ public class Main {
>               String digest = HashCrypt.getDigestHash(args[1]);
>               System.out.println(digest);
>           } else if (args[0].equals("-kek")) {
> +            AesCipherService cs = new AesCipherService();
> +            System.out.println(Base64.encodeBase64String(cs.generateNewKey().getEncoded()));
> +        } else if (args[0].equals("-kek-old")) {
>               System.out.println(Base64.encodeBase64String(DesCrypt.generateKey().getEncoded()));
>           }
>       }
>
> Modified: ofbiz/trunk/framework/entity/src/org/ofbiz/entity/Delegator.java
> URL: http://svn.apache.org/viewvc/ofbiz/trunk/framework/entity/src/org/ofbiz/entity/Delegator.java?rev=1684608&r1=1684607&r2=1684608&view=diff
> ==============================================================================
> --- ofbiz/trunk/framework/entity/src/org/ofbiz/entity/Delegator.java (original)
> +++ ofbiz/trunk/framework/entity/src/org/ofbiz/entity/Delegator.java Wed Jun 10 09:01:30 2015
> @@ -269,8 +269,11 @@ public interface Delegator {
>       @Deprecated
>       void encryptFields(List<? extends GenericEntity> entities) throws GenericEntityException;
>   
> +    @Deprecated
>       Object decryptFieldValue(String entityName, String encValue) throws EntityCryptoException;
>   
> +    Object decryptFieldValue(String entityName, ModelField.EncryptMethod encryptMethod, String encValue) throws EntityCryptoException;
> +
>       @Deprecated
>       Object encryptFieldValue(String entityName, Object fieldValue) throws EntityCryptoException;
>   
>
> Modified: ofbiz/trunk/framework/entity/src/org/ofbiz/entity/GenericDelegator.java
> URL: http://svn.apache.org/viewvc/ofbiz/trunk/framework/entity/src/org/ofbiz/entity/GenericDelegator.java?rev=1684608&r1=1684607&r2=1684608&view=diff
> ==============================================================================
> --- ofbiz/trunk/framework/entity/src/org/ofbiz/entity/GenericDelegator.java (original)
> +++ ofbiz/trunk/framework/entity/src/org/ofbiz/entity/GenericDelegator.java Wed Jun 10 09:01:30 2015
> @@ -2070,6 +2070,9 @@ public class GenericDelegator implements
>           if (dcc != null) {
>               dcc.clearAllCaches();
>           }
> +        if (this.crypto != null) {
> +            this.crypto.clearKeyCache();
> +        }
>       }
>   
>       /* (non-Javadoc)
> @@ -2677,13 +2680,22 @@ public class GenericDelegator implements
>           return fieldValue;
>       }
>   
> +    @Override
> +    @Deprecated
> +    public Object decryptFieldValue(String entityName, String encValue) throws EntityCryptoException {
> +        if (UtilValidate.isNotEmpty(encValue)) {
> +            return this.crypto.decrypt(entityName, ModelField.EncryptMethod.TRUE, encValue);
> +        }
> +        return null;
> +    }
> +
>       /* (non-Javadoc)
>        * @see org.ofbiz.entity.Delegator#encryptFieldValue(java.lang.String, java.lang.Object)
>        */
>       @Override
> -    public Object decryptFieldValue(String entityName, String encValue) throws EntityCryptoException {
> +    public Object decryptFieldValue(String entityName, ModelField.EncryptMethod encryptMethod, String encValue) throws EntityCryptoException {
>           if (UtilValidate.isNotEmpty(encValue)) {
> -            return this.crypto.decrypt(entityName, encValue);
> +            return this.crypto.decrypt(entityName, encryptMethod, encValue);
>           }
>           return null;
>       }
>
> Modified: ofbiz/trunk/framework/entity/src/org/ofbiz/entity/jdbc/SqlJdbcUtil.java
> URL: http://svn.apache.org/viewvc/ofbiz/trunk/framework/entity/src/org/ofbiz/entity/jdbc/SqlJdbcUtil.java?rev=1684608&r1=1684607&r2=1684608&view=diff
> ==============================================================================
> --- ofbiz/trunk/framework/entity/src/org/ofbiz/entity/jdbc/SqlJdbcUtil.java (original)
> +++ ofbiz/trunk/framework/entity/src/org/ofbiz/entity/jdbc/SqlJdbcUtil.java Wed Jun 10 09:01:30 2015
> @@ -540,7 +540,7 @@ public class SqlJdbcUtil {
>               try {
>                   Object jdbcValue = handler.getValue(rs, ind);
>                   if (jdbcValue instanceof String && curField.getEncryptMethod().isEncrypted()) {
> -                    jdbcValue = entity.getDelegator().decryptFieldValue(encryptionKeyName, (String) jdbcValue);
> +                    jdbcValue = entity.getDelegator().decryptFieldValue(encryptionKeyName, curField.getEncryptMethod(), (String) jdbcValue);
>                   }
>                   entity.dangerousSetNoCheckButFast(curField, jdbcValue);
>                   return;
> @@ -597,7 +597,7 @@ public class SqlJdbcUtil {
>                       } else {
>                           String value = rs.getString(ind);
>                           if (value instanceof String && curField.getEncryptMethod().isEncrypted()) {
> -                            value = (String) entity.getDelegator().decryptFieldValue(encryptionKeyName, value);
> +                            value = (String) entity.getDelegator().decryptFieldValue(encryptionKeyName, curField.getEncryptMethod(), value);
>                           }
>                           entity.dangerousSetNoCheckButFast(curField, value);
>                       }
>
> Modified: ofbiz/trunk/framework/entity/src/org/ofbiz/entity/test/EntityCryptoTestSuite.java
> URL: http://svn.apache.org/viewvc/ofbiz/trunk/framework/entity/src/org/ofbiz/entity/test/EntityCryptoTestSuite.java?rev=1684608&r1=1684607&r2=1684608&view=diff
> ==============================================================================
> --- ofbiz/trunk/framework/entity/src/org/ofbiz/entity/test/EntityCryptoTestSuite.java (original)
> +++ ofbiz/trunk/framework/entity/src/org/ofbiz/entity/test/EntityCryptoTestSuite.java Wed Jun 10 09:01:30 2015
> @@ -33,6 +33,26 @@ public class EntityCryptoTestSuite exten
>           super(name);
>       }
>   
> +    public void testCrypto() throws Exception {
> +        String nanoTime = "" + System.nanoTime();
> +        delegator.removeByAnd("TestingCrypto", UtilMisc.toMap("testingCryptoTypeId", "BASIC"));
> +        delegator.create("TestingCrypto", UtilMisc.toMap("testingCryptoId", "1", "testingCryptoTypeId", "BASIC"));
> +        GenericValue entity = EntityQuery.use(delegator).from("TestingCrypto").where("testingCryptoId", "1").queryOne();
> +        assertNull(entity.getString("unencryptedValue"));
> +        assertNull(entity.getString("encryptedValue"));
> +        entity.setString("unencryptedValue", nanoTime);
> +        entity.setString("encryptedValue", nanoTime);
> +        entity.setString("saltedEncryptedValue", nanoTime);
> +        assertEquals(nanoTime, entity.getString("unencryptedValue"));
> +        assertEquals(nanoTime, entity.getString("encryptedValue"));
> +        assertEquals(nanoTime, entity.getString("saltedEncryptedValue"));
> +        entity.store();
> +        entity.refresh();
> +        assertEquals(nanoTime, entity.getString("unencryptedValue"));
> +        assertEquals(nanoTime, entity.getString("encryptedValue"));
> +        assertEquals(nanoTime, entity.getString("saltedEncryptedValue"));
> +    }
> +
>       public void testCryptoEncryption() throws Exception {
>           // clear out all values
>           delegator.removeByAnd("TestingCrypto", UtilMisc.toMap("testingCryptoTypeId", "BASIC"));
>
> Modified: ofbiz/trunk/framework/entity/src/org/ofbiz/entity/util/EntityCrypto.java
> URL: http://svn.apache.org/viewvc/ofbiz/trunk/framework/entity/src/org/ofbiz/entity/util/EntityCrypto.java?rev=1684608&r1=1684607&r2=1684608&view=diff
> ==============================================================================
> --- ofbiz/trunk/framework/entity/src/org/ofbiz/entity/util/EntityCrypto.java (original)
> +++ ofbiz/trunk/framework/entity/src/org/ofbiz/entity/util/EntityCrypto.java Wed Jun 10 09:01:30 2015
> @@ -25,9 +25,14 @@ import java.util.concurrent.Callable;
>   import java.util.concurrent.ConcurrentHashMap;
>   import java.util.concurrent.ConcurrentMap;
>   
> -import javax.crypto.SecretKey;
> +import java.security.Key;
>   
>   import org.apache.commons.codec.binary.Base64;
> +import org.apache.shiro.crypto.AesCipherService;
> +import org.apache.shiro.crypto.OperationMode;
> +import org.apache.shiro.crypto.hash.HashRequest;
> +import org.apache.shiro.crypto.hash.HashService;
> +import org.apache.shiro.crypto.hash.DefaultHashService;
>   import org.ofbiz.base.crypto.DesCrypt;
>   import org.ofbiz.base.crypto.HashCrypt;
>   import org.ofbiz.base.util.Debug;
> @@ -47,24 +52,25 @@ public final class EntityCrypto {
>       public static final String module = EntityCrypto.class.getName();
>   
>       protected final Delegator delegator;
> -    protected final ConcurrentMap<String, SecretKey> keyMap = new ConcurrentHashMap<String, SecretKey>();
> +    protected final ConcurrentMap<String, byte[]> keyMap = new ConcurrentHashMap<String, byte[]>();
>       protected final StorageHandler[] handlers;
>   
>       public EntityCrypto(Delegator delegator, String kekText) throws EntityCryptoException {
>           this.delegator = delegator;
> -        SecretKey kek;
> -        try {
> -            kek = UtilValidate.isNotEmpty(kekText) ? DesCrypt.getDesKey(Base64.decodeBase64(kekText)) : null;
> -        } catch (GeneralException e) {
> -            throw new EntityCryptoException(e);
> -        }
> +        byte[] kek;
> +        kek = UtilValidate.isNotEmpty(kekText) ? Base64.decodeBase64(kekText) : null;
>           handlers = new StorageHandler[] {
> +            new ShiroStorageHandler(kek),
>               new SaltedBase64StorageHandler(kek),
>               NormalHashStorageHandler,
>               OldFunnyHashStorageHandler,
>           };
>       }
>   
> +    public void clearKeyCache() {
> +        keyMap.clear();
> +    }
> +
>       /** Encrypts an Object into an encrypted hex encoded String */
>       @Deprecated
>       public String encrypt(String keyName, Object obj) throws EntityCryptoException {
> @@ -74,11 +80,11 @@ public final class EntityCrypto {
>       /** Encrypts an Object into an encrypted hex encoded String */
>       public String encrypt(String keyName, EncryptMethod encryptMethod, Object obj) throws EntityCryptoException {
>           try {
> -            SecretKey key = this.findKey(keyName, handlers[0]);
> +            byte[] key = this.findKey(keyName, handlers[0]);
>               if (key == null) {
>                   EntityCryptoException caught = null;
>                   try {
> -                    this.createKey(keyName, handlers[0]);
> +                    this.createKey(keyName, handlers[0], encryptMethod);
>                   } catch (EntityCryptoException e) {
>                       // either a database read error, or a duplicate key insert
>                       // if the latter, try to fetch the value created by the
> @@ -89,7 +95,7 @@ public final class EntityCrypto {
>                           key = this.findKey(keyName, handlers[0]);
>                       } catch (EntityCryptoException e) {
>                           // this is bad, couldn't lookup the value, some bad juju
> -                        // is occuring; rethrow the original exception if available
> +                        // is occurring; rethrow the original exception if available
>                           throw caught != null ? caught : e;
>                       }
>                       if (key == null) {
> @@ -115,15 +121,15 @@ public final class EntityCrypto {
>       */
>   
>       /** Decrypts a hex encoded String into an Object */
> -    public Object decrypt(String keyName, String encryptedString) throws EntityCryptoException {
> +    public Object decrypt(String keyName, EncryptMethod encryptMethod, String encryptedString) throws EntityCryptoException {
>           try {
> -            return doDecrypt(keyName, encryptedString, handlers[0]);
> +            return doDecrypt(keyName, encryptMethod, encryptedString, handlers[0]);
>           } catch (GeneralException e) {
>               Debug.logInfo("Decrypt with DES key from standard key name hash failed, trying old/funny variety of key name hash", module);
>               for (int i = 1; i < handlers.length; i++) {
>                   try {
>                       // try using the old/bad hex encoding approach; this is another path the code may take, ie if there is an exception thrown in decrypt
> -                    return doDecrypt(keyName, encryptedString, handlers[i]);
> +                    return doDecrypt(keyName, encryptMethod, encryptedString, handlers[i]);
>                   } catch (GeneralException e1) {
>                       // NOTE: this throws the original exception back, not the new one if it fails using the other approach
>                       //throw new EntityCryptoException(e);
> @@ -133,12 +139,12 @@ public final class EntityCrypto {
>           }
>       }
>   
> -    protected Object doDecrypt(String keyName, String encryptedString, StorageHandler handler) throws GeneralException {
> -        SecretKey key = this.findKey(keyName, handler);
> +    protected Object doDecrypt(String keyName, EncryptMethod encryptMethod, String encryptedString, StorageHandler handler) throws GeneralException {
> +        byte[] key = this.findKey(keyName, handler);
>           if (key == null) {
>               throw new EntityCryptoException("key(" + keyName + ") not found in database");
>           }
> -        byte[] decryptedBytes = handler.decryptValue(key, encryptedString);
> +        byte[] decryptedBytes = handler.decryptValue(key, encryptMethod, encryptedString);
>           try {
>               return UtilObject.getObjectException(decryptedBytes);
>           } catch (ClassNotFoundException e) {
> @@ -148,7 +154,7 @@ public final class EntityCrypto {
>           }
>       }
>   
> -    protected SecretKey findKey(String originalKeyName, StorageHandler handler) throws EntityCryptoException {
> +    protected byte[] findKey(String originalKeyName, StorageHandler handler) throws EntityCryptoException {
>           String hashedKeyName = handler.getHashedKeyName(originalKeyName);
>           String keyMapName = handler.getKeyMapPrefix(hashedKeyName) + hashedKeyName;
>           if (keyMap.containsKey(keyMapName)) {
> @@ -170,8 +176,7 @@ public final class EntityCrypto {
>           }
>           try {
>               byte[] keyBytes = handler.decodeKeyBytes(keyValue.getString("keyText"));
> -            SecretKey key = DesCrypt.getDesKey(keyBytes);
> -            keyMap.putIfAbsent(keyMapName, key);
> +            keyMap.putIfAbsent(keyMapName, keyBytes);
>               // Do not remove the next line, it's there to handle the
>               // case of multiple threads trying to find the same key
>               // both threads will do the findOne call, only one will
> @@ -183,17 +188,12 @@ public final class EntityCrypto {
>           }
>       }
>   
> -    protected void createKey(String originalKeyName, StorageHandler handler) throws EntityCryptoException {
> +    protected void createKey(String originalKeyName, StorageHandler handler, EncryptMethod encryptMethod) throws EntityCryptoException {
>           String hashedKeyName = handler.getHashedKeyName(originalKeyName);
> -        SecretKey key = null;
> -        try {
> -            key = DesCrypt.generateKey();
> -        } catch (NoSuchAlgorithmException e) {
> -            throw new EntityCryptoException(e);
> -        }
> +        Key key = handler.generateNewKey();
>           final GenericValue newValue = delegator.makeValue("EntityKeyStore");
>           try {
> -            newValue.set("keyText", handler.encodeKey(key));
> +            newValue.set("keyText", handler.encodeKey(key.getEncoded()));
>           } catch (GeneralException e) {
>               throw new EntityCryptoException(e);
>           }
> @@ -212,35 +212,115 @@ public final class EntityCrypto {
>       }
>   
>       protected abstract static class StorageHandler {
> +        protected abstract Key generateNewKey() throws EntityCryptoException;
> +
>           protected abstract String getHashedKeyName(String originalKeyName);
>           protected abstract String getKeyMapPrefix(String hashedKeyName);
>   
>           protected abstract byte[] decodeKeyBytes(String keyText) throws GeneralException;
> -        protected abstract String encodeKey(SecretKey key) throws GeneralException;
> +        protected abstract String encodeKey(byte[] key) throws GeneralException;
> +
> +        protected abstract byte[] decryptValue(byte[] key, EncryptMethod encryptMethod, String encryptedString) throws GeneralException;
> +        protected abstract String encryptValue(EncryptMethod encryptMethod, byte[] key, byte[] objBytes) throws GeneralException;
> +    }
> +
> +    protected static final class ShiroStorageHandler extends StorageHandler {
> +        private final HashService hashService;
> +        private final AesCipherService cipherService;
> +        private final AesCipherService saltedCipherService;
> +        private final byte[] kek;
> +
> +        protected ShiroStorageHandler(byte[] kek) {
> +            hashService = new DefaultHashService();
> +            cipherService = new AesCipherService();
> +            cipherService.setMode(OperationMode.ECB);
> +            saltedCipherService = new AesCipherService();
> +            this.kek = kek;
> +        }
> +
> +        @Override
> +        protected Key generateNewKey() {
> +            return saltedCipherService.generateNewKey();
> +        }
> +
> +        @Override
> +        protected String getHashedKeyName(String originalKeyName) {
> +            HashRequest hashRequest = new HashRequest.Builder().setSource(originalKeyName).build();
> +            return hashService.computeHash(hashRequest).toBase64();
> +        }
> +
> +        @Override
> +        protected String getKeyMapPrefix(String hashedKeyName) {
> +            return "{shiro}";
> +        }
> +
> +        @Override
> +        protected byte[] decodeKeyBytes(String keyText) throws GeneralException {
> +            byte[] keyBytes = Base64.decodeBase64(keyText);
> +            if (kek != null) {
> +                keyBytes = saltedCipherService.decrypt(keyBytes, kek).getBytes();
> +            }
> +            return keyBytes;
> +        }
>   
> -        protected abstract byte[] decryptValue(SecretKey key, String encryptedString) throws GeneralException;
> -        protected abstract String encryptValue(EncryptMethod encryptMethod, SecretKey key, byte[] objBytes) throws GeneralException;
> +        @Override
> +        protected String encodeKey(byte[] key) throws GeneralException {
> +            if (kek != null) {
> +                return saltedCipherService.encrypt(key, kek).toBase64();
> +            } else {
> +                return Base64.encodeBase64String(key);
> +            }
> +        }
> +
> +        @Override
> +        protected byte[] decryptValue(byte[] key, EncryptMethod encryptMethod, String encryptedString) throws GeneralException {
> +            switch (encryptMethod) {
> +                case SALT:
> +                    return saltedCipherService.decrypt(Base64.decodeBase64(encryptedString), key).getBytes();
> +                default:
> +                    return cipherService.decrypt(Base64.decodeBase64(encryptedString), key).getBytes();
> +            }
> +        }
> +
> +        @Override
> +        protected String encryptValue(EncryptMethod encryptMethod, byte[] key, byte[] objBytes) throws GeneralException {
> +            switch (encryptMethod) {
> +                case SALT:
> +                    return saltedCipherService.encrypt(objBytes, key).toBase64();
> +                default:
> +                    return cipherService.encrypt(objBytes, key).toBase64();
> +            }
> +        }
>       }
>   
>       protected static abstract class LegacyStorageHandler extends StorageHandler {
>           @Override
> +        protected Key generateNewKey() throws EntityCryptoException {
> +            try {
> +                return DesCrypt.generateKey();
> +            } catch (NoSuchAlgorithmException e) {
> +                throw new EntityCryptoException(e);
> +            }
> +        }
> +
> +        @Override
>           protected byte[] decodeKeyBytes(String keyText) throws GeneralException {
>               return StringUtil.fromHexString(keyText);
>           }
>   
>           @Override
> -        protected String encodeKey(SecretKey key) {
> -            return StringUtil.toHexString(key.getEncoded());
> +        protected String encodeKey(byte[] key) {
> +            return StringUtil.toHexString(key);
>           }
>   
>           @Override
> -        protected byte[] decryptValue(SecretKey key, String encryptedString) throws GeneralException {
> -            return DesCrypt.decrypt(key, StringUtil.fromHexString(encryptedString));
> +        protected byte[] decryptValue(byte[] key, EncryptMethod encryptMethod, String encryptedString) throws GeneralException {
> +            return DesCrypt.decrypt(DesCrypt.getDesKey(key), StringUtil.fromHexString(encryptedString));
>           }
>   
>           @Override
> -        protected String encryptValue(EncryptMethod encryptMethod, SecretKey key, byte[] objBytes) throws GeneralException {
> -            return StringUtil.toHexString(DesCrypt.encrypt(key, objBytes));
> +        protected String encryptValue(EncryptMethod encryptMethod, byte[] key, byte[] objBytes) throws GeneralException {
> +            return StringUtil.toHexString(DesCrypt.encrypt(DesCrypt.getDesKey(key), objBytes));
>           }
>       };
>   
> @@ -269,10 +349,27 @@ public final class EntityCrypto {
>       };
>   
>       protected static final class SaltedBase64StorageHandler extends StorageHandler {
> -        private final SecretKey kek;
> +        private final Key kek;
>   
> -        protected SaltedBase64StorageHandler(SecretKey kek) {
> -            this.kek = kek;
> +        protected SaltedBase64StorageHandler(byte[] kek) throws EntityCryptoException {
> +            Key key = null;
> +            if (kek != null) {
> +                try {
> +                    key = DesCrypt.getDesKey(kek);
> +                } catch (GeneralException e) {
> +                    Debug.logInfo("Invalid key-encryption-key specified for SaltedBase64StorageHandler; the key is probably valid for the newer ShiroStorageHandler", module);
> +                }
> +            }
> +            this.kek = key;
> +        }
> +
> +        @Override
> +        protected Key generateNewKey() throws EntityCryptoException {
> +            try {
> +                return DesCrypt.generateKey();
> +            } catch (NoSuchAlgorithmException e) {
> +                throw new EntityCryptoException(e);
> +            }
>           }
>   
>           @Override
> @@ -295,17 +392,16 @@ public final class EntityCrypto {
>           }
>   
>           @Override
> -        protected String encodeKey(SecretKey key) throws GeneralException {
> -            byte[] keyBytes = key.getEncoded();
> +        protected String encodeKey(byte[] key) throws GeneralException {
>               if (kek != null) {
> -                keyBytes = DesCrypt.encrypt(kek, keyBytes);
> +                key = DesCrypt.encrypt(kek, key);
>               }
> -            return Base64.encodeBase64String(keyBytes);
> +            return Base64.encodeBase64String(key);
>           }
>   
>           @Override
> -        protected byte[] decryptValue(SecretKey key, String encryptedString) throws GeneralException {
> -            byte[] allBytes = DesCrypt.decrypt(key, Base64.decodeBase64(encryptedString));
> +        protected byte[] decryptValue(byte[] key, EncryptMethod encryptMethod, String encryptedString) throws GeneralException {
> +            byte[] allBytes = DesCrypt.decrypt(DesCrypt.getDesKey(key), Base64.decodeBase64(encryptedString));
>               int length = allBytes[0];
>               byte[] objBytes = new byte[allBytes.length - 1 - length];
>               System.arraycopy(allBytes, 1 + length, objBytes, 0, objBytes.length);
> @@ -313,7 +409,7 @@ public final class EntityCrypto {
>           }
>   
>           @Override
> -        protected String encryptValue(EncryptMethod encryptMethod, SecretKey key, byte[] objBytes) throws GeneralException {
> +        protected String encryptValue(EncryptMethod encryptMethod, byte[] key, byte[] objBytes) throws GeneralException {
>               byte[] saltBytes;
>               switch (encryptMethod) {
>                   case SALT:
> @@ -330,7 +426,7 @@ public final class EntityCrypto {
>               allBytes[0] = (byte) saltBytes.length;
>               System.arraycopy(saltBytes, 0, allBytes, 1, saltBytes.length);
>               System.arraycopy(objBytes, 0, allBytes, 1 + saltBytes.length, objBytes.length);
> -            String result = Base64.encodeBase64String(DesCrypt.encrypt(key, allBytes));
> +            String result = Base64.encodeBase64String(DesCrypt.encrypt(DesCrypt.getDesKey(key), allBytes));
>               return result;
>           }
>       };
>
> Modified: ofbiz/trunk/framework/entityext/build.xml
> URL: http://svn.apache.org/viewvc/ofbiz/trunk/framework/entityext/build.xml?rev=1684608&r1=1684607&r2=1684608&view=diff
> ==============================================================================
> --- ofbiz/trunk/framework/entityext/build.xml (original)
> +++ ofbiz/trunk/framework/entityext/build.xml Wed Jun 10 09:01:30 2015
> @@ -31,6 +31,7 @@ under the License.
>   
>       <path id="local.class.path">
>           <fileset dir="../base/lib" includes="*.jar"/>
> +        <fileset dir="../base/lib/commons" includes="*.jar"/>
>           <fileset dir="../base/lib/j2eespecs" includes="*.jar"/>
>           <fileset dir="../base/build/lib" includes="*.jar"/>
>           <fileset dir="../entity/lib" includes="*.jar"/>
>
> Modified: ofbiz/trunk/framework/entityext/servicedef/services.xml
> URL: http://svn.apache.org/viewvc/ofbiz/trunk/framework/entityext/servicedef/services.xml?rev=1684608&r1=1684607&r2=1684608&view=diff
> ==============================================================================
> --- ofbiz/trunk/framework/entityext/servicedef/services.xml (original)
> +++ ofbiz/trunk/framework/entityext/servicedef/services.xml Wed Jun 10 09:01:30 2015
> @@ -153,6 +153,19 @@ under the License.
>           <attribute name="fieldName" type="String" mode="IN" optional="false"/>
>       </service>
>   
> +    <service name="reencryptPrivateKeys" engine="java" auth="true" transaction-timeout="14400"
> +        location="org.ofbiz.entityext.data.EntityDataServices" invoke="reencryptPrivateKeys">
> +        <description>Re-encrypt the private keys, encrypted in EntityKeyStore with oldKey, using the newKey.</description>
> +        <attribute name="oldKey" type="String" mode="IN" optional="true"/>
> +        <attribute name="newKey" type="String" mode="IN" optional="true"/>
> +    </service>
> +
> +    <service name="reencryptFields" engine="java" auth="true" transaction-timeout="14400"
> +            location="org.ofbiz.entityext.data.EntityDataServices" invoke="reencryptFields">
> +        <description>Re-encrypt all the encrypted fields in the data model.</description>
> +        <attribute name="groupName" type="String" mode="IN" optional="true" default-value="org.ofbiz"/>
> +    </service>
> +
>       <!-- EntitySync Services -->
>       <service name="createEntitySync" default-entity-name="EntitySync" engine="simple"
>               location="component://entityext/script/org/ofbiz/entityext/synchronization/EntitySyncServices.xml" invoke="createEntitySync" auth="true">
>
> Modified: ofbiz/trunk/framework/entityext/src/org/ofbiz/entityext/data/EntityDataServices.java
> URL: http://svn.apache.org/viewvc/ofbiz/trunk/framework/entityext/src/org/ofbiz/entityext/data/EntityDataServices.java?rev=1684608&r1=1684607&r2=1684608&view=diff
> ==============================================================================
> --- ofbiz/trunk/framework/entityext/src/org/ofbiz/entityext/data/EntityDataServices.java (original)
> +++ ofbiz/trunk/framework/entityext/src/org/ofbiz/entityext/data/EntityDataServices.java Wed Jun 10 09:01:30 2015
> @@ -31,6 +31,9 @@ import java.util.List;
>   import java.util.Locale;
>   import java.util.Map;
>   
> +import org.apache.commons.codec.binary.Base64;
> +import org.apache.shiro.crypto.AesCipherService;
> +import org.ofbiz.base.crypto.DesCrypt;
>   import org.ofbiz.base.util.Debug;
>   import org.ofbiz.base.util.FileUtil;
>   import org.ofbiz.base.util.GeneralException;
> @@ -44,6 +47,7 @@ import org.ofbiz.entity.GenericValue;
>   import org.ofbiz.entity.datasource.GenericHelperInfo;
>   import org.ofbiz.entity.jdbc.DatabaseUtil;
>   import org.ofbiz.entity.model.ModelEntity;
> +import org.ofbiz.entity.model.ModelField;
>   import org.ofbiz.entity.util.EntityListIterator;
>   import org.ofbiz.entity.util.EntityQuery;
>   import org.ofbiz.security.Security;
> @@ -445,4 +449,95 @@ public class EntityDataServices {
>   
>           return ServiceUtil.returnSuccess();
>       }
> +
> +    public static Map<String, Object> reencryptPrivateKeys(DispatchContext dctx, Map<String, Object> context) {
> +        Delegator delegator = dctx.getDelegator();
> +        Security security = dctx.getSecurity();
> +        Locale locale = (Locale) context.get("locale");
> +
> +        // check permission
> +        GenericValue userLogin = (GenericValue) context.get("userLogin");
> +        if (!security.hasPermission("ENTITY_MAINT", userLogin)) {
> +            return ServiceUtil.returnError(UtilProperties.getMessage(resource, "EntityExtServicePermissionNotGranted", locale));
> +        }
> +        String oldKey = (String) context.get("oldKey");
> +        String newKey = (String) context.get("newKey");
> +        AesCipherService cipherService = new AesCipherService();
> +        try {
> +            List<GenericValue> rows = EntityQuery.use(delegator).from("EntityKeyStore").queryList();
> +            for (GenericValue row: rows) {
> +                byte[] keyBytes = Base64.decodeBase64(row.getString("keyText"));
> +                Debug.logInfo("Processing entry " + row.getString("keyName") + " with key: " + row.getString("keyText"), module);
> +                if (oldKey != null) {
> +                    Debug.logInfo("Decrypting with old key: " + oldKey, module);
> +                    try {
> +                        keyBytes = cipherService.decrypt(keyBytes, Base64.decodeBase64(oldKey)).getBytes();
> +                    } catch(Exception e) {
> +                        Debug.logInfo("Failed to decrypt with Shiro cipher; trying with old cipher", module);
> +                        try {
> +                            keyBytes = DesCrypt.decrypt(DesCrypt.getDesKey(Base64.decodeBase64(oldKey)), keyBytes);
> +                        } catch(Exception e1) {
> +                            Debug.logError(e1, module);
> +                            return ServiceUtil.returnError(e1.getMessage());
> +                        }
> +                    }
> +                }
> +                String newKeyText;
> +                if (newKey != null) {
> +                    Debug.logInfo("Encrypting with new key: " + oldKey, module);
> +                    newKeyText = cipherService.encrypt(keyBytes, Base64.decodeBase64(newKey)).toBase64();
> +                } else {
> +                    newKeyText = Base64.encodeBase64String(keyBytes);
> +                }
> +                Debug.logInfo("Storing new encrypted value: " + newKeyText, module);
> +                row.setString("keyText", newKeyText);
> +                row.store();
> +            }
> +        } catch(GenericEntityException gee) {
> +            Debug.logError(gee, module);
> +            return ServiceUtil.returnError(gee.getMessage());
> +        }
> +        delegator.clearAllCaches();
> +        return ServiceUtil.returnSuccess();
> +    }
> +
> +    public static Map<String, Object> reencryptFields(DispatchContext dctx, Map<String, Object> context) {
> +        Delegator delegator = dctx.getDelegator();
> +        Security security = dctx.getSecurity();
> +        Locale locale = (Locale) context.get("locale");
> +
> +        // check permission
> +        GenericValue userLogin = (GenericValue) context.get("userLogin");
> +        if (!security.hasPermission("ENTITY_MAINT", userLogin)) {
> +            return ServiceUtil.returnError(UtilProperties.getMessage(resource, "EntityExtServicePermissionNotGranted", locale));
> +        }
> +
> +        String groupName = (String) context.get("groupName");
> +
> +        Map<String, ModelEntity> modelEntities;
> +        try {
> +            modelEntities = delegator.getModelEntityMapByGroup(groupName);
> +        } catch (GenericEntityException e) {
> +            Debug.logError(e, "Error getting list of entities in group: " + e.toString(), module);
> +            return ServiceUtil.returnError(UtilProperties.getMessage(resource, "EntityExtErrorGettingListOfEntityInGroup", UtilMisc.toMap("errorString", e.toString()), locale));
> +        }
> +
> +        for (ModelEntity modelEntity: modelEntities.values()) {
> +            List<ModelField> fields = modelEntity.getFieldsUnmodifiable();
> +            for (ModelField field: fields) {
> +                if (field.getEncryptMethod().isEncrypted()) {
> +                    try {
> +                        List<GenericValue> rows = EntityQuery.use(delegator).from(modelEntity.getEntityName()).select(field.getName()).queryList();
> +                        for (GenericValue row: rows) {
> +                            row.setString(field.getName(), row.getString(field.getName()));
> +                            row.store();
> +                        }
> +                    } catch(GenericEntityException gee) {
> +                        return ServiceUtil.returnError(gee.getMessage());
> +                    }
> +                }
> +            }
> +        }
> +        return ServiceUtil.returnSuccess();
> +    }
>   }
>
>
>


Re: svn commit: r1684608 - in /ofbiz/trunk: ./ framework/base/lib/ framework/base/src/org/ofbiz/base/crypto/ framework/entity/src/org/ofbiz/entity/ framework/entity/src/org/ofbiz/entity/jdbc/ framework/entity/src/org/ofbiz/entity/test/ framework/entity/src...

Posted by Pierre Smits <pi...@gmail.com>.
Kudos, Jacopo!

Best regards,

Pierre Smits

*ORRTIZ.COM <http://www.orrtiz.com>*
Services & Solutions for Cloud-
Based Manufacturing, Professional
Services and Retail & Trade
http://www.orrtiz.com

On Wed, Jun 10, 2015 at 12:26 PM, Jacopo Cappellato <
jacopo.cappellato@hotwaxsystems.com> wrote:

>
> On Jun 10, 2015, at 12:05 PM, Jacques Le Roux <
> jacques.le.roux@les7arts.com> wrote:
>
> > Hi Jacopo,
> >
> > Very happy about that, I don't have time to review in details yet, but
> I'm already impressed by the comment and a 1st cursory review :)
> >
> > Just a question, since I have no experience with Moqui code, is there a
> relation or ideas coming from there?
> >
> > Jacques
>
> Thank you Jacques! No, I didn't look at the Moqui implementation, this is
> an effort I did based on the code we have in OFBiz only.
>
> Jacopo
>
>
> >
> > Le 10/06/2015 11:01, jacopoc@apache.org a écrit :
> >> Author: jacopoc
> >> Date: Wed Jun 10 09:01:30 2015
> >> New Revision: 1684608
> >>
> >> URL: http://svn.apache.org/r1684608
> >> Log:
> >> New implementation of the two-way cryptographic services of OFBiz based
> on Apache Shiro:
> >> * two-way encryption is now delegated to Apache Shiro, with stronger
> initialization vectors
> >> * the mechanism is backward compatible
> >> * new tools to update the encryption of private keys, useful to upgrade
> older versions of OFBiz and most of all to replace old keys with new ones
> (this is critical to implement stronger security practices as requested by
> PCI)
> >> * unit tests
> >>
> >>
> >> Added:
> >>     ofbiz/trunk/framework/base/lib/shiro-core-1.2.3.jar   (with props)
> >> Modified:
> >>     ofbiz/trunk/LICENSE
> >>     ofbiz/trunk/build.xml
> >>     ofbiz/trunk/framework/base/src/org/ofbiz/base/crypto/DesCrypt.java
> >>     ofbiz/trunk/framework/base/src/org/ofbiz/base/crypto/Main.java
> >>     ofbiz/trunk/framework/entity/src/org/ofbiz/entity/Delegator.java
> >>
>  ofbiz/trunk/framework/entity/src/org/ofbiz/entity/GenericDelegator.java
> >>
>  ofbiz/trunk/framework/entity/src/org/ofbiz/entity/jdbc/SqlJdbcUtil.java
> >>
>  ofbiz/trunk/framework/entity/src/org/ofbiz/entity/test/EntityCryptoTestSuite.java
> >>
>  ofbiz/trunk/framework/entity/src/org/ofbiz/entity/util/EntityCrypto.java
> >>     ofbiz/trunk/framework/entityext/build.xml
> >>     ofbiz/trunk/framework/entityext/servicedef/services.xml
> >>
>  ofbiz/trunk/framework/entityext/src/org/ofbiz/entityext/data/EntityDataServices.java
> >>
> >> Modified: ofbiz/trunk/LICENSE
> >> URL:
> http://svn.apache.org/viewvc/ofbiz/trunk/LICENSE?rev=1684608&r1=1684607&r2=1684608&view=diff
> >>
> ==============================================================================
> >> --- ofbiz/trunk/LICENSE (original)
> >> +++ ofbiz/trunk/LICENSE Wed Jun 10 09:01:30 2015
> >> @@ -38,6 +38,7 @@ framework/base/lib/log4j-slf4j-impl-2.3.
> >>  framework/base/lib/nekohtml-1.9.16.jar
> >>  framework/base/lib/resolver-2.9.1.jar
> >>  framework/base/lib/serializer-2.9.1.jar
> >> +framework/base/lib/shiro-core-1.2.3.jar
> >>  framework/base/lib/ws-commons-java5-1.0.1.jar
> >>  framework/base/lib/ws-commons-util-1.0.2.jar
> >>  framework/base/lib/xercesImpl-2.9.1.jar
> >>
> >> Modified: ofbiz/trunk/build.xml
> >> URL:
> http://svn.apache.org/viewvc/ofbiz/trunk/build.xml?rev=1684608&r1=1684607&r2=1684608&view=diff
> >>
> ==============================================================================
> >> --- ofbiz/trunk/build.xml (original)
> >> +++ ofbiz/trunk/build.xml Wed Jun 10 09:01:30 2015
> >> @@ -1536,6 +1536,8 @@ under the License.
> >>              <classpath>
> >>                  <path
> location="framework/base/build/lib/ofbiz-base.jar"/>
> >>                  <path
> location="framework/base/lib/commons/commons-codec-1.10.jar"/>
> >> +                <path
> location="framework/base/lib/shiro-core-1.2.3.jar"/>
> >> +                <path
> location="framework/base/lib/slf4j-api-1.6.4.jar"/>
> >>              </classpath>
> >>          </java>
> >>      </target>
> >>
> >> Added: ofbiz/trunk/framework/base/lib/shiro-core-1.2.3.jar
> >> URL:
> http://svn.apache.org/viewvc/ofbiz/trunk/framework/base/lib/shiro-core-1.2.3.jar?rev=1684608&view=auto
> >>
> ==============================================================================
> >> Binary file - no diff available.
> >>
> >> Propchange: ofbiz/trunk/framework/base/lib/shiro-core-1.2.3.jar
> >>
> ------------------------------------------------------------------------------
> >>     svn:mime-type = application/octet-stream
> >>
> >> Modified:
> ofbiz/trunk/framework/base/src/org/ofbiz/base/crypto/DesCrypt.java
> >> URL:
> http://svn.apache.org/viewvc/ofbiz/trunk/framework/base/src/org/ofbiz/base/crypto/DesCrypt.java?rev=1684608&r1=1684607&r2=1684608&view=diff
> >>
> ==============================================================================
> >> --- ofbiz/trunk/framework/base/src/org/ofbiz/base/crypto/DesCrypt.java
> (original)
> >> +++ ofbiz/trunk/framework/base/src/org/ofbiz/base/crypto/DesCrypt.java
> Wed Jun 10 09:01:30 2015
> >> @@ -21,11 +21,11 @@ package org.ofbiz.base.crypto;
> >>  import java.security.NoSuchAlgorithmException;
> >>  import java.security.InvalidKeyException;
> >>  import java.security.InvalidAlgorithmParameterException;
> >> +import java.security.Key;
> >>  import java.security.spec.InvalidKeySpecException;
> >>  import javax.crypto.Cipher;
> >>  import javax.crypto.IllegalBlockSizeException;
> >>  import javax.crypto.BadPaddingException;
> >> -import javax.crypto.SecretKey;
> >>  import javax.crypto.NoSuchPaddingException;
> >>  import javax.crypto.KeyGenerator;
> >>  import javax.crypto.SecretKeyFactory;
> >> @@ -42,14 +42,14 @@ public class DesCrypt {
> >>        public static final String module = DesCrypt.class.getName();
> >>  -    public static SecretKey generateKey() throws
> NoSuchAlgorithmException {
> >> +    public static Key generateKey() throws NoSuchAlgorithmException {
> >>          KeyGenerator keyGen = KeyGenerator.getInstance("DESede");
> >>            // generate the DES3 key
> >>          return keyGen.generateKey();
> >>      }
> >>  -    public static byte[] encrypt(SecretKey key, byte[] bytes) throws
> GeneralException {
> >> +    public static byte[] encrypt(Key key, byte[] bytes) throws
> GeneralException {
> >>          Cipher cipher = DesCrypt.getCipher(key, Cipher.ENCRYPT_MODE);
> >>          byte[] encBytes = null;
> >>          try {
> >> @@ -64,7 +64,7 @@ public class DesCrypt {
> >>          return encBytes;
> >>      }
> >>  -    public static byte[] decrypt(SecretKey key, byte[] bytes) throws
> GeneralException {
> >> +    public static byte[] decrypt(Key key, byte[] bytes) throws
> GeneralException {
> >>          Cipher cipher = DesCrypt.getCipher(key, Cipher.DECRYPT_MODE);
> >>          byte[] decBytes = null;
> >>          try {
> >> @@ -79,7 +79,7 @@ public class DesCrypt {
> >>          return decBytes;
> >>      }
> >>  -    public static SecretKey getDesKey(byte[] rawKey) throws
> GeneralException {
> >> +    public static Key getDesKey(byte[] rawKey) throws GeneralException
> {
> >>          SecretKeyFactory skf = null;
> >>          try {
> >>              skf = SecretKeyFactory.getInstance("DESede");
> >> @@ -97,7 +97,7 @@ public class DesCrypt {
> >>              }
> >>                // create the SecretKey Object
> >> -            SecretKey key = null;
> >> +            Key key = null;
> >>              try {
> >>                  key = skf.generateSecret(desedeSpec1);
> >>              } catch (InvalidKeySpecException e) {
> >> @@ -110,7 +110,7 @@ public class DesCrypt {
> >>      }
> >>        // return a cipher for a key - DESede/CBC/PKCS5Padding IV = 0
> >> -    protected static Cipher getCipher(SecretKey key, int mode) throws
> GeneralException {
> >> +    protected static Cipher getCipher(Key key, int mode) throws
> GeneralException {
> >>          byte[] zeros = { 0, 0, 0, 0, 0, 0, 0, 0 };
> >>          IvParameterSpec iv = new IvParameterSpec(zeros);
> >>
> >> Modified: ofbiz/trunk/framework/base/src/org/ofbiz/base/crypto/Main.java
> >> URL:
> http://svn.apache.org/viewvc/ofbiz/trunk/framework/base/src/org/ofbiz/base/crypto/Main.java?rev=1684608&r1=1684607&r2=1684608&view=diff
> >>
> ==============================================================================
> >> --- ofbiz/trunk/framework/base/src/org/ofbiz/base/crypto/Main.java
> (original)
> >> +++ ofbiz/trunk/framework/base/src/org/ofbiz/base/crypto/Main.java Wed
> Jun 10 09:01:30 2015
> >> @@ -19,6 +19,7 @@
> >>  package org.ofbiz.base.crypto;
> >>    import org.apache.commons.codec.binary.Base64;
> >> +import org.apache.shiro.crypto.AesCipherService;
> >>    public class Main {
> >>      public static void main(String[] args) throws Exception {
> >> @@ -29,6 +30,9 @@ public class Main {
> >>              String digest = HashCrypt.getDigestHash(args[1]);
> >>              System.out.println(digest);
> >>          } else if (args[0].equals("-kek")) {
> >> +            AesCipherService cs = new AesCipherService();
> >> +
> System.out.println(Base64.encodeBase64String(cs.generateNewKey().getEncoded()));
> >> +        } else if (args[0].equals("-kek-old")) {
> >>
> System.out.println(Base64.encodeBase64String(DesCrypt.generateKey().getEncoded()));
> >>          }
> >>      }
> >>
> >> Modified:
> ofbiz/trunk/framework/entity/src/org/ofbiz/entity/Delegator.java
> >> URL:
> http://svn.apache.org/viewvc/ofbiz/trunk/framework/entity/src/org/ofbiz/entity/Delegator.java?rev=1684608&r1=1684607&r2=1684608&view=diff
> >>
> ==============================================================================
> >> --- ofbiz/trunk/framework/entity/src/org/ofbiz/entity/Delegator.java
> (original)
> >> +++ ofbiz/trunk/framework/entity/src/org/ofbiz/entity/Delegator.java
> Wed Jun 10 09:01:30 2015
> >> @@ -269,8 +269,11 @@ public interface Delegator {
> >>      @Deprecated
> >>      void encryptFields(List<? extends GenericEntity> entities) throws
> GenericEntityException;
> >>  +    @Deprecated
> >>      Object decryptFieldValue(String entityName, String encValue)
> throws EntityCryptoException;
> >>  +    Object decryptFieldValue(String entityName,
> ModelField.EncryptMethod encryptMethod, String encValue) throws
> EntityCryptoException;
> >> +
> >>      @Deprecated
> >>      Object encryptFieldValue(String entityName, Object fieldValue)
> throws EntityCryptoException;
> >>
> >> Modified:
> ofbiz/trunk/framework/entity/src/org/ofbiz/entity/GenericDelegator.java
> >> URL:
> http://svn.apache.org/viewvc/ofbiz/trunk/framework/entity/src/org/ofbiz/entity/GenericDelegator.java?rev=1684608&r1=1684607&r2=1684608&view=diff
> >>
> ==============================================================================
> >> ---
> ofbiz/trunk/framework/entity/src/org/ofbiz/entity/GenericDelegator.java
> (original)
> >> +++
> ofbiz/trunk/framework/entity/src/org/ofbiz/entity/GenericDelegator.java Wed
> Jun 10 09:01:30 2015
> >> @@ -2070,6 +2070,9 @@ public class GenericDelegator implements
> >>          if (dcc != null) {
> >>              dcc.clearAllCaches();
> >>          }
> >> +        if (this.crypto != null) {
> >> +            this.crypto.clearKeyCache();
> >> +        }
> >>      }
> >>        /* (non-Javadoc)
> >> @@ -2677,13 +2680,22 @@ public class GenericDelegator implements
> >>          return fieldValue;
> >>      }
> >>  +    @Override
> >> +    @Deprecated
> >> +    public Object decryptFieldValue(String entityName, String
> encValue) throws EntityCryptoException {
> >> +        if (UtilValidate.isNotEmpty(encValue)) {
> >> +            return this.crypto.decrypt(entityName,
> ModelField.EncryptMethod.TRUE, encValue);
> >> +        }
> >> +        return null;
> >> +    }
> >> +
> >>      /* (non-Javadoc)
> >>       * @see
> org.ofbiz.entity.Delegator#encryptFieldValue(java.lang.String,
> java.lang.Object)
> >>       */
> >>      @Override
> >> -    public Object decryptFieldValue(String entityName, String
> encValue) throws EntityCryptoException {
> >> +    public Object decryptFieldValue(String entityName,
> ModelField.EncryptMethod encryptMethod, String encValue) throws
> EntityCryptoException {
> >>          if (UtilValidate.isNotEmpty(encValue)) {
> >> -            return this.crypto.decrypt(entityName, encValue);
> >> +            return this.crypto.decrypt(entityName, encryptMethod,
> encValue);
> >>          }
> >>          return null;
> >>      }
> >>
> >> Modified:
> ofbiz/trunk/framework/entity/src/org/ofbiz/entity/jdbc/SqlJdbcUtil.java
> >> URL:
> http://svn.apache.org/viewvc/ofbiz/trunk/framework/entity/src/org/ofbiz/entity/jdbc/SqlJdbcUtil.java?rev=1684608&r1=1684607&r2=1684608&view=diff
> >>
> ==============================================================================
> >> ---
> ofbiz/trunk/framework/entity/src/org/ofbiz/entity/jdbc/SqlJdbcUtil.java
> (original)
> >> +++
> ofbiz/trunk/framework/entity/src/org/ofbiz/entity/jdbc/SqlJdbcUtil.java Wed
> Jun 10 09:01:30 2015
> >> @@ -540,7 +540,7 @@ public class SqlJdbcUtil {
> >>              try {
> >>                  Object jdbcValue = handler.getValue(rs, ind);
> >>                  if (jdbcValue instanceof String &&
> curField.getEncryptMethod().isEncrypted()) {
> >> -                    jdbcValue =
> entity.getDelegator().decryptFieldValue(encryptionKeyName, (String)
> jdbcValue);
> >> +                    jdbcValue =
> entity.getDelegator().decryptFieldValue(encryptionKeyName,
> curField.getEncryptMethod(), (String) jdbcValue);
> >>                  }
> >>                  entity.dangerousSetNoCheckButFast(curField, jdbcValue);
> >>                  return;
> >> @@ -597,7 +597,7 @@ public class SqlJdbcUtil {
> >>                      } else {
> >>                          String value = rs.getString(ind);
> >>                          if (value instanceof String &&
> curField.getEncryptMethod().isEncrypted()) {
> >> -                            value = (String)
> entity.getDelegator().decryptFieldValue(encryptionKeyName, value);
> >> +                            value = (String)
> entity.getDelegator().decryptFieldValue(encryptionKeyName,
> curField.getEncryptMethod(), value);
> >>                          }
> >>                          entity.dangerousSetNoCheckButFast(curField,
> value);
> >>                      }
> >>
> >> Modified:
> ofbiz/trunk/framework/entity/src/org/ofbiz/entity/test/EntityCryptoTestSuite.java
> >> URL:
> http://svn.apache.org/viewvc/ofbiz/trunk/framework/entity/src/org/ofbiz/entity/test/EntityCryptoTestSuite.java?rev=1684608&r1=1684607&r2=1684608&view=diff
> >>
> ==============================================================================
> >> ---
> ofbiz/trunk/framework/entity/src/org/ofbiz/entity/test/EntityCryptoTestSuite.java
> (original)
> >> +++
> ofbiz/trunk/framework/entity/src/org/ofbiz/entity/test/EntityCryptoTestSuite.java
> Wed Jun 10 09:01:30 2015
> >> @@ -33,6 +33,26 @@ public class EntityCryptoTestSuite exten
> >>          super(name);
> >>      }
> >>  +    public void testCrypto() throws Exception {
> >> +        String nanoTime = "" + System.nanoTime();
> >> +        delegator.removeByAnd("TestingCrypto",
> UtilMisc.toMap("testingCryptoTypeId", "BASIC"));
> >> +        delegator.create("TestingCrypto",
> UtilMisc.toMap("testingCryptoId", "1", "testingCryptoTypeId", "BASIC"));
> >> +        GenericValue entity =
> EntityQuery.use(delegator).from("TestingCrypto").where("testingCryptoId",
> "1").queryOne();
> >> +        assertNull(entity.getString("unencryptedValue"));
> >> +        assertNull(entity.getString("encryptedValue"));
> >> +        entity.setString("unencryptedValue", nanoTime);
> >> +        entity.setString("encryptedValue", nanoTime);
> >> +        entity.setString("saltedEncryptedValue", nanoTime);
> >> +        assertEquals(nanoTime, entity.getString("unencryptedValue"));
> >> +        assertEquals(nanoTime, entity.getString("encryptedValue"));
> >> +        assertEquals(nanoTime,
> entity.getString("saltedEncryptedValue"));
> >> +        entity.store();
> >> +        entity.refresh();
> >> +        assertEquals(nanoTime, entity.getString("unencryptedValue"));
> >> +        assertEquals(nanoTime, entity.getString("encryptedValue"));
> >> +        assertEquals(nanoTime,
> entity.getString("saltedEncryptedValue"));
> >> +    }
> >> +
> >>      public void testCryptoEncryption() throws Exception {
> >>          // clear out all values
> >>          delegator.removeByAnd("TestingCrypto",
> UtilMisc.toMap("testingCryptoTypeId", "BASIC"));
> >>
> >> Modified:
> ofbiz/trunk/framework/entity/src/org/ofbiz/entity/util/EntityCrypto.java
> >> URL:
> http://svn.apache.org/viewvc/ofbiz/trunk/framework/entity/src/org/ofbiz/entity/util/EntityCrypto.java?rev=1684608&r1=1684607&r2=1684608&view=diff
> >>
> ==============================================================================
> >> ---
> ofbiz/trunk/framework/entity/src/org/ofbiz/entity/util/EntityCrypto.java
> (original)
> >> +++
> ofbiz/trunk/framework/entity/src/org/ofbiz/entity/util/EntityCrypto.java
> Wed Jun 10 09:01:30 2015
> >> @@ -25,9 +25,14 @@ import java.util.concurrent.Callable;
> >>  import java.util.concurrent.ConcurrentHashMap;
> >>  import java.util.concurrent.ConcurrentMap;
> >>  -import javax.crypto.SecretKey;
> >> +import java.security.Key;
> >>    import org.apache.commons.codec.binary.Base64;
> >> +import org.apache.shiro.crypto.AesCipherService;
> >> +import org.apache.shiro.crypto.OperationMode;
> >> +import org.apache.shiro.crypto.hash.HashRequest;
> >> +import org.apache.shiro.crypto.hash.HashService;
> >> +import org.apache.shiro.crypto.hash.DefaultHashService;
> >>  import org.ofbiz.base.crypto.DesCrypt;
> >>  import org.ofbiz.base.crypto.HashCrypt;
> >>  import org.ofbiz.base.util.Debug;
> >> @@ -47,24 +52,25 @@ public final class EntityCrypto {
> >>      public static final String module = EntityCrypto.class.getName();
> >>        protected final Delegator delegator;
> >> -    protected final ConcurrentMap<String, SecretKey> keyMap = new
> ConcurrentHashMap<String, SecretKey>();
> >> +    protected final ConcurrentMap<String, byte[]> keyMap = new
> ConcurrentHashMap<String, byte[]>();
> >>      protected final StorageHandler[] handlers;
> >>        public EntityCrypto(Delegator delegator, String kekText) throws
> EntityCryptoException {
> >>          this.delegator = delegator;
> >> -        SecretKey kek;
> >> -        try {
> >> -            kek = UtilValidate.isNotEmpty(kekText) ?
> DesCrypt.getDesKey(Base64.decodeBase64(kekText)) : null;
> >> -        } catch (GeneralException e) {
> >> -            throw new EntityCryptoException(e);
> >> -        }
> >> +        byte[] kek;
> >> +        kek = UtilValidate.isNotEmpty(kekText) ?
> Base64.decodeBase64(kekText) : null;
> >>          handlers = new StorageHandler[] {
> >> +            new ShiroStorageHandler(kek),
> >>              new SaltedBase64StorageHandler(kek),
> >>              NormalHashStorageHandler,
> >>              OldFunnyHashStorageHandler,
> >>          };
> >>      }
> >>  +    public void clearKeyCache() {
> >> +        keyMap.clear();
> >> +    }
> >> +
> >>      /** Encrypts an Object into an encrypted hex encoded String */
> >>      @Deprecated
> >>      public String encrypt(String keyName, Object obj) throws
> EntityCryptoException {
> >> @@ -74,11 +80,11 @@ public final class EntityCrypto {
> >>      /** Encrypts an Object into an encrypted hex encoded String */
> >>      public String encrypt(String keyName, EncryptMethod encryptMethod,
> Object obj) throws EntityCryptoException {
> >>          try {
> >> -            SecretKey key = this.findKey(keyName, handlers[0]);
> >> +            byte[] key = this.findKey(keyName, handlers[0]);
> >>              if (key == null) {
> >>                  EntityCryptoException caught = null;
> >>                  try {
> >> -                    this.createKey(keyName, handlers[0]);
> >> +                    this.createKey(keyName, handlers[0],
> encryptMethod);
> >>                  } catch (EntityCryptoException e) {
> >>                      // either a database read error, or a duplicate
> key insert
> >>                      // if the latter, try to fetch the value created
> by the
> >> @@ -89,7 +95,7 @@ public final class EntityCrypto {
> >>                          key = this.findKey(keyName, handlers[0]);
> >>                      } catch (EntityCryptoException e) {
> >>                          // this is bad, couldn't lookup the value,
> some bad juju
> >> -                        // is occuring; rethrow the original exception
> if available
> >> +                        // is occurring; rethrow the original
> exception if available
> >>                          throw caught != null ? caught : e;
> >>                      }
> >>                      if (key == null) {
> >> @@ -115,15 +121,15 @@ public final class EntityCrypto {
> >>      */
> >>        /** Decrypts a hex encoded String into an Object */
> >> -    public Object decrypt(String keyName, String encryptedString)
> throws EntityCryptoException {
> >> +    public Object decrypt(String keyName, EncryptMethod encryptMethod,
> String encryptedString) throws EntityCryptoException {
> >>          try {
> >> -            return doDecrypt(keyName, encryptedString, handlers[0]);
> >> +            return doDecrypt(keyName, encryptMethod, encryptedString,
> handlers[0]);
> >>          } catch (GeneralException e) {
> >>              Debug.logInfo("Decrypt with DES key from standard key name
> hash failed, trying old/funny variety of key name hash", module);
> >>              for (int i = 1; i < handlers.length; i++) {
> >>                  try {
> >>                      // try using the old/bad hex encoding approach;
> this is another path the code may take, ie if there is an exception thrown
> in decrypt
> >> -                    return doDecrypt(keyName, encryptedString,
> handlers[i]);
> >> +                    return doDecrypt(keyName, encryptMethod,
> encryptedString, handlers[i]);
> >>                  } catch (GeneralException e1) {
> >>                      // NOTE: this throws the original exception back,
> not the new one if it fails using the other approach
> >>                      //throw new EntityCryptoException(e);
> >> @@ -133,12 +139,12 @@ public final class EntityCrypto {
> >>          }
> >>      }
> >>  -    protected Object doDecrypt(String keyName, String
> encryptedString, StorageHandler handler) throws GeneralException {
> >> -        SecretKey key = this.findKey(keyName, handler);
> >> +    protected Object doDecrypt(String keyName, EncryptMethod
> encryptMethod, String encryptedString, StorageHandler handler) throws
> GeneralException {
> >> +        byte[] key = this.findKey(keyName, handler);
> >>          if (key == null) {
> >>              throw new EntityCryptoException("key(" + keyName + ") not
> found in database");
> >>          }
> >> -        byte[] decryptedBytes = handler.decryptValue(key,
> encryptedString);
> >> +        byte[] decryptedBytes = handler.decryptValue(key,
> encryptMethod, encryptedString);
> >>          try {
> >>              return UtilObject.getObjectException(decryptedBytes);
> >>          } catch (ClassNotFoundException e) {
> >> @@ -148,7 +154,7 @@ public final class EntityCrypto {
> >>          }
> >>      }
> >>  -    protected SecretKey findKey(String originalKeyName,
> StorageHandler handler) throws EntityCryptoException {
> >> +    protected byte[] findKey(String originalKeyName, StorageHandler
> handler) throws EntityCryptoException {
> >>          String hashedKeyName =
> handler.getHashedKeyName(originalKeyName);
> >>          String keyMapName = handler.getKeyMapPrefix(hashedKeyName) +
> hashedKeyName;
> >>          if (keyMap.containsKey(keyMapName)) {
> >> @@ -170,8 +176,7 @@ public final class EntityCrypto {
> >>          }
> >>          try {
> >>              byte[] keyBytes =
> handler.decodeKeyBytes(keyValue.getString("keyText"));
> >> -            SecretKey key = DesCrypt.getDesKey(keyBytes);
> >> -            keyMap.putIfAbsent(keyMapName, key);
> >> +            keyMap.putIfAbsent(keyMapName, keyBytes);
> >>              // Do not remove the next line, it's there to handle the
> >>              // case of multiple threads trying to find the same key
> >>              // both threads will do the findOne call, only one will
> >> @@ -183,17 +188,12 @@ public final class EntityCrypto {
> >>          }
> >>      }
> >>  -    protected void createKey(String originalKeyName, StorageHandler
> handler) throws EntityCryptoException {
> >> +    protected void createKey(String originalKeyName, StorageHandler
> handler, EncryptMethod encryptMethod) throws EntityCryptoException {
> >>          String hashedKeyName =
> handler.getHashedKeyName(originalKeyName);
> >> -        SecretKey key = null;
> >> -        try {
> >> -            key = DesCrypt.generateKey();
> >> -        } catch (NoSuchAlgorithmException e) {
> >> -            throw new EntityCryptoException(e);
> >> -        }
> >> +        Key key = handler.generateNewKey();
> >>          final GenericValue newValue =
> delegator.makeValue("EntityKeyStore");
> >>          try {
> >> -            newValue.set("keyText", handler.encodeKey(key));
> >> +            newValue.set("keyText",
> handler.encodeKey(key.getEncoded()));
> >>          } catch (GeneralException e) {
> >>              throw new EntityCryptoException(e);
> >>          }
> >> @@ -212,35 +212,115 @@ public final class EntityCrypto {
> >>      }
> >>        protected abstract static class StorageHandler {
> >> +        protected abstract Key generateNewKey() throws
> EntityCryptoException;
> >> +
> >>          protected abstract String getHashedKeyName(String
> originalKeyName);
> >>          protected abstract String getKeyMapPrefix(String
> hashedKeyName);
> >>            protected abstract byte[] decodeKeyBytes(String keyText)
> throws GeneralException;
> >> -        protected abstract String encodeKey(SecretKey key) throws
> GeneralException;
> >> +        protected abstract String encodeKey(byte[] key) throws
> GeneralException;
> >> +
> >> +        protected abstract byte[] decryptValue(byte[] key,
> EncryptMethod encryptMethod, String encryptedString) throws
> GeneralException;
> >> +        protected abstract String encryptValue(EncryptMethod
> encryptMethod, byte[] key, byte[] objBytes) throws GeneralException;
> >> +    }
> >> +
> >> +    protected static final class ShiroStorageHandler extends
> StorageHandler {
> >> +        private final HashService hashService;
> >> +        private final AesCipherService cipherService;
> >> +        private final AesCipherService saltedCipherService;
> >> +        private final byte[] kek;
> >> +
> >> +        protected ShiroStorageHandler(byte[] kek) {
> >> +            hashService = new DefaultHashService();
> >> +            cipherService = new AesCipherService();
> >> +            cipherService.setMode(OperationMode.ECB);
> >> +            saltedCipherService = new AesCipherService();
> >> +            this.kek = kek;
> >> +        }
> >> +
> >> +        @Override
> >> +        protected Key generateNewKey() {
> >> +            return saltedCipherService.generateNewKey();
> >> +        }
> >> +
> >> +        @Override
> >> +        protected String getHashedKeyName(String originalKeyName) {
> >> +            HashRequest hashRequest = new
> HashRequest.Builder().setSource(originalKeyName).build();
> >> +            return hashService.computeHash(hashRequest).toBase64();
> >> +        }
> >> +
> >> +        @Override
> >> +        protected String getKeyMapPrefix(String hashedKeyName) {
> >> +            return "{shiro}";
> >> +        }
> >> +
> >> +        @Override
> >> +        protected byte[] decodeKeyBytes(String keyText) throws
> GeneralException {
> >> +            byte[] keyBytes = Base64.decodeBase64(keyText);
> >> +            if (kek != null) {
> >> +                keyBytes = saltedCipherService.decrypt(keyBytes,
> kek).getBytes();
> >> +            }
> >> +            return keyBytes;
> >> +        }
> >>  -        protected abstract byte[] decryptValue(SecretKey key, String
> encryptedString) throws GeneralException;
> >> -        protected abstract String encryptValue(EncryptMethod
> encryptMethod, SecretKey key, byte[] objBytes) throws GeneralException;
> >> +        @Override
> >> +        protected String encodeKey(byte[] key) throws GeneralException
> {
> >> +            if (kek != null) {
> >> +                return saltedCipherService.encrypt(key,
> kek).toBase64();
> >> +            } else {
> >> +                return Base64.encodeBase64String(key);
> >> +            }
> >> +        }
> >> +
> >> +        @Override
> >> +        protected byte[] decryptValue(byte[] key, EncryptMethod
> encryptMethod, String encryptedString) throws GeneralException {
> >> +            switch (encryptMethod) {
> >> +                case SALT:
> >> +                    return
> saltedCipherService.decrypt(Base64.decodeBase64(encryptedString),
> key).getBytes();
> >> +                default:
> >> +                    return
> cipherService.decrypt(Base64.decodeBase64(encryptedString), key).getBytes();
> >> +            }
> >> +        }
> >> +
> >> +        @Override
> >> +        protected String encryptValue(EncryptMethod encryptMethod,
> byte[] key, byte[] objBytes) throws GeneralException {
> >> +            switch (encryptMethod) {
> >> +                case SALT:
> >> +                    return saltedCipherService.encrypt(objBytes,
> key).toBase64();
> >> +                default:
> >> +                    return cipherService.encrypt(objBytes,
> key).toBase64();
> >> +            }
> >> +        }
> >>      }
> >>        protected static abstract class LegacyStorageHandler extends
> StorageHandler {
> >>          @Override
> >> +        protected Key generateNewKey() throws EntityCryptoException {
> >> +            try {
> >> +                return DesCrypt.generateKey();
> >> +            } catch (NoSuchAlgorithmException e) {
> >> +                throw new EntityCryptoException(e);
> >> +            }
> >> +        }
> >> +
> >> +        @Override
> >>          protected byte[] decodeKeyBytes(String keyText) throws
> GeneralException {
> >>              return StringUtil.fromHexString(keyText);
> >>          }
> >>            @Override
> >> -        protected String encodeKey(SecretKey key) {
> >> -            return StringUtil.toHexString(key.getEncoded());
> >> +        protected String encodeKey(byte[] key) {
> >> +            return StringUtil.toHexString(key);
> >>          }
> >>            @Override
> >> -        protected byte[] decryptValue(SecretKey key, String
> encryptedString) throws GeneralException {
> >> -            return DesCrypt.decrypt(key,
> StringUtil.fromHexString(encryptedString));
> >> +        protected byte[] decryptValue(byte[] key, EncryptMethod
> encryptMethod, String encryptedString) throws GeneralException {
> >> +            return DesCrypt.decrypt(DesCrypt.getDesKey(key),
> StringUtil.fromHexString(encryptedString));
> >>          }
> >>            @Override
> >> -        protected String encryptValue(EncryptMethod encryptMethod,
> SecretKey key, byte[] objBytes) throws GeneralException {
> >> -            return StringUtil.toHexString(DesCrypt.encrypt(key,
> objBytes));
> >> +        protected String encryptValue(EncryptMethod encryptMethod,
> byte[] key, byte[] objBytes) throws GeneralException {
> >> +            return
> StringUtil.toHexString(DesCrypt.encrypt(DesCrypt.getDesKey(key), objBytes));
> >>          }
> >>      };
> >>  @@ -269,10 +349,27 @@ public final class EntityCrypto {
> >>      };
> >>        protected static final class SaltedBase64StorageHandler extends
> StorageHandler {
> >> -        private final SecretKey kek;
> >> +        private final Key kek;
> >>  -        protected SaltedBase64StorageHandler(SecretKey kek) {
> >> -            this.kek = kek;
> >> +        protected SaltedBase64StorageHandler(byte[] kek) throws
> EntityCryptoException {
> >> +            Key key = null;
> >> +            if (kek != null) {
> >> +                try {
> >> +                    key = DesCrypt.getDesKey(kek);
> >> +                } catch (GeneralException e) {
> >> +                    Debug.logInfo("Invalid key-encryption-key
> specified for SaltedBase64StorageHandler; the key is probably valid for the
> newer ShiroStorageHandler", module);
> >> +                }
> >> +            }
> >> +            this.kek = key;
> >> +        }
> >> +
> >> +        @Override
> >> +        protected Key generateNewKey() throws EntityCryptoException {
> >> +            try {
> >> +                return DesCrypt.generateKey();
> >> +            } catch (NoSuchAlgorithmException e) {
> >> +                throw new EntityCryptoException(e);
> >> +            }
> >>          }
> >>            @Override
> >> @@ -295,17 +392,16 @@ public final class EntityCrypto {
> >>          }
> >>            @Override
> >> -        protected String encodeKey(SecretKey key) throws
> GeneralException {
> >> -            byte[] keyBytes = key.getEncoded();
> >> +        protected String encodeKey(byte[] key) throws GeneralException
> {
> >>              if (kek != null) {
> >> -                keyBytes = DesCrypt.encrypt(kek, keyBytes);
> >> +                key = DesCrypt.encrypt(kek, key);
> >>              }
> >> -            return Base64.encodeBase64String(keyBytes);
> >> +            return Base64.encodeBase64String(key);
> >>          }
> >>            @Override
> >> -        protected byte[] decryptValue(SecretKey key, String
> encryptedString) throws GeneralException {
> >> -            byte[] allBytes = DesCrypt.decrypt(key,
> Base64.decodeBase64(encryptedString));
> >> +        protected byte[] decryptValue(byte[] key, EncryptMethod
> encryptMethod, String encryptedString) throws GeneralException {
> >> +            byte[] allBytes =
> DesCrypt.decrypt(DesCrypt.getDesKey(key),
> Base64.decodeBase64(encryptedString));
> >>              int length = allBytes[0];
> >>              byte[] objBytes = new byte[allBytes.length - 1 - length];
> >>              System.arraycopy(allBytes, 1 + length, objBytes, 0,
> objBytes.length);
> >> @@ -313,7 +409,7 @@ public final class EntityCrypto {
> >>          }
> >>            @Override
> >> -        protected String encryptValue(EncryptMethod encryptMethod,
> SecretKey key, byte[] objBytes) throws GeneralException {
> >> +        protected String encryptValue(EncryptMethod encryptMethod,
> byte[] key, byte[] objBytes) throws GeneralException {
> >>              byte[] saltBytes;
> >>              switch (encryptMethod) {
> >>                  case SALT:
> >> @@ -330,7 +426,7 @@ public final class EntityCrypto {
> >>              allBytes[0] = (byte) saltBytes.length;
> >>              System.arraycopy(saltBytes, 0, allBytes, 1,
> saltBytes.length);
> >>              System.arraycopy(objBytes, 0, allBytes, 1 +
> saltBytes.length, objBytes.length);
> >> -            String result =
> Base64.encodeBase64String(DesCrypt.encrypt(key, allBytes));
> >> +            String result =
> Base64.encodeBase64String(DesCrypt.encrypt(DesCrypt.getDesKey(key),
> allBytes));
> >>              return result;
> >>          }
> >>      };
> >>
> >> Modified: ofbiz/trunk/framework/entityext/build.xml
> >> URL:
> http://svn.apache.org/viewvc/ofbiz/trunk/framework/entityext/build.xml?rev=1684608&r1=1684607&r2=1684608&view=diff
> >>
> ==============================================================================
> >> --- ofbiz/trunk/framework/entityext/build.xml (original)
> >> +++ ofbiz/trunk/framework/entityext/build.xml Wed Jun 10 09:01:30 2015
> >> @@ -31,6 +31,7 @@ under the License.
> >>        <path id="local.class.path">
> >>          <fileset dir="../base/lib" includes="*.jar"/>
> >> +        <fileset dir="../base/lib/commons" includes="*.jar"/>
> >>          <fileset dir="../base/lib/j2eespecs" includes="*.jar"/>
> >>          <fileset dir="../base/build/lib" includes="*.jar"/>
> >>          <fileset dir="../entity/lib" includes="*.jar"/>
> >>
> >> Modified: ofbiz/trunk/framework/entityext/servicedef/services.xml
> >> URL:
> http://svn.apache.org/viewvc/ofbiz/trunk/framework/entityext/servicedef/services.xml?rev=1684608&r1=1684607&r2=1684608&view=diff
> >>
> ==============================================================================
> >> --- ofbiz/trunk/framework/entityext/servicedef/services.xml (original)
> >> +++ ofbiz/trunk/framework/entityext/servicedef/services.xml Wed Jun 10
> 09:01:30 2015
> >> @@ -153,6 +153,19 @@ under the License.
> >>          <attribute name="fieldName" type="String" mode="IN"
> optional="false"/>
> >>      </service>
> >>  +    <service name="reencryptPrivateKeys" engine="java" auth="true"
> transaction-timeout="14400"
> >> +        location="org.ofbiz.entityext.data.EntityDataServices"
> invoke="reencryptPrivateKeys">
> >> +        <description>Re-encrypt the private keys, encrypted in
> EntityKeyStore with oldKey, using the newKey.</description>
> >> +        <attribute name="oldKey" type="String" mode="IN"
> optional="true"/>
> >> +        <attribute name="newKey" type="String" mode="IN"
> optional="true"/>
> >> +    </service>
> >> +
> >> +    <service name="reencryptFields" engine="java" auth="true"
> transaction-timeout="14400"
> >> +            location="org.ofbiz.entityext.data.EntityDataServices"
> invoke="reencryptFields">
> >> +        <description>Re-encrypt all the encrypted fields in the data
> model.</description>
> >> +        <attribute name="groupName" type="String" mode="IN"
> optional="true" default-value="org.ofbiz"/>
> >> +    </service>
> >> +
> >>      <!-- EntitySync Services -->
> >>      <service name="createEntitySync" default-entity-name="EntitySync"
> engine="simple"
> >>
> location="component://entityext/script/org/ofbiz/entityext/synchronization/EntitySyncServices.xml"
> invoke="createEntitySync" auth="true">
> >>
> >> Modified:
> ofbiz/trunk/framework/entityext/src/org/ofbiz/entityext/data/EntityDataServices.java
> >> URL:
> http://svn.apache.org/viewvc/ofbiz/trunk/framework/entityext/src/org/ofbiz/entityext/data/EntityDataServices.java?rev=1684608&r1=1684607&r2=1684608&view=diff
> >>
> ==============================================================================
> >> ---
> ofbiz/trunk/framework/entityext/src/org/ofbiz/entityext/data/EntityDataServices.java
> (original)
> >> +++
> ofbiz/trunk/framework/entityext/src/org/ofbiz/entityext/data/EntityDataServices.java
> Wed Jun 10 09:01:30 2015
> >> @@ -31,6 +31,9 @@ import java.util.List;
> >>  import java.util.Locale;
> >>  import java.util.Map;
> >>  +import org.apache.commons.codec.binary.Base64;
> >> +import org.apache.shiro.crypto.AesCipherService;
> >> +import org.ofbiz.base.crypto.DesCrypt;
> >>  import org.ofbiz.base.util.Debug;
> >>  import org.ofbiz.base.util.FileUtil;
> >>  import org.ofbiz.base.util.GeneralException;
> >> @@ -44,6 +47,7 @@ import org.ofbiz.entity.GenericValue;
> >>  import org.ofbiz.entity.datasource.GenericHelperInfo;
> >>  import org.ofbiz.entity.jdbc.DatabaseUtil;
> >>  import org.ofbiz.entity.model.ModelEntity;
> >> +import org.ofbiz.entity.model.ModelField;
> >>  import org.ofbiz.entity.util.EntityListIterator;
> >>  import org.ofbiz.entity.util.EntityQuery;
> >>  import org.ofbiz.security.Security;
> >> @@ -445,4 +449,95 @@ public class EntityDataServices {
> >>            return ServiceUtil.returnSuccess();
> >>      }
> >> +
> >> +    public static Map<String, Object>
> reencryptPrivateKeys(DispatchContext dctx, Map<String, Object> context) {
> >> +        Delegator delegator = dctx.getDelegator();
> >> +        Security security = dctx.getSecurity();
> >> +        Locale locale = (Locale) context.get("locale");
> >> +
> >> +        // check permission
> >> +        GenericValue userLogin = (GenericValue)
> context.get("userLogin");
> >> +        if (!security.hasPermission("ENTITY_MAINT", userLogin)) {
> >> +            return
> ServiceUtil.returnError(UtilProperties.getMessage(resource,
> "EntityExtServicePermissionNotGranted", locale));
> >> +        }
> >> +        String oldKey = (String) context.get("oldKey");
> >> +        String newKey = (String) context.get("newKey");
> >> +        AesCipherService cipherService = new AesCipherService();
> >> +        try {
> >> +            List<GenericValue> rows =
> EntityQuery.use(delegator).from("EntityKeyStore").queryList();
> >> +            for (GenericValue row: rows) {
> >> +                byte[] keyBytes =
> Base64.decodeBase64(row.getString("keyText"));
> >> +                Debug.logInfo("Processing entry " +
> row.getString("keyName") + " with key: " + row.getString("keyText"),
> module);
> >> +                if (oldKey != null) {
> >> +                    Debug.logInfo("Decrypting with old key: " +
> oldKey, module);
> >> +                    try {
> >> +                        keyBytes = cipherService.decrypt(keyBytes,
> Base64.decodeBase64(oldKey)).getBytes();
> >> +                    } catch(Exception e) {
> >> +                        Debug.logInfo("Failed to decrypt with Shiro
> cipher; trying with old cipher", module);
> >> +                        try {
> >> +                            keyBytes =
> DesCrypt.decrypt(DesCrypt.getDesKey(Base64.decodeBase64(oldKey)), keyBytes);
> >> +                        } catch(Exception e1) {
> >> +                            Debug.logError(e1, module);
> >> +                            return
> ServiceUtil.returnError(e1.getMessage());
> >> +                        }
> >> +                    }
> >> +                }
> >> +                String newKeyText;
> >> +                if (newKey != null) {
> >> +                    Debug.logInfo("Encrypting with new key: " +
> oldKey, module);
> >> +                    newKeyText = cipherService.encrypt(keyBytes,
> Base64.decodeBase64(newKey)).toBase64();
> >> +                } else {
> >> +                    newKeyText = Base64.encodeBase64String(keyBytes);
> >> +                }
> >> +                Debug.logInfo("Storing new encrypted value: " +
> newKeyText, module);
> >> +                row.setString("keyText", newKeyText);
> >> +                row.store();
> >> +            }
> >> +        } catch(GenericEntityException gee) {
> >> +            Debug.logError(gee, module);
> >> +            return ServiceUtil.returnError(gee.getMessage());
> >> +        }
> >> +        delegator.clearAllCaches();
> >> +        return ServiceUtil.returnSuccess();
> >> +    }
> >> +
> >> +    public static Map<String, Object> reencryptFields(DispatchContext
> dctx, Map<String, Object> context) {
> >> +        Delegator delegator = dctx.getDelegator();
> >> +        Security security = dctx.getSecurity();
> >> +        Locale locale = (Locale) context.get("locale");
> >> +
> >> +        // check permission
> >> +        GenericValue userLogin = (GenericValue)
> context.get("userLogin");
> >> +        if (!security.hasPermission("ENTITY_MAINT", userLogin)) {
> >> +            return
> ServiceUtil.returnError(UtilProperties.getMessage(resource,
> "EntityExtServicePermissionNotGranted", locale));
> >> +        }
> >> +
> >> +        String groupName = (String) context.get("groupName");
> >> +
> >> +        Map<String, ModelEntity> modelEntities;
> >> +        try {
> >> +            modelEntities =
> delegator.getModelEntityMapByGroup(groupName);
> >> +        } catch (GenericEntityException e) {
> >> +            Debug.logError(e, "Error getting list of entities in
> group: " + e.toString(), module);
> >> +            return
> ServiceUtil.returnError(UtilProperties.getMessage(resource,
> "EntityExtErrorGettingListOfEntityInGroup", UtilMisc.toMap("errorString",
> e.toString()), locale));
> >> +        }
> >> +
> >> +        for (ModelEntity modelEntity: modelEntities.values()) {
> >> +            List<ModelField> fields =
> modelEntity.getFieldsUnmodifiable();
> >> +            for (ModelField field: fields) {
> >> +                if (field.getEncryptMethod().isEncrypted()) {
> >> +                    try {
> >> +                        List<GenericValue> rows =
> EntityQuery.use(delegator).from(modelEntity.getEntityName()).select(field.getName()).queryList();
> >> +                        for (GenericValue row: rows) {
> >> +                            row.setString(field.getName(),
> row.getString(field.getName()));
> >> +                            row.store();
> >> +                        }
> >> +                    } catch(GenericEntityException gee) {
> >> +                        return
> ServiceUtil.returnError(gee.getMessage());
> >> +                    }
> >> +                }
> >> +            }
> >> +        }
> >> +        return ServiceUtil.returnSuccess();
> >> +    }
> >>  }
> >>
> >>
> >>
> >
>
>
>

Re: svn commit: r1684608 - in /ofbiz/trunk: ./ framework/base/lib/ framework/base/src/org/ofbiz/base/crypto/ framework/entity/src/org/ofbiz/entity/ framework/entity/src/org/ofbiz/entity/jdbc/ framework/entity/src/org/ofbiz/entity/test/ framework/entity/src...

Posted by Jacopo Cappellato <ja...@hotwaxsystems.com>.
On Jun 10, 2015, at 12:05 PM, Jacques Le Roux <ja...@les7arts.com> wrote:

> Hi Jacopo,
> 
> Very happy about that, I don't have time to review in details yet, but I'm already impressed by the comment and a 1st cursory review :)
> 
> Just a question, since I have no experience with Moqui code, is there a relation or ideas coming from there?
> 
> Jacques

Thank you Jacques! No, I didn't look at the Moqui implementation, this is an effort I did based on the code we have in OFBiz only.

Jacopo


> 
> Le 10/06/2015 11:01, jacopoc@apache.org a écrit :
>> Author: jacopoc
>> Date: Wed Jun 10 09:01:30 2015
>> New Revision: 1684608
>> 
>> URL: http://svn.apache.org/r1684608
>> Log:
>> New implementation of the two-way cryptographic services of OFBiz based on Apache Shiro:
>> * two-way encryption is now delegated to Apache Shiro, with stronger initialization vectors
>> * the mechanism is backward compatible
>> * new tools to update the encryption of private keys, useful to upgrade older versions of OFBiz and most of all to replace old keys with new ones (this is critical to implement stronger security practices as requested by PCI)
>> * unit tests
>> 
>> 
>> Added:
>>     ofbiz/trunk/framework/base/lib/shiro-core-1.2.3.jar   (with props)
>> Modified:
>>     ofbiz/trunk/LICENSE
>>     ofbiz/trunk/build.xml
>>     ofbiz/trunk/framework/base/src/org/ofbiz/base/crypto/DesCrypt.java
>>     ofbiz/trunk/framework/base/src/org/ofbiz/base/crypto/Main.java
>>     ofbiz/trunk/framework/entity/src/org/ofbiz/entity/Delegator.java
>>     ofbiz/trunk/framework/entity/src/org/ofbiz/entity/GenericDelegator.java
>>     ofbiz/trunk/framework/entity/src/org/ofbiz/entity/jdbc/SqlJdbcUtil.java
>>     ofbiz/trunk/framework/entity/src/org/ofbiz/entity/test/EntityCryptoTestSuite.java
>>     ofbiz/trunk/framework/entity/src/org/ofbiz/entity/util/EntityCrypto.java
>>     ofbiz/trunk/framework/entityext/build.xml
>>     ofbiz/trunk/framework/entityext/servicedef/services.xml
>>     ofbiz/trunk/framework/entityext/src/org/ofbiz/entityext/data/EntityDataServices.java
>> 
>> Modified: ofbiz/trunk/LICENSE
>> URL: http://svn.apache.org/viewvc/ofbiz/trunk/LICENSE?rev=1684608&r1=1684607&r2=1684608&view=diff
>> ==============================================================================
>> --- ofbiz/trunk/LICENSE (original)
>> +++ ofbiz/trunk/LICENSE Wed Jun 10 09:01:30 2015
>> @@ -38,6 +38,7 @@ framework/base/lib/log4j-slf4j-impl-2.3.
>>  framework/base/lib/nekohtml-1.9.16.jar
>>  framework/base/lib/resolver-2.9.1.jar
>>  framework/base/lib/serializer-2.9.1.jar
>> +framework/base/lib/shiro-core-1.2.3.jar
>>  framework/base/lib/ws-commons-java5-1.0.1.jar
>>  framework/base/lib/ws-commons-util-1.0.2.jar
>>  framework/base/lib/xercesImpl-2.9.1.jar
>> 
>> Modified: ofbiz/trunk/build.xml
>> URL: http://svn.apache.org/viewvc/ofbiz/trunk/build.xml?rev=1684608&r1=1684607&r2=1684608&view=diff
>> ==============================================================================
>> --- ofbiz/trunk/build.xml (original)
>> +++ ofbiz/trunk/build.xml Wed Jun 10 09:01:30 2015
>> @@ -1536,6 +1536,8 @@ under the License.
>>              <classpath>
>>                  <path location="framework/base/build/lib/ofbiz-base.jar"/>
>>                  <path location="framework/base/lib/commons/commons-codec-1.10.jar"/>
>> +                <path location="framework/base/lib/shiro-core-1.2.3.jar"/>
>> +                <path location="framework/base/lib/slf4j-api-1.6.4.jar"/>
>>              </classpath>
>>          </java>
>>      </target>
>> 
>> Added: ofbiz/trunk/framework/base/lib/shiro-core-1.2.3.jar
>> URL: http://svn.apache.org/viewvc/ofbiz/trunk/framework/base/lib/shiro-core-1.2.3.jar?rev=1684608&view=auto
>> ==============================================================================
>> Binary file - no diff available.
>> 
>> Propchange: ofbiz/trunk/framework/base/lib/shiro-core-1.2.3.jar
>> ------------------------------------------------------------------------------
>>     svn:mime-type = application/octet-stream
>> 
>> Modified: ofbiz/trunk/framework/base/src/org/ofbiz/base/crypto/DesCrypt.java
>> URL: http://svn.apache.org/viewvc/ofbiz/trunk/framework/base/src/org/ofbiz/base/crypto/DesCrypt.java?rev=1684608&r1=1684607&r2=1684608&view=diff
>> ==============================================================================
>> --- ofbiz/trunk/framework/base/src/org/ofbiz/base/crypto/DesCrypt.java (original)
>> +++ ofbiz/trunk/framework/base/src/org/ofbiz/base/crypto/DesCrypt.java Wed Jun 10 09:01:30 2015
>> @@ -21,11 +21,11 @@ package org.ofbiz.base.crypto;
>>  import java.security.NoSuchAlgorithmException;
>>  import java.security.InvalidKeyException;
>>  import java.security.InvalidAlgorithmParameterException;
>> +import java.security.Key;
>>  import java.security.spec.InvalidKeySpecException;
>>  import javax.crypto.Cipher;
>>  import javax.crypto.IllegalBlockSizeException;
>>  import javax.crypto.BadPaddingException;
>> -import javax.crypto.SecretKey;
>>  import javax.crypto.NoSuchPaddingException;
>>  import javax.crypto.KeyGenerator;
>>  import javax.crypto.SecretKeyFactory;
>> @@ -42,14 +42,14 @@ public class DesCrypt {
>>        public static final String module = DesCrypt.class.getName();
>>  -    public static SecretKey generateKey() throws NoSuchAlgorithmException {
>> +    public static Key generateKey() throws NoSuchAlgorithmException {
>>          KeyGenerator keyGen = KeyGenerator.getInstance("DESede");
>>            // generate the DES3 key
>>          return keyGen.generateKey();
>>      }
>>  -    public static byte[] encrypt(SecretKey key, byte[] bytes) throws GeneralException {
>> +    public static byte[] encrypt(Key key, byte[] bytes) throws GeneralException {
>>          Cipher cipher = DesCrypt.getCipher(key, Cipher.ENCRYPT_MODE);
>>          byte[] encBytes = null;
>>          try {
>> @@ -64,7 +64,7 @@ public class DesCrypt {
>>          return encBytes;
>>      }
>>  -    public static byte[] decrypt(SecretKey key, byte[] bytes) throws GeneralException {
>> +    public static byte[] decrypt(Key key, byte[] bytes) throws GeneralException {
>>          Cipher cipher = DesCrypt.getCipher(key, Cipher.DECRYPT_MODE);
>>          byte[] decBytes = null;
>>          try {
>> @@ -79,7 +79,7 @@ public class DesCrypt {
>>          return decBytes;
>>      }
>>  -    public static SecretKey getDesKey(byte[] rawKey) throws GeneralException {
>> +    public static Key getDesKey(byte[] rawKey) throws GeneralException {
>>          SecretKeyFactory skf = null;
>>          try {
>>              skf = SecretKeyFactory.getInstance("DESede");
>> @@ -97,7 +97,7 @@ public class DesCrypt {
>>              }
>>                // create the SecretKey Object
>> -            SecretKey key = null;
>> +            Key key = null;
>>              try {
>>                  key = skf.generateSecret(desedeSpec1);
>>              } catch (InvalidKeySpecException e) {
>> @@ -110,7 +110,7 @@ public class DesCrypt {
>>      }
>>        // return a cipher for a key - DESede/CBC/PKCS5Padding IV = 0
>> -    protected static Cipher getCipher(SecretKey key, int mode) throws GeneralException {
>> +    protected static Cipher getCipher(Key key, int mode) throws GeneralException {
>>          byte[] zeros = { 0, 0, 0, 0, 0, 0, 0, 0 };
>>          IvParameterSpec iv = new IvParameterSpec(zeros);
>>  
>> Modified: ofbiz/trunk/framework/base/src/org/ofbiz/base/crypto/Main.java
>> URL: http://svn.apache.org/viewvc/ofbiz/trunk/framework/base/src/org/ofbiz/base/crypto/Main.java?rev=1684608&r1=1684607&r2=1684608&view=diff
>> ==============================================================================
>> --- ofbiz/trunk/framework/base/src/org/ofbiz/base/crypto/Main.java (original)
>> +++ ofbiz/trunk/framework/base/src/org/ofbiz/base/crypto/Main.java Wed Jun 10 09:01:30 2015
>> @@ -19,6 +19,7 @@
>>  package org.ofbiz.base.crypto;
>>    import org.apache.commons.codec.binary.Base64;
>> +import org.apache.shiro.crypto.AesCipherService;
>>    public class Main {
>>      public static void main(String[] args) throws Exception {
>> @@ -29,6 +30,9 @@ public class Main {
>>              String digest = HashCrypt.getDigestHash(args[1]);
>>              System.out.println(digest);
>>          } else if (args[0].equals("-kek")) {
>> +            AesCipherService cs = new AesCipherService();
>> +            System.out.println(Base64.encodeBase64String(cs.generateNewKey().getEncoded()));
>> +        } else if (args[0].equals("-kek-old")) {
>>              System.out.println(Base64.encodeBase64String(DesCrypt.generateKey().getEncoded()));
>>          }
>>      }
>> 
>> Modified: ofbiz/trunk/framework/entity/src/org/ofbiz/entity/Delegator.java
>> URL: http://svn.apache.org/viewvc/ofbiz/trunk/framework/entity/src/org/ofbiz/entity/Delegator.java?rev=1684608&r1=1684607&r2=1684608&view=diff
>> ==============================================================================
>> --- ofbiz/trunk/framework/entity/src/org/ofbiz/entity/Delegator.java (original)
>> +++ ofbiz/trunk/framework/entity/src/org/ofbiz/entity/Delegator.java Wed Jun 10 09:01:30 2015
>> @@ -269,8 +269,11 @@ public interface Delegator {
>>      @Deprecated
>>      void encryptFields(List<? extends GenericEntity> entities) throws GenericEntityException;
>>  +    @Deprecated
>>      Object decryptFieldValue(String entityName, String encValue) throws EntityCryptoException;
>>  +    Object decryptFieldValue(String entityName, ModelField.EncryptMethod encryptMethod, String encValue) throws EntityCryptoException;
>> +
>>      @Deprecated
>>      Object encryptFieldValue(String entityName, Object fieldValue) throws EntityCryptoException;
>>  
>> Modified: ofbiz/trunk/framework/entity/src/org/ofbiz/entity/GenericDelegator.java
>> URL: http://svn.apache.org/viewvc/ofbiz/trunk/framework/entity/src/org/ofbiz/entity/GenericDelegator.java?rev=1684608&r1=1684607&r2=1684608&view=diff
>> ==============================================================================
>> --- ofbiz/trunk/framework/entity/src/org/ofbiz/entity/GenericDelegator.java (original)
>> +++ ofbiz/trunk/framework/entity/src/org/ofbiz/entity/GenericDelegator.java Wed Jun 10 09:01:30 2015
>> @@ -2070,6 +2070,9 @@ public class GenericDelegator implements
>>          if (dcc != null) {
>>              dcc.clearAllCaches();
>>          }
>> +        if (this.crypto != null) {
>> +            this.crypto.clearKeyCache();
>> +        }
>>      }
>>        /* (non-Javadoc)
>> @@ -2677,13 +2680,22 @@ public class GenericDelegator implements
>>          return fieldValue;
>>      }
>>  +    @Override
>> +    @Deprecated
>> +    public Object decryptFieldValue(String entityName, String encValue) throws EntityCryptoException {
>> +        if (UtilValidate.isNotEmpty(encValue)) {
>> +            return this.crypto.decrypt(entityName, ModelField.EncryptMethod.TRUE, encValue);
>> +        }
>> +        return null;
>> +    }
>> +
>>      /* (non-Javadoc)
>>       * @see org.ofbiz.entity.Delegator#encryptFieldValue(java.lang.String, java.lang.Object)
>>       */
>>      @Override
>> -    public Object decryptFieldValue(String entityName, String encValue) throws EntityCryptoException {
>> +    public Object decryptFieldValue(String entityName, ModelField.EncryptMethod encryptMethod, String encValue) throws EntityCryptoException {
>>          if (UtilValidate.isNotEmpty(encValue)) {
>> -            return this.crypto.decrypt(entityName, encValue);
>> +            return this.crypto.decrypt(entityName, encryptMethod, encValue);
>>          }
>>          return null;
>>      }
>> 
>> Modified: ofbiz/trunk/framework/entity/src/org/ofbiz/entity/jdbc/SqlJdbcUtil.java
>> URL: http://svn.apache.org/viewvc/ofbiz/trunk/framework/entity/src/org/ofbiz/entity/jdbc/SqlJdbcUtil.java?rev=1684608&r1=1684607&r2=1684608&view=diff
>> ==============================================================================
>> --- ofbiz/trunk/framework/entity/src/org/ofbiz/entity/jdbc/SqlJdbcUtil.java (original)
>> +++ ofbiz/trunk/framework/entity/src/org/ofbiz/entity/jdbc/SqlJdbcUtil.java Wed Jun 10 09:01:30 2015
>> @@ -540,7 +540,7 @@ public class SqlJdbcUtil {
>>              try {
>>                  Object jdbcValue = handler.getValue(rs, ind);
>>                  if (jdbcValue instanceof String && curField.getEncryptMethod().isEncrypted()) {
>> -                    jdbcValue = entity.getDelegator().decryptFieldValue(encryptionKeyName, (String) jdbcValue);
>> +                    jdbcValue = entity.getDelegator().decryptFieldValue(encryptionKeyName, curField.getEncryptMethod(), (String) jdbcValue);
>>                  }
>>                  entity.dangerousSetNoCheckButFast(curField, jdbcValue);
>>                  return;
>> @@ -597,7 +597,7 @@ public class SqlJdbcUtil {
>>                      } else {
>>                          String value = rs.getString(ind);
>>                          if (value instanceof String && curField.getEncryptMethod().isEncrypted()) {
>> -                            value = (String) entity.getDelegator().decryptFieldValue(encryptionKeyName, value);
>> +                            value = (String) entity.getDelegator().decryptFieldValue(encryptionKeyName, curField.getEncryptMethod(), value);
>>                          }
>>                          entity.dangerousSetNoCheckButFast(curField, value);
>>                      }
>> 
>> Modified: ofbiz/trunk/framework/entity/src/org/ofbiz/entity/test/EntityCryptoTestSuite.java
>> URL: http://svn.apache.org/viewvc/ofbiz/trunk/framework/entity/src/org/ofbiz/entity/test/EntityCryptoTestSuite.java?rev=1684608&r1=1684607&r2=1684608&view=diff
>> ==============================================================================
>> --- ofbiz/trunk/framework/entity/src/org/ofbiz/entity/test/EntityCryptoTestSuite.java (original)
>> +++ ofbiz/trunk/framework/entity/src/org/ofbiz/entity/test/EntityCryptoTestSuite.java Wed Jun 10 09:01:30 2015
>> @@ -33,6 +33,26 @@ public class EntityCryptoTestSuite exten
>>          super(name);
>>      }
>>  +    public void testCrypto() throws Exception {
>> +        String nanoTime = "" + System.nanoTime();
>> +        delegator.removeByAnd("TestingCrypto", UtilMisc.toMap("testingCryptoTypeId", "BASIC"));
>> +        delegator.create("TestingCrypto", UtilMisc.toMap("testingCryptoId", "1", "testingCryptoTypeId", "BASIC"));
>> +        GenericValue entity = EntityQuery.use(delegator).from("TestingCrypto").where("testingCryptoId", "1").queryOne();
>> +        assertNull(entity.getString("unencryptedValue"));
>> +        assertNull(entity.getString("encryptedValue"));
>> +        entity.setString("unencryptedValue", nanoTime);
>> +        entity.setString("encryptedValue", nanoTime);
>> +        entity.setString("saltedEncryptedValue", nanoTime);
>> +        assertEquals(nanoTime, entity.getString("unencryptedValue"));
>> +        assertEquals(nanoTime, entity.getString("encryptedValue"));
>> +        assertEquals(nanoTime, entity.getString("saltedEncryptedValue"));
>> +        entity.store();
>> +        entity.refresh();
>> +        assertEquals(nanoTime, entity.getString("unencryptedValue"));
>> +        assertEquals(nanoTime, entity.getString("encryptedValue"));
>> +        assertEquals(nanoTime, entity.getString("saltedEncryptedValue"));
>> +    }
>> +
>>      public void testCryptoEncryption() throws Exception {
>>          // clear out all values
>>          delegator.removeByAnd("TestingCrypto", UtilMisc.toMap("testingCryptoTypeId", "BASIC"));
>> 
>> Modified: ofbiz/trunk/framework/entity/src/org/ofbiz/entity/util/EntityCrypto.java
>> URL: http://svn.apache.org/viewvc/ofbiz/trunk/framework/entity/src/org/ofbiz/entity/util/EntityCrypto.java?rev=1684608&r1=1684607&r2=1684608&view=diff
>> ==============================================================================
>> --- ofbiz/trunk/framework/entity/src/org/ofbiz/entity/util/EntityCrypto.java (original)
>> +++ ofbiz/trunk/framework/entity/src/org/ofbiz/entity/util/EntityCrypto.java Wed Jun 10 09:01:30 2015
>> @@ -25,9 +25,14 @@ import java.util.concurrent.Callable;
>>  import java.util.concurrent.ConcurrentHashMap;
>>  import java.util.concurrent.ConcurrentMap;
>>  -import javax.crypto.SecretKey;
>> +import java.security.Key;
>>    import org.apache.commons.codec.binary.Base64;
>> +import org.apache.shiro.crypto.AesCipherService;
>> +import org.apache.shiro.crypto.OperationMode;
>> +import org.apache.shiro.crypto.hash.HashRequest;
>> +import org.apache.shiro.crypto.hash.HashService;
>> +import org.apache.shiro.crypto.hash.DefaultHashService;
>>  import org.ofbiz.base.crypto.DesCrypt;
>>  import org.ofbiz.base.crypto.HashCrypt;
>>  import org.ofbiz.base.util.Debug;
>> @@ -47,24 +52,25 @@ public final class EntityCrypto {
>>      public static final String module = EntityCrypto.class.getName();
>>        protected final Delegator delegator;
>> -    protected final ConcurrentMap<String, SecretKey> keyMap = new ConcurrentHashMap<String, SecretKey>();
>> +    protected final ConcurrentMap<String, byte[]> keyMap = new ConcurrentHashMap<String, byte[]>();
>>      protected final StorageHandler[] handlers;
>>        public EntityCrypto(Delegator delegator, String kekText) throws EntityCryptoException {
>>          this.delegator = delegator;
>> -        SecretKey kek;
>> -        try {
>> -            kek = UtilValidate.isNotEmpty(kekText) ? DesCrypt.getDesKey(Base64.decodeBase64(kekText)) : null;
>> -        } catch (GeneralException e) {
>> -            throw new EntityCryptoException(e);
>> -        }
>> +        byte[] kek;
>> +        kek = UtilValidate.isNotEmpty(kekText) ? Base64.decodeBase64(kekText) : null;
>>          handlers = new StorageHandler[] {
>> +            new ShiroStorageHandler(kek),
>>              new SaltedBase64StorageHandler(kek),
>>              NormalHashStorageHandler,
>>              OldFunnyHashStorageHandler,
>>          };
>>      }
>>  +    public void clearKeyCache() {
>> +        keyMap.clear();
>> +    }
>> +
>>      /** Encrypts an Object into an encrypted hex encoded String */
>>      @Deprecated
>>      public String encrypt(String keyName, Object obj) throws EntityCryptoException {
>> @@ -74,11 +80,11 @@ public final class EntityCrypto {
>>      /** Encrypts an Object into an encrypted hex encoded String */
>>      public String encrypt(String keyName, EncryptMethod encryptMethod, Object obj) throws EntityCryptoException {
>>          try {
>> -            SecretKey key = this.findKey(keyName, handlers[0]);
>> +            byte[] key = this.findKey(keyName, handlers[0]);
>>              if (key == null) {
>>                  EntityCryptoException caught = null;
>>                  try {
>> -                    this.createKey(keyName, handlers[0]);
>> +                    this.createKey(keyName, handlers[0], encryptMethod);
>>                  } catch (EntityCryptoException e) {
>>                      // either a database read error, or a duplicate key insert
>>                      // if the latter, try to fetch the value created by the
>> @@ -89,7 +95,7 @@ public final class EntityCrypto {
>>                          key = this.findKey(keyName, handlers[0]);
>>                      } catch (EntityCryptoException e) {
>>                          // this is bad, couldn't lookup the value, some bad juju
>> -                        // is occuring; rethrow the original exception if available
>> +                        // is occurring; rethrow the original exception if available
>>                          throw caught != null ? caught : e;
>>                      }
>>                      if (key == null) {
>> @@ -115,15 +121,15 @@ public final class EntityCrypto {
>>      */
>>        /** Decrypts a hex encoded String into an Object */
>> -    public Object decrypt(String keyName, String encryptedString) throws EntityCryptoException {
>> +    public Object decrypt(String keyName, EncryptMethod encryptMethod, String encryptedString) throws EntityCryptoException {
>>          try {
>> -            return doDecrypt(keyName, encryptedString, handlers[0]);
>> +            return doDecrypt(keyName, encryptMethod, encryptedString, handlers[0]);
>>          } catch (GeneralException e) {
>>              Debug.logInfo("Decrypt with DES key from standard key name hash failed, trying old/funny variety of key name hash", module);
>>              for (int i = 1; i < handlers.length; i++) {
>>                  try {
>>                      // try using the old/bad hex encoding approach; this is another path the code may take, ie if there is an exception thrown in decrypt
>> -                    return doDecrypt(keyName, encryptedString, handlers[i]);
>> +                    return doDecrypt(keyName, encryptMethod, encryptedString, handlers[i]);
>>                  } catch (GeneralException e1) {
>>                      // NOTE: this throws the original exception back, not the new one if it fails using the other approach
>>                      //throw new EntityCryptoException(e);
>> @@ -133,12 +139,12 @@ public final class EntityCrypto {
>>          }
>>      }
>>  -    protected Object doDecrypt(String keyName, String encryptedString, StorageHandler handler) throws GeneralException {
>> -        SecretKey key = this.findKey(keyName, handler);
>> +    protected Object doDecrypt(String keyName, EncryptMethod encryptMethod, String encryptedString, StorageHandler handler) throws GeneralException {
>> +        byte[] key = this.findKey(keyName, handler);
>>          if (key == null) {
>>              throw new EntityCryptoException("key(" + keyName + ") not found in database");
>>          }
>> -        byte[] decryptedBytes = handler.decryptValue(key, encryptedString);
>> +        byte[] decryptedBytes = handler.decryptValue(key, encryptMethod, encryptedString);
>>          try {
>>              return UtilObject.getObjectException(decryptedBytes);
>>          } catch (ClassNotFoundException e) {
>> @@ -148,7 +154,7 @@ public final class EntityCrypto {
>>          }
>>      }
>>  -    protected SecretKey findKey(String originalKeyName, StorageHandler handler) throws EntityCryptoException {
>> +    protected byte[] findKey(String originalKeyName, StorageHandler handler) throws EntityCryptoException {
>>          String hashedKeyName = handler.getHashedKeyName(originalKeyName);
>>          String keyMapName = handler.getKeyMapPrefix(hashedKeyName) + hashedKeyName;
>>          if (keyMap.containsKey(keyMapName)) {
>> @@ -170,8 +176,7 @@ public final class EntityCrypto {
>>          }
>>          try {
>>              byte[] keyBytes = handler.decodeKeyBytes(keyValue.getString("keyText"));
>> -            SecretKey key = DesCrypt.getDesKey(keyBytes);
>> -            keyMap.putIfAbsent(keyMapName, key);
>> +            keyMap.putIfAbsent(keyMapName, keyBytes);
>>              // Do not remove the next line, it's there to handle the
>>              // case of multiple threads trying to find the same key
>>              // both threads will do the findOne call, only one will
>> @@ -183,17 +188,12 @@ public final class EntityCrypto {
>>          }
>>      }
>>  -    protected void createKey(String originalKeyName, StorageHandler handler) throws EntityCryptoException {
>> +    protected void createKey(String originalKeyName, StorageHandler handler, EncryptMethod encryptMethod) throws EntityCryptoException {
>>          String hashedKeyName = handler.getHashedKeyName(originalKeyName);
>> -        SecretKey key = null;
>> -        try {
>> -            key = DesCrypt.generateKey();
>> -        } catch (NoSuchAlgorithmException e) {
>> -            throw new EntityCryptoException(e);
>> -        }
>> +        Key key = handler.generateNewKey();
>>          final GenericValue newValue = delegator.makeValue("EntityKeyStore");
>>          try {
>> -            newValue.set("keyText", handler.encodeKey(key));
>> +            newValue.set("keyText", handler.encodeKey(key.getEncoded()));
>>          } catch (GeneralException e) {
>>              throw new EntityCryptoException(e);
>>          }
>> @@ -212,35 +212,115 @@ public final class EntityCrypto {
>>      }
>>        protected abstract static class StorageHandler {
>> +        protected abstract Key generateNewKey() throws EntityCryptoException;
>> +
>>          protected abstract String getHashedKeyName(String originalKeyName);
>>          protected abstract String getKeyMapPrefix(String hashedKeyName);
>>            protected abstract byte[] decodeKeyBytes(String keyText) throws GeneralException;
>> -        protected abstract String encodeKey(SecretKey key) throws GeneralException;
>> +        protected abstract String encodeKey(byte[] key) throws GeneralException;
>> +
>> +        protected abstract byte[] decryptValue(byte[] key, EncryptMethod encryptMethod, String encryptedString) throws GeneralException;
>> +        protected abstract String encryptValue(EncryptMethod encryptMethod, byte[] key, byte[] objBytes) throws GeneralException;
>> +    }
>> +
>> +    protected static final class ShiroStorageHandler extends StorageHandler {
>> +        private final HashService hashService;
>> +        private final AesCipherService cipherService;
>> +        private final AesCipherService saltedCipherService;
>> +        private final byte[] kek;
>> +
>> +        protected ShiroStorageHandler(byte[] kek) {
>> +            hashService = new DefaultHashService();
>> +            cipherService = new AesCipherService();
>> +            cipherService.setMode(OperationMode.ECB);
>> +            saltedCipherService = new AesCipherService();
>> +            this.kek = kek;
>> +        }
>> +
>> +        @Override
>> +        protected Key generateNewKey() {
>> +            return saltedCipherService.generateNewKey();
>> +        }
>> +
>> +        @Override
>> +        protected String getHashedKeyName(String originalKeyName) {
>> +            HashRequest hashRequest = new HashRequest.Builder().setSource(originalKeyName).build();
>> +            return hashService.computeHash(hashRequest).toBase64();
>> +        }
>> +
>> +        @Override
>> +        protected String getKeyMapPrefix(String hashedKeyName) {
>> +            return "{shiro}";
>> +        }
>> +
>> +        @Override
>> +        protected byte[] decodeKeyBytes(String keyText) throws GeneralException {
>> +            byte[] keyBytes = Base64.decodeBase64(keyText);
>> +            if (kek != null) {
>> +                keyBytes = saltedCipherService.decrypt(keyBytes, kek).getBytes();
>> +            }
>> +            return keyBytes;
>> +        }
>>  -        protected abstract byte[] decryptValue(SecretKey key, String encryptedString) throws GeneralException;
>> -        protected abstract String encryptValue(EncryptMethod encryptMethod, SecretKey key, byte[] objBytes) throws GeneralException;
>> +        @Override
>> +        protected String encodeKey(byte[] key) throws GeneralException {
>> +            if (kek != null) {
>> +                return saltedCipherService.encrypt(key, kek).toBase64();
>> +            } else {
>> +                return Base64.encodeBase64String(key);
>> +            }
>> +        }
>> +
>> +        @Override
>> +        protected byte[] decryptValue(byte[] key, EncryptMethod encryptMethod, String encryptedString) throws GeneralException {
>> +            switch (encryptMethod) {
>> +                case SALT:
>> +                    return saltedCipherService.decrypt(Base64.decodeBase64(encryptedString), key).getBytes();
>> +                default:
>> +                    return cipherService.decrypt(Base64.decodeBase64(encryptedString), key).getBytes();
>> +            }
>> +        }
>> +
>> +        @Override
>> +        protected String encryptValue(EncryptMethod encryptMethod, byte[] key, byte[] objBytes) throws GeneralException {
>> +            switch (encryptMethod) {
>> +                case SALT:
>> +                    return saltedCipherService.encrypt(objBytes, key).toBase64();
>> +                default:
>> +                    return cipherService.encrypt(objBytes, key).toBase64();
>> +            }
>> +        }
>>      }
>>        protected static abstract class LegacyStorageHandler extends StorageHandler {
>>          @Override
>> +        protected Key generateNewKey() throws EntityCryptoException {
>> +            try {
>> +                return DesCrypt.generateKey();
>> +            } catch (NoSuchAlgorithmException e) {
>> +                throw new EntityCryptoException(e);
>> +            }
>> +        }
>> +
>> +        @Override
>>          protected byte[] decodeKeyBytes(String keyText) throws GeneralException {
>>              return StringUtil.fromHexString(keyText);
>>          }
>>            @Override
>> -        protected String encodeKey(SecretKey key) {
>> -            return StringUtil.toHexString(key.getEncoded());
>> +        protected String encodeKey(byte[] key) {
>> +            return StringUtil.toHexString(key);
>>          }
>>            @Override
>> -        protected byte[] decryptValue(SecretKey key, String encryptedString) throws GeneralException {
>> -            return DesCrypt.decrypt(key, StringUtil.fromHexString(encryptedString));
>> +        protected byte[] decryptValue(byte[] key, EncryptMethod encryptMethod, String encryptedString) throws GeneralException {
>> +            return DesCrypt.decrypt(DesCrypt.getDesKey(key), StringUtil.fromHexString(encryptedString));
>>          }
>>            @Override
>> -        protected String encryptValue(EncryptMethod encryptMethod, SecretKey key, byte[] objBytes) throws GeneralException {
>> -            return StringUtil.toHexString(DesCrypt.encrypt(key, objBytes));
>> +        protected String encryptValue(EncryptMethod encryptMethod, byte[] key, byte[] objBytes) throws GeneralException {
>> +            return StringUtil.toHexString(DesCrypt.encrypt(DesCrypt.getDesKey(key), objBytes));
>>          }
>>      };
>>  @@ -269,10 +349,27 @@ public final class EntityCrypto {
>>      };
>>        protected static final class SaltedBase64StorageHandler extends StorageHandler {
>> -        private final SecretKey kek;
>> +        private final Key kek;
>>  -        protected SaltedBase64StorageHandler(SecretKey kek) {
>> -            this.kek = kek;
>> +        protected SaltedBase64StorageHandler(byte[] kek) throws EntityCryptoException {
>> +            Key key = null;
>> +            if (kek != null) {
>> +                try {
>> +                    key = DesCrypt.getDesKey(kek);
>> +                } catch (GeneralException e) {
>> +                    Debug.logInfo("Invalid key-encryption-key specified for SaltedBase64StorageHandler; the key is probably valid for the newer ShiroStorageHandler", module);
>> +                }
>> +            }
>> +            this.kek = key;
>> +        }
>> +
>> +        @Override
>> +        protected Key generateNewKey() throws EntityCryptoException {
>> +            try {
>> +                return DesCrypt.generateKey();
>> +            } catch (NoSuchAlgorithmException e) {
>> +                throw new EntityCryptoException(e);
>> +            }
>>          }
>>            @Override
>> @@ -295,17 +392,16 @@ public final class EntityCrypto {
>>          }
>>            @Override
>> -        protected String encodeKey(SecretKey key) throws GeneralException {
>> -            byte[] keyBytes = key.getEncoded();
>> +        protected String encodeKey(byte[] key) throws GeneralException {
>>              if (kek != null) {
>> -                keyBytes = DesCrypt.encrypt(kek, keyBytes);
>> +                key = DesCrypt.encrypt(kek, key);
>>              }
>> -            return Base64.encodeBase64String(keyBytes);
>> +            return Base64.encodeBase64String(key);
>>          }
>>            @Override
>> -        protected byte[] decryptValue(SecretKey key, String encryptedString) throws GeneralException {
>> -            byte[] allBytes = DesCrypt.decrypt(key, Base64.decodeBase64(encryptedString));
>> +        protected byte[] decryptValue(byte[] key, EncryptMethod encryptMethod, String encryptedString) throws GeneralException {
>> +            byte[] allBytes = DesCrypt.decrypt(DesCrypt.getDesKey(key), Base64.decodeBase64(encryptedString));
>>              int length = allBytes[0];
>>              byte[] objBytes = new byte[allBytes.length - 1 - length];
>>              System.arraycopy(allBytes, 1 + length, objBytes, 0, objBytes.length);
>> @@ -313,7 +409,7 @@ public final class EntityCrypto {
>>          }
>>            @Override
>> -        protected String encryptValue(EncryptMethod encryptMethod, SecretKey key, byte[] objBytes) throws GeneralException {
>> +        protected String encryptValue(EncryptMethod encryptMethod, byte[] key, byte[] objBytes) throws GeneralException {
>>              byte[] saltBytes;
>>              switch (encryptMethod) {
>>                  case SALT:
>> @@ -330,7 +426,7 @@ public final class EntityCrypto {
>>              allBytes[0] = (byte) saltBytes.length;
>>              System.arraycopy(saltBytes, 0, allBytes, 1, saltBytes.length);
>>              System.arraycopy(objBytes, 0, allBytes, 1 + saltBytes.length, objBytes.length);
>> -            String result = Base64.encodeBase64String(DesCrypt.encrypt(key, allBytes));
>> +            String result = Base64.encodeBase64String(DesCrypt.encrypt(DesCrypt.getDesKey(key), allBytes));
>>              return result;
>>          }
>>      };
>> 
>> Modified: ofbiz/trunk/framework/entityext/build.xml
>> URL: http://svn.apache.org/viewvc/ofbiz/trunk/framework/entityext/build.xml?rev=1684608&r1=1684607&r2=1684608&view=diff
>> ==============================================================================
>> --- ofbiz/trunk/framework/entityext/build.xml (original)
>> +++ ofbiz/trunk/framework/entityext/build.xml Wed Jun 10 09:01:30 2015
>> @@ -31,6 +31,7 @@ under the License.
>>        <path id="local.class.path">
>>          <fileset dir="../base/lib" includes="*.jar"/>
>> +        <fileset dir="../base/lib/commons" includes="*.jar"/>
>>          <fileset dir="../base/lib/j2eespecs" includes="*.jar"/>
>>          <fileset dir="../base/build/lib" includes="*.jar"/>
>>          <fileset dir="../entity/lib" includes="*.jar"/>
>> 
>> Modified: ofbiz/trunk/framework/entityext/servicedef/services.xml
>> URL: http://svn.apache.org/viewvc/ofbiz/trunk/framework/entityext/servicedef/services.xml?rev=1684608&r1=1684607&r2=1684608&view=diff
>> ==============================================================================
>> --- ofbiz/trunk/framework/entityext/servicedef/services.xml (original)
>> +++ ofbiz/trunk/framework/entityext/servicedef/services.xml Wed Jun 10 09:01:30 2015
>> @@ -153,6 +153,19 @@ under the License.
>>          <attribute name="fieldName" type="String" mode="IN" optional="false"/>
>>      </service>
>>  +    <service name="reencryptPrivateKeys" engine="java" auth="true" transaction-timeout="14400"
>> +        location="org.ofbiz.entityext.data.EntityDataServices" invoke="reencryptPrivateKeys">
>> +        <description>Re-encrypt the private keys, encrypted in EntityKeyStore with oldKey, using the newKey.</description>
>> +        <attribute name="oldKey" type="String" mode="IN" optional="true"/>
>> +        <attribute name="newKey" type="String" mode="IN" optional="true"/>
>> +    </service>
>> +
>> +    <service name="reencryptFields" engine="java" auth="true" transaction-timeout="14400"
>> +            location="org.ofbiz.entityext.data.EntityDataServices" invoke="reencryptFields">
>> +        <description>Re-encrypt all the encrypted fields in the data model.</description>
>> +        <attribute name="groupName" type="String" mode="IN" optional="true" default-value="org.ofbiz"/>
>> +    </service>
>> +
>>      <!-- EntitySync Services -->
>>      <service name="createEntitySync" default-entity-name="EntitySync" engine="simple"
>>              location="component://entityext/script/org/ofbiz/entityext/synchronization/EntitySyncServices.xml" invoke="createEntitySync" auth="true">
>> 
>> Modified: ofbiz/trunk/framework/entityext/src/org/ofbiz/entityext/data/EntityDataServices.java
>> URL: http://svn.apache.org/viewvc/ofbiz/trunk/framework/entityext/src/org/ofbiz/entityext/data/EntityDataServices.java?rev=1684608&r1=1684607&r2=1684608&view=diff
>> ==============================================================================
>> --- ofbiz/trunk/framework/entityext/src/org/ofbiz/entityext/data/EntityDataServices.java (original)
>> +++ ofbiz/trunk/framework/entityext/src/org/ofbiz/entityext/data/EntityDataServices.java Wed Jun 10 09:01:30 2015
>> @@ -31,6 +31,9 @@ import java.util.List;
>>  import java.util.Locale;
>>  import java.util.Map;
>>  +import org.apache.commons.codec.binary.Base64;
>> +import org.apache.shiro.crypto.AesCipherService;
>> +import org.ofbiz.base.crypto.DesCrypt;
>>  import org.ofbiz.base.util.Debug;
>>  import org.ofbiz.base.util.FileUtil;
>>  import org.ofbiz.base.util.GeneralException;
>> @@ -44,6 +47,7 @@ import org.ofbiz.entity.GenericValue;
>>  import org.ofbiz.entity.datasource.GenericHelperInfo;
>>  import org.ofbiz.entity.jdbc.DatabaseUtil;
>>  import org.ofbiz.entity.model.ModelEntity;
>> +import org.ofbiz.entity.model.ModelField;
>>  import org.ofbiz.entity.util.EntityListIterator;
>>  import org.ofbiz.entity.util.EntityQuery;
>>  import org.ofbiz.security.Security;
>> @@ -445,4 +449,95 @@ public class EntityDataServices {
>>            return ServiceUtil.returnSuccess();
>>      }
>> +
>> +    public static Map<String, Object> reencryptPrivateKeys(DispatchContext dctx, Map<String, Object> context) {
>> +        Delegator delegator = dctx.getDelegator();
>> +        Security security = dctx.getSecurity();
>> +        Locale locale = (Locale) context.get("locale");
>> +
>> +        // check permission
>> +        GenericValue userLogin = (GenericValue) context.get("userLogin");
>> +        if (!security.hasPermission("ENTITY_MAINT", userLogin)) {
>> +            return ServiceUtil.returnError(UtilProperties.getMessage(resource, "EntityExtServicePermissionNotGranted", locale));
>> +        }
>> +        String oldKey = (String) context.get("oldKey");
>> +        String newKey = (String) context.get("newKey");
>> +        AesCipherService cipherService = new AesCipherService();
>> +        try {
>> +            List<GenericValue> rows = EntityQuery.use(delegator).from("EntityKeyStore").queryList();
>> +            for (GenericValue row: rows) {
>> +                byte[] keyBytes = Base64.decodeBase64(row.getString("keyText"));
>> +                Debug.logInfo("Processing entry " + row.getString("keyName") + " with key: " + row.getString("keyText"), module);
>> +                if (oldKey != null) {
>> +                    Debug.logInfo("Decrypting with old key: " + oldKey, module);
>> +                    try {
>> +                        keyBytes = cipherService.decrypt(keyBytes, Base64.decodeBase64(oldKey)).getBytes();
>> +                    } catch(Exception e) {
>> +                        Debug.logInfo("Failed to decrypt with Shiro cipher; trying with old cipher", module);
>> +                        try {
>> +                            keyBytes = DesCrypt.decrypt(DesCrypt.getDesKey(Base64.decodeBase64(oldKey)), keyBytes);
>> +                        } catch(Exception e1) {
>> +                            Debug.logError(e1, module);
>> +                            return ServiceUtil.returnError(e1.getMessage());
>> +                        }
>> +                    }
>> +                }
>> +                String newKeyText;
>> +                if (newKey != null) {
>> +                    Debug.logInfo("Encrypting with new key: " + oldKey, module);
>> +                    newKeyText = cipherService.encrypt(keyBytes, Base64.decodeBase64(newKey)).toBase64();
>> +                } else {
>> +                    newKeyText = Base64.encodeBase64String(keyBytes);
>> +                }
>> +                Debug.logInfo("Storing new encrypted value: " + newKeyText, module);
>> +                row.setString("keyText", newKeyText);
>> +                row.store();
>> +            }
>> +        } catch(GenericEntityException gee) {
>> +            Debug.logError(gee, module);
>> +            return ServiceUtil.returnError(gee.getMessage());
>> +        }
>> +        delegator.clearAllCaches();
>> +        return ServiceUtil.returnSuccess();
>> +    }
>> +
>> +    public static Map<String, Object> reencryptFields(DispatchContext dctx, Map<String, Object> context) {
>> +        Delegator delegator = dctx.getDelegator();
>> +        Security security = dctx.getSecurity();
>> +        Locale locale = (Locale) context.get("locale");
>> +
>> +        // check permission
>> +        GenericValue userLogin = (GenericValue) context.get("userLogin");
>> +        if (!security.hasPermission("ENTITY_MAINT", userLogin)) {
>> +            return ServiceUtil.returnError(UtilProperties.getMessage(resource, "EntityExtServicePermissionNotGranted", locale));
>> +        }
>> +
>> +        String groupName = (String) context.get("groupName");
>> +
>> +        Map<String, ModelEntity> modelEntities;
>> +        try {
>> +            modelEntities = delegator.getModelEntityMapByGroup(groupName);
>> +        } catch (GenericEntityException e) {
>> +            Debug.logError(e, "Error getting list of entities in group: " + e.toString(), module);
>> +            return ServiceUtil.returnError(UtilProperties.getMessage(resource, "EntityExtErrorGettingListOfEntityInGroup", UtilMisc.toMap("errorString", e.toString()), locale));
>> +        }
>> +
>> +        for (ModelEntity modelEntity: modelEntities.values()) {
>> +            List<ModelField> fields = modelEntity.getFieldsUnmodifiable();
>> +            for (ModelField field: fields) {
>> +                if (field.getEncryptMethod().isEncrypted()) {
>> +                    try {
>> +                        List<GenericValue> rows = EntityQuery.use(delegator).from(modelEntity.getEntityName()).select(field.getName()).queryList();
>> +                        for (GenericValue row: rows) {
>> +                            row.setString(field.getName(), row.getString(field.getName()));
>> +                            row.store();
>> +                        }
>> +                    } catch(GenericEntityException gee) {
>> +                        return ServiceUtil.returnError(gee.getMessage());
>> +                    }
>> +                }
>> +            }
>> +        }
>> +        return ServiceUtil.returnSuccess();
>> +    }
>>  }
>> 
>> 
>> 
>