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
This commit is contained in:
zzz
2013-09-14 15:53:08 +00:00
parent 68aa1aea8e
commit b5dc9bc0ba
4 changed files with 98 additions and 19 deletions

View File

@@ -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;
/**

View File

@@ -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) {}
}

View File

@@ -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;
}

View File

@@ -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) {