//============================================================================== // tribble/security/KeyReader.java //------------------------------------------------------------------------------ package tribble.security; // System imports import java.io.BufferedReader; import java.io.FileReader; import java.io.InputStreamReader; import java.io.IOException; import java.io.Reader; import java.lang.String; import java.lang.StringBuffer; import java.lang.System; import java.security.GeneralSecurityException; import java.security.Key; import java.security.KeyFactory; import java.security.NoSuchAlgorithmException; import java.security.PrivateKey; import java.security.PublicKey; import java.security.spec.KeySpec; import java.security.spec.PKCS8EncodedKeySpec; import java.security.spec.X509EncodedKeySpec; // Local imports import tribble.crypto.AESCipher; import tribble.crypto.SymmetricCipher; /******************************************************************************* * Public/private encryption key reader. * Provides the capability of reading public or private encryption keys contained * in XML text files that were generated by class {@link GenKeyPair}. * *
* Note that this is not a full-fledged XML parser, but rather an extemely
* simplified scanner that assumes that the XML input text is in a particular
* format. Input XML text that deviates too far from the assumed format will
* not be parsed correctly.
*
* @version $Revision: 1.3 $ $Date: 2003/03/18 03:28:09 $
* @since 2003-03-14
* @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 #main
* @see GenKeyPair
*/
public class KeyReader
{
// Identification
/** Source revision information. */
static final String REV =
"@(#)tribble/security/KeyReader.java $Revision: 1.3+ $ $Date: 2003/03/18 03:28:09 $\n";
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// Constants
// (None)
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// Public static methods
/***************************************************************************
* Read one or more XML keyfiles and display information about the public or
* private encryption keys.
*
*
* Usage *
* java tribble.security.KeyReader [option...] keyfile.xml ... ** *
* Options: *
*
* Note that this is not a full-fledged XML parser, but rather an extemely * simplified scanner that assumes that the XML input text is in a particular * format. Input XML text that deviates too far from the assumed format will * not be parsed correctly. * * @return * A public or private encryption key, or null if the end of the input stream * was reached before finding a key. * * @throws IOException * Thrown if an I/O (read) error occurs. * * @since 1.1, 2003-03-14 */ public synchronized Key readKey() throws IOException, GeneralSecurityException { // Read an unprotected (unencrypted) key return (readKey(null)); } /*************************************************************************** * Read a public or private encryption key from the XML input stream of this * key reader. * *
* Note that this is not a full-fledged XML parser, but rather an extemely * simplified scanner that assumes that the XML input text is in a particular * format. Input XML text that deviates too far from the assumed format will * not be parsed correctly. * * @param passphrase * Passphrase to use to decrypt private keys. * * @return * A public or private encryption key, or null if the end of the input stream * was reached before finding a key. * * @throws IOException * Thrown if an I/O (read) error occurs. * * @since 1.4, 2003-03-27 */ public synchronized Key readKey(String passphrase) throws IOException, GeneralSecurityException { String type = "?"; String created = "?"; String algo = "?"; String format = "?"; String protect = "no"; String encoding = "?"; String size = "?"; String keyData; StringBuffer keyLine = new StringBuffer(800); byte[] enc; int len; KeyFactory keyFact; KeySpec spec; Key key; // Read formatted text lines for (;;) { String line; // Read a key as a formatted text line line = readLine(); // Check the text line if (line == null) break; if (line.startsWith(" 0; ) k[i] = (byte) 0x00; // Decrypt the encoded key System.out.println("% enc.len=" + enc.length); d = cipher.doAllFinal(enc, 0, enc.length); System.out.println("% d.len=" + d.length + ", [0..3]=" + Integer.toHexString(d[0] & 0xFF) + "." + Integer.toHexString(d[1] & 0xFF) + ", " + Integer.toHexString(d[2] & 0xFF) + "." + Integer.toHexString(d[3] & 0xFF)); +++*/ // Verify the decrypted sentinel byte if (d[0] != (byte) 0xAA || d[1] != (byte) 0x55) throw new GeneralSecurityException("Wrong passphrase"); // Extract the decrypted encoded key len = ((d[2] & 0xFF) << 8) + (d[3] & 0xFF); len = d.length/0x10000*0x10000 + len; enc = new byte[len-4]; System.out.println("% e.len=" + enc.length); System.arraycopy(d, 4, enc, 0, len-4); for (int i = d.length; i-- > 0; ) d[i] = (byte) 0x00; } // Convert encoded bytes into a key object keyFact = KeyFactory.getInstance(algo); if (format.equalsIgnoreCase("X.509") || format.equalsIgnoreCase("X509")) spec = new X509EncodedKeySpec(enc); else if (format.equalsIgnoreCase("PKCS#8") || format.equalsIgnoreCase("PKCS8")) spec = new PKCS8EncodedKeySpec(enc); else throw new NoSuchAlgorithmException("Unsupported key format: " + format); if (type.equals("public")) key = keyFact.generatePublic(spec); else if (type.equals("private")) key = keyFact.generatePrivate(spec); else throw new NoSuchAlgorithmException("Unsupported key type: " + type); // Done m_type = type; m_created = created; m_alg = algo; m_format = format; m_protected = protect; m_encoding = encoding; m_key = key; return (key); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // Private constructors /*************************************************************************** * Default constructor. * Do not used this constructor. * * @since 1.1, 2003-03-14 */ private KeyReader() { // Do nothing } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // Private methods /*************************************************************************** * Read a non-blank line from the XML input stream of this key reader. * Also cleans up the contents of the line by removing spaces and quote * marks. * * @return * A string containing the contents of a non-blank text line, or null if the * end of the input stream was reached before finding a key. * * @throws IOException * Thrown if an I/O (read) error occurs. * * @since 1.1, 2003-03-14 */ private String readLine() throws IOException { String line; // Check input stream if (m_in == null) throw new IOException("Null input stream"); // Read a non-blank text line do { int i; int j; int len; char quote; StringBuffer buf; // Read a text line from the input stream line = m_in.readLine(); // Check for end of file if (line == null) return (null); // Clean up the XML text line line = line.trim(); len = line.length(); buf = new StringBuffer(80); quote = '\0'; for (i = 0, j = 0; i < len; i++) { char ch; // Get the next character from the XML text line ch = line.charAt(i); // Handle quotes and whitespace if (ch == '\'' && quote == '\0') { quote = ch; continue; } else if (ch == '"' && quote == '\0') { quote = ch; continue; } else if (ch == quote && quote != '\0') { quote = '\0'; continue; } else if ((ch == ' ' || ch == '\t') && quote == '\0') continue; if (ch == '>' && i == len-1) continue; // Insert the cleaned char buf.append(ch); } // Replace the XML text line with its cleaned-up version if (j != len) line = buf.toString(); } while (line.length() == 0); // Done return (line); } } // End KeyReader.java