Java tutorial
/* * The LockSmith, as the name suggests, makes Locks and matching keys which it saves * as PGP ascii-armored keyring files in the keys directory. * * MIT Licensed * * * */ package uk.co.platosys.dinigma; import java.io.File; import java.io.FileOutputStream; import java.math.BigInteger; import java.security.KeyPair; import java.security.KeyPairGenerator; import java.security.Security; import java.security.spec.AlgorithmParameterSpec; import java.util.Date; import org.bouncycastle.bcpg.ArmoredOutputStream; import org.bouncycastle.bcpg.CompressionAlgorithmTags; import org.bouncycastle.bcpg.HashAlgorithmTags; import org.bouncycastle.bcpg.PublicKeyAlgorithmTags; import org.bouncycastle.bcpg.SymmetricKeyAlgorithmTags; import org.bouncycastle.jce.provider.BouncyCastleProvider; import org.bouncycastle.jce.spec.ElGamalParameterSpec; import org.bouncycastle.openpgp.PGPEncryptedData; import org.bouncycastle.openpgp.PGPException; import org.bouncycastle.openpgp.PGPKeyPair; import org.bouncycastle.openpgp.PGPKeyRingGenerator; import org.bouncycastle.openpgp.PGPPublicKey; import org.bouncycastle.openpgp.PGPPublicKeyRing; import org.bouncycastle.openpgp.PGPSecretKeyRing; import org.bouncycastle.openpgp.PGPSignature; import org.bouncycastle.openpgp.operator.PBESecretKeyEncryptor; import org.bouncycastle.openpgp.operator.PGPContentSignerBuilder; import org.bouncycastle.openpgp.operator.PGPDigestCalculator; import org.bouncycastle.openpgp.operator.jcajce.JcaPGPContentSignerBuilder; import org.bouncycastle.openpgp.operator.jcajce.JcaPGPDigestCalculatorProviderBuilder; import org.bouncycastle.openpgp.operator.jcajce.JcaPGPKeyPair; import org.bouncycastle.openpgp.operator.jcajce.JcePBESecretKeyEncryptorBuilder; import uk.co.platosys.dinigma.exceptions.DuplicateNameException; import uk.co.platosys.dinigma.exceptions.MinigmaException; import uk.co.platosys.dinigma.utils.FileTools; /** * @author edward * This is a key-pair generator - it has one method which generates a pair of keys and writes them to file. * Note that in fact it generates two key pairs: one for encryption, and one for signatures. * But they have the same passphrase. */ public class LockSmith { private static String PROVIDER = "BC"; static final String SIGNATURE_ALGORITHM = "DSA"; static final String ASYMMETRIC_ALGORITHM = "ELGAMAL"; static final int SIGNATURE_ALGORITHM_TAG = PublicKeyAlgorithmTags.DSA; /** * * @param keyDirectory the directory in which the private key is to be saved. This could be on a removable drive. * @param lockDirectory the directory in which the Lock(the public key) is to be saved. * @param userName * @param passPhrase * @return The key_id of the signing key. * @throws MinigmaException */ public static long createLockset(File keyDirectory, File lockDirectory, String userName, char[] passPhrase) throws MinigmaException, DuplicateNameException { String filename; File lockFile; File keyFile; //test that parameters have been set: if (keyDirectory == null) { throw new MinigmaException("Locksmith - key directory is null"); } if (!keyDirectory.isDirectory()) { throw new MinigmaException("Locksmith: " + keyDirectory.toString() + " is not a directory"); } if (!keyDirectory.canWrite()) { throw new MinigmaException("Locksmith: can't write to " + keyDirectory.toString()); } if (lockDirectory == null) { throw new MinigmaException("Locksmith - lock directory is null"); } if (!lockDirectory.isDirectory()) { throw new MinigmaException("Locksmith: " + keyDirectory.toString() + " is not a directory"); } if (!lockDirectory.canWrite()) { throw new MinigmaException("Locksmith: can't write to " + keyDirectory.toString()); } try { if (Security.getProvider(PROVIDER) == null) { Security.addProvider(new BouncyCastleProvider()); } } catch (Exception e) { throw new MinigmaException("Locksmith: problem adding security provider", e); } // KeyPairGenerator generator; KeyPair dsaKeyPair; KeyPair elgKeyPair; BigInteger g; BigInteger p; File lockFolder; File keyFolder; PGPKeyPair pgpSigKeyPair; PGPKeyPair pgpEncKeyPair; PGPKeyRingGenerator pgpKeyRingGenerator; PGPPublicKeyRing pgpPublicKeyRing; PGPSecretKeyRing pgpSecretKeyRing; try { //the DSA key for signing generator = KeyPairGenerator.getInstance(SIGNATURE_ALGORITHM, PROVIDER); generator.initialize(1024); dsaKeyPair = generator.generateKeyPair(); } catch (Exception e) { throw new MinigmaException("Locksmith: failed to generate dsa key pair", e); } try { //the strong ElGamal key for encrypting generator = KeyPairGenerator.getInstance(ASYMMETRIC_ALGORITHM, PROVIDER); g = new BigInteger( "153d5d6172adb43045b68ae8e1de1070b6137005686d29d3d73a7749199681ee5b212c9b96bfdcfa5b20cd5e3fd2044895d609cf9b410b7a0f12ca1cb9a428cc", 16); p = new BigInteger( "9494fec095f3b85ee286542b3836fc81a5dd0a0349b4c239dd38744d488cf8e31db8bcb7d33b41abb9e5a33cca9144b1cef332c94bf0573bf047a3aca98cdf3b", 16); AlgorithmParameterSpec elGamalParameters = new ElGamalParameterSpec(p, g); generator.initialize(elGamalParameters); elgKeyPair = generator.generateKeyPair(); } catch (Exception e) { throw new MinigmaException("Locksmith: failed to generate elgamal key pair", e); } try { filename = FileTools.removeFunnyCharacters(userName); lockFolder = new File(lockDirectory, Minigma.LOCK_DIRNAME); if (!lockFolder.exists()) { if (!lockFolder.mkdirs()) { throw new MinigmaException("Can't create lock folder"); } } lockFile = new File(lockFolder, filename); if (lockFile.exists()) { throw new DuplicateNameException("lockfile with name " + lockFile.getName() + " already exists"); } keyFolder = new File(keyDirectory, Minigma.KEY_DIRNAME); if (!keyFolder.exists()) { if (!keyFolder.mkdirs()) { throw new MinigmaException("Can't create key folder"); } } keyFile = new File(keyFolder, filename); if (lockFile.exists()) { throw new DuplicateNameException("keyfile with name " + keyFile.getName() + " already exists"); } } catch (Exception exc) { throw new MinigmaException("Locksmith: error setting up key files", exc); } try { pgpSigKeyPair = new JcaPGPKeyPair(PGPPublicKey.DSA, dsaKeyPair, new Date()); } catch (Exception e) { throw new MinigmaException("Locksmith: failed to generate pgp-dsa key pair", e); } try { pgpEncKeyPair = new JcaPGPKeyPair(PGPPublicKey.ELGAMAL_ENCRYPT, elgKeyPair, new Date()); } catch (Exception e) { throw new MinigmaException("Locksmith: failed to generate pgp-elgamal key pair", e); } PGPDigestCalculator pgpDigestCalculator = null; PGPContentSignerBuilder pgpContentSignerBuilder = null; PBESecretKeyEncryptor pbeSecretKeyEncryptor = null; try { pgpDigestCalculator = new JcaPGPDigestCalculatorProviderBuilder().build().get(HashAlgorithmTags.SHA1); pgpContentSignerBuilder = new JcaPGPContentSignerBuilder(SIGNATURE_ALGORITHM_TAG, HashAlgorithmTags.SHA512); pbeSecretKeyEncryptor = new JcePBESecretKeyEncryptorBuilder(PGPEncryptedData.AES_256, pgpDigestCalculator).setProvider(PROVIDER).build(passPhrase); } catch (Exception e) { throw new MinigmaException("failed to initialise KRG components", e); } try { pgpKeyRingGenerator = new PGPKeyRingGenerator(PGPSignature.POSITIVE_CERTIFICATION, //certification level pgpSigKeyPair, //master key userName, // id pgpDigestCalculator, //PGPDigestCalculator null, //PGPSignatureSubpacketsVector hashed packets null, //PGPSignatureSubpacketsVector unhashed packets pgpContentSignerBuilder, //PGPContentSignerBuilder pbeSecretKeyEncryptor//PBESecretKeyEncryptor ); } catch (PGPException e) { throw new MinigmaException("Locksmith: failed to create PGP-keyring generator", e); } try { pgpKeyRingGenerator.addSubKey(pgpEncKeyPair); } catch (Exception e) { throw new MinigmaException("Locksmith: failed to add elgamal subkey to ring", e); } try { ArmoredOutputStream secOut = new ArmoredOutputStream(new FileOutputStream(keyFile)); pgpSecretKeyRing = pgpKeyRingGenerator.generateSecretKeyRing(); pgpSecretKeyRing.encode(secOut); secOut.close(); } catch (Exception e) { throw new MinigmaException("Locksmith: failed to encode secret key output", e); } try { ArmoredOutputStream pubOut = new ArmoredOutputStream(new FileOutputStream(lockFile)); pgpPublicKeyRing = pgpKeyRingGenerator.generatePublicKeyRing(); pgpPublicKeyRing.encode(pubOut); pubOut.close(); } catch (Exception e) { throw new MinigmaException("Locksmith: failed to encode pubring output", e); } return pgpSigKeyPair.getKeyID(); } }