forked from I2P_Developers/i2p.i2p
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:
@@ -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;
|
||||
|
||||
/**
|
||||
|
@@ -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) {}
|
||||
}
|
||||
|
@@ -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;
|
||||
}
|
||||
|
@@ -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) {
|
||||
|
Reference in New Issue
Block a user