001    /*
002     * Cumulus4j - Securing your data in the cloud - http://cumulus4j.org
003     * Copyright (C) 2011 NightLabs Consulting GmbH
004     *
005     * This program is free software: you can redistribute it and/or modify
006     * it under the terms of the GNU Affero General Public License as
007     * published by the Free Software Foundation, either version 3 of the
008     * License, or (at your option) any later version.
009     *
010     * This program is distributed in the hope that it will be useful,
011     * but WITHOUT ANY WARRANTY; without even the implied warranty of
012     * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
013     * GNU Affero General Public License for more details.
014     *
015     * You should have received a copy of the GNU Affero General Public License
016     * along with this program.  If not, see <http://www.gnu.org/licenses/>.
017     */
018    package org.cumulus4j.store;
019    
020    import javax.crypto.BadPaddingException;
021    import javax.crypto.Cipher;
022    import javax.crypto.IllegalBlockSizeException;
023    import javax.crypto.spec.IvParameterSpec;
024    import javax.crypto.spec.SecretKeySpec;
025    
026    import org.cumulus4j.store.crypto.AbstractCryptoManager;
027    import org.cumulus4j.store.crypto.AbstractCryptoSession;
028    import org.cumulus4j.store.crypto.Ciphertext;
029    import org.cumulus4j.store.crypto.CryptoContext;
030    import org.cumulus4j.store.crypto.CryptoSession;
031    import org.cumulus4j.store.crypto.Plaintext;
032    
033    /**
034     * Dummy crypto-manager for debugging and testing.
035     *
036     * @author Marco หงุ่ยตระกูล-Schulze - marco at nightlabs dot de
037     */
038    public class DummyCryptoManager extends AbstractCryptoManager
039    {
040            @Override
041            protected CryptoSession createCryptoSession() {
042                    return new DummySession();
043            }
044    
045            private static final class DummySession
046            extends AbstractCryptoSession
047            {
048                    // key length: 128 bits
049                    private static final byte[] dummyKey = { 'D', 'e', 'r', ' ', 'F', 'e', 'r', 'd', ' ', 'h', 'a', 't', ' ', 'v', 'i', 'e' };
050                    // initialization vector length: 128 bits
051                    private static final IvParameterSpec iv = new IvParameterSpec(new byte[] {'b', 'l', 'a', 't', 'r', 'u', 'l', 'l', 'a', 'l', 'a', 't', 'r', 'a', 'r', 'a'});
052    
053                    private static final String ALGORITHM = "AES";
054                    private static final String ALGORITHM_WITH_PARAMS = ALGORITHM + "/CBC/PKCS5Padding";
055    
056                    private Cipher encrypter;
057                    private Cipher decrypter;
058                    {
059                            try {
060                                    SecretKeySpec key = new SecretKeySpec(dummyKey, ALGORITHM);
061                                    encrypter = Cipher.getInstance(ALGORITHM_WITH_PARAMS);
062                                    encrypter.init(Cipher.ENCRYPT_MODE, key, iv);
063                                    decrypter = Cipher.getInstance(ALGORITHM_WITH_PARAMS);
064                                    decrypter.init(Cipher.DECRYPT_MODE, key, iv);
065                            } catch (Exception ex) {
066                                    throw new RuntimeException(ex);
067                            }
068                    }
069    
070                    @Override
071                    public Ciphertext encrypt(CryptoContext cryptoContext, Plaintext plaintext)
072                    {
073                            // First get the required resources (that are cleared in close()).
074                            Cipher c = encrypter;
075    
076                            // Then assert that we are not yet closed. This makes sure that we definitely can continue
077                            // even if close() is called right now simultaneously.
078                            assertNotClosed();
079    
080                            Ciphertext result = new Ciphertext();
081                            result.setKeyID(12345);
082    
083                            synchronized (c) {
084                                    try {
085                                            result.setData(
086                                                            c.doFinal(plaintext.getData())
087                                            );
088                                    } catch (IllegalBlockSizeException e) {
089                                            throw new RuntimeException(e);
090                                    } catch (BadPaddingException e) {
091                                            throw new RuntimeException(e);
092                                    }
093                            }
094    
095                            return result;
096                    }
097    
098                    @Override
099                    public Plaintext decrypt(CryptoContext cryptoContext, Ciphertext ciphertext)
100                    {
101                            if (ciphertext.getKeyID() != 12345)
102                                    throw new IllegalArgumentException("No key with this keyID: " + ciphertext.getKeyID());
103    
104                            // First get the required resources (that are cleared in close()).
105                            Cipher c = decrypter;
106    
107                            // Then assert that we are not yet closed. This makes sure that we definitely can continue
108                            // even if close() is called right now simultaneously.
109                            assertNotClosed();
110    
111                            Plaintext result = new Plaintext();
112    
113                            synchronized (c) {
114                                    try {
115                                            result.setData(
116                                                            c.doFinal(ciphertext.getData())
117                                            );
118                                    } catch (IllegalBlockSizeException e) {
119                                            throw new RuntimeException(e);
120                                    } catch (BadPaddingException e) {
121                                            throw new RuntimeException(e);
122                                    }
123                            }
124    
125                            return result;
126                    }
127    
128                    @Override
129                    public void close() {
130                            super.close();
131                            encrypter = null;
132                            decrypter = null;
133                    }
134            }
135    
136    }