From 3e3399adc66681946e88c99f29038a4065b16bd1 Mon Sep 17 00:00:00 2001 From: zzz Date: Mon, 9 Sep 2013 00:49:14 +0000 Subject: [PATCH] - Add Java key import to SigUtil - Import priv key to SU3File in Java encoded format instead of I2P format - New KeyRing stub --- core/java/src/net/i2p/crypto/KeyRing.java | 37 ++++++++++++++++ core/java/src/net/i2p/crypto/SU3File.java | 15 +++---- core/java/src/net/i2p/crypto/SigUtil.java | 54 +++++++++++++++++++++++ 3 files changed, 97 insertions(+), 9 deletions(-) create mode 100644 core/java/src/net/i2p/crypto/KeyRing.java diff --git a/core/java/src/net/i2p/crypto/KeyRing.java b/core/java/src/net/i2p/crypto/KeyRing.java new file mode 100644 index 0000000000..6efba6fd99 --- /dev/null +++ b/core/java/src/net/i2p/crypto/KeyRing.java @@ -0,0 +1,37 @@ +package net.i2p.crypto; + +/* + * free (adj.): unencumbered; not under the control of others + * No warranty of any kind, either expressed or implied. + */ + +import java.io.IOException; +import java.security.GeneralSecurityException; + +import net.i2p.data.SigningPublicKey; + +/** + * A backend for storing and retrieving SigningPublicKeys + * to be used for verifying signatures. + * + * @since 0.9.9 + */ +public interface KeyRing { + + /** + * Get a key. + * Throws on all errors. + * @param scope a domain identifier, indicating router update, reseed, etc. + * @return null if none + */ + public SigningPublicKey getKey(String keyName, String scope, SigType type) + throws GeneralSecurityException, IOException; + + /** + * Store a key. + * Throws on all errors. + * @param scope a domain identifier, indicating router update, reseed, etc. + */ + public void setKey(String keyName, String scope, SigningPublicKey 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 e55828c6ef..dfb88ee6ca 100644 --- a/core/java/src/net/i2p/crypto/SU3File.java +++ b/core/java/src/net/i2p/crypto/SU3File.java @@ -11,6 +11,7 @@ import java.io.IOException; import java.io.OutputStream; import java.security.DigestInputStream; import java.security.DigestOutputStream; +import java.security.GeneralSecurityException; import java.security.MessageDigest; import java.security.PrivateKey; import java.security.PublicKey; @@ -485,26 +486,22 @@ public class SU3File { */ private static final boolean signCLI(SigType type, String inputFile, String signedFile, String privateKeyFile, String version, String signerName) { - InputStream in = null; try { - in = new FileInputStream(privateKeyFile); - SigningPrivateKey spk = new SigningPrivateKey(type); - spk.readBytes(in); - in.close(); + File pkfile = new File(privateKeyFile); + PrivateKey pk = SigUtil.importJavaPrivateKey(pkfile, type); + SigningPrivateKey spk = SigUtil.fromJavaKey(pk, type); SU3File file = new SU3File(signedFile); file.write(new File(inputFile), CONTENT_ROUTER, version, signerName, spk); System.out.println("Input file '" + inputFile + "' signed and written to '" + signedFile + "'"); return true; - } catch (DataFormatException dfe) { + } catch (GeneralSecurityException gse) { System.out.println("Error signing input file '" + inputFile + "'"); - dfe.printStackTrace(); + gse.printStackTrace(); return false; } catch (IOException ioe) { System.out.println("Error signing input file '" + inputFile + "'"); ioe.printStackTrace(); return false; - } finally { - if (in != null) try { in.close(); } catch (IOException ioe) {} } } diff --git a/core/java/src/net/i2p/crypto/SigUtil.java b/core/java/src/net/i2p/crypto/SigUtil.java index 124ed29354..641515758f 100644 --- a/core/java/src/net/i2p/crypto/SigUtil.java +++ b/core/java/src/net/i2p/crypto/SigUtil.java @@ -1,5 +1,11 @@ package net.i2p.crypto; +import java.io.ByteArrayOutputStream; +import java.io.File; +import java.io.FileInputStream; +import java.io.InputStream; +import java.io.IOException; + import java.math.BigInteger; import java.security.GeneralSecurityException; import java.security.InvalidKeyException; @@ -22,6 +28,8 @@ import java.security.spec.ECPublicKeySpec; import java.security.spec.ECPoint; import java.security.spec.EllipticCurve; import java.security.spec.KeySpec; +import java.security.spec.PKCS8EncodedKeySpec; +import java.security.spec.X509EncodedKeySpec; import java.util.Map; import net.i2p.data.Signature; @@ -234,6 +242,52 @@ class SigUtil { return new Signature(type, aSN1ToSigBytes(asn, type.getSigLen())); } + /** + * @return JAVA key! + */ + public static PublicKey importJavaPublicKey(File file, SigType type) + throws GeneralSecurityException, IOException { + byte[] data = getData(file); + KeySpec ks = new X509EncodedKeySpec(data); + String algo = type == SigType.DSA_SHA1 ? "DSA" : "EC"; + KeyFactory kf = KeyFactory.getInstance(algo); + return kf.generatePublic(ks); + } + + /** + * @return JAVA key! + */ + public static PrivateKey importJavaPrivateKey(File file, SigType type) + throws GeneralSecurityException, IOException { + byte[] data = getData(file); + KeySpec ks = new PKCS8EncodedKeySpec(data); + String algo = type == SigType.DSA_SHA1 ? "DSA" : "EC"; + KeyFactory kf = KeyFactory.getInstance(algo); + return kf.generatePrivate(ks); + } + + /** 16 KB max */ + private static byte[] getData(File file) throws IOException { + byte buf[] = new byte[1024]; + InputStream in = null; + ByteArrayOutputStream out = new ByteArrayOutputStream(1024); + try { + in = new FileInputStream(file); + int read = 0; + int tot = 0; + while ( (read = in.read(buf)) != -1) { + out.write(buf, 0, read); + tot += read; + if (tot > 16*1024) + throw new IOException("too big"); + } + return out.toByteArray(); + } finally { + if (in != null) + try { in.close(); } catch (IOException ioe) {} + } + } + /** * @param bi non-negative * @return array of exactly len bytes