Java tutorial
/** * Copyright (C) 2010-2014 Fabric project group, Cornell University * * This file is part of Fabric. * * Fabric is free software: you can redistribute it and/or modify it under the * terms of the GNU General Public License as published by the Free Software * Foundation, either version 2 of the License, or (at your option) any later * version. * * Fabric 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 General Public License for more * details. */ package fabric.common; import java.math.BigInteger; import java.security.GeneralSecurityException; import java.security.InvalidAlgorithmParameterException; import java.security.InvalidKeyException; import java.security.KeyPair; import java.security.KeyPairGenerator; import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; import java.security.PrivateKey; import java.security.PublicKey; import java.security.SecureRandom; import java.security.Security; import java.security.Signature; import java.security.cert.CertPath; import java.security.cert.CertPathValidator; import java.security.cert.Certificate; import java.security.cert.CertificateFactory; import java.security.cert.PKIXParameters; import java.security.cert.TrustAnchor; import java.security.cert.X509Certificate; import java.util.Arrays; import java.util.Calendar; import java.util.Date; import java.util.Set; import javax.crypto.Cipher; import javax.crypto.KeyGenerator; import javax.crypto.NoSuchPaddingException; import javax.crypto.NullCipher; import javax.crypto.SecretKey; import javax.crypto.spec.IvParameterSpec; import javax.crypto.spec.SecretKeySpec; import javax.naming.InvalidNameException; import javax.naming.ldap.LdapName; import org.bouncycastle.asn1.x509.X509Name; import org.bouncycastle.jce.provider.BouncyCastleProvider; import org.bouncycastle.x509.X509V3CertificateGenerator; import fabric.common.exceptions.InternalError; /** * This is the clearing house for all things crypto. */ public final class Crypto { public static final String ALG_SIGNATURE = "SHA256withRSA"; public static final String ALG_SECRET_KEY_GEN = "AES"; public static final int SIZE_SECRET_KEY = 128; public static final String ALG_SECRET_CRYPTO = "AES/CBC/PKCS5Padding"; public static final String ALG_PUBLIC_KEY_GEN = "RSA"; public static final int SIZE_PUBLIC_KEY = 1024; public static final String ALG_HASH = "SHA-256"; private static final KeyGenerator secretKeyGen; private static final KeyPairGenerator publicKeyGen; private static final SecureRandom random = new SecureRandom(); static { Security.addProvider(new BouncyCastleProvider()); secretKeyGen = secretKeyGenInstance(); publicKeyGen = publicKeyGenInstance(); } public static MessageDigest digestInstance() { try { return MessageDigest.getInstance(ALG_HASH); } catch (NoSuchAlgorithmException e) { throw new InternalError(e); } } public static Signature signatureInstance() { try { return Signature.getInstance(ALG_SIGNATURE); } catch (NoSuchAlgorithmException e) { throw new InternalError(e); } } public static KeyGenerator secretKeyGenInstance() { try { KeyGenerator result = KeyGenerator.getInstance(ALG_SECRET_KEY_GEN); result.init(SIZE_SECRET_KEY); return result; } catch (NoSuchAlgorithmException e) { throw new InternalError(e); } } public static SecretKey genSecretKey() { synchronized (secretKeyGen) { return secretKeyGen.generateKey(); } } public static KeyPairGenerator publicKeyGenInstance() { try { KeyPairGenerator result = KeyPairGenerator.getInstance(ALG_PUBLIC_KEY_GEN); result.initialize(SIZE_PUBLIC_KEY); return result; } catch (NoSuchAlgorithmException e) { throw new InternalError(e); } } public static KeyPair genKeyPair() { synchronized (publicKeyGen) { return publicKeyGen.generateKeyPair(); } } /** * Fills an initialization vector with random bytes. */ public static void fillIV(byte[] iv) { synchronized (random) { random.nextBytes(iv); } } /** * Creates a new initialization vector. */ public static byte[] makeIV() { byte[] result = new byte[16]; fillIV(result); return result; } /** * Creates an initializes a new Cipher instance with the given parameters. * * @param opmode * The mode of operation. One of the mode constants in Cipher. * @param key * The secret key to use. * @param iv * The initialization vector to use. For encryption, this should be * randomly generated; for decryption, this should match the one used * during encryption. */ public static Cipher cipherInstance(int opmode, byte[] key, byte[] iv) throws NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException, InvalidAlgorithmParameterException { if (key == null) return new NullCipher(); Cipher result = Cipher.getInstance(ALG_SECRET_CRYPTO); if (iv != null) { IvParameterSpec ivSpec = new IvParameterSpec(iv); result.init(opmode, new SecretKeySpec(key, ALG_SECRET_KEY_GEN), ivSpec); } else { result.init(opmode, new SecretKeySpec(key, ALG_SECRET_KEY_GEN)); } return result; } /** * Validates the given certificate chain against the given trust store. */ public static void validateCertificateChain(Certificate[] certificateChain, Set<TrustAnchor> trustStore) throws GeneralSecurityException { PKIXParameters params = new PKIXParameters(trustStore); params.setSigProvider(BouncyCastleProvider.PROVIDER_NAME); params.setRevocationEnabled(false); CertificateFactory certFactory = CertificateFactory.getInstance("X509"); CertPath certPath = certFactory.generateCertPath(Arrays.asList(certificateChain)); CertPathValidator pathValidator = CertPathValidator.getInstance("PKIX"); pathValidator.validate(certPath, params); } /** * Generates a certificate, signed by the issuer, binding the subject's name * to their public key. */ public static X509Certificate createCertificate(String subjectName, PublicKey subjectKey, String issuerName, PrivateKey issuerKey) throws GeneralSecurityException { Calendar expiry = Calendar.getInstance(); expiry.add(Calendar.YEAR, 1); X509V3CertificateGenerator certGen = new X509V3CertificateGenerator(); certGen.setSerialNumber(BigInteger.valueOf(System.currentTimeMillis())); certGen.setIssuerDN(new X509Name("CN=" + issuerName)); certGen.setSubjectDN(new X509Name("CN=" + subjectName)); certGen.setSignatureAlgorithm("SHA1withRSA"); certGen.setPublicKey(subjectKey); certGen.setNotBefore(new Date(System.currentTimeMillis())); certGen.setNotAfter(expiry.getTime()); return certGen.generate(issuerKey); } /** * Extracts the CN component of a Distinguished Name. */ public static String getCN(String dn) { try { LdapName ldapName = new LdapName(dn); for (int i = 0; i < ldapName.size(); i++) { String component = ldapName.get(i); if (component.substring(0, 3).equalsIgnoreCase("cn=")) { return component.substring(3); } } } catch (InvalidNameException e) { } return null; } }