You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@cayenne.apache.org by aa...@apache.org on 2014/04/03 13:03:51 UTC

svn commit: r1584340 - in /cayenne/main/trunk/cayenne-crypto/src: main/java/org/apache/cayenne/crypto/ main/java/org/apache/cayenne/crypto/cipher/ main/java/org/apache/cayenne/crypto/transformer/bytes/ test/java/org/apache/cayenne/crypto/transformer/by...

Author: aadamchik
Date: Thu Apr  3 11:03:51 2014
New Revision: 1584340

URL: http://svn.apache.org/r1584340
Log:
CAY-1916 cayenne-crypto module that enables data encryption for certain model attributes

BytesTransformer to encapsulate crypto protocol .. IN PROGRESS

Added:
    cayenne/main/trunk/cayenne-crypto/src/main/java/org/apache/cayenne/crypto/transformer/bytes/
    cayenne/main/trunk/cayenne-crypto/src/main/java/org/apache/cayenne/crypto/transformer/bytes/BytesTransformer.java
      - copied, changed from r1584339, cayenne/main/trunk/cayenne-crypto/src/main/java/org/apache/cayenne/crypto/cipher/CipherFactory.java
    cayenne/main/trunk/cayenne-crypto/src/main/java/org/apache/cayenne/crypto/transformer/bytes/BytesTransformerFactory.java
      - copied, changed from r1584339, cayenne/main/trunk/cayenne-crypto/src/main/java/org/apache/cayenne/crypto/cipher/CipherFactory.java
    cayenne/main/trunk/cayenne-crypto/src/main/java/org/apache/cayenne/crypto/transformer/bytes/CbcBytesTransformerFactory.java
    cayenne/main/trunk/cayenne-crypto/src/main/java/org/apache/cayenne/crypto/transformer/bytes/CbcEncryptor.java
    cayenne/main/trunk/cayenne-crypto/src/main/java/org/apache/cayenne/crypto/transformer/bytes/DefaultBytesTransformerFactory.java
    cayenne/main/trunk/cayenne-crypto/src/main/java/org/apache/cayenne/crypto/transformer/bytes/EncryptorWithKeyName.java
      - copied, changed from r1584339, cayenne/main/trunk/cayenne-crypto/src/main/java/org/apache/cayenne/crypto/cipher/CipherFactory.java
    cayenne/main/trunk/cayenne-crypto/src/test/java/org/apache/cayenne/crypto/transformer/bytes/
    cayenne/main/trunk/cayenne-crypto/src/test/java/org/apache/cayenne/crypto/transformer/bytes/CbcEncryptorTest.java
    cayenne/main/trunk/cayenne-crypto/src/test/java/org/apache/cayenne/crypto/transformer/bytes/EncryptorWithKeyNameTest.java
      - copied, changed from r1584339, cayenne/main/trunk/cayenne-crypto/src/main/java/org/apache/cayenne/crypto/cipher/CipherFactory.java
Modified:
    cayenne/main/trunk/cayenne-crypto/src/main/java/org/apache/cayenne/crypto/CryptoConstants.java
    cayenne/main/trunk/cayenne-crypto/src/main/java/org/apache/cayenne/crypto/CryptoModuleBuilder.java
    cayenne/main/trunk/cayenne-crypto/src/main/java/org/apache/cayenne/crypto/cipher/CipherFactory.java
    cayenne/main/trunk/cayenne-crypto/src/main/java/org/apache/cayenne/crypto/cipher/DefaultCipherFactory.java

Modified: cayenne/main/trunk/cayenne-crypto/src/main/java/org/apache/cayenne/crypto/CryptoConstants.java
URL: http://svn.apache.org/viewvc/cayenne/main/trunk/cayenne-crypto/src/main/java/org/apache/cayenne/crypto/CryptoConstants.java?rev=1584340&r1=1584339&r2=1584340&view=diff
==============================================================================
--- cayenne/main/trunk/cayenne-crypto/src/main/java/org/apache/cayenne/crypto/CryptoConstants.java (original)
+++ cayenne/main/trunk/cayenne-crypto/src/main/java/org/apache/cayenne/crypto/CryptoConstants.java Thu Apr  3 11:03:51 2014
@@ -53,4 +53,9 @@ public interface CryptoConstants {
      */
     public static final String KEY_PASSWORD = "cayenne.crypto.key.password";
 
+    /**
+     * A symbolic name of the default encryption key in the keystore.
+     */
+    public static final String DEFAULT_KEY_ALIAS = "cayenne.crypto.key.alias";
+
 }

Modified: cayenne/main/trunk/cayenne-crypto/src/main/java/org/apache/cayenne/crypto/CryptoModuleBuilder.java
URL: http://svn.apache.org/viewvc/cayenne/main/trunk/cayenne-crypto/src/main/java/org/apache/cayenne/crypto/CryptoModuleBuilder.java?rev=1584340&r1=1584339&r2=1584340&view=diff
==============================================================================
--- cayenne/main/trunk/cayenne-crypto/src/main/java/org/apache/cayenne/crypto/CryptoModuleBuilder.java (original)
+++ cayenne/main/trunk/cayenne-crypto/src/main/java/org/apache/cayenne/crypto/CryptoModuleBuilder.java Thu Apr  3 11:03:51 2014
@@ -34,6 +34,8 @@ import org.apache.cayenne.crypto.map.Pat
 import org.apache.cayenne.crypto.reader.CryptoRowReaderFactoryDecorator;
 import org.apache.cayenne.crypto.transformer.DefaultTransformerFactory;
 import org.apache.cayenne.crypto.transformer.TransformerFactory;
+import org.apache.cayenne.crypto.transformer.bytes.BytesTransformerFactory;
+import org.apache.cayenne.crypto.transformer.bytes.DefaultBytesTransformerFactory;
 import org.apache.cayenne.crypto.transformer.value.ValueTransformerFactory;
 import org.apache.cayenne.di.Binder;
 import org.apache.cayenne.di.MapBuilder;
@@ -231,6 +233,7 @@ public class CryptoModuleBuilder {
                 binder.bind(CipherFactory.class).to(cipherFactoryType);
                 binder.bind(TransformerFactory.class).to(DefaultTransformerFactory.class);
                 binder.bind(ValueTransformerFactory.class).to(valueTransformerFactoryType);
+                binder.bind(BytesTransformerFactory.class).to(DefaultBytesTransformerFactory.class);
                 binder.bind(KeySource.class).to(keySourceType);
 
                 if (columnMapperPattern != null) {

Modified: cayenne/main/trunk/cayenne-crypto/src/main/java/org/apache/cayenne/crypto/cipher/CipherFactory.java
URL: http://svn.apache.org/viewvc/cayenne/main/trunk/cayenne-crypto/src/main/java/org/apache/cayenne/crypto/cipher/CipherFactory.java?rev=1584340&r1=1584339&r2=1584340&view=diff
==============================================================================
--- cayenne/main/trunk/cayenne-crypto/src/main/java/org/apache/cayenne/crypto/cipher/CipherFactory.java (original)
+++ cayenne/main/trunk/cayenne-crypto/src/main/java/org/apache/cayenne/crypto/cipher/CipherFactory.java Thu Apr  3 11:03:51 2014
@@ -33,4 +33,11 @@ public interface CipherFactory {
      *         null if the factory does not support cipher-based encryption.
      */
     Cipher cipher();
+
+    /**
+     * Returns the block size for the ciphers created by this factory. This
+     * information is needed for the callers to presize they various arrays
+     * before a cipher is available.
+     */
+    int blockSize();
 }

Modified: cayenne/main/trunk/cayenne-crypto/src/main/java/org/apache/cayenne/crypto/cipher/DefaultCipherFactory.java
URL: http://svn.apache.org/viewvc/cayenne/main/trunk/cayenne-crypto/src/main/java/org/apache/cayenne/crypto/cipher/DefaultCipherFactory.java?rev=1584340&r1=1584339&r2=1584340&view=diff
==============================================================================
--- cayenne/main/trunk/cayenne-crypto/src/main/java/org/apache/cayenne/crypto/cipher/DefaultCipherFactory.java (original)
+++ cayenne/main/trunk/cayenne-crypto/src/main/java/org/apache/cayenne/crypto/cipher/DefaultCipherFactory.java Thu Apr  3 11:03:51 2014
@@ -37,6 +37,7 @@ import org.apache.cayenne.di.Inject;
 public class DefaultCipherFactory implements CipherFactory {
 
     protected String transformation;
+    protected int blockSize;
 
     public DefaultCipherFactory(@Inject(CryptoConstants.PROPERTIES_MAP) Map<String, String> properties) {
         String algorithm = properties.get(CryptoConstants.CIPHER_ALGORITHM);
@@ -58,6 +59,7 @@ public class DefaultCipherFactory implem
         }
 
         this.transformation = algorithm + "/" + mode + "/" + padding;
+        this.blockSize = cipher().getBlockSize();
     }
 
     @Override
@@ -70,4 +72,9 @@ public class DefaultCipherFactory implem
             throw new CayenneCryptoException("Error instantiating a cipher - no such padding: " + transformation, e);
         }
     }
+    
+    @Override
+    public int blockSize() {
+        return blockSize;
+    }
 }

Copied: cayenne/main/trunk/cayenne-crypto/src/main/java/org/apache/cayenne/crypto/transformer/bytes/BytesTransformer.java (from r1584339, cayenne/main/trunk/cayenne-crypto/src/main/java/org/apache/cayenne/crypto/cipher/CipherFactory.java)
URL: http://svn.apache.org/viewvc/cayenne/main/trunk/cayenne-crypto/src/main/java/org/apache/cayenne/crypto/transformer/bytes/BytesTransformer.java?p2=cayenne/main/trunk/cayenne-crypto/src/main/java/org/apache/cayenne/crypto/transformer/bytes/BytesTransformer.java&p1=cayenne/main/trunk/cayenne-crypto/src/main/java/org/apache/cayenne/crypto/cipher/CipherFactory.java&r1=1584339&r2=1584340&rev=1584340&view=diff
==============================================================================
--- cayenne/main/trunk/cayenne-crypto/src/main/java/org/apache/cayenne/crypto/cipher/CipherFactory.java (original)
+++ cayenne/main/trunk/cayenne-crypto/src/main/java/org/apache/cayenne/crypto/transformer/bytes/BytesTransformer.java Thu Apr  3 11:03:51 2014
@@ -16,21 +16,18 @@
  *  specific language governing permissions and limitations
  *  under the License.
  ****************************************************************/
-package org.apache.cayenne.crypto.cipher;
-
-import javax.crypto.Cipher;
+package org.apache.cayenne.crypto.transformer.bytes;
 
 /**
  * @since 3.2
  */
-public interface CipherFactory {
+public interface BytesTransformer {
 
     /**
-     * Creates and returns a new {@link Cipher} configured using settings known
-     * to the factory implementation.
-     * 
-     * @return a new Cipher that is guaranteed to be unused by other callers or
-     *         null if the factory does not support cipher-based encryption.
+     * Returns the size of the transformed data in bytes. This information
+     * allows the caller to pre-size the output array.
      */
-    Cipher cipher();
+    int getOutputSize(int inputLength);
+
+    void transform(byte[] input, byte[] output, int outputOffset);
 }

Copied: cayenne/main/trunk/cayenne-crypto/src/main/java/org/apache/cayenne/crypto/transformer/bytes/BytesTransformerFactory.java (from r1584339, cayenne/main/trunk/cayenne-crypto/src/main/java/org/apache/cayenne/crypto/cipher/CipherFactory.java)
URL: http://svn.apache.org/viewvc/cayenne/main/trunk/cayenne-crypto/src/main/java/org/apache/cayenne/crypto/transformer/bytes/BytesTransformerFactory.java?p2=cayenne/main/trunk/cayenne-crypto/src/main/java/org/apache/cayenne/crypto/transformer/bytes/BytesTransformerFactory.java&p1=cayenne/main/trunk/cayenne-crypto/src/main/java/org/apache/cayenne/crypto/cipher/CipherFactory.java&r1=1584339&r2=1584340&rev=1584340&view=diff
==============================================================================
--- cayenne/main/trunk/cayenne-crypto/src/main/java/org/apache/cayenne/crypto/cipher/CipherFactory.java (original)
+++ cayenne/main/trunk/cayenne-crypto/src/main/java/org/apache/cayenne/crypto/transformer/bytes/BytesTransformerFactory.java Thu Apr  3 11:03:51 2014
@@ -16,21 +16,17 @@
  *  specific language governing permissions and limitations
  *  under the License.
  ****************************************************************/
-package org.apache.cayenne.crypto.cipher;
-
-import javax.crypto.Cipher;
+package org.apache.cayenne.crypto.transformer.bytes;
 
 /**
+ * A class that encapsulates Cayenne cryptography protocol, which is usually
+ * dependent on the encryption mode.
+ * 
  * @since 3.2
  */
-public interface CipherFactory {
+public interface BytesTransformerFactory {
+
+    BytesTransformer encryptor();
 
-    /**
-     * Creates and returns a new {@link Cipher} configured using settings known
-     * to the factory implementation.
-     * 
-     * @return a new Cipher that is guaranteed to be unused by other callers or
-     *         null if the factory does not support cipher-based encryption.
-     */
-    Cipher cipher();
+    BytesTransformer decryptor();
 }

Added: cayenne/main/trunk/cayenne-crypto/src/main/java/org/apache/cayenne/crypto/transformer/bytes/CbcBytesTransformerFactory.java
URL: http://svn.apache.org/viewvc/cayenne/main/trunk/cayenne-crypto/src/main/java/org/apache/cayenne/crypto/transformer/bytes/CbcBytesTransformerFactory.java?rev=1584340&view=auto
==============================================================================
--- cayenne/main/trunk/cayenne-crypto/src/main/java/org/apache/cayenne/crypto/transformer/bytes/CbcBytesTransformerFactory.java (added)
+++ cayenne/main/trunk/cayenne-crypto/src/main/java/org/apache/cayenne/crypto/transformer/bytes/CbcBytesTransformerFactory.java Thu Apr  3 11:03:51 2014
@@ -0,0 +1,114 @@
+/*****************************************************************
+ *   Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ ****************************************************************/
+package org.apache.cayenne.crypto.transformer.bytes;
+
+import java.io.UnsupportedEncodingException;
+import java.security.Key;
+import java.security.SecureRandom;
+import java.util.Queue;
+import java.util.concurrent.ConcurrentLinkedQueue;
+
+import javax.crypto.Cipher;
+
+import org.apache.cayenne.crypto.CayenneCryptoException;
+import org.apache.cayenne.crypto.cipher.CipherFactory;
+import org.apache.cayenne.crypto.key.KeySource;
+
+public class CbcBytesTransformerFactory implements BytesTransformerFactory {
+
+    private static final String KEY_NAME_CHARSET = "UTF-8";
+
+    private CipherFactory cipherFactory;
+    private Key key;
+    private byte[] keyName;
+    private int blockSize;
+    private Queue<SecureRandom> randoms;
+
+    public CbcBytesTransformerFactory(CipherFactory cipherFactory, KeySource keySource, String keyName) {
+
+        this.randoms = new ConcurrentLinkedQueue<SecureRandom>();
+        this.cipherFactory = cipherFactory;
+        this.blockSize = cipherFactory.blockSize();
+
+        byte[] keyNameBytes;
+        try {
+            keyNameBytes = keyName.getBytes(KEY_NAME_CHARSET);
+        } catch (UnsupportedEncodingException e) {
+            throw new CayenneCryptoException("Can't encode in " + KEY_NAME_CHARSET, e);
+        }
+
+        if (keyNameBytes.length == blockSize) {
+            this.keyName = keyNameBytes;
+        } else if (keyNameBytes.length < blockSize) {
+            this.keyName = new byte[blockSize];
+            System.arraycopy(keyNameBytes, 0, this.keyName, 0, keyNameBytes.length);
+        } else {
+            throw new CayenneCryptoException("Key name '" + keyName + "' is too long. Its byte form should not exceed "
+                    + blockSize + " bytes");
+        }
+    }
+
+    protected byte[] generateSeedIv() {
+
+        byte[] iv = new byte[blockSize];
+
+        // the idea of a queue of SecureRandoms for concurrency is taken from
+        // Tomcat's SessionIdGenerator. Also some code...
+
+        SecureRandom random = randoms.poll();
+        if (random == null) {
+            random = createSecureRandom();
+        }
+
+        random.nextBytes(iv);
+        randoms.add(random);
+
+        return iv;
+    }
+
+    /**
+     * Create a new random number generator instance we should use for
+     * generating session identifiers.
+     */
+    private SecureRandom createSecureRandom() {
+
+        // TODO: allow to customize provider?
+        SecureRandom result = new SecureRandom();
+
+        // Force seeding to take place
+        result.nextInt();
+        return result;
+    }
+
+    @Override
+    public BytesTransformer encryptor() {
+        Cipher cipher = cipherFactory.cipher();
+
+        BytesTransformer cbcEncryptor = new CbcEncryptor(cipher, key, generateSeedIv());
+
+        // TODO: make adding key name for versioning an optional property
+        return new EncryptorWithKeyName(cbcEncryptor, keyName, blockSize);
+    }
+
+    @Override
+    public BytesTransformer decryptor() {
+        throw new UnsupportedOperationException("TODO");
+    }
+
+}

Added: cayenne/main/trunk/cayenne-crypto/src/main/java/org/apache/cayenne/crypto/transformer/bytes/CbcEncryptor.java
URL: http://svn.apache.org/viewvc/cayenne/main/trunk/cayenne-crypto/src/main/java/org/apache/cayenne/crypto/transformer/bytes/CbcEncryptor.java?rev=1584340&view=auto
==============================================================================
--- cayenne/main/trunk/cayenne-crypto/src/main/java/org/apache/cayenne/crypto/transformer/bytes/CbcEncryptor.java (added)
+++ cayenne/main/trunk/cayenne-crypto/src/main/java/org/apache/cayenne/crypto/transformer/bytes/CbcEncryptor.java Thu Apr  3 11:03:51 2014
@@ -0,0 +1,89 @@
+/*****************************************************************
+ *   Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ ****************************************************************/
+package org.apache.cayenne.crypto.transformer.bytes;
+
+import java.security.InvalidAlgorithmParameterException;
+import java.security.InvalidKeyException;
+import java.security.Key;
+
+import javax.crypto.BadPaddingException;
+import javax.crypto.Cipher;
+import javax.crypto.IllegalBlockSizeException;
+import javax.crypto.ShortBufferException;
+import javax.crypto.spec.IvParameterSpec;
+
+import org.apache.cayenne.crypto.CayenneCryptoException;
+
+/**
+ * A {@link BytesTransformer} that encrypts the provided bytes. The first block
+ * in the encrypted bytes is the value of IV used to seed the CBC
+ * transformation. It will be needed for decryption. The object is stateful and
+ * is not thread-safe.
+ * 
+ * @since 3.2
+ */
+public class CbcEncryptor implements BytesTransformer {
+
+    private Cipher cipher;
+    private byte[] iv;
+    private Key key;
+    private int blockSize;
+
+    public CbcEncryptor(Cipher cipher, Key key, byte[] seedIv) {
+        this.key = key;
+        this.cipher = cipher;
+        this.iv = seedIv;
+        this.blockSize = cipher.getBlockSize();
+
+        if (iv.length != blockSize) {
+            throw new CayenneCryptoException("IV size is expected to be the same as block size. Was " + iv.length
+                    + "; block size was: " + blockSize);
+        }
+    }
+
+    @Override
+    public int getOutputSize(int inputLength) {
+        // add one block for IV storage
+        return blockSize + cipher.getOutputSize(inputLength);
+    }
+
+    @Override
+    public void transform(byte[] input, byte[] output, int outputOffset) {
+        try {
+            encrypt(input, output, outputOffset);
+        } catch (Exception e) {
+            throw new CayenneCryptoException("Error on encryption", e);
+        }
+    }
+
+    protected void encrypt(byte[] plain, byte[] encrypted, int outputOffset) throws InvalidKeyException,
+            InvalidAlgorithmParameterException, ShortBufferException, IllegalBlockSizeException, BadPaddingException {
+
+        // copy IV in the first block
+        System.arraycopy(iv, 0, encrypted, outputOffset, blockSize);
+
+        cipher.init(Cipher.ENCRYPT_MODE, key, new IvParameterSpec(iv));
+        int encBytes = cipher.doFinal(plain, 0, plain.length, encrypted, outputOffset + blockSize);
+
+        // store the last block of ciphertext to use as an IV for the next round
+        // of encryption...
+        System.arraycopy(encrypted, outputOffset + encBytes, iv, 0, blockSize);
+    }
+
+}

Added: cayenne/main/trunk/cayenne-crypto/src/main/java/org/apache/cayenne/crypto/transformer/bytes/DefaultBytesTransformerFactory.java
URL: http://svn.apache.org/viewvc/cayenne/main/trunk/cayenne-crypto/src/main/java/org/apache/cayenne/crypto/transformer/bytes/DefaultBytesTransformerFactory.java?rev=1584340&view=auto
==============================================================================
--- cayenne/main/trunk/cayenne-crypto/src/main/java/org/apache/cayenne/crypto/transformer/bytes/DefaultBytesTransformerFactory.java (added)
+++ cayenne/main/trunk/cayenne-crypto/src/main/java/org/apache/cayenne/crypto/transformer/bytes/DefaultBytesTransformerFactory.java Thu Apr  3 11:03:51 2014
@@ -0,0 +1,70 @@
+/*****************************************************************
+ *   Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ ****************************************************************/
+package org.apache.cayenne.crypto.transformer.bytes;
+
+import java.util.Map;
+
+import org.apache.cayenne.crypto.CayenneCryptoException;
+import org.apache.cayenne.crypto.CryptoConstants;
+import org.apache.cayenne.crypto.cipher.CipherFactory;
+import org.apache.cayenne.crypto.key.KeySource;
+import org.apache.cayenne.di.Inject;
+
+/**
+ * A {@link BytesTransformerFactory} that creates transformers depending on the
+ * encryption mode specified via properties.
+ * 
+ * @since 3.2
+ */
+public class DefaultBytesTransformerFactory implements BytesTransformerFactory {
+
+    private BytesTransformerFactory delegate;
+
+    public DefaultBytesTransformerFactory(@Inject(CryptoConstants.PROPERTIES_MAP) Map<String, String> properties,
+            @Inject CipherFactory cipherFactory, @Inject KeySource keySource) {
+
+        String mode = properties.get(CryptoConstants.CIPHER_MODE);
+        if (mode == null) {
+            throw new CayenneCryptoException("Cipher mode is not set. Property name: " + CryptoConstants.CIPHER_MODE);
+        }
+
+        String keyName = properties.get(CryptoConstants.DEFAULT_KEY_ALIAS);
+        if (keyName == null) {
+            throw new CayenneCryptoException("Default key alias is not set. Property name: "
+                    + CryptoConstants.DEFAULT_KEY_ALIAS);
+        }
+
+        if ("CBC".equals(mode)) {
+            this.delegate = new CbcBytesTransformerFactory(cipherFactory, keySource, keyName);
+        }
+        // TODO: ECB and other modes...
+        else {
+            throw new CayenneCryptoException("Unsupported mode: " + mode
+                    + ". The following modes are currently supported:  CBC");
+        }
+    }
+
+    public BytesTransformer encryptor() {
+        return delegate.encryptor();
+    }
+
+    public BytesTransformer decryptor() {
+        return delegate.decryptor();
+    }
+}

Copied: cayenne/main/trunk/cayenne-crypto/src/main/java/org/apache/cayenne/crypto/transformer/bytes/EncryptorWithKeyName.java (from r1584339, cayenne/main/trunk/cayenne-crypto/src/main/java/org/apache/cayenne/crypto/cipher/CipherFactory.java)
URL: http://svn.apache.org/viewvc/cayenne/main/trunk/cayenne-crypto/src/main/java/org/apache/cayenne/crypto/transformer/bytes/EncryptorWithKeyName.java?p2=cayenne/main/trunk/cayenne-crypto/src/main/java/org/apache/cayenne/crypto/transformer/bytes/EncryptorWithKeyName.java&p1=cayenne/main/trunk/cayenne-crypto/src/main/java/org/apache/cayenne/crypto/cipher/CipherFactory.java&r1=1584339&r2=1584340&rev=1584340&view=diff
==============================================================================
--- cayenne/main/trunk/cayenne-crypto/src/main/java/org/apache/cayenne/crypto/cipher/CipherFactory.java (original)
+++ cayenne/main/trunk/cayenne-crypto/src/main/java/org/apache/cayenne/crypto/transformer/bytes/EncryptorWithKeyName.java Thu Apr  3 11:03:51 2014
@@ -16,21 +16,30 @@
  *  specific language governing permissions and limitations
  *  under the License.
  ****************************************************************/
-package org.apache.cayenne.crypto.cipher;
+package org.apache.cayenne.crypto.transformer.bytes;
 
-import javax.crypto.Cipher;
+public class EncryptorWithKeyName implements BytesTransformer {
+
+    private BytesTransformer delegate;
+    private int blockSize;
+    private byte[] keyName;
+
+    public EncryptorWithKeyName(BytesTransformer delegate, byte[] keyName, int blockSize) {
+        this.delegate = delegate;
+        this.blockSize = blockSize;
+        this.keyName = keyName;
+    }
+
+    @Override
+    public int getOutputSize(int inputLength) {
+        // add one block for key name storage
+        return blockSize + delegate.getOutputSize(inputLength);
+    }
+
+    @Override
+    public void transform(byte[] input, byte[] output, int outputOffset) {
+        System.arraycopy(keyName, 0, output, outputOffset, blockSize);
+        delegate.transform(input, output, outputOffset + blockSize);
+    }
 
-/**
- * @since 3.2
- */
-public interface CipherFactory {
-
-    /**
-     * Creates and returns a new {@link Cipher} configured using settings known
-     * to the factory implementation.
-     * 
-     * @return a new Cipher that is guaranteed to be unused by other callers or
-     *         null if the factory does not support cipher-based encryption.
-     */
-    Cipher cipher();
 }

Added: cayenne/main/trunk/cayenne-crypto/src/test/java/org/apache/cayenne/crypto/transformer/bytes/CbcEncryptorTest.java
URL: http://svn.apache.org/viewvc/cayenne/main/trunk/cayenne-crypto/src/test/java/org/apache/cayenne/crypto/transformer/bytes/CbcEncryptorTest.java?rev=1584340&view=auto
==============================================================================
--- cayenne/main/trunk/cayenne-crypto/src/test/java/org/apache/cayenne/crypto/transformer/bytes/CbcEncryptorTest.java (added)
+++ cayenne/main/trunk/cayenne-crypto/src/test/java/org/apache/cayenne/crypto/transformer/bytes/CbcEncryptorTest.java Thu Apr  3 11:03:51 2014
@@ -0,0 +1,67 @@
+/*****************************************************************
+ *   Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ ****************************************************************/
+package org.apache.cayenne.crypto.transformer.bytes;
+
+import static org.junit.Assert.assertEquals;
+import static org.mockito.Mockito.mock;
+
+import java.io.UnsupportedEncodingException;
+import java.security.InvalidKeyException;
+import java.security.Key;
+import java.security.NoSuchAlgorithmException;
+
+import javax.crypto.Cipher;
+import javax.crypto.NoSuchPaddingException;
+import javax.crypto.spec.SecretKeySpec;
+
+import org.apache.cayenne.crypto.CayenneCryptoException;
+import org.junit.Test;
+
+public class CbcEncryptorTest {
+
+    @Test(expected = CayenneCryptoException.class)
+    public void testConstructor() throws UnsupportedEncodingException, NoSuchAlgorithmException, NoSuchPaddingException {
+
+        byte[] iv = { 1, 2, 3, 4, 5, 6 };
+        Key key = mock(Key.class);
+        Cipher cipher = Cipher.getInstance("DES/CBC/PKCS5Padding");
+        assertEquals(8, cipher.getBlockSize());
+
+        // must throw as IV sie and block size are different
+        new CbcEncryptor(cipher, key, iv);
+    }
+
+    @Test
+    public void testGetOutputSize() throws UnsupportedEncodingException, NoSuchAlgorithmException,
+            NoSuchPaddingException, InvalidKeyException {
+
+        byte[] iv = { 1, 2, 3, 4, 5, 6, 7, 8 };
+        byte[] keyBytes = { 1, 2, 3, 4, 5, 6, 7, 8 };
+        Key key = new SecretKeySpec(keyBytes, "DES");
+
+        Cipher cipher = Cipher.getInstance("DES/CBC/PKCS5Padding");
+        cipher.init(Cipher.ENCRYPT_MODE, key);
+        assertEquals(8, cipher.getBlockSize());
+
+        // try with non-standard block size too...
+        CbcEncryptor encryptor = new CbcEncryptor(cipher, key, iv);
+        assertEquals(24, encryptor.getOutputSize(11));
+    }
+
+}

Copied: cayenne/main/trunk/cayenne-crypto/src/test/java/org/apache/cayenne/crypto/transformer/bytes/EncryptorWithKeyNameTest.java (from r1584339, cayenne/main/trunk/cayenne-crypto/src/main/java/org/apache/cayenne/crypto/cipher/CipherFactory.java)
URL: http://svn.apache.org/viewvc/cayenne/main/trunk/cayenne-crypto/src/test/java/org/apache/cayenne/crypto/transformer/bytes/EncryptorWithKeyNameTest.java?p2=cayenne/main/trunk/cayenne-crypto/src/test/java/org/apache/cayenne/crypto/transformer/bytes/EncryptorWithKeyNameTest.java&p1=cayenne/main/trunk/cayenne-crypto/src/main/java/org/apache/cayenne/crypto/cipher/CipherFactory.java&r1=1584339&r2=1584340&rev=1584340&view=diff
==============================================================================
--- cayenne/main/trunk/cayenne-crypto/src/main/java/org/apache/cayenne/crypto/cipher/CipherFactory.java (original)
+++ cayenne/main/trunk/cayenne-crypto/src/test/java/org/apache/cayenne/crypto/transformer/bytes/EncryptorWithKeyNameTest.java Thu Apr  3 11:03:51 2014
@@ -16,21 +16,28 @@
  *  specific language governing permissions and limitations
  *  under the License.
  ****************************************************************/
-package org.apache.cayenne.crypto.cipher;
+package org.apache.cayenne.crypto.transformer.bytes;
 
-import javax.crypto.Cipher;
+import static org.junit.Assert.assertEquals;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+import java.io.UnsupportedEncodingException;
+
+import org.junit.Test;
+
+public class EncryptorWithKeyNameTest {
+
+    @Test
+    public void testGetOutputSize() throws UnsupportedEncodingException {
+
+        byte[] keyName = "mykey".getBytes("UTF-8");
+        BytesTransformer delegate = mock(BytesTransformer.class);
+        when(delegate.getOutputSize(8)).thenReturn(8);
+
+        // try with non-standard block size..
+        EncryptorWithKeyName encryptor = new EncryptorWithKeyName(delegate, keyName, 17);
+        assertEquals(25, encryptor.getOutputSize(8));
+    }
 
-/**
- * @since 3.2
- */
-public interface CipherFactory {
-
-    /**
-     * Creates and returns a new {@link Cipher} configured using settings known
-     * to the factory implementation.
-     * 
-     * @return a new Cipher that is guaranteed to be unused by other callers or
-     *         null if the factory does not support cipher-based encryption.
-     */
-    Cipher cipher();
 }