//============================================================================== // tribble/security/GenKeyPair.java //------------------------------------------------------------------------------ package tribble.security; // System imports import java.io.BufferedWriter; import java.io.FileWriter; import java.io.IOException; import java.io.OutputStreamWriter; import java.lang.Integer; import java.lang.String; import java.security.GeneralSecurityException; import java.security.InvalidAlgorithmParameterException; import java.security.Key; import java.security.KeyPair; import java.security.KeyPairGenerator; import java.security.NoSuchAlgorithmException; import java.security.PrivateKey; import java.security.PublicKey; import java.security.SecureRandom; import java.text.SimpleDateFormat; import java.util.Date; import java.util.SimpleTimeZone; // Local imports // (None) /******************************************************************************* * Public/private key pair generator. * Generates a public/private key pair to be used for asymmetric (public key) * encryption. * *
* The public and private keys are written to text files formatted as XML.
* These key files can then be read by class {@link KeyReader}.
*
*
* @version $Revision: 1.6 $ $Date: 2003/08/09 17:24:32 $
* @since 2003-03-13
* @author
* David R. Tribble
* (david@tribble.com).
*
* Copyright ©2003 by David R. Tribble, all rights reserved.
*
* Permission is granted to freely use and distribute this source code
* provided that the original copyright and authorship notices remain
* intact.
*
* @see KeyReader
*/
public class GenKeyPair
{
// Identification
/** Source revision information. */
static final String REV =
"@(#)tribble/security/GenKeyPair.java $Revision: 1.6 $ $Date: 2003/08/09 17:24:32 $\n";
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// Public constants
/** Default key pair generation algorithm ("RSA"). */
public static final String DFL_ALGORITHM = "RSA";
/** Default key pair bit size (1024). */
public static final int DFL_KEYSIZE = 1024;
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// Public static methods
/***************************************************************************
* Generate a public/private encryption key pair.
*
*
* Usage * * java tribble.security.GenKeyPair * [-option...] public.xml private.xml * * *
* Options: *
*
* Writes the public half of the generated key pair to file * public.xml, and the private half to file * private.xml. * The output files are in stand-alone XML format. * * * @throws GeneralSecurityException * Thrown if a security exception occurs. * * @throws IOException * Thrown if and I/O (write) error occurs. * * @since 1.1, 2003-03-13 */ public static void main(String[] args) throws IOException, GeneralSecurityException { String algorithm = DFL_ALGORITHM; int keysize = DFL_KEYSIZE; Date now; SimpleDateFormat fmt; String pubFname; BufferedWriter pubFile; String priFname; BufferedWriter priFile; GenKeyPair kpGen; KeyPair kp; int i; // Get command options for (i = 0; i < args.length; i++) { if (args[i].charAt(0) != '-') break; if (args[i].equals("-a")) algorithm = args[++i]; else if (args[i].equals("-s")) keysize = Integer.parseInt(args[++i]); } // Check usage if (args.length < i+2) { System.out.println("Generate a public/private key pair."); System.out.println(); System.out.println("usage: java " + GenKeyPair.class.getName() + " [-option...] public.xml private.xml"); System.out.println(); System.out.println("Options:"); System.out.println(" -a alg Algorithm (default is " + DFL_ALGORITHM + ")."); System.out.println(" -s num Key size (default is " + DFL_KEYSIZE + ")."); System.exit(255); } // Open/write the public key output file pubFname = args[i++]; if (pubFname.equals("-")) { // Write to standard output pubFile = new BufferedWriter(new OutputStreamWriter(System.out)); } else { // Open/write the output file pubFile = new BufferedWriter(new FileWriter(pubFname)); } // Open/write the private key output file priFname = args[i++]; if (priFname.equals("-")) { // Write to standard output priFile = new BufferedWriter(new OutputStreamWriter(System.out)); } else { // Open/write the output file priFile = new BufferedWriter(new FileWriter(priFname)); } // Display the current date now = new Date(); fmt = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); fmt.setTimeZone(new SimpleTimeZone(0, "Z")); System.out.println(fmt.format(now) + " Z"); // Generate the public/private key pair System.out.print("Generating a public/private key pair (" + algorithm + ", " + keysize + ")..."); System.out.flush(); kpGen = new GenKeyPair(algorithm, keysize); kp = kpGen.generate(); System.out.println(" done"); System.out.flush(); // Write the public key System.out.println(); System.out.println(pubFname); writeEncoded(kp.getPublic(), keysize, now, pubFile); // Write the private key System.out.println(); System.out.println(priFname); writeEncoded(kp.getPrivate(), keysize, now, priFile); // Clean up if (!pubFname.equals("-")) pubFile.close(); if (!priFname.equals("-")) priFile.close(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // Private static methods /*************************************************************************** * Writes the public or private key to an output stream, formatted as XML. * *
* The XML output looks like: *
* <public-key or <private-key
* created="2003-03-15 20:20:15 Z"
* algorithm="RSA"
* format="X.509" or format="PKCS#8"
* protected="no"
* encoding="base16"
* size="1024">
* 308201B73082012C06072A8648CE3804013082011F02818100FD7F53811D7512
* 2952DF4A9C2EECE4E7F611B7523CEF4400C31E3F80B6512669455D402251FB59
* ...etc...
* 13C1142A157B6177C9F5943CA2093903FF1AEC04B90CC670D2B738341C310FEC
* 2618E3BA191F1884FEDD72C8B2C5191C34FBD45A5F5CADD6347018
* </public-key> or </private-key>
*
*
* @param key
* A public or private key.
*
* @param keysize
* Size (in bits) of the public or private key.
*
* @param when
* Date that the key was generated.
*
* @param out
* An output stream.
*
* @throws IOException
* Thrown if and I/O (write) error occurs.
*
* @since 1.6, 2003-08-09 (2003-03-14)
*
* @see #main
*/
private static void writeEncoded(Key key, int keysize, Date when,
BufferedWriter out)
throws IOException, GeneralSecurityException
{
String type;
SimpleDateFormat fmt;
byte[] enc;
// Display key info
enc = key.getEncoded();
type = (key instanceof PublicKey ? "public" : "private");
fmt = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
fmt.setTimeZone(new SimpleTimeZone(0, "Z"));
System.out.println(type + " key:");
System.out.println(" algorithm: " + key.getAlgorithm());
System.out.println(" format: " + key.getFormat());
System.out.println(" size: " + keysize);
//out.write("");
//out.newLine();
out.write("<" + type + "-key");
out.newLine();
out.write(" created=\"" + fmt.format(when) + " Z\"");
out.newLine();
out.write(" algorithm=\"" + key.getAlgorithm() + "\"");
out.newLine();
out.write(" format=\"" + key.getFormat() + "\"");
out.newLine();
out.write(" encoding=\"" + "base16" + "\"");
out.newLine();
if (key instanceof PrivateKey)
{
out.write(" protected=\"no\"");
out.newLine();
}
out.write(" size=\"" + keysize + "\">");
out.newLine();
// Write the key as a hexadecimal string
for (int i = 0; i < enc.length; i++)
{
int b;
int d;
if (i % 32 == 0 && i > 0)
out.newLine();
// Write the next encoded byte as two hex digits
b = enc[i] & 0xFF;
d = b >> 4;
d = (d > 9 ? d-0xA+'A' : d+'0');
out.write((char) d);
d = b & 0x0F;
d = (d > 9 ? d-0xA+'A' : d+'0');
out.write((char) d);
}
out.newLine();
// Finish
out.write("" + type + "-key>");
out.newLine();
out.flush();
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// Private variables
/** Key pair generator. */
private KeyPairGenerator m_gen;
/** Random number generator. */
private SecureRandom m_rand;
/** Public/private key pair. */
private KeyPair m_keys;
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// Public constructors
/***************************************************************************
* Default constructor.
*
* @throws NoSuchAlgorithmException
* Thrown if the default generator algorithm is not available.
*
* @since 1.1, 2003-03-13
*/
public GenKeyPair()
throws GeneralSecurityException
{
// Create a key pair generator using a default algorithm
this(DFL_ALGORITHM, DFL_KEYSIZE);
}
/***************************************************************************
* Constructor.
*
* @param algo
* Name of the public/private key pair generation algorithm to use, e.g.,
* "DSA".
*
* @param size
* Key size (in bits), e.g., 1024.
*
* @throws NoSuchAlgorithmException
* Thrown if the specified generator algorithm is not available.
*
* @since 1.1, 2003-03-13
*/
public GenKeyPair(String algo, int size)
throws GeneralSecurityException
{
// Check args
if (size % 8 != 0)
throw new InvalidAlgorithmParameterException(
"Key size is not a multiple of 8");
// Create a new key pair generator
m_gen = KeyPairGenerator.getInstance(algo);
// Initialize the generator
m_rand = new SecureRandom();
m_gen.initialize(size, m_rand);
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// Public methods
/***************************************************************************
* Generate a public/private key pair.
*
* @return
* A public/private key pair.
* Note that the private key of the pair must be kept secret by the user of
* the key pair.
*
* @since 1.1, 2003-03-13
*/
public KeyPair generate()
{
// Generate a public/private key pair
m_keys = m_gen.genKeyPair();
return (m_keys);
}
}
// End GenKeyPair.java