PageRenderTime 50ms CodeModel.GetById 1ms app.highlight 44ms RepoModel.GetById 1ms app.codeStats 1ms

/hazelcast/src/main/java/com/hazelcast/nio/CipherHelper.java

https://bitbucket.org/gabral6_gmailcom/hazelcast
Java | 253 lines | 204 code | 29 blank | 20 comment | 30 complexity | 380f1248decd829a16874cc47b8f148b MD5 | raw file
  1/*
  2 * Copyright (c) 2008-2013, Hazelcast, Inc. All Rights Reserved.
  3 *
  4 * Licensed under the Apache License, Version 2.0 (the "License");
  5 * you may not use this file except in compliance with the License.
  6 * You may obtain a copy of the License at
  7 *
  8 * http://www.apache.org/licenses/LICENSE-2.0
  9 *
 10 * Unless required by applicable law or agreed to in writing, software
 11 * distributed under the License is distributed on an "AS IS" BASIS,
 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 13 * See the License for the specific language governing permissions and
 14 * limitations under the License.
 15 */
 16
 17package com.hazelcast.nio;
 18
 19import com.hazelcast.config.AsymmetricEncryptionConfig;
 20import com.hazelcast.config.SymmetricEncryptionConfig;
 21import com.hazelcast.logging.ILogger;
 22import com.hazelcast.logging.Logger;
 23
 24import javax.crypto.Cipher;
 25import javax.crypto.SecretKey;
 26import javax.crypto.SecretKeyFactory;
 27import javax.crypto.spec.*;
 28import java.nio.ByteBuffer;
 29import java.security.*;
 30import java.security.spec.AlgorithmParameterSpec;
 31import java.security.spec.KeySpec;
 32import java.util.logging.Level;
 33
 34final class CipherHelper {
 35    private static AsymmetricCipherBuilder asymmetricCipherBuilder = null;
 36    private static SymmetricCipherBuilder symmetricCipherBuilder = null;
 37
 38    final static ILogger logger = Logger.getLogger(CipherHelper.class.getName());
 39
 40    static {
 41        try {
 42            if (Boolean.getBoolean("hazelcast.security.bouncy.enabled")) {
 43                String provider = "org.bouncycastle.jce.provider.BouncyCastleProvider";
 44                Security.addProvider((Provider) Class.forName(provider).newInstance());
 45            }
 46        } catch (Exception e) {
 47            logger.log(Level.WARNING, e.getMessage(), e);
 48        }
 49    }
 50
 51    @SuppressWarnings("SynchronizedMethod")
 52    public static synchronized Cipher createAsymmetricReaderCipher(IOService ioService, String remoteAlias) throws Exception {
 53        if (asymmetricCipherBuilder == null) {
 54            asymmetricCipherBuilder = new AsymmetricCipherBuilder(ioService);
 55        }
 56        return asymmetricCipherBuilder.getReaderCipher(remoteAlias);
 57    }
 58
 59    @SuppressWarnings("SynchronizedMethod")
 60    public static synchronized Cipher createAsymmetricWriterCipher(IOService ioService) throws Exception {
 61        if (asymmetricCipherBuilder == null) {
 62            asymmetricCipherBuilder = new AsymmetricCipherBuilder(ioService);
 63        }
 64        return asymmetricCipherBuilder.getWriterCipher();
 65    }
 66
 67    @SuppressWarnings("SynchronizedMethod")
 68    public static synchronized Cipher createSymmetricReaderCipher(IOService ioService) throws Exception {
 69        if (symmetricCipherBuilder == null) {
 70            symmetricCipherBuilder = new SymmetricCipherBuilder(ioService.getSymmetricEncryptionConfig());
 71        }
 72        return symmetricCipherBuilder.getReaderCipher(null);
 73    }
 74
 75    @SuppressWarnings("SynchronizedMethod")
 76    public static synchronized Cipher createSymmetricWriterCipher(IOService ioService) throws Exception {
 77        if (symmetricCipherBuilder == null) {
 78            symmetricCipherBuilder = new SymmetricCipherBuilder(ioService.getSymmetricEncryptionConfig());
 79        }
 80        return symmetricCipherBuilder.getWriterCipher();
 81    }
 82
 83    public static boolean isAsymmetricEncryptionEnabled(IOService ioService) {
 84        AsymmetricEncryptionConfig aec = ioService.getAsymmetricEncryptionConfig();
 85        return (aec != null && aec.isEnabled());
 86    }
 87
 88    public static boolean isSymmetricEncryptionEnabled(IOService ioService) {
 89        SymmetricEncryptionConfig sec = ioService.getSymmetricEncryptionConfig();
 90        return (sec != null && sec.isEnabled());
 91    }
 92
 93    public static String getKeyAlias(IOService ioService) {
 94        AsymmetricEncryptionConfig aec = ioService.getAsymmetricEncryptionConfig();
 95        return aec.getKeyAlias();
 96    }
 97
 98    interface CipherBuilder {
 99        Cipher getWriterCipher() throws Exception;
100
101        Cipher getReaderCipher(String param) throws Exception;
102
103        boolean isAsymmetric();
104    }
105
106    static class AsymmetricCipherBuilder implements CipherBuilder {
107        String algorithm = "RSA/NONE/PKCS1PADDING";
108        KeyStore keyStore;
109        private final IOService ioService;
110
111        AsymmetricCipherBuilder(IOService ioService) {
112            this.ioService = ioService;
113            try {
114                AsymmetricEncryptionConfig aec = ioService.getAsymmetricEncryptionConfig();
115                algorithm = aec.getAlgorithm();
116                keyStore = KeyStore.getInstance(aec.getStoreType());
117                // get user password and file input stream
118                char[] password = aec.getStorePassword().toCharArray();
119                java.io.FileInputStream fis =
120                        new java.io.FileInputStream(aec.getStorePath());
121                keyStore.load(fis, password);
122                fis.close();
123            } catch (Exception e) {
124                logger.log(Level.WARNING, e.getMessage(), e);
125            }
126        }
127
128        public Cipher getReaderCipher(String remoteAlias) throws Exception {
129            java.security.cert.Certificate certificate = keyStore.getCertificate(remoteAlias);
130            PublicKey publicKey = certificate.getPublicKey();
131            Cipher cipher = Cipher.getInstance(algorithm);
132            cipher.init(Cipher.DECRYPT_MODE, publicKey);
133            return cipher;
134        }
135
136        public Cipher getWriterCipher() throws Exception {
137            AsymmetricEncryptionConfig aec = ioService.getAsymmetricEncryptionConfig();
138            Cipher cipher = Cipher.getInstance(algorithm);
139            KeyStore.PrivateKeyEntry pkEntry = (KeyStore.PrivateKeyEntry)
140                    keyStore.getEntry(aec.getKeyAlias(), new KeyStore.PasswordProtection(aec.getKeyPassword().toCharArray()));
141            PrivateKey privateKey = pkEntry.getPrivateKey();
142            cipher.init(Cipher.ENCRYPT_MODE, privateKey);
143            return cipher;
144        }
145
146        public boolean isAsymmetric() {
147            return true;
148        }
149    }
150
151    static class SymmetricCipherBuilder implements CipherBuilder {
152        final String algorithm;
153        // 8-byte Salt
154        final byte[] salt;
155        final String passPhrase;
156        final int iterationCount;
157        byte[] keyBytes;
158
159        SymmetricCipherBuilder(SymmetricEncryptionConfig sec) {
160            algorithm = sec.getAlgorithm();
161            passPhrase = sec.getPassword();
162            salt = createSalt(sec.getSalt());
163            iterationCount = sec.getIterationCount();
164            keyBytes = sec.getKey();
165        }
166
167        byte[] createSalt(String saltStr) {
168            long hash = 0;
169            char chars[] = saltStr.toCharArray();
170            for (char c : chars) {
171                hash = 31 * hash + c;
172            }
173            byte[] theSalt = new byte[8];
174            theSalt[0] = (byte) (hash >>> 56);
175            theSalt[1] = (byte) (hash >>> 48);
176            theSalt[2] = (byte) (hash >>> 40);
177            theSalt[3] = (byte) (hash >>> 32);
178            theSalt[4] = (byte) (hash >>> 24);
179            theSalt[5] = (byte) (hash >>> 16);
180            theSalt[6] = (byte) (hash >>> 8);
181            theSalt[7] = (byte) (hash);
182            return theSalt;
183        }
184
185        public Cipher create(boolean encryptMode) {
186            try {
187                int mode = (encryptMode) ? Cipher.ENCRYPT_MODE : Cipher.DECRYPT_MODE;
188                Cipher cipher = Cipher.getInstance(algorithm);
189                String keyAlgorithm = algorithm;
190                if (algorithm.indexOf('/') != -1) {
191                    keyAlgorithm = algorithm.substring(0, algorithm.indexOf('/'));
192                }
193                // 32-bit digest key=pass+salt
194                ByteBuffer bbPass = ByteBuffer.allocate(32);
195                MessageDigest md = MessageDigest.getInstance("MD5");
196                bbPass.put(md.digest(passPhrase.getBytes()));
197                md.reset();
198                byte[] saltDigest = md.digest(salt);
199                bbPass.put(saltDigest);
200                boolean isCBC = algorithm.indexOf("/CBC/") != -1;
201                SecretKey key = null;
202                //CBC mode requires IvParameter with 8 byte input
203                int ivLength = 8;
204                AlgorithmParameterSpec paramSpec = null;
205                if (keyBytes == null) {
206                    keyBytes = bbPass.array();
207                }
208                if (algorithm.startsWith("AES")) {
209                    ivLength = 16;
210                    key = new SecretKeySpec(keyBytes, "AES");
211                } else if (algorithm.startsWith("Blowfish")) {
212                    key = new SecretKeySpec(keyBytes, "Blowfish");
213                } else if (algorithm.startsWith("DESede")) {
214                    //requires at least 192 bits (24 bytes)
215                    KeySpec keySpec = new DESedeKeySpec(keyBytes);
216                    key = SecretKeyFactory.getInstance("DESede").generateSecret(keySpec);
217                } else if (algorithm.startsWith("DES")) {
218                    KeySpec keySpec = new DESKeySpec(keyBytes);
219                    key = SecretKeyFactory.getInstance("DES").generateSecret(keySpec);
220                } else if (algorithm.startsWith("PBEWith")) {
221                    paramSpec = new PBEParameterSpec(salt, iterationCount);
222                    KeySpec keySpec = new PBEKeySpec(passPhrase.toCharArray(), salt, iterationCount);
223                    key = SecretKeyFactory.getInstance(keyAlgorithm).generateSecret(keySpec);
224                }
225                if (isCBC) {
226                    byte[] iv = (ivLength == 8) ? salt : saltDigest;
227                    paramSpec = new IvParameterSpec(iv);
228                }
229                cipher.init(mode, key, paramSpec);
230                return cipher;
231            } catch (Throwable e) {
232                throw new RuntimeException("unable to create Cipher:" + e.getMessage(), e);
233            }
234        }
235
236        public Cipher getWriterCipher() {
237            return create(true);
238        }
239
240        public Cipher getReaderCipher(String ignored) {
241            return create(false);
242        }
243
244        public boolean isAsymmetric() {
245            return false;
246        }
247    }
248
249    public static void handleCipherException(Exception e, Connection connection) {
250        logger.log(Level.WARNING, e.getMessage(), e);
251        connection.close();
252    }
253}