Java tutorial
/* * Copyright (c) 2008-2011, Martijn Brinkers, Djigzo. * * This file is part of Djigzo email encryption. * * Djigzo is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License * version 3, 19 November 2007 as published by the Free Software * Foundation. * * Djigzo is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Affero General Public License for more details. * * You should have received a copy of the GNU Affero General Public * License along with Djigzo. If not, see <http://www.gnu.org/licenses/> * * Additional permission under GNU AGPL version 3 section 7 * * If you modify this Program, or any covered work, by linking or * combining it with aspectjrt.jar, aspectjweaver.jar, tyrex-1.0.3.jar, * freemarker.jar, dom4j.jar, mx4j-jmx.jar, mx4j-tools.jar, * spice-classman-1.0.jar, spice-loggerstore-0.5.jar, spice-salt-0.8.jar, * spice-xmlpolicy-1.0.jar, saaj-api-1.3.jar, saaj-impl-1.3.jar, * wsdl4j-1.6.1.jar (or modified versions of these libraries), * containing parts covered by the terms of Eclipse Public License, * tyrex license, freemarker license, dom4j license, mx4j license, * Spice Software License, Common Development and Distribution License * (CDDL), Common Public License (CPL) the licensors of this Program grant * you additional permission to convey the resulting work. */ package mitm.common.security.keystore.hibernate; import java.io.IOException; import java.io.Serializable; import java.security.InvalidKeyException; import java.security.Key; import java.security.KeyStoreException; import java.security.NoSuchAlgorithmException; import java.security.NoSuchProviderException; import java.security.PrivateKey; import java.security.PublicKey; import java.security.UnrecoverableKeyException; import java.security.spec.InvalidKeySpecException; import java.security.spec.KeySpec; import java.security.spec.PKCS8EncodedKeySpec; import java.security.spec.X509EncodedKeySpec; import javax.crypto.BadPaddingException; import javax.crypto.IllegalBlockSizeException; import javax.crypto.NoSuchPaddingException; import javax.crypto.spec.SecretKeySpec; import mitm.common.security.SecurityFactory; import mitm.common.security.SecurityFactoryFactory; import mitm.common.security.password.PBEncryption; import org.apache.commons.lang.SerializationUtils; /** * SerializableKeyEntry is used to store private keys as a byte array. The keys are stored in a format that allows the * keys to be recreated from the byte array (should be obvious ;). * * WARNING: this class is used for long term serialization. The class should there not be moved or renamed. Be careful * with any changes made to class members, changes might result in changes to deserialization. * * @author Martijn Brinkers * */ public class SerializableKeyEntry implements Serializable { private static final long serialVersionUID = 7017905345537973303L; /* * The type of the key */ private enum KeyType { PRIVATE, PUBLIC, SECRET }; /* * If and how keys are protected */ private enum Protection { NONE, ENCRYPTED }; /* * The encoding of the key */ private enum Format { PKCS8, X509, RAW }; /* * Raw key material. */ private final byte[] rawKey; /* * The algorithm uses to create the key */ private final String algorithm; /* * The format of encoded key */ private final String format; /* * The type of the key */ private final KeyType keyType; /* * Stores how the key is protected */ private final Protection protection; public SerializableKeyEntry(Key key) throws InvalidKeyException, InvalidKeySpecException, NoSuchAlgorithmException, NoSuchProviderException, NoSuchPaddingException, IllegalBlockSizeException, BadPaddingException, IOException { this(key, null, null); } public SerializableKeyEntry(Key key, char[] password, PBEncryption encryptor) throws InvalidKeyException, InvalidKeySpecException, NoSuchAlgorithmException, NoSuchProviderException, NoSuchPaddingException, IllegalBlockSizeException, BadPaddingException, IOException { if (encryptor == null || password == null) { this.rawKey = key.getEncoded(); this.protection = Protection.NONE; } else { this.rawKey = encryptor.encrypt(key.getEncoded(), password); this.protection = Protection.ENCRYPTED; } this.algorithm = key.getAlgorithm(); this.format = key.getFormat(); if (key instanceof PrivateKey) { keyType = KeyType.PRIVATE; } else { if (key instanceof PublicKey) { keyType = KeyType.PUBLIC; } else { keyType = KeyType.SECRET; } } } private SecurityFactory getSecurityFactory() { return SecurityFactoryFactory.getSecurityFactory(); } /** * Deserialize the serialized SerializableKeyEntry object. * * @param serialized the serialized SerializableKeyEntry * @return a deserialized object * @throws UnrecoverableKeyException */ public static SerializableKeyEntry deserialize(byte[] serialized) throws UnrecoverableKeyException { Object o = SerializationUtils.deserialize(serialized); if (!(o instanceof SerializableKeyEntry)) { throw new UnrecoverableKeyException("The serialized is not the correct type."); } return (SerializableKeyEntry) o; } /** * Serializes this object * * @return serialized this */ public byte[] serialize() { return SerializationUtils.serialize(this); } private Format toFormat(String format) throws KeyStoreException { if (format.equals("PKCS#8") || format.equals("PKCS8")) { return Format.PKCS8; } if (format.equals("X.509") || format.equals("X509")) { return Format.X509; } if (format.equals("RAW")) { return Format.RAW; } throw new KeyStoreException("Unknown key format " + format); } /** * Creates the key from the given byte array using the stored format and type. * * @param keyBytes * @return the key * @throws KeyStoreException * @throws InvalidKeySpecException * @throws NoSuchAlgorithmException * @throws NoSuchProviderException */ private Key getKey(byte[] rawKey) throws KeyStoreException, InvalidKeySpecException, NoSuchAlgorithmException, NoSuchProviderException { KeySpec keySpec; Format keyFormat = toFormat(format); switch (keyFormat) { case PKCS8: keySpec = new PKCS8EncodedKeySpec(rawKey); break; case X509: keySpec = new X509EncodedKeySpec(rawKey); break; case RAW: return new SecretKeySpec(rawKey, algorithm); default: throw new KeyStoreException("Unknown key format " + keyFormat); } SecurityFactory securityFactory = getSecurityFactory(); switch (keyType) { case PRIVATE: return securityFactory.createKeyFactory(algorithm).generatePrivate(keySpec); case PUBLIC: return securityFactory.createKeyFactory(algorithm).generatePublic(keySpec); case SECRET: return securityFactory.createSecretKeyFactory(algorithm).generateSecret(keySpec); default: throw new KeyStoreException("Unknown key type " + keyType); } } /** * Returns a unprotected key. If the key is a protected key (ie. Protection != NONE) a KeyStoreException * will be thrown. * * @return the key * @throws KeyStoreException * @throws InvalidKeySpecException * @throws NoSuchAlgorithmException * @throws NoSuchProviderException */ public Key getKey() throws KeyStoreException, InvalidKeySpecException, NoSuchAlgorithmException, NoSuchProviderException { if (protection != Protection.NONE) { throw new KeyStoreException("This entry is protected."); } return getKey(rawKey); } /** * Returns a password protected key. * * @param password the password used to decrypt the key. * @param decryptor the decryptor used to decrypt the key. If null it is assumed that the * key is not password protected * * @return the key * @throws KeyStoreException * @throws InvalidKeyException * @throws InvalidKeySpecException * @throws NoSuchAlgorithmException * @throws NoSuchProviderException * @throws NoSuchPaddingException * @throws IllegalBlockSizeException * @throws BadPaddingException * @throws IOException */ public Key getKey(char[] password, PBEncryption decryptor) throws KeyStoreException, InvalidKeyException, InvalidKeySpecException, NoSuchAlgorithmException, NoSuchProviderException, NoSuchPaddingException, IllegalBlockSizeException, BadPaddingException, IOException { if (protection != Protection.ENCRYPTED) { throw new KeyStoreException("This entry is not an encrypted entry."); } if (decryptor == null) { throw new KeyStoreException("The decryptor should not be null."); } byte[] decryptedKey = decryptor.decrypt(rawKey, password); return getKey(decryptedKey); } }