* Start of ECDSA branch:

- Add ECConstants which looks for named curves and falls back to
     explicitly defining the curves
   - Add SigUtil with converters from Java formats (ASN.1, X.509,
     PKCS#8) to I2P formats for Signatures and SigningKeys
   - Move ASN.1 converter from DSAEngine to SigUtil, generalize
     for variable length, add support for longer sequences,
     add more sanity checks, add more exceptions
   - Attempt to add BC as a Provider
   - Add parameters (curve specs) to SigTypes
   - Add support for ECDSA to DSAEngine and KeyGenerator
   - Add KeyGenerator main() tests
   - More javadocs

  All is Java 1.5 compatible but the actual algorithms, curves,
  and other support aren't necessarily present in any JVM.
  Todo: More tests, more fallbacks for various JVMs
This commit is contained in:
zzz
2013-09-06 12:04:22 +00:00
parent f4039b085a
commit 4d62f63c71
6 changed files with 838 additions and 119 deletions

View File

@@ -30,6 +30,7 @@ package net.i2p.crypto;
*/ */
import java.math.BigInteger; import java.math.BigInteger;
import java.security.spec.DSAParameterSpec;
import net.i2p.util.NativeBigInteger; import net.i2p.util.NativeBigInteger;
@@ -63,4 +64,9 @@ public class CryptoConstants {
+ "DE2BCBF6955817183995497CEA956AE515D2261898FA0510" + "DE2BCBF6955817183995497CEA956AE515D2261898FA0510"
+ "15728E5A8AACAA68FFFFFFFFFFFFFFFF", 16); + "15728E5A8AACAA68FFFFFFFFFFFFFFFF", 16);
public static final BigInteger elgg = new NativeBigInteger("2"); public static final BigInteger elgg = new NativeBigInteger("2");
/**
* @since 0.9.9
*/
public static final DSAParameterSpec DSA_SHA1_SPEC = new DSAParameterSpec(dsap, dsaq, dsag);
} }

View File

@@ -62,6 +62,12 @@ import net.i2p.util.NativeBigInteger;
* *
* Params and rv's changed from Hash to SHA1Hash for version 0.8.1 * Params and rv's changed from Hash to SHA1Hash for version 0.8.1
* Hash variants of sign() and verifySignature() restored in 0.8.3, required by Syndie. * Hash variants of sign() and verifySignature() restored in 0.8.3, required by Syndie.
*
* As of 0.9.9, certain methods support ECDSA keys and signatures, i.e. all types
* specified in SigType. The type is specified by the getType() method in
* Signature, SigningPublicKey, and SigningPrivateKey. See Javadocs for individual
* methods for the supported types. Methods encountering an unsupported type
* will throw an IllegalArgumentException.
*/ */
public class DSAEngine { public class DSAEngine {
private final Log _log; private final Log _log;
@@ -80,11 +86,26 @@ public class DSAEngine {
} }
/** /**
* Verify using DSA-SHA1. * Verify using DSA-SHA1 or ECDSA.
* Uses TheCrypto code unless configured to use the java.security libraries. * Uses TheCrypto code for DSA-SHA1 unless configured to use the java.security libraries.
*/ */
public boolean verifySignature(Signature signature, byte signedData[], SigningPublicKey verifyingKey) { public boolean verifySignature(Signature signature, byte signedData[], SigningPublicKey verifyingKey) {
boolean rv; boolean rv;
SigType type = signature.getType();
if (type != verifyingKey.getType())
throw new IllegalArgumentException("type mismatch sig=" + signature.getType() + " key=" + verifyingKey.getType());
if (type != SigType.DSA_SHA1) {
try {
rv = altVerifySig(signature, signedData, verifyingKey);
if ((!rv) && _log.shouldLog(Log.WARN))
_log.warn(type + " Sig Verify Fail");
return rv;
} catch (GeneralSecurityException gse) {
if (_log.shouldLog(Log.WARN))
_log.warn(type + " Sig Verify Fail", gse);
return false;
}
}
if (_useJavaLibs) { if (_useJavaLibs) {
try { try {
rv = altVerifySigSHA1(signature, signedData, verifyingKey); rv = altVerifySigSHA1(signature, signedData, verifyingKey);
@@ -104,25 +125,29 @@ public class DSAEngine {
} }
/** /**
* Verify using DSA-SHA1 * Verify using DSA-SHA1 ONLY
*/ */
public boolean verifySignature(Signature signature, byte signedData[], int offset, int size, SigningPublicKey verifyingKey) { public boolean verifySignature(Signature signature, byte signedData[], int offset, int size, SigningPublicKey verifyingKey) {
return verifySignature(signature, calculateHash(signedData, offset, size), verifyingKey); return verifySignature(signature, calculateHash(signedData, offset, size), verifyingKey);
} }
/** /**
* Verify using DSA-SHA1 * Verify using DSA-SHA1 ONLY
*/ */
public boolean verifySignature(Signature signature, InputStream in, SigningPublicKey verifyingKey) { public boolean verifySignature(Signature signature, InputStream in, SigningPublicKey verifyingKey) {
return verifySignature(signature, calculateHash(in), verifyingKey); return verifySignature(signature, calculateHash(in), verifyingKey);
} }
/** @param hash SHA-1 hash, NOT a SHA-256 hash */ /**
* Verify using DSA-SHA1 ONLY
* @param hash SHA-1 hash, NOT a SHA-256 hash
*/
public boolean verifySignature(Signature signature, SHA1Hash hash, SigningPublicKey verifyingKey) { public boolean verifySignature(Signature signature, SHA1Hash hash, SigningPublicKey verifyingKey) {
return verifySig(signature, hash, verifyingKey); return verifySig(signature, hash, verifyingKey);
} }
/** /**
* Nonstandard.
* Used by Syndie. * Used by Syndie.
* @since 0.8.3 (restored, was removed in 0.8.1 and 0.8.2) * @since 0.8.3 (restored, was removed in 0.8.1 and 0.8.2)
*/ */
@@ -131,10 +156,15 @@ public class DSAEngine {
} }
/** /**
* Verify using DSA-SHA1 or Syndie DSA-SHA256 ONLY.
* @param hash either a Hash or a SHA1Hash * @param hash either a Hash or a SHA1Hash
* @since 0.8.3 * @since 0.8.3
*/ */
private boolean verifySig(Signature signature, SimpleDataStructure hash, SigningPublicKey verifyingKey) { private boolean verifySig(Signature signature, SimpleDataStructure hash, SigningPublicKey verifyingKey) {
if (signature.getType() != SigType.DSA_SHA1)
throw new IllegalArgumentException("Bad sig type " + signature.getType());
if (verifyingKey.getType() != SigType.DSA_SHA1)
throw new IllegalArgumentException("Bad key type " + verifyingKey.getType());
long start = _context.clock().now(); long start = _context.clock().now();
try { try {
@@ -184,10 +214,22 @@ public class DSAEngine {
} }
/** /**
* Sign using DSA-SHA1. * Sign using DSA-SHA1 or ECDSA.
* Uses TheCrypto code unless configured to use the java.security libraries. * Uses TheCrypto code unless configured to use the java.security libraries.
*
* @return null on error
*/ */
public Signature sign(byte data[], SigningPrivateKey signingKey) { public Signature sign(byte data[], SigningPrivateKey signingKey) {
SigType type = signingKey.getType();
if (type != SigType.DSA_SHA1) {
try {
return altSign(data, signingKey);
} catch (GeneralSecurityException gse) {
if (_log.shouldLog(Log.WARN))
_log.warn(type + " Sign Fail", gse);
return null;
}
}
if (_useJavaLibs) { if (_useJavaLibs) {
try { try {
return altSignSHA1(data, signingKey); return altSignSHA1(data, signingKey);
@@ -201,7 +243,9 @@ public class DSAEngine {
} }
/** /**
* Sign using DSA-SHA1 * Sign using DSA-SHA1 ONLY
*
* @return null on error
*/ */
public Signature sign(byte data[], int offset, int length, SigningPrivateKey signingKey) { public Signature sign(byte data[], int offset, int length, SigningPrivateKey signingKey) {
if ((signingKey == null) || (data == null) || (data.length <= 0)) return null; if ((signingKey == null) || (data == null) || (data.length <= 0)) return null;
@@ -210,8 +254,10 @@ public class DSAEngine {
} }
/** /**
* Sign using DSA-SHA1. * Sign using DSA-SHA1 ONLY.
* Reads the stream until EOF. Does not close the stream. * Reads the stream until EOF. Does not close the stream.
*
* @return null on error
*/ */
public Signature sign(InputStream in, SigningPrivateKey signingKey) { public Signature sign(InputStream in, SigningPrivateKey signingKey) {
if ((signingKey == null) || (in == null) ) return null; if ((signingKey == null) || (in == null) ) return null;
@@ -219,13 +265,21 @@ public class DSAEngine {
return sign(h, signingKey); return sign(h, signingKey);
} }
/** @param hash SHA-1 hash, NOT a SHA-256 hash */ /**
* Sign using DSA-SHA1 ONLY.
*
* @param hash SHA-1 hash, NOT a SHA-256 hash
* @return null on error
*/
public Signature sign(SHA1Hash hash, SigningPrivateKey signingKey) { public Signature sign(SHA1Hash hash, SigningPrivateKey signingKey) {
return signIt(hash, signingKey); return signIt(hash, signingKey);
} }
/** /**
* Nonstandard.
* Used by Syndie. * Used by Syndie.
*
* @return null on error
* @since 0.8.3 (restored, was removed in 0.8.1 and 0.8.2) * @since 0.8.3 (restored, was removed in 0.8.1 and 0.8.2)
*/ */
public Signature sign(Hash hash, SigningPrivateKey signingKey) { public Signature sign(Hash hash, SigningPrivateKey signingKey) {
@@ -233,11 +287,16 @@ public class DSAEngine {
} }
/** /**
* Sign using DSA-SHA1 or Syndie DSA-SHA256 ONLY.
*
* @param hash either a Hash or a SHA1Hash * @param hash either a Hash or a SHA1Hash
* @return null on error
* @since 0.8.3 * @since 0.8.3
*/ */
private Signature signIt(SimpleDataStructure hash, SigningPrivateKey signingKey) { private Signature signIt(SimpleDataStructure hash, SigningPrivateKey signingKey) {
if ((signingKey == null) || (hash == null)) return null; if ((signingKey == null) || (hash == null)) return null;
if (signingKey.getType() != SigType.DSA_SHA1)
throw new IllegalArgumentException("Bad key type " + signingKey.getType());
long start = _context.clock().now(); long start = _context.clock().now();
Signature sig = new Signature(); Signature sig = new Signature();
@@ -337,6 +396,27 @@ public class DSAEngine {
return new SHA1Hash(digested); return new SHA1Hash(digested);
} }
/**
* Generic verify DSA_SHA1 or ECDSA
* @throws GeneralSecurityException if algorithm unvailable or on other errors
* @since 0.9.9
*/
private boolean altVerifySig(Signature signature, byte[] data, SigningPublicKey verifyingKey)
throws GeneralSecurityException {
SigType type = signature.getType();
if (type != verifyingKey.getType())
throw new IllegalArgumentException("type mismatch sig=" + signature.getType() + " key=" + verifyingKey.getType());
if (type == SigType.DSA_SHA1)
return altVerifySigSHA1(signature, data, verifyingKey);
java.security.Signature jsig = java.security.Signature.getInstance(type.getAlgorithmName());
PublicKey pubKey = SigUtil.toJavaECKey(verifyingKey);
jsig.initVerify(pubKey);
jsig.update(data);
boolean rv = jsig.verify(SigUtil.toJavaSig(signature));
return rv;
}
/** /**
* Alternate to verifySignature() using java.security libraries. * Alternate to verifySignature() using java.security libraries.
* @throws GeneralSecurityException if algorithm unvailable or on other errors * @throws GeneralSecurityException if algorithm unvailable or on other errors
@@ -353,7 +433,7 @@ public class DSAEngine {
PublicKey pubKey = keyFact.generatePublic(spec); PublicKey pubKey = keyFact.generatePublic(spec);
jsig.initVerify(pubKey); jsig.initVerify(pubKey);
jsig.update(data); jsig.update(data);
boolean rv = jsig.verify(sigBytesToASN1(signature.getData())); boolean rv = jsig.verify(SigUtil.toJavaSig(signature));
//if (!rv) { //if (!rv) {
// System.out.println("BAD SIG\n" + net.i2p.util.HexDump.dump(signature.getData())); // System.out.println("BAD SIG\n" + net.i2p.util.HexDump.dump(signature.getData()));
// System.out.println("BAD SIG\n" + net.i2p.util.HexDump.dump(sigBytesToASN1(signature.getData()))); // System.out.println("BAD SIG\n" + net.i2p.util.HexDump.dump(sigBytesToASN1(signature.getData())));
@@ -361,6 +441,23 @@ public class DSAEngine {
return rv; return rv;
} }
/**
* Generic sign DSA_SHA1 or ECDSA
* @throws GeneralSecurityException if algorithm unvailable or on other errors
* @since 0.9.9
*/
private Signature altSign(byte[] data, SigningPrivateKey privateKey) throws GeneralSecurityException {
SigType type = privateKey.getType();
if (type == SigType.DSA_SHA1)
return altSignSHA1(data, privateKey);
java.security.Signature jsig = java.security.Signature.getInstance(type.getAlgorithmName());
PrivateKey privKey = SigUtil.toJavaECKey(privateKey);
jsig.initSign(privKey, _context.random());
jsig.update(data);
return SigUtil.fromJavaSig(jsig.sign(), type);
}
/** /**
* Alternate to sign() using java.security libraries. * Alternate to sign() using java.security libraries.
* @throws GeneralSecurityException if algorithm unvailable or on other errors * @throws GeneralSecurityException if algorithm unvailable or on other errors
@@ -377,81 +474,7 @@ public class DSAEngine {
PrivateKey privKey = keyFact.generatePrivate(spec); PrivateKey privKey = keyFact.generatePrivate(spec);
jsig.initSign(privKey, _context.random()); jsig.initSign(privKey, _context.random());
jsig.update(data); jsig.update(data);
return new Signature(aSN1ToSigBytes(jsig.sign())); return SigUtil.fromJavaSig(jsig.sign(), SigType.DSA_SHA1);
}
/**
* http://download.oracle.com/javase/1.5.0/docs/guide/security/CryptoSpec.html
* Signature Format ASN.1 sequence of two INTEGER values: r and s, in that order:
* SEQUENCE ::= { r INTEGER, s INTEGER }
*
* http://en.wikipedia.org/wiki/Abstract_Syntax_Notation_One
* 30 -- tag indicating SEQUENCE
* xx - length in octets
*
* 02 -- tag indicating INTEGER
* xx - length in octets
* xxxxxx - value
*
* Convert to BigInteger and back so we have the minimum length representation, as required.
* r and s are always non-negative.
*
* @since 0.8.7
*/
private static byte[] sigBytesToASN1(byte[] sig) {
//System.out.println("pre TO asn1\n" + net.i2p.util.HexDump.dump(sig));
ByteArrayOutputStream baos = new ByteArrayOutputStream(48);
baos.write(0x30);
baos.write(0); // length to be filled in below
byte[] tmp = new byte[20];
baos.write(2);
System.arraycopy(sig, 0, tmp, 0, 20);
BigInteger r = new BigInteger(1, tmp);
byte[] b = r.toByteArray();
baos.write(b.length);
baos.write(b, 0, b.length);
baos.write(2);
System.arraycopy(sig, 20, tmp, 0, 20);
BigInteger s = new BigInteger(1, tmp);
b = s.toByteArray();
baos.write(b.length);
baos.write(b, 0, b.length);
byte[] rv = baos.toByteArray();
rv[1] = (byte) (rv.length - 2);
//System.out.println("post TO asn1\n" + net.i2p.util.HexDump.dump(rv));
return rv;
}
/**
* See above.
* @since 0.8.7
*/
private static byte[] aSN1ToSigBytes(byte[] asn) {
//System.out.println("pre from asn1\n" + net.i2p.util.HexDump.dump(asn));
byte[] rv = new byte[40];
int rlen = asn[3];
if ((asn[4] & 0x80) != 0)
throw new IllegalArgumentException("R is negative");
if (rlen > 21)
throw new IllegalArgumentException("R too big " + rlen);
else if (rlen == 21) {
System.arraycopy(asn, 5, rv, 0, 20);
} else
System.arraycopy(asn, 4, rv, 20 - rlen, rlen);
int slenloc = 25 + rlen - 20;
int slen = asn[slenloc];
if ((asn[slenloc + 1] & 0x80) != 0)
throw new IllegalArgumentException("S is negative");
if (slen > 21)
throw new IllegalArgumentException("S too big " + slen);
else if (slen == 21) {
System.arraycopy(asn, slenloc + 2, rv, 20, 20);
} else
System.arraycopy(asn, slenloc + 1, rv, 40 - slen, slen);
//System.out.println("post from asn1\n" + net.i2p.util.HexDump.dump(rv));
return rv;
} }
//private static final int RUNS = 1000; //private static final int RUNS = 1000;

View File

@@ -0,0 +1,308 @@
package net.i2p.crypto;
import java.lang.reflect.Constructor;
import java.math.BigInteger;
import java.security.AlgorithmParameters;
import java.security.AlgorithmParameterGenerator;
import java.security.GeneralSecurityException;
import java.security.Provider;
import java.security.Security;
import java.security.spec.AlgorithmParameterSpec;
import java.security.spec.ECField;
import java.security.spec.ECFieldFp;
import java.security.spec.ECGenParameterSpec;
import java.security.spec.ECParameterSpec;
import java.security.spec.ECPoint;
import java.security.spec.EllipticCurve;
import net.i2p.util.NativeBigInteger;
/**
* Constants for elliptic curves, from NIST FIPS 186-4 (2013) / ANSI X9.62
*
* @since 0.9.9
*/
public class ECConstants {
private static final boolean DEBUG = true;
private static void log(String s) {
log(s, null);
}
private static void log(String s, Throwable t) {
if (DEBUG) {
System.out.println("ECConstants: " + s);
if (t != null)
t.printStackTrace();
}
}
static {
if (Security.getProvider("BC") == null) {
try {
Class cls = Class.forName("org.bouncycastle.jce.provider.BouncyCastleProvider");
Constructor con = cls.getConstructor(new Class[0]);
Provider bc = (Provider)con.newInstance(new Object[0]);
Security.addProvider(bc);
log("Added BC provider");
} catch (Exception e) {
log("Unable to add BC provider", e);
}
} else {
log("BC provider already loaded");
}
}
private static class ECParms {
public final String ps, ns, ss, bs, gxs, gys;
private static final BigInteger A = new NativeBigInteger("-3");
private static final int H = 1;
/**
* P and N in decimal, no spaces;
* Seed, B, Gx, Gy in hex, spaces allowed
*/
public ECParms(String pss, String nss, String sss, String bss, String gxss, String gyss) {
ps = pss; ns = nss; ss = sss; bs = bss; gxs = gxss; gys = gyss;
}
public ECParameterSpec genSpec() {
BigInteger pb = new NativeBigInteger(ps);
BigInteger nb = new NativeBigInteger(ns);
BigInteger sb = new NativeBigInteger(ss.replace(" ", ""), 16);
BigInteger bb = new NativeBigInteger(bs.replace(" ", ""), 16);
BigInteger gxb = new NativeBigInteger(gxs.replace(" ", ""), 16);
BigInteger gyb = new NativeBigInteger(gys.replace(" ", ""), 16);
BigInteger ab = new NativeBigInteger(A.mod(pb));
ECField field = new ECFieldFp(pb);
EllipticCurve curve = new EllipticCurve(field, ab, bb, sb.toByteArray());
ECPoint g = new ECPoint(gxb, gyb);
return new ECParameterSpec(curve, g, nb, H);
}
}
/*
D.1.2 Curves over Prime Fields
For each prime p, a pseudo-random curve
E : y**2 = x**3 -3x +b (mod p)
of prime order n is listed 4. (Thus, for these curves, the cofactor is always h = 1.) The following
parameters are given:
The selection a a = -3 for the coefficient of x was made for reasons of efficiency; see IEEE Std 1363-2000.
* The prime modulus p
* The order n
* The 160-bit input seed SEED to the SHA-1 based algorithm (i.e., the domain parameter
seed)
* The output c of the SHA-1 based algorithm
* The coefficient b (satisfying b**2 c = -27 (mod p))
* The base point x coordinate G x
* The base point y coordinate G y
The integers p and n are given in decimal form; bit strings and field elements are given in
hexadecimal.
*/
/*
D.1.2.1 Curve P-192
p= 6277101735386680763835789423207666416083908700390324961279
n= 6277101735386680763835789423176059013767194773182842284081
SEED = 3045ae6f c8422f64 ed579528 d38120ea e12196d5
c= 3099d2bb bfcb2538 542dcd5f b078b6ef 5f3d6fe2 c745de65
b= 64210519 e59c80e7 0fa7e9ab 72243049 feb8deec c146b9b1
Gx= 188da80e b03090f6 7cbf20eb 43a18800 f4ff0afd 82ff1012
Gy= 07192b95 ffc8da78 631011ed 6b24cdd5 73f977a1 1e794811
*/
private static final ECParms PARM_P192 = new ECParms(
// P N Seed B Gx Gy
"6277101735386680763835789423207666416083908700390324961279",
"6277101735386680763835789423176059013767194773182842284081",
"3045ae6f c8422f64 ed579528 d38120ea e12196d5",
"64210519 e59c80e7 0fa7e9ab 72243049 feb8deec c146b9b1",
"188da80e b03090f6 7cbf20eb 43a18800 f4ff0afd 82ff1012",
"07192b95 ffc8da78 631011ed 6b24cdd5 73f977a1 1e794811"
);
/*
D.1.2.3 Curve P-256
p=
1157920892103562487626974469494075735300861434152903141955
33631308867097853951
n=
115792089210356248762697446949407573529996955224135760342
422259061068512044369
SEED = c49d3608 86e70493 6a6678e1 139d26b7 819f7e90
c=
7efba166 2985be94 03cb055c 75d4f7e0 ce8d84a9 c5114abc
af317768 0104fa0d
b=
5ac635d8 aa3a93e7 b3ebbd55 769886bc 651d06b0 cc53b0f6
3bce3c3e 27d2604b
Gx=
6b17d1f2 e12c4247 f8bce6e5 63a440f2 77037d81 2deb33a0
f4a13945 d898c296
Gy=
4fe342e2 fe1a7f9b 8ee7eb4a 7c0f9e16 2bce3357 6b315ece
cbb64068 37bf51f5
*/
private static final ECParms PARM_P256 = new ECParms(
// P N Seed B Gx Gy
"1157920892103562487626974469494075735300861434152903141955" +
"33631308867097853951",
"115792089210356248762697446949407573529996955224135760342" +
"422259061068512044369",
"c49d3608 86e70493 6a6678e1 139d26b7 819f7e90",
"5ac635d8 aa3a93e7 b3ebbd55 769886bc 651d06b0 cc53b0f6" +
"3bce3c3e 27d2604b",
"6b17d1f2 e12c4247 f8bce6e5 63a440f2 77037d81 2deb33a0" +
"f4a13945 d898c296",
"4fe342e2 fe1a7f9b 8ee7eb4a 7c0f9e16 2bce3357 6b315ece" +
"cbb64068 37bf51f5"
);
/*
D.1.2.4 Curve P-384
p=
3940200619639447921227904010014361380507973927046544666794
8293404245721771496870329047266088258938001861606973112319
n=
3940200619639447921227904010014361380507973927046544666794
6905279627659399113263569398956308152294913554433653942643
SEED = a335926a a319a27a 1d00896a 6773a482 7acdac73
c=
79d1e655 f868f02f ff48dcde e14151dd b80643c1 406d0ca1
0dfe6fc5 2009540a 495e8042 ea5f744f 6e184667 cc722483
b=
b3312fa7 e23ee7e4 988e056b e3f82d19 181d9c6e fe814112
0314088f 5013875a c656398d 8a2ed19d 2a85c8ed d3ec2aef
Gx=
aa87ca22 be8b0537 8eb1c71e f320ad74 6e1d3b62 8ba79b98
59f741e0 82542a38 5502f25d bf55296c 3a545e38 72760ab7
G y=
3617de4a 96262c6f 5d9e98bf 9292dc29 f8f41dbd 289a147c
e9da3113 b5f0b8c0 0a60b1ce 1d7e819d 7a431d7c 90ea0e5f
*/
private static final ECParms PARM_P384 = new ECParms(
// P N Seed B Gx Gy
"3940200619639447921227904010014361380507973927046544666794" +
"8293404245721771496870329047266088258938001861606973112319",
"3940200619639447921227904010014361380507973927046544666794" +
"6905279627659399113263569398956308152294913554433653942643",
"a335926a a319a27a 1d00896a 6773a482 7acdac73",
"b3312fa7 e23ee7e4 988e056b e3f82d19 181d9c6e fe814112" +
"0314088f 5013875a c656398d 8a2ed19d 2a85c8ed d3ec2aef",
"aa87ca22 be8b0537 8eb1c71e f320ad74 6e1d3b62 8ba79b98" +
"59f741e0 82542a38 5502f25d bf55296c 3a545e38 72760ab7",
"3617de4a 96262c6f 5d9e98bf 9292dc29 f8f41dbd 289a147c" +
"e9da3113 b5f0b8c0 0a60b1ce 1d7e819d 7a431d7c 90ea0e5f"
);
/*
D.1.2.5 Curve P-521
p=
686479766013060971498190079908139321726943530014330540939
446345918554318339765605212255964066145455497729631139148
0858037121987999716643812574028291115057151
n=
686479766013060971498190079908139321726943530014330540939
446345918554318339765539424505774633321719753296399637136
3321113864768612440380340372808892707005449
SEED = d09e8800 291cb853 96cc6717 393284aa a0da64ba
c=
0b4 8bfa5f42 0a349495 39d2bdfc 264eeeeb 077688e4
4fbf0ad8 f6d0edb3 7bd6b533 28100051 8e19f1b9 ffbe0fe9
ed8a3c22 00b8f875 e523868c 70c1e5bf 55bad637
b=
051 953eb961 8e1c9a1f 929a21a0 b68540ee a2da725b
99b315f3 b8b48991 8ef109e1 56193951 ec7e937b 1652c0bd
3bb1bf07 3573df88 3d2c34f1 ef451fd4 6b503f00
Gx=
c6 858e06b7 0404e9cd 9e3ecb66 2395b442 9c648139
053fb521 f828af60 6b4d3dba a14b5e77 efe75928 fe1dc127
a2ffa8de 3348b3c1 856a429b f97e7e31 c2e5bd66
Gy=
118 39296a78 9a3bc004 5c8a5fb4 2c7d1bd9 98f54449
579b4468 17afbd17 273e662c 97ee7299 5ef42640 c550b901
3fad0761 353c7086 a272c240 88be9476 9fd16650
*/
private static final ECParms PARM_P521 = new ECParms(
"686479766013060971498190079908139321726943530014330540939" +
"446345918554318339765605212255964066145455497729631139148" +
"0858037121987999716643812574028291115057151",
"686479766013060971498190079908139321726943530014330540939" +
"446345918554318339765539424505774633321719753296399637136" +
"3321113864768612440380340372808892707005449",
"d09e8800 291cb853 96cc6717 393284aa a0da64ba",
"051 953eb961 8e1c9a1f 929a21a0 b68540ee a2da725b" +
"99b315f3 b8b48991 8ef109e1 56193951 ec7e937b 1652c0bd" +
"3bb1bf07 3573df88 3d2c34f1 ef451fd4 6b503f00",
"c6 858e06b7 0404e9cd 9e3ecb66 2395b442 9c648139" +
"053fb521 f828af60 6b4d3dba a14b5e77 efe75928 fe1dc127" +
"a2ffa8de 3348b3c1 856a429b f97e7e31 c2e5bd66",
"118 39296a78 9a3bc004 5c8a5fb4 2c7d1bd9 98f54449" +
"579b4468 17afbd17 273e662c 97ee7299 5ef42640 c550b901" +
"3fad0761 353c7086 a272c240 88be9476 9fd16650"
);
/**
* Generate a spec from a curve name
* @return null iffail
*/
private static ECParameterSpec genSpec(String name) {
// convert the ECGenParameterSpecs to ECParameterSpecs for several reasons:
// 1) to check availability
// 2) efficiency
// 3) SigUtil must cast the AlgorithmParameterSpec to a ECParameterSpec
// to convert a I2P key to a Java key. Sadly, a ECGenParameterSpec
// is not a ECParameterSpec.
try {
AlgorithmParameters ap = AlgorithmParameters.getInstance("EC");
ECGenParameterSpec ecgps = new ECGenParameterSpec(name);
ap.init(ecgps);
ECParameterSpec rv = ap.getParameterSpec(ECParameterSpec.class);
log("Named curve " + name + " loaded");
return rv;
} catch (Exception e) {
log("Named curve " + name + " is not available", e);
return null;
}
}
/**
* Tries curve name1, then name2, then creates new from parms.
* @return null if all fail
*/
private static ECParameterSpec genSpec(String name1, String name2, ECParms parms) {
ECParameterSpec rv = genSpec(name1);
if (rv == null) {
rv = genSpec(name2);
if (rv == null) {
rv = parms.genSpec();
if (rv != null)
log("Curve " + name2 + " created");
}
}
return rv;
}
// standard curve names
// first is OpenJDK 6/7
// second is BC
public static final ECParameterSpec P192_SPEC = genSpec("secp192r1", "P-192", PARM_P192);
public static final ECParameterSpec P256_SPEC = genSpec("secp256r1", "P-256", PARM_P256);
public static final ECParameterSpec P384_SPEC = genSpec("secp384r1", "P-384", PARM_P384);
public static final ECParameterSpec P521_SPEC = genSpec("secp521r1", "P-521", PARM_P521);
}

View File

@@ -10,6 +10,13 @@ package net.i2p.crypto;
*/ */
import java.math.BigInteger; import java.math.BigInteger;
import java.security.GeneralSecurityException;
import java.security.InvalidKeyException;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.interfaces.ECPrivateKey;
import java.security.interfaces.ECPublicKey;
import java.security.spec.ECPoint;
import net.i2p.I2PAppContext; import net.i2p.I2PAppContext;
import net.i2p.data.Hash; import net.i2p.data.Hash;
@@ -21,6 +28,12 @@ import net.i2p.data.SigningPublicKey;
import net.i2p.data.SimpleDataStructure; import net.i2p.data.SimpleDataStructure;
import net.i2p.util.NativeBigInteger; import net.i2p.util.NativeBigInteger;
// main()
import net.i2p.data.DataHelper;
import net.i2p.data.Signature;
import net.i2p.util.Clock;
import net.i2p.util.RandomSource;
/** Define a way of generating asymmetrical key pairs as well as symmetrical keys /** Define a way of generating asymmetrical key pairs as well as symmetrical keys
* @author jrandom * @author jrandom
*/ */
@@ -100,14 +113,16 @@ public class KeyGenerator {
SimpleDataStructure[] keys = new SimpleDataStructure[2]; SimpleDataStructure[] keys = new SimpleDataStructure[2];
keys[0] = new PublicKey(); keys[0] = new PublicKey();
keys[1] = new PrivateKey(); keys[1] = new PrivateKey();
byte[] k0 = aalpha.toByteArray();
byte[] k1 = a.toByteArray();
// bigInteger.toByteArray returns SIGNED integers, but since they'return positive, // bigInteger.toByteArray returns SIGNED integers, but since they'return positive,
// signed two's complement is the same as unsigned // signed two's complement is the same as unsigned
keys[0].setData(padBuffer(k0, PublicKey.KEYSIZE_BYTES)); try {
keys[1].setData(padBuffer(k1, PrivateKey.KEYSIZE_BYTES)); keys[0].setData(SigUtil.rectify(aalpha, PublicKey.KEYSIZE_BYTES));
keys[1].setData(SigUtil.rectify(a, PrivateKey.KEYSIZE_BYTES));
} catch (InvalidKeyException ike) {
throw new IllegalArgumentException(ike);
}
return keys; return keys;
} }
@@ -120,13 +135,18 @@ public class KeyGenerator {
BigInteger a = new NativeBigInteger(1, priv.toByteArray()); BigInteger a = new NativeBigInteger(1, priv.toByteArray());
BigInteger aalpha = CryptoConstants.elgg.modPow(a, CryptoConstants.elgp); BigInteger aalpha = CryptoConstants.elgg.modPow(a, CryptoConstants.elgp);
PublicKey pub = new PublicKey(); PublicKey pub = new PublicKey();
byte [] pubBytes = aalpha.toByteArray(); try {
pub.setData(padBuffer(pubBytes, PublicKey.KEYSIZE_BYTES)); pub.setData(SigUtil.rectify(aalpha, PublicKey.KEYSIZE_BYTES));
} catch (InvalidKeyException ike) {
throw new IllegalArgumentException(ike);
}
return pub; return pub;
} }
/** Generate a pair of DSA keys, where index 0 is a SigningPublicKey, and /** Generate a pair of DSA keys, where index 0 is a SigningPublicKey, and
* index 1 is a SigningPrivateKey * index 1 is a SigningPrivateKey.
* DSA-SHA1 only.
*
* @return pair of keys * @return pair of keys
*/ */
public Object[] generateSigningKeypair() { public Object[] generateSigningKeypair() {
@@ -134,6 +154,8 @@ public class KeyGenerator {
} }
/** /**
* DSA-SHA1 only.
*
* Same as above but different return type * Same as above but different return type
* @since 0.8.7 * @since 0.8.7
*/ */
@@ -149,15 +171,36 @@ public class KeyGenerator {
BigInteger y = CryptoConstants.dsag.modPow(x, CryptoConstants.dsap); BigInteger y = CryptoConstants.dsag.modPow(x, CryptoConstants.dsap);
keys[0] = new SigningPublicKey(); keys[0] = new SigningPublicKey();
keys[1] = new SigningPrivateKey(); keys[1] = new SigningPrivateKey();
byte k0[] = padBuffer(y.toByteArray(), SigningPublicKey.KEYSIZE_BYTES); try {
byte k1[] = padBuffer(x.toByteArray(), SigningPrivateKey.KEYSIZE_BYTES); keys[0].setData(SigUtil.rectify(y, SigningPublicKey.KEYSIZE_BYTES));
keys[1].setData(SigUtil.rectify(x, SigningPrivateKey.KEYSIZE_BYTES));
keys[0].setData(k0); } catch (InvalidKeyException ike) {
keys[1].setData(k1); throw new IllegalStateException(ike);
}
return keys; return keys;
} }
/** Convert a SigningPrivateKey to a SigningPublicKey /**
* Generic signature type, supports DSA and ECDSA
* @since 0.9.9
*/
public SimpleDataStructure[] generateSigningKeys(SigType type) throws GeneralSecurityException {
if (type == SigType.DSA_SHA1)
return generateSigningKeys();
KeyPairGenerator kpg = KeyPairGenerator.getInstance("EC");
kpg.initialize(type.getParams(), _context.random());
KeyPair kp = kpg.generateKeyPair();
ECPublicKey pubkey = (ECPublicKey) kp.getPublic();
ECPrivateKey privkey = (ECPrivateKey) kp.getPrivate();
SimpleDataStructure[] keys = new SimpleDataStructure[2];
keys[0] = SigUtil.fromJavaKey(pubkey, type);
keys[1] = SigUtil.fromJavaKey(privkey, type);
return keys;
}
/** Convert a SigningPrivateKey to a SigningPublicKey.
* DSA-SHA1 only.
*
* @param priv a SigningPrivateKey object * @param priv a SigningPrivateKey object
* @return a SigningPublicKey object * @return a SigningPublicKey object
*/ */
@@ -165,27 +208,61 @@ public class KeyGenerator {
BigInteger x = new NativeBigInteger(1, priv.toByteArray()); BigInteger x = new NativeBigInteger(1, priv.toByteArray());
BigInteger y = CryptoConstants.dsag.modPow(x, CryptoConstants.dsap); BigInteger y = CryptoConstants.dsag.modPow(x, CryptoConstants.dsap);
SigningPublicKey pub = new SigningPublicKey(); SigningPublicKey pub = new SigningPublicKey();
byte [] pubBytes = padBuffer(y.toByteArray(), SigningPublicKey.KEYSIZE_BYTES); try {
pub.setData(pubBytes); pub.setData(SigUtil.rectify(y, SigningPublicKey.KEYSIZE_BYTES));
} catch (InvalidKeyException ike) {
throw new IllegalArgumentException(ike);
}
return pub; return pub;
} }
/** public static void main(String args[]) {
* Pad the buffer w/ leading 0s or trim off leading bits so the result is the try {
* given length. main2(args);
*/ } catch (Exception e) {
private final static byte[] padBuffer(byte src[], int length) { e.printStackTrace();
byte buf[] = new byte[length]; }
}
if (src.length > buf.length) // extra bits, chop leading bits public static void main2(String args[]) {
System.arraycopy(src, src.length - buf.length, buf, 0, buf.length); RandomSource.getInstance().nextBoolean();
else if (src.length < buf.length) // short bits, padd w/ 0s try { Thread.sleep(1000); } catch (InterruptedException ie) {}
System.arraycopy(src, 0, buf, buf.length - src.length, src.length); int runs = 500; // warmup
else for (int j = 0; j < 2; j++) {
// eq for (int i = 0; i <= 100; i++) {
System.arraycopy(src, 0, buf, 0, buf.length); SigType type = SigType.getByCode(i);
if (type == null)
break;
try {
System.out.println("Testing " + type);
testSig(type, runs);
} catch (Exception e) {
System.out.println("error testing " + type);
e.printStackTrace();
}
}
runs = 2000;
}
}
return buf; private static void testSig(SigType type, int runs) throws GeneralSecurityException {
byte src[] = new byte[512];
long time = 0;
SimpleDataStructure keys[] = KeyGenerator.getInstance().generateSigningKeys(type);
//System.out.println("pubkey " + keys[0]);
//System.out.println("privkey " + keys[1]);
for (int i = 0; i < runs; i++) {
RandomSource.getInstance().nextBytes(src);
long start = System.nanoTime();
Signature sig = DSAEngine.getInstance().sign(src, (SigningPrivateKey) keys[1]);
boolean ok = DSAEngine.getInstance().verifySignature(sig, src, (SigningPublicKey) keys[0]);
long end = System.nanoTime();
time += end - start;
if (!ok)
throw new GeneralSecurityException(type + " V(S(data)) fail");
}
time /= 1000*1000;
System.out.println("Signing Keygen " + runs + " times: " + time + " ms = " + (((double) time) / runs) + " each");
} }
/****** /******

View File

@@ -23,15 +23,27 @@ public enum SigType {
* Pubkey 128 bytes; privkey 20 bytes; hash 20 bytes; sig 40 bytes * Pubkey 128 bytes; privkey 20 bytes; hash 20 bytes; sig 40 bytes
* @since 0.9.8 * @since 0.9.8
*/ */
DSA_SHA1(0, 128, 20, 20, 40, "SHA-1", "SHA1withDSA", null), DSA_SHA1(0, 128, 20, 20, 40, "SHA-1", "SHA1withDSA", CryptoConstants.DSA_SHA1_SPEC),
/** Pubkey 48 bytes; privkey 24 bytes; hash 20 bytes; sig 48 bytes */ /** Pubkey 48 bytes; privkey 24 bytes; hash 20 bytes; sig 48 bytes */
ECDSA_SHA1_P192(1, 48, 24, 20, 48, "SHA-1", "SHA1withECDSA", null), ECDSA_SHA1_P192(1, 48, 24, 20, 48, "SHA-1", "SHA1withECDSA", ECConstants.P192_SPEC),
/** Pubkey 64 bytes; privkey 32 bytes; hash 32 bytes; sig 64 bytes */ /** Pubkey 64 bytes; privkey 32 bytes; hash 32 bytes; sig 64 bytes */
ECDSA_SHA256_P256(2, 64, 32, 32, 64, "SHA-256", "SHA256withECDSA", null), ECDSA_SHA256_P256(2, 64, 32, 32, 64, "SHA-256", "SHA256withECDSA", ECConstants.P256_SPEC),
/** Pubkey 96 bytes; privkey 48 bytes; hash 48 bytes; sig 96 bytes */ /** Pubkey 96 bytes; privkey 48 bytes; hash 48 bytes; sig 96 bytes */
ECDSA_SHA384_P384(3, 96, 48, 48, 96, "SHA-384", "SHA384withECDSA", null), ECDSA_SHA384_P384(3, 96, 48, 48, 96, "SHA-384", "SHA384withECDSA", ECConstants.P384_SPEC),
/** Pubkey 132 bytes; privkey 66 bytes; hash 64 bytes; sig 132 bytes */ /** Pubkey 132 bytes; privkey 66 bytes; hash 64 bytes; sig 132 bytes */
ECDSA_SHA512_P521(4, 132, 66, 64, 132, "SHA-512", "SHA512withECDSA", null), ECDSA_SHA512_P521(4, 132, 66, 64, 132, "SHA-512", "SHA512withECDSA", ECConstants.P521_SPEC),
// TESTING....................
ECDSA_SHA256_P192(5, 48, 24, 20, 48, "SHA-1", "SHA256withECDSA", ECConstants.P192_SPEC),
ECDSA_SHA256_P384(6, 96, 48, 32, 96, "SHA-256", "SHA256withECDSA", ECConstants.P384_SPEC),
ECDSA_SHA256_P521(7, 132, 66, 32, 132, "SHA-256", "SHA256withECDSA", ECConstants.P521_SPEC),
ECDSA_SHA384_P256(8, 64, 32, 48, 64, "SHA-384", "SHA384withECDSA", ECConstants.P256_SPEC),
ECDSA_SHA384_P521(9, 132, 66, 48, 132, "SHA-384", "SHA384withECDSA", ECConstants.P521_SPEC),
ECDSA_SHA512_P256(10, 64, 32, 64, 64, "SHA-512", "SHA512withECDSA", ECConstants.P256_SPEC),
ECDSA_SHA512_P384(11, 96, 48, 64, 96, "SHA-512", "SHA512withECDSA", ECConstants.P384_SPEC),
//MD5 //MD5
//ELGAMAL_SHA256 //ELGAMAL_SHA256

View File

@@ -0,0 +1,293 @@
package net.i2p.crypto;
import java.math.BigInteger;
import java.security.GeneralSecurityException;
import java.security.InvalidKeyException;
import java.security.KeyFactory;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.SignatureException;
import java.security.interfaces.ECPrivateKey;
import java.security.interfaces.ECPublicKey;
import java.security.spec.ECField;
import java.security.spec.ECFieldFp;
import java.security.spec.ECGenParameterSpec;
import java.security.spec.ECParameterSpec;
import java.security.spec.ECPrivateKeySpec;
import java.security.spec.ECPublicKeySpec;
import java.security.spec.ECPoint;
import java.security.spec.EllipticCurve;
import net.i2p.data.Signature;
import net.i2p.data.SigningPrivateKey;
import net.i2p.data.SigningPublicKey;
/**
* Utilities for Signing keys and Signatures
*
* @since 0.9.9
*/
class SigUtil {
/**
* @return JAVA key!
*/
public static PublicKey toJavaKey(SigningPublicKey pk)
throws GeneralSecurityException {
if (pk.getType() == SigType.DSA_SHA1)
throw new UnsupportedOperationException();
else
return toJavaECKey(pk);
}
/**
* @return JAVA key!
*/
public static PrivateKey toJavaKey(SigningPrivateKey pk)
throws GeneralSecurityException {
if (pk.getType() == SigType.DSA_SHA1)
throw new UnsupportedOperationException();
else
return toJavaECKey(pk);
}
/**
* @param pk JAVA key!
*/
public static SigningPublicKey fromJavaKey(PublicKey pk, SigType type)
throws GeneralSecurityException {
if (type == SigType.DSA_SHA1)
throw new UnsupportedOperationException();
else
return fromJavaKey((ECPublicKey) pk, type);
}
/**
* @param pk JAVA key!
*/
public static SigningPrivateKey fromJavaKey(PrivateKey pk, SigType type)
throws GeneralSecurityException {
if (type == SigType.DSA_SHA1)
throw new UnsupportedOperationException();
else
return fromJavaKey((ECPrivateKey) pk, type);
}
public static ECPublicKey toJavaECKey(SigningPublicKey pk)
throws GeneralSecurityException {
SigType type = pk.getType();
int len = type.getPubkeyLen();
int sublen = len / 2;
byte[] b = pk.getData();
byte[] bx = new byte[sublen];
byte[] by = new byte[sublen];
System.arraycopy(b, 0, bx, 0, sublen);
System.arraycopy(b, sublen, by, 0, sublen);
BigInteger x = new BigInteger(1, bx);
BigInteger y = new BigInteger(1, by);
ECPoint w = new ECPoint(x, y);
// see ECConstants re: casting
ECPublicKeySpec ks = new ECPublicKeySpec(w, (ECParameterSpec) type.getParams());
KeyFactory kf = KeyFactory.getInstance("EC");
return (ECPublicKey) kf.generatePublic(ks);
}
public static ECPrivateKey toJavaECKey(SigningPrivateKey pk)
throws GeneralSecurityException {
SigType type = pk.getType();
int len = type.getPubkeyLen();
int sublen = len / 2;
byte[] b = pk.getData();
BigInteger s = new BigInteger(1, b);
// see ECConstants re: casting
ECPrivateKeySpec ks = new ECPrivateKeySpec(s, (ECParameterSpec) type.getParams());
KeyFactory kf = KeyFactory.getInstance("EC");
return (ECPrivateKey) kf.generatePrivate(ks);
}
public static SigningPublicKey fromJavaKey(ECPublicKey pk, SigType type)
throws GeneralSecurityException {
ECPoint w = pk.getW();
BigInteger x = w.getAffineX();
BigInteger y = w.getAffineY();
int len = type.getPubkeyLen();
int sublen = len / 2;
byte[] b = new byte[len];
byte[] bx = rectify(x, sublen);
byte[] by = rectify(y, sublen);
System.arraycopy(bx, 0, b, 0, sublen);
System.arraycopy(by, 0, b, sublen, sublen);
return new SigningPublicKey(type, b);
}
public static SigningPrivateKey fromJavaKey(ECPrivateKey pk, SigType type)
throws GeneralSecurityException {
BigInteger s = pk.getS();
int len = type.getPrivkeyLen();
byte[] bs = rectify(s, len);
return new SigningPrivateKey(type, bs);
}
/**
* @return ASN.1 representation
*/
public static byte[] toJavaSig(Signature sig) {
return sigBytesToASN1(sig.getData());
}
/**
* @param asn ASN.1 representation
* @return a Signature with SigType type
*/
public static Signature fromJavaSig(byte[] asn, SigType type)
throws SignatureException {
return new Signature(type, aSN1ToSigBytes(asn, type.getSigLen()));
}
/**
* @param bi non-negative
* @return array of exactly len bytes
*/
public static byte[] rectify(BigInteger bi, int len)
throws InvalidKeyException {
byte[] b = bi.toByteArray();
if (b.length == len) {
// just right
return b;
}
if (b.length > len + 1)
throw new InvalidKeyException("key too big (" + b.length + ") max is " + (len + 1));
byte[] rv = new byte[len];
if (b.length == 0)
return rv;
if ((b[0] & 0x80) != 0)
throw new InvalidKeyException("negative");
if (b.length > len) {
// leading 0 byte
if (b[0] != 0)
throw new InvalidKeyException("key too big (" + b.length + ") max is " + len);
System.arraycopy(b, 1, rv, 0, len);
} else {
// smaller
System.arraycopy(b, 0, rv, len - b.length, b.length);
}
return rv;
}
/**
* http://download.oracle.com/javase/1.5.0/docs/guide/security/CryptoSpec.html
* Signature Format ASN.1 sequence of two INTEGER values: r and s, in that order:
* SEQUENCE ::= { r INTEGER, s INTEGER }
*
* http://en.wikipedia.org/wiki/Abstract_Syntax_Notation_One
* 30 -- tag indicating SEQUENCE
* xx - length in octets
*
* 02 -- tag indicating INTEGER
* xx - length in octets
* xxxxxx - value
*
* Convert to BigInteger and back so we have the minimum length representation, as required.
* r and s are always non-negative.
*
* Only supports sigs up to about 252 bytes. See code to fix BER encoding for this before you
* add a SigType with bigger signatures.
*
* @throws IllegalArgumentException if too big
* @since 0.8.7, moved to SigUtil in 0.9.9
*/
private static byte[] sigBytesToASN1(byte[] sig) {
//System.out.println("pre TO asn1\n" + net.i2p.util.HexDump.dump(sig));
int len = sig.length;
int sublen = len / 2;
byte[] tmp = new byte[sublen];
System.arraycopy(sig, 0, tmp, 0, sublen);
BigInteger r = new BigInteger(1, tmp);
byte[] rb = r.toByteArray();
if (rb.length > 127)
throw new IllegalArgumentException("FIXME R length > 127");
System.arraycopy(sig, sublen, tmp, 0, sublen);
BigInteger s = new BigInteger(1, tmp);
byte[] sb = s.toByteArray();
if (sb.length > 127)
throw new IllegalArgumentException("FIXME S length > 127");
int seqlen = rb.length + sb.length + 4;
if (seqlen > 255)
throw new IllegalArgumentException("FIXME seq length > 255");
int totlen = seqlen + 2;
if (seqlen > 127)
totlen++;
byte[] rv = new byte[totlen];
int idx = 0;
rv[idx++] = 0x30;
if (seqlen > 127)
rv[idx++] =(byte) 0x81;
rv[idx++] = (byte) seqlen;
rv[idx++] = 0x02;
rv[idx++] = (byte) rb.length;
System.arraycopy(rb, 0, rv, idx, rb.length);
idx += rb.length;
rv[idx++] = 0x02;
rv[idx++] = (byte) sb.length;
System.arraycopy(sb, 0, rv, idx, sb.length);
//System.out.println("post TO asn1\n" + net.i2p.util.HexDump.dump(rv));
return rv;
}
/**
* See above.
* Only supports sigs up to about 252 bytes. See code to fix BER encoding for bigger than that.
*
* @return len bytes
* @since 0.8.7, moved to SigUtil in 0.9.9
*/
private static byte[] aSN1ToSigBytes(byte[] asn, int len)
throws SignatureException {
//System.out.println("pre from asn1 len=" + len + "\n" + net.i2p.util.HexDump.dump(asn));
if (asn[0] != 0x30)
throw new SignatureException("asn[0] = " + (asn[0] & 0xff));
// handles total len > 127
int idx = 2;
if ((asn[1] & 0x80) != 0)
idx += asn[1] & 0x7f;
if (asn[idx] != 0x02)
throw new SignatureException("asn[2] = " + (asn[idx] & 0xff));
byte[] rv = new byte[len];
int sublen = len / 2;
int rlen = asn[++idx];
if ((rlen & 0x80) != 0)
throw new SignatureException("FIXME R length > 127");
if ((asn[++idx] & 0x80) != 0)
throw new SignatureException("R is negative");
if (rlen > sublen + 1)
throw new SignatureException("R too big " + rlen);
if (rlen == sublen + 1)
System.arraycopy(asn, idx + 1, rv, 0, sublen);
else
System.arraycopy(asn, idx, rv, sublen - rlen, rlen);
idx += rlen;
int slenloc = idx + 1;
if (asn[idx] != 0x02)
throw new SignatureException("asn[s] = " + (asn[idx] & 0xff));
int slen = asn[slenloc];
if ((slen & 0x80) != 0)
throw new SignatureException("FIXME S length > 127");
if ((asn[slenloc + 1] & 0x80) != 0)
throw new SignatureException("S is negative");
if (slen > sublen + 1)
throw new SignatureException("S too big " + slen);
if (slen == sublen + 1)
System.arraycopy(asn, slenloc + 2, rv, sublen, sublen);
else
System.arraycopy(asn, slenloc + 1, rv, len - slen, slen);
//System.out.println("post from asn1\n" + net.i2p.util.HexDump.dump(rv));
return rv;
}
}