From b5dc9bc0ba6958a03810fea7fb093a3e46e5e687 Mon Sep 17 00:00:00 2001 From: zzz Date: Sat, 14 Sep 2013 15:53:08 +0000 Subject: [PATCH] DSAEngine: Add sign/verify methods using Java keys SU3File: Use Java keys to sign and verify so we don't lose the key parameters in the conversion to I2P keys --- core/java/src/net/i2p/crypto/DSAEngine.java | 91 +++++++++++++++++++- core/java/src/net/i2p/crypto/DirKeyRing.java | 9 +- core/java/src/net/i2p/crypto/KeyRing.java | 7 +- core/java/src/net/i2p/crypto/SU3File.java | 10 +-- 4 files changed, 98 insertions(+), 19 deletions(-) diff --git a/core/java/src/net/i2p/crypto/DSAEngine.java b/core/java/src/net/i2p/crypto/DSAEngine.java index 1d397f480..51256db38 100644 --- a/core/java/src/net/i2p/crypto/DSAEngine.java +++ b/core/java/src/net/i2p/crypto/DSAEngine.java @@ -38,6 +38,9 @@ import java.security.KeyFactory; import java.security.MessageDigest; import java.security.PrivateKey; import java.security.PublicKey; +import java.security.interfaces.DSAPrivateKey; +import java.security.interfaces.ECPrivateKey; +import java.security.interfaces.RSAPrivateKey; import net.i2p.I2PAppContext; import net.i2p.data.Hash; @@ -176,6 +179,25 @@ public class DSAEngine { } } + /** + * Generic signature type. + * If you have a Java pubkey, use this, so you don't lose the key parameters, + * which may be different than the ones defined in SigType. + * + * @param hash SHA1Hash, Hash, Hash384, or Hash512 + * @param pubKey Java key + * @since 0.9.9 + */ + public boolean verifySignature(Signature signature, SimpleDataStructure hash, PublicKey pubKey) { + try { + return altVerifySigRaw(signature, hash, pubKey); + } catch (GeneralSecurityException gse) { + if (_log.shouldLog(Log.WARN)) + _log.warn(signature.getType() + " Sig Verify Fail", gse); + return false; + } + } + /** * Verify using DSA-SHA1 or Syndie DSA-SHA256 ONLY. * @param hash either a Hash or a SHA1Hash @@ -330,6 +352,28 @@ public class DSAEngine { } } + /** + * Generic signature type. + * If you have a Java privkey, use this, so you don't lose the key parameters, + * which may be different than the ones defined in SigType. + * + * @param hash SHA1Hash, Hash, Hash384, or Hash512 + * @param pubKey Java key + * @param type returns a Signature of this type + * @return null on error + * @since 0.9.9 + */ + public Signature sign(SimpleDataStructure hash, PrivateKey privKey, SigType type) { + try { + String algo = getRawAlgo(privKey); + return altSignRaw(algo, hash, privKey, type); + } catch (GeneralSecurityException gse) { + if (_log.shouldLog(Log.WARN)) + _log.warn(type + " Sign Fail", gse); + return null; + } + } + /** * Sign using DSA-SHA1 or Syndie DSA-SHA256 ONLY. * @@ -477,13 +521,29 @@ public class DSAEngine { SigType type = signature.getType(); if (type != verifyingKey.getType()) throw new IllegalArgumentException("type mismatch sig=" + type + " key=" + verifyingKey.getType()); + + PublicKey pubKey = SigUtil.toJavaKey(verifyingKey); + return verifySignature(signature, hash, pubKey); + } + + /** + * Generic raw verify any type. + * If you have a Java pubkey, use this, so you don't lose the key parameters, + * which may be different than the ones defined in SigType. + * + * @throws GeneralSecurityException if algorithm unvailable or on other errors + * @param verifyingKey Java key + * @since 0.9.9 + */ + private boolean altVerifySigRaw(Signature signature, SimpleDataStructure hash, PublicKey pubKey) + throws GeneralSecurityException { + SigType type = signature.getType(); int hashlen = hash.length(); if (type.getHashLen() != hashlen) throw new IllegalArgumentException("type mismatch hash=" + hash.getClass() + " key=" + type); String algo = getRawAlgo(type); java.security.Signature jsig = java.security.Signature.getInstance(algo); - PublicKey pubKey = SigUtil.toJavaKey(verifyingKey); jsig.initVerify(pubKey); jsig.update(hash.getData()); boolean rv = jsig.verify(SigUtil.toJavaSig(signature)); @@ -533,13 +593,26 @@ public class DSAEngine { */ private Signature altSignRaw(SimpleDataStructure hash, SigningPrivateKey privateKey) throws GeneralSecurityException { SigType type = privateKey.getType(); + String algo = getRawAlgo(type); + java.security.Signature jsig = java.security.Signature.getInstance(algo); + PrivateKey privKey = SigUtil.toJavaKey(privateKey); + return altSignRaw(algo, hash, privKey, type); + } + + /** + * Generic raw verify any type + * @param hash SHA1Hash, Hash, Hash384, or Hash512 + * @param type returns a Signature of this type + * @throws GeneralSecurityException if algorithm unvailable or on other errors + * @since 0.9.9 + */ + private Signature altSignRaw(String algo, SimpleDataStructure hash, PrivateKey privKey, SigType type) + throws GeneralSecurityException { int hashlen = hash.length(); if (type.getHashLen() != hashlen) throw new IllegalArgumentException("type mismatch hash=" + hash.getClass() + " key=" + type); - String algo = getRawAlgo(type); java.security.Signature jsig = java.security.Signature.getInstance(algo); - PrivateKey privKey = SigUtil.toJavaKey(privateKey); jsig.initSign(privKey, _context.random()); jsig.update(hash.getData()); return SigUtil.fromJavaSig(jsig.sign(), type); @@ -558,6 +631,7 @@ public class DSAEngine { return SigUtil.fromJavaSig(jsig.sign(), SigType.DSA_SHA1); } + /** @since 0.9.9 */ private static String getRawAlgo(SigType type) { switch (type.getBaseAlgorithm()) { case DSA: @@ -571,6 +645,17 @@ public class DSAEngine { } } + /** @since 0.9.9 */ + private static String getRawAlgo(PrivateKey privKey) { + if (privKey instanceof DSAPrivateKey) + return "NONEwithDSA"; + if (privKey instanceof ECPrivateKey) + return "NONEwithECDSA"; + if (privKey instanceof RSAPrivateKey) + return "NONEwithRSA"; + throw new IllegalArgumentException(); + } + //private static final int RUNS = 1000; /** diff --git a/core/java/src/net/i2p/crypto/DirKeyRing.java b/core/java/src/net/i2p/crypto/DirKeyRing.java index 6a3996580..5ace71335 100644 --- a/core/java/src/net/i2p/crypto/DirKeyRing.java +++ b/core/java/src/net/i2p/crypto/DirKeyRing.java @@ -14,8 +14,6 @@ import java.security.PublicKey; import java.security.cert.CertificateFactory; import java.security.cert.X509Certificate; -import net.i2p.data.SigningPublicKey; - /** * Dumb storage in a directory for testing. * No sanitization of filenames, unsafe. @@ -30,7 +28,7 @@ class DirKeyRing implements KeyRing { _base = baseDir; } - public SigningPublicKey getKey(String keyName, String scope, SigType type) + public PublicKey getKey(String keyName, String scope, SigType type) throws GeneralSecurityException, IOException { keyName = keyName.replace("@", "_at_"); File test = new File(keyName); @@ -46,12 +44,11 @@ class DirKeyRing implements KeyRing { fis = new FileInputStream(kd); CertificateFactory cf = CertificateFactory.getInstance("X.509"); X509Certificate cert = (X509Certificate)cf.generateCertificate(fis); - PublicKey pk = cert.getPublicKey(); - return SigUtil.fromJavaKey(pk, type); + return cert.getPublicKey(); } finally { try { if (fis != null) fis.close(); } catch (IOException foo) {} } } - public void setKey(String keyName, String scope, SigningPublicKey key) {} + public void setKey(String keyName, String scope, PublicKey key) {} } diff --git a/core/java/src/net/i2p/crypto/KeyRing.java b/core/java/src/net/i2p/crypto/KeyRing.java index 6efba6fd9..b28837ba4 100644 --- a/core/java/src/net/i2p/crypto/KeyRing.java +++ b/core/java/src/net/i2p/crypto/KeyRing.java @@ -7,8 +7,7 @@ package net.i2p.crypto; import java.io.IOException; import java.security.GeneralSecurityException; - -import net.i2p.data.SigningPublicKey; +import java.security.PublicKey; /** * A backend for storing and retrieving SigningPublicKeys @@ -24,7 +23,7 @@ public interface KeyRing { * @param scope a domain identifier, indicating router update, reseed, etc. * @return null if none */ - public SigningPublicKey getKey(String keyName, String scope, SigType type) + public PublicKey getKey(String keyName, String scope, SigType type) throws GeneralSecurityException, IOException; /** @@ -32,6 +31,6 @@ public interface KeyRing { * Throws on all errors. * @param scope a domain identifier, indicating router update, reseed, etc. */ - public void setKey(String keyName, String scope, SigningPublicKey key) + public void setKey(String keyName, String scope, PublicKey key) throws GeneralSecurityException, IOException; } diff --git a/core/java/src/net/i2p/crypto/SU3File.java b/core/java/src/net/i2p/crypto/SU3File.java index 1c2cda6a8..f5e25f1b0 100644 --- a/core/java/src/net/i2p/crypto/SU3File.java +++ b/core/java/src/net/i2p/crypto/SU3File.java @@ -47,7 +47,7 @@ public class SU3File { private int _signerLength; private ContentType _contentType; private long _contentLength; - private SigningPublicKey _signerPubkey; + private PublicKey _signerPubkey; private boolean _headerVerified; private SigType _sigType; @@ -330,13 +330,12 @@ public class SU3File { * @param signer ID of the public key, 1-255 bytes when converted to UTF-8 */ public void write(File content, int contentType, String version, - String signer, SigningPrivateKey privkey) throws IOException { + String signer, PrivateKey privkey, SigType sigType) throws IOException { InputStream in = null; DigestOutputStream out = null; boolean ok = false; try { in = new BufferedInputStream(new FileInputStream(content)); - SigType sigType = privkey.getType(); MessageDigest md = sigType.getDigestInstance(); out = new DigestOutputStream(new BufferedOutputStream(new FileOutputStream(_file)), md); out.write(MAGIC); @@ -385,7 +384,7 @@ public class SU3File { out.on(false); SimpleDataStructure hash = sigType.getHashInstance(); hash.setData(sha); - Signature signature = _context.dsa().sign(hash, privkey); + Signature signature = _context.dsa().sign(hash, privkey, sigType); //System.out.println("hash\n" + HexDump.dump(sha)); //System.out.println("sig\n" + HexDump.dump(signature.getData())); signature.writeBytes(out); @@ -548,9 +547,8 @@ public class SU3File { System.out.println("Private key for " + signerName + " not found in keystore " + privateKeyFile); return false; } - SigningPrivateKey spk = SigUtil.fromJavaKey(pk, type); SU3File file = new SU3File(signedFile); - file.write(new File(inputFile), CONTENT_ROUTER, version, signerName, spk); + file.write(new File(inputFile), CONTENT_ROUTER, version, signerName, pk, type); System.out.println("Input file '" + inputFile + "' signed and written to '" + signedFile + "'"); return true; } catch (GeneralSecurityException gse) {