[Webfunds-commits] java/webfunds/sox Crypto.java
Jeroen C. van Gelderen
gelderen@cypherpunks.ai
Mon, 4 Sep 2000 19:16:59 -0400 (AST)
gelderen 00/09/04 19:16:59
Modified: webfunds/sox Crypto.java
Log:
Do Asymmetric crypto with Cryptix JCE. We have to include a couple of hacks
to work around long-standing RSA bugs in Cryptix 3 which is used by fielded
WebFunds implementations. These hacks can go as soon as those implentations
are retired.
Revision Changes Path
1.50 +140 -191 java/webfunds/sox/Crypto.java
Index: Crypto.java
===================================================================
RCS file: /home/webfunds/cvsroot/java/webfunds/sox/Crypto.java,v
retrieving revision 1.49
retrieving revision 1.50
diff -u -r1.49 -r1.50
--- Crypto.java 2000/08/24 02:02:08 1.49
+++ Crypto.java 2000/09/04 23:16:59 1.50
@@ -1,4 +1,4 @@
-/* $Id: Crypto.java,v 1.49 2000/08/24 02:02:08 gelderen Exp $
+/* $Id: Crypto.java,v 1.50 2000/09/04 23:16:59 gelderen Exp $
*
* Copyright (c) Systemics Inc. 1995-2000 on behalf of
* The WebFunds Development Team. All Rights Reserved.
@@ -22,10 +22,12 @@
import java.security.ProviderException;
import java.security.PublicKey;
import java.security.SecureRandom;
+import java.security.Security;
import java.security.Signature;
import java.security.SignatureException;
import java.security.cert.Certificate;
import java.security.interfaces.RSAPrivateCrtKey;
+import java.security.interfaces.RSAPrivateKey;
import java.security.interfaces.RSAPublicKey;
import java.security.spec.RSAPublicKeySpec;
import java.security.spec.RSAPrivateKeySpec;
@@ -41,15 +43,15 @@
import javax.crypto.spec.IvParameterSpec;
import cryptix.jce.provider.asn.*;
+import cryptix.jce.provider.key.RawSecretKey;
+import cryptix.jce.provider.rsa.RSAPrivateCrtKeyCryptix;
+import cryptix.jce.provider.rsa.RSAPrivateKeyCryptix;
+import cryptix.jce.provider.rsa.RSAPublicKeyImpl;
import cryptix.openpgp.PGPPublicKey;
import cryptix.openpgp.PGPSecretKey;
import cryptix.openpgp.algorithm.PGPRSA;
-import cryptix.provider.key.RawSecretKey;
-import cryptix.provider.rsa.RawRSAPrivateKey;
-import cryptix.provider.rsa.RawRSAPublicKey;
-
import webfunds.utils.Hex;
@@ -58,7 +60,7 @@
*
* Centralized crypto methods. Currently being overhauled.
*
- * @version $Revision: 1.49 $
+ * @version $Revision: 1.50 $
*/
public final class Crypto
{
@@ -73,22 +75,18 @@
//............................................................................
static {
- java.security.Security.addProvider(
- new cryptix.jce.provider.CryptixCrypto() );
-
- //'till JCE porting is complete, Cryptix3 MUST come AFTER CryptixCrypto
- java.security.Security.addProvider(new cryptix.provider.Cryptix());
+ Security.addProvider( new cryptix.jce.provider.CryptixCrypto() );
}
- private static String
+ private static final String
CIPHER_ALGORITHM = "DESede",
CIPHER_TRANSFORM = "DESede/CBC/PKCS#5",
MD_ALGORITHM = "SHA";
- public static int cipher_keylen = 24;
- public static String pk_alg = "RSA";
- public static String sig_alg = "MD5/RSA";
+ public static final int cipher_keylen = 24;
+ public static final String pk_alg = "RSA";
+ public static final String sig_alg = "MD5withRSA";
public static SecureRandom sr;
@@ -140,7 +138,7 @@
logDebug("generateKeys(...)");
try {
if (keyGen == null)
- keyGen = KeyPairGenerator.getInstance(pk_alg, "CryptixCrypto");
+ keyGen = KeyPairGenerator.getInstance("RSA", "CryptixCrypto");
keyGen.initialize(bits, getSecureRandom());
KeyPair keyPair = keyGen.generateKeyPair();
@@ -148,7 +146,7 @@
return keyPair;
} catch(NoSuchAlgorithmException ex) {
- throw new ProviderException(pk_alg+" Algorithm missing, " + ex);
+ throw new ProviderException("RSA algorithm missing, " + ex);
} catch(NoSuchProviderException e) {
throw new ProviderException();
@@ -188,7 +186,7 @@
*/
public static PublicKey getPublicKeyFromCert(Certificate cert)
{
- logDebug(cert.toString());
+ logDebug("getPublicKeyFromCert returns:\n" + cert.toString());
return toCryptixKey( cert.getPublicKey() );
}
@@ -414,49 +412,11 @@
throws KeyException
{
try {
- java.security.Cipher rsa =
- java.security.Cipher.getInstance(pk_alg);
- pk = toCryptixKey(pk);
- rsa.initEncrypt(pk);
+ Cipher rsa = Cipher.getInstance("RSA/ECB/PKCS#1", "CryptixCrypto");
+ rsa.init(Cipher.ENCRYPT_MODE, pk);
byte[] keyData = key.getEncoded();
- byte[] rsa_pkt = new byte[rsa.getPlaintextBlockSize()];
-
- //
- // Generate the padding
- //
- int padlen = rsa_pkt.length - keyData.length - 3;
- if (padlen < 8)
- throw new InternalError("No room for padding");
-
- byte[] padding = new byte[padlen];
- SecureRandom sr = getSecureRandom();
- sr.nextBytes(padding);
-
- // Find a random non-zero number ...
- byte rnd = padding[0];
- for (int i = padlen-1; rnd == 0 && i >= 0; i--)
- rnd = padding[i];
-
- // ... with which to replace zero bytes in the padding
- // (since this padding must be non-zero)
- for (int i = padlen-1; i >= 0; i--)
- if (padding[i] == 0)
- padding[i] = rnd;
-
- //
- // Generate the PKCS#1 packet
- //
- rsa_pkt[0] = 0;
- rsa_pkt[1] = 2;
- System.arraycopy(padding, 0, rsa_pkt, 2, padlen);
- rsa_pkt[padlen+2] = 0;
- System.arraycopy(keyData, 0, rsa_pkt, padlen+3, keyData.length);
-
- //
- // Encrypt the data
- //
- byte[] encHdr = rsa.crypt(rsa_pkt);
+ byte[] encHdr = rsa.doFinal(keyData);
byte[] encData = encrypt(key, data, offset, len);
//
@@ -467,9 +427,9 @@
System.arraycopy(encData, 0, retval, encHdr.length, encData.length);
return retval;
- } catch (NoSuchAlgorithmException e) {
- throw new ProviderException(
- "Algorithm (" + pk_alg + ") not found (" + e.getMessage()+")");
+ } catch(Exception e) {
+ e.printStackTrace();
+ throw new ProviderException("NY");
}
}
@@ -490,7 +450,7 @@
byte[] data, int offset, int len)
throws KeyException
{
- return pk_encrypt(generateKey(), pk, data, offset, len);
+ return pk_encrypt(generateKey(), pk, data, offset, len);
}
/**
@@ -506,7 +466,7 @@
public static byte[] pk_encrypt(Key key, PublicKey pk, byte[] data)
throws KeyException
{
- return pk_encrypt(key, pk, data, 0, data.length);
+ return pk_encrypt(key, pk, data, 0, data.length);
}
@@ -524,50 +484,15 @@
byte[] data, int offset, int len)
throws KeyException
{
- pk = translateKey(pk);
try {
- //
- // Decrypt the key
- //
- java.security.Cipher rsa = java.security.Cipher.getInstance(pk_alg);
- rsa.initDecrypt(pk);
-
- int pktlen = rsa.getCiphertextBlockSize() + 1;
-
- System.err.println("pktlen: "+pktlen+", data.length: "+data.length);
-
- byte[] rsa_pkt = rsa.crypt(data, offset, pktlen);
- len -= pktlen;
- offset += pktlen;
-
- //
- // Unpack the PKCS#1 packet
- //
- if (rsa_pkt[0] != 0)
- throw new KeyException(
- "Bad start of PKCS1 packet in decrypted data");
-
- if (rsa_pkt[1] != 2)
- throw new KeyException("Bad block type in decrypted data");
-
- // Data starts after first zero octet
- int pad_start = 2;
- while(pad_start < rsa_pkt.length && rsa_pkt[pad_start++] != 0)
- ;
-
- if (pad_start == rsa_pkt.length)
- throw new KeyException("Bad PKCS#1 packet in decrypted data");
-
- byte[] key = new byte[rsa_pkt.length - pad_start];
- if (key.length != cipher_keylen)
- throw new KeyException("Unexpected size of PKCS#1 data field");
-
- System.arraycopy(rsa_pkt, pad_start, key, 0, key.length);
+ Cipher rsa = Cipher.getInstance("RSA/ECB/PKCS#1", "CryptixCrypto");
+ rsa.init(Cipher.DECRYPT_MODE, pk);
+ int pktlen = getKeyLength(pk);
+ byte[] key = rsa.doFinal(data, offset, pktlen);
return new RawSecretKey(CIPHER_ALGORITHM, key);
- } catch (NoSuchAlgorithmException e) {
- throw new ProviderException(
- pk_alg+" Algorithm not found ("+e.getMessage()+")");
+ } catch(Exception e) {
+ throw new ProviderException("NY");
}
}
@@ -589,20 +514,22 @@
byte[] data, int offset, int len)
throws KeyException
{
- pk = translateKey(pk);
- try {
- // Only using cipher to get packet length ...
- java.security.Cipher rsa = java.security.Cipher.getInstance(pk_alg);
- rsa.initDecrypt(pk);
- int pktlen = rsa.getCiphertextBlockSize();
- return decrypt(key, data, offset+pktlen, len-pktlen);
- } catch (NoSuchAlgorithmException e) {
- throw new ProviderException(
- pk_alg+" Algorithm not found ("+e.getMessage()+")");
- }
+ int pktlen = getKeyLength(pk);
+ return decrypt(key, data, offset+pktlen, len-pktlen);
}
+ private static int getKeyLength(PrivateKey key) {
+
+ if( !(key instanceof RSAPrivateKey) )
+ throw new IllegalArgumentException(
+ "!(key instanceof RSAPrivateKey)");
+
+ RSAPrivateKey privKey = (RSAPrivateKey)key;
+ return (privKey.getModulus().bitLength()+7) / 8;
+ }
+
+
/**
* Decrypt data, and return the original plaintext
*
@@ -672,14 +599,18 @@
*/
public static byte[] sign(PrivateKey key, byte[] data) throws KeyException {
try {
- Signature sig = Signature.getInstance(sig_alg);
+ Signature sig = Signature.getInstance(sig_alg, "CryptixCrypto");
sig.initSign(key);
sig.update(data);
- return encodeSignature(sig.sign());
+ byte[] sigBytes = sig.sign();
+ return encodeSignature(sigBytes);
} catch (NoSuchAlgorithmException e) {
throw new ProviderException(
- pk_alg+" Algorithm not found ("+e.getMessage()+")");
+ sig_alg+" Algorithm not found ("+e.getMessage()+")");
+
+ } catch (NoSuchProviderException e) {
+ throw new ProviderException("Provider CryptixCrypto not found.");
} catch (SignatureException e) {
throw new InternalError("sign() failed ("+e.getMessage()+")");
@@ -712,7 +643,7 @@
return sig.verify(decodeSignature(sigX509));
} catch (NoSuchAlgorithmException e) {
- throw new ProviderException(pk_alg+" Algorithm not found ("+
+ throw new ProviderException(sig_alg+" Algorithm not found ("+
e.getMessage()+")");
} catch (SignatureException e) {
e.printStackTrace();
@@ -758,22 +689,50 @@
}
- /**
- * Generate a "fingerprint" from an X509 key
- * The fingerprint is simply an message digest of the encoded X509Key.
- *
- * @param key An X509Key object, from which to extract the public key data
- * @return the key "fingerprint"
- * @exception InvalidKeyException the X509Key is invalid
- * (i.e. incorrectly formatted)
- */
- public static byte[] fingerprint(PublicKey key) throws InvalidKeyException {
- key = translateKey(key);
- return digest(key.getEncoded());
+ public static byte[] fingerprint(PublicKey key)
+ throws InvalidKeyException
+ {
+ if( !(key instanceof RSAPublicKey) )
+ throw new IllegalArgumentException(
+ "!(key instanceof RSAPublicKey)");
+
+ RSAPublicKey pubKey = (RSAPublicKey)key;
+
+ try {
+ BigInteger e = pubKey.getPublicExponent();
+ int eBitLen = e.bitLength();
+
+ BigInteger n = pubKey.getModulus();
+ int nBitLen = n.bitLength();
+
+ ByteArrayOutputStream baos = new ByteArrayOutputStream();
+ baos.write(eBitLen >>> 8);
+ baos.write(eBitLen & 0xFF);
+ baos.write(getMagnitude(e));
+
+ baos.write(nBitLen >>> 8);
+ baos.write(nBitLen & 0xFF);
+ baos.write(getMagnitude(n));
+
+ return digest(baos.toByteArray());
+ } catch(IOException e) {
+ throw new InternalError("PANIC");
+ }
}
+ public static byte[] getMagnitude(BigInteger x) {
+ byte[] y = x.toByteArray(); // including leading 0(s).
+ int i = 0;
+ for ( ; y[i] == 0 && i < y.length - 1; i++)
+ ;
+ byte[] result = new byte[y.length - i]; // excluding leading 0(s).
+ System.arraycopy(y, i, result, 0, y.length - i);
+ return result;
+ }
+
+
////////////////////////////////////////////////////////////////////////
// Methods for encoding and decoding X509 signatures
////////////////////////////////////////////////////////////////////////
@@ -880,7 +839,7 @@
AsnInteger n = (AsnInteger)seq.get(0);
AsnInteger e = (AsnInteger)seq.get(1);
- return new RawRSAPublicKey(
+ return new RSAPublicKeyImpl(
n.toBigInteger(),
e.toBigInteger());
@@ -899,7 +858,6 @@
* @return the encoded key (as a byte array)
*/
public static byte[] encodePublicKey(PublicKey key) {
- key = translateKey(key);
/*
* An RSA public key is defined as:
@@ -910,15 +868,15 @@
* }
*/
- if( !(key instanceof RawRSAPublicKey) )
+ if( !(key instanceof RSAPublicKey) )
throw new InternalError("Unexpected object");
- RawRSAPublicKey pub = (RawRSAPublicKey)key;
+ RSAPublicKey pub = (RSAPublicKey)key;
try {
AsnSequence seq = new AsnSequence(
new AsnInteger( pub.getModulus() ),
- new AsnInteger( pub.getExponent() ) );
+ new AsnInteger( pub.getPublicExponent() ) );
AsnOutputStream dos = new AsnOutputStream();
dos.write(seq);
@@ -985,10 +943,14 @@
* Note: Cryptix RSA private key constructor doesn't bother
* with values n, e, dmp1 or dmq1.
*/
- return new RawRSAPrivateKey(
- d.toBigInteger(),
+ return new RSAPrivateCrtKeyCryptix(
+ n.toBigInteger(),
+ e.toBigInteger(),
+ d.toBigInteger(),
p.toBigInteger(),
q.toBigInteger(),
+ dmp1.toBigInteger(),
+ dmq1.toBigInteger(),
u.toBigInteger() );
} catch(ClassCastException e) {
@@ -1007,7 +969,6 @@
*/
public static byte[] encodePrivateKey(PrivateKey key)
{
- key = translateKey(key);
// An RSA private key is defined as:
//
// SEQUENCE {
@@ -1021,12 +982,11 @@
// Integer U (IQMP)
// }
//
+
+ if( !(key instanceof RSAPrivateCrtKey) )
+ throw new InternalError("Unexpected object");
- // Convert to a Cryptix key
- if (!(key instanceof cryptix.provider.rsa.RawRSAPrivateKey))
- throw new InternalError("Unexpected object");
- cryptix.provider.rsa.RawRSAPrivateKey priv;
- priv = (cryptix.provider.rsa.RawRSAPrivateKey)key;
+ RSAPrivateCrtKey priv = (RSAPrivateCrtKey)key;
try {
//
@@ -1036,9 +996,9 @@
//
BigInteger one = BigInteger.valueOf(1L);
BigInteger m = priv.getModulus();
- BigInteger p = priv.getP();
- BigInteger q = priv.getQ();
- BigInteger d = priv.getExponent();
+ BigInteger p = priv.getPrimeP();
+ BigInteger q = priv.getPrimeQ();
+ BigInteger d = priv.getPrivateExponent();
BigInteger phi = p.subtract(one).multiply(q.subtract(one));
BigInteger e = d.modInverse(phi);
BigInteger dmp1 = d.mod(p.subtract(one));
@@ -1052,7 +1012,7 @@
vals[4] = new AsnInteger(q);
vals[5] = new AsnInteger(dmp1);
vals[6] = new AsnInteger(dmq1);
- vals[7] = new AsnInteger( priv.getInverseOfQModP() );
+ vals[7] = new AsnInteger( priv.getCrtCoefficient() );
AsnSequence seq = new AsnSequence(vals);
AsnOutputStream os = new AsnOutputStream();
@@ -1064,37 +1024,11 @@
}
}
- private static PrivateKey translateKey(PrivateKey key) {
- if( key.getFormat().equals("Cryptix") ) {
- RSAPrivateCrtKey rsapk = (RSAPrivateCrtKey)key;
- return new RawRSAPrivateKey(
- rsapk.getPrivateExponent(),
- rsapk.getPrimeP(),
- rsapk.getPrimeQ(),
- rsapk.getCrtCoefficient() );
- }
-
- return key;
- }
-
-
- private static PublicKey translateKey(PublicKey key) {
- return toCryptixKey(key);
- }
-
- /**
- * Convert the given key to a Cryptix' RawRSAPublicKey.
- *
- * <p>This is a no-op when the given key already is RawRSAPublicKey.</p>
- */
public static PublicKey toCryptixKey(PublicKey pk) {
// XXX: move out of Certificate.java. Can go for JCE 1.2
- /*
- * Don't do conversion when the key is a Cryptix RAW-encoded key.
- 1G*/
if( pk.getFormat().equals("RAW") )
return pk;
@@ -1102,7 +1036,7 @@
RSAPublicKey rsapk = (RSAPublicKey)pk;
BigInteger n = rsapk.getModulus();
BigInteger e = rsapk.getPublicExponent();
- return new RawRSAPublicKey(n, e);
+ return new RSAPublicKeyImpl(n, e);
}
if( pk.getFormat().equals("OpenPGP") ) {
@@ -1112,7 +1046,7 @@
RSAPublicKeySpec rsapubspec = pgprsa.getRSAPublicKeySpec();
BigInteger n = rsapubspec.getModulus();
BigInteger e = rsapubspec.getPublicExponent();
- return new RawRSAPublicKey(n, e);
+ return new RSAPublicKeyImpl(n, e);
} else {
return pk;
}
@@ -1126,7 +1060,7 @@
seq = (AsnSequence)is.read();
AsnInteger n = (AsnInteger)seq.get(0);
AsnInteger e = (AsnInteger)seq.get(1);
- return new RawRSAPublicKey(n.toBigInteger(), e.toBigInteger());
+ return new RSAPublicKeyImpl(n.toBigInteger(), e.toBigInteger());
} catch(IOException e) {
return null;
}
@@ -1143,7 +1077,7 @@
RSAPrivateKeySpec rsaprivspec = pgprsa.getRSAPrivateKeySpec();
BigInteger n = rsaprivspec.getModulus();
BigInteger d = rsaprivspec.getPrivateExponent();
- return new RawRSAPrivateKey(n, d);
+ return new RSAPrivateKeyCryptix(n, d);
} else {
return pk;
}
@@ -1151,7 +1085,20 @@
} else {
return null;
}
+ }
+
+
+ public static PublicKey toCryptixJCEKey(PublicKey pk) {
+ logDebug("toCryptixJCEKey: pk instanceof " + pk.getClass());
+
+ if( pk instanceof cryptix.jce.provider.rsa.RSAPublicKeyCryptix )
+ return pk;
+
+ if( pk instanceof cryptix.jce.provider.rsa.RSAPublicKeyImpl )
+ return pk;
+
+ throw new RuntimeException();
}
@@ -1159,20 +1106,22 @@
// Test code
////////////////////////////////////////////////////////////////////////
- /**
- * Test code
- */
public static void main(String args[])
throws Exception
{
- args = null;
- Key key = Crypto.generateKey();
- ByteArrayOutputStream baos = new ByteArrayOutputStream();
- baos.write("x".getBytes());
- baos.write(encrypt(key, "stuff".getBytes(), 1, 3));
- baos.write("x".getBytes());
- byte[] encData = baos.toByteArray();
- String s = new String(decrypt(key, encData, 1, encData.length-2));
- System.out.println("Decrypt="+s);
+ KeyPair kp = generateKeys(1024);
+
+ byte[] pt = new byte[16];
+ System.out.println("pt: " + Hex.data2hex(pt));
+
+ byte[] ct = pk_encrypt(kp.getPublic(), pt, 0, pt.length);
+
+ System.out.println("ct: " + Hex.data2hex(ct));
+
+ byte[] protoPt = pk_decrypt(kp.getPrivate(), ct, 0, ct.length);
+ System.out.println("ppt: " + Hex.data2hex(protoPt));
+
+ for(int i=0; i<protoPt.length; i++)
+ if( protoPt[i] != 0 ) System.out.println("Oops!");
}
}