| /* |
| * 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.synapse.securevault; |
| |
| import org.apache.commons.logging.Log; |
| import org.apache.commons.logging.LogFactory; |
| import org.apache.synapse.securevault.definition.CipherInformation; |
| import org.apache.synapse.securevault.definition.IdentityKeyStoreInformation; |
| import org.apache.synapse.securevault.definition.KeyStoreInformation; |
| import org.apache.synapse.securevault.definition.TrustKeyStoreInformation; |
| import org.apache.synapse.securevault.keystore.IdentityKeyStoreWrapper; |
| import org.apache.synapse.securevault.keystore.KeyStoreWrapper; |
| import org.apache.synapse.securevault.keystore.TrustKeyStoreWrapper; |
| import org.apache.synapse.securevault.secret.SecretInformation; |
| |
| import javax.crypto.Cipher; |
| import javax.crypto.CipherOutputStream; |
| import javax.crypto.NoSuchPaddingException; |
| import java.io.ByteArrayInputStream; |
| import java.io.ByteArrayOutputStream; |
| import java.io.IOException; |
| import java.io.InputStream; |
| import java.security.InvalidKeyException; |
| import java.security.Key; |
| import java.security.NoSuchAlgorithmException; |
| import java.security.NoSuchProviderException; |
| |
| /** |
| * Wraps the cipher and expose abstraction need for synapse ciphering |
| */ |
| public abstract class BaseCipher implements EncryptionProvider, DecryptionProvider { |
| |
| private CipherInformation cipherInformation; |
| private KeyStoreInformation keystoreInformation; |
| private static Log log = LogFactory.getLog(BaseCipher.class); |
| /* Underlying cipher instance*/ |
| private Cipher cipher; |
| protected KeyStoreWrapper keyStoreWrapper; |
| private Key key; |
| |
| protected BaseCipher(CipherInformation cipherInformation, |
| KeyStoreInformation keystoreInformation) { |
| this.cipherInformation = cipherInformation; |
| this.keystoreInformation = keystoreInformation; |
| if (keystoreInformation instanceof TrustKeyStoreInformation) { |
| keyStoreWrapper = new TrustKeyStoreWrapper(); |
| ((TrustKeyStoreWrapper) keyStoreWrapper).init( |
| (TrustKeyStoreInformation) keystoreInformation); |
| } else { |
| keyStoreWrapper = new IdentityKeyStoreWrapper(); |
| IdentityKeyStoreInformation identityKeyStore = |
| (IdentityKeyStoreInformation) keystoreInformation; |
| |
| SecretInformation secretInformation = identityKeyStore.getKeyPasswordProvider(); |
| if (secretInformation != null) { //TODO validate |
| ((IdentityKeyStoreWrapper) keyStoreWrapper).init(identityKeyStore, |
| secretInformation.getResolvedSecret()); |
| } |
| } |
| init(); |
| } |
| |
| protected BaseCipher(CipherInformation cipherInformation, |
| KeyStoreWrapper keyStoreWrapper) { |
| this.keyStoreWrapper = keyStoreWrapper; |
| this.cipherInformation = cipherInformation; |
| init(); |
| } |
| |
| protected BaseCipher(CipherInformation cipherInformation, Key key) { |
| this.key = key; |
| this.cipherInformation = cipherInformation; |
| init(); |
| } |
| |
| private void init() { |
| |
| String algorithm = cipherInformation.getAlgorithm(); |
| CipherOperationMode opMode = cipherInformation.getCipherOperationMode(); |
| if (key == null) { |
| key = getKey(opMode); |
| } |
| if (log.isDebugEnabled()) { |
| log.debug("Initializing cipher with algorithm " + |
| "'" + algorithm + "' in mode '" + opMode + "'"); |
| } |
| try { |
| String provider = cipherInformation.getProvider(); |
| if (provider != null && !"".equals(provider)) { |
| try { |
| cipher = Cipher.getInstance(algorithm, provider.trim()); |
| } catch (NoSuchProviderException e) { |
| throw new SecureVaultException("Invalid Provider : " + provider, log); |
| } |
| } else { |
| cipher = Cipher.getInstance(algorithm); |
| } |
| if (opMode == CipherOperationMode.ENCRYPT) { |
| cipher.init(Cipher.ENCRYPT_MODE, key); |
| } else if (opMode == CipherOperationMode.DECRYPT) { |
| cipher.init(Cipher.DECRYPT_MODE, key); |
| } else { |
| throw new SecureVaultException("Invalid mode : " + opMode, log); |
| } |
| |
| } catch (NoSuchAlgorithmException e) { |
| throw new SecureVaultException("There is no algorithm support for " + |
| "'" + algorithm + "' in the operation mode '" + opMode + "'" + e, log); |
| } catch (NoSuchPaddingException e) { |
| throw new SecureVaultException("There is no padding scheme for " + |
| "'" + algorithm + "' in the operation mode '" + opMode + "'" + e, log); |
| } catch (InvalidKeyException e) { |
| throw new SecureVaultException("Invalid key ", e, log); |
| } |
| } |
| |
| public CipherInformation getCipherInformation() { |
| return cipherInformation; |
| } |
| |
| public KeyStoreInformation getKeyStoreInformation() { |
| return keystoreInformation; |
| } |
| |
| /** |
| * Returns the correct key for correct operation |
| * |
| * @param operationMode Ciper operation |
| * @return A key |
| */ |
| public abstract Key getKey(CipherOperationMode operationMode); |
| |
| /** |
| * Do cryptographic operation |
| * |
| * @param inputStream Input Stream |
| * @return result |
| */ |
| private byte[] doCipherOperation(byte[] inputStream) { |
| |
| InputStream sourceStream = new ByteArrayInputStream(inputStream); |
| if (cipherInformation.getInType() != null) { |
| try { |
| sourceStream = EncodingHelper.decode( |
| sourceStream, cipherInformation.getInType()); |
| } catch (IOException e) { |
| throw new SecureVaultException("IOError when decoding the input " + |
| "stream for cipher ", e, log); |
| } |
| } |
| |
| ByteArrayOutputStream baos = new ByteArrayOutputStream(); |
| CipherOutputStream out = new CipherOutputStream(baos, cipher); |
| |
| byte[] buffer = new byte[64]; |
| int length; |
| try { |
| while ((length = sourceStream.read(buffer)) != -1) { |
| out.write(buffer, 0, length); |
| } |
| } catch (IOException e) { |
| throw new SecureVaultException("IOError when reading the input" + |
| " stream for cipher ", e, log); |
| } finally { |
| try { |
| sourceStream.close(); |
| out.flush(); |
| out.close(); |
| } catch (IOException ignored) { |
| // ignore exception |
| } |
| } |
| |
| if (cipherInformation.getOutType() != null) { |
| return EncodingHelper.encode(baos, cipherInformation.getOutType()); |
| } else { |
| return baos.toByteArray(); |
| } |
| } |
| |
| public byte[] encrypt(byte[] plainText) { |
| return doCipherOperation(plainText); |
| } |
| |
| public byte[] decrypt(byte[] cipherText) { |
| return doCipherOperation(cipherText); |
| } |
| } |