/** * */ package com.emc.vipr.transform.encryption; import java.io.InputStream; import java.io.OutputStream; import java.security.GeneralSecurityException; import java.security.InvalidKeyException; import java.security.KeyPair; import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; import java.security.Provider; import java.security.SecureRandom; import java.security.interfaces.RSAPrivateKey; import java.util.HashMap; import java.util.Map; import javax.crypto.Cipher; import javax.crypto.KeyGenerator; import javax.crypto.NoSuchPaddingException; import javax.crypto.SecretKey; import com.emc.vipr.transform.TransformConstants; /** * @author cwikj * */ public class BasicEncryptionOutputTransform extends EncryptionOutputTransform { byte[] iv; SecretKey k; private String masterEncryptionKeyFingerprint; private KeyPair masterKey; /** * @param streamToEncodeTo * @param metadataToEncode * @param masterEncryptionKeyFingerprint * @throws NoSuchPaddingException * @throws NoSuchAlgorithmException * @throws InvalidKeyException */ public BasicEncryptionOutputTransform(OutputStream streamToEncodeTo, Map<String, String> metadataToEncode, String masterEncryptionKeyFingerprint, KeyPair asymmetricKey, String encryptionTransform, int keySize, Provider provider) { super(streamToEncodeTo, metadataToEncode, TransformConstants.ENCRYPTION_CLASS + ":" + encryptionTransform, provider); this.masterEncryptionKeyFingerprint = masterEncryptionKeyFingerprint; this.masterKey = asymmetricKey; try { Cipher cipher = initCipher(encryptionTransform, keySize); MessageDigest sha1 = null; if (provider != null) { sha1 = MessageDigest.getInstance("SHA1", provider); } else { sha1 = MessageDigest.getInstance("SHA1"); } pushStream = new EncryptionOutputStream(streamToEncodeTo, cipher, sha1); } catch (GeneralSecurityException e) { throw new RuntimeException("Error initializing output transform: " + e.getMessage(), e); } } public BasicEncryptionOutputTransform(InputStream streamToEncode, Map<String, String> metadataToEncode, String masterEncryptionKeyFingerprint, KeyPair asymmetricKey, String encryptionTransform, int keySize, Provider provider) { super(streamToEncode, metadataToEncode, TransformConstants.ENCRYPTION_CLASS + ":" + encryptionTransform, provider); this.masterEncryptionKeyFingerprint = masterEncryptionKeyFingerprint; this.masterKey = asymmetricKey; try { Cipher cipher = initCipher(encryptionTransform, keySize); MessageDigest sha1 = null; if (provider != null) { sha1 = MessageDigest.getInstance("SHA1", provider); } else { sha1 = MessageDigest.getInstance("SHA1"); } pullStream = new EncryptionInputFilter(streamToEncode, cipher, sha1); } catch (GeneralSecurityException e) { throw new RuntimeException("Error initializing output transform: " + e.getMessage(), e); } } private Cipher initCipher(String encryptionTransform, int keySize) throws GeneralSecurityException { Cipher cipher = null; if (provider != null) { cipher = Cipher.getInstance(encryptionTransform, provider); } else { cipher = Cipher.getInstance(encryptionTransform); } // Per FIPS bulletin 2013-09, make sure we don't use Dual_EC_DRBG SecureRandom rand; if(provider != null) { rand = SecureRandom.getInstance("SHA1PRNG", provider); } else { rand = SecureRandom.getInstance("SHA1PRNG"); } // Generate a secret key String[] algParts = encryptionTransform.split("/"); KeyGenerator keygen = null; if (provider != null) { keygen = KeyGenerator.getInstance(algParts[0], provider); } else { keygen = KeyGenerator.getInstance(algParts[0]); } keygen.init(keySize, rand); k = keygen.generateKey(); //System.out.println("Key: " + KeyUtils.toHexPadded(k.getEncoded())); cipher.init(Cipher.ENCRYPT_MODE, k, rand); iv = cipher.getIV(); //System.out.println("IV: " + KeyUtils.toHexPadded(iv)); return cipher; } /* * (non-Javadoc) * * @see com.emc.vipr.transform.OutputTransform#getEncodedMetadata() */ @Override public Map<String, String> getEncodedMetadata() { Map<String, String> encodedMetadata = new HashMap<String, String>(); encodedMetadata.putAll(metadataToEncode); // Add x-emc fields String encodedIv = KeyUtils.urlSafeEncodeBase64(iv); encodedMetadata.put(TransformConstants.META_ENCRYPTION_IV, encodedIv); encodedMetadata.put(TransformConstants.META_ENCRYPTION_KEY_ID, masterEncryptionKeyFingerprint); try { encodedMetadata.put(TransformConstants.META_ENCRYPTION_OBJECT_KEY, KeyUtils.encryptKey(k, provider, masterKey.getPublic())); } catch (GeneralSecurityException e) { throw new RuntimeException("Could not encrypt key: " + e, e); } switch(getStreamMode()) { case PULL: EncryptionInputFilter is = (EncryptionInputFilter)pullStream; encodedMetadata.put(TransformConstants.META_ENCRYPTION_UNENC_SHA1, KeyUtils.toHexPadded(is.getDigest())); encodedMetadata.put(TransformConstants.META_ENCRYPTION_UNENC_SIZE, ""+is.getByteCount()); break; case PUSH: EncryptionOutputStream os = (EncryptionOutputStream)pushStream; encodedMetadata.put(TransformConstants.META_ENCRYPTION_UNENC_SHA1, KeyUtils.toHexPadded(os.getDigest())); encodedMetadata.put(TransformConstants.META_ENCRYPTION_UNENC_SIZE, ""+os.getByteCount()); break; } // Sign x-emc fields. encodedMetadata.put(TransformConstants.META_ENCRYPTION_META_SIG, KeyUtils.signMetadata(encodedMetadata, (RSAPrivateKey) masterKey.getPrivate(), provider)); return encodedMetadata; } }