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; import java.security.KeyFactory; import java.security.PrivateKey; import java.security.PublicKey; import java.security.SignatureException; import java.security.interfaces.DSAPrivateKey; import java.security.interfaces.DSAPublicKey; import java.security.interfaces.ECPrivateKey; import java.security.interfaces.ECPublicKey; import java.security.interfaces.RSAPrivateKey; import java.security.interfaces.RSAPublicKey; import java.security.spec.AlgorithmParameterSpec; import java.security.spec.DSAPrivateKeySpec; import java.security.spec.DSAPublicKeySpec; import java.security.spec.ECParameterSpec; import java.security.spec.ECPrivateKeySpec; import java.security.spec.ECPublicKeySpec; import java.security.spec.ECPoint; import java.security.spec.KeySpec; import java.security.spec.PKCS8EncodedKeySpec; import java.security.spec.RSAKeyGenParameterSpec; import java.security.spec.RSAPrivateKeySpec; import java.security.spec.RSAPublicKeySpec; import java.security.spec.X509EncodedKeySpec; import java.util.Map; import net.i2p.crypto.eddsa.EdDSAPrivateKey; import net.i2p.crypto.eddsa.EdDSAPublicKey; import net.i2p.crypto.eddsa.spec.EdDSAParameterSpec; import net.i2p.crypto.eddsa.spec.EdDSAPrivateKeySpec; import net.i2p.crypto.eddsa.spec.EdDSAPublicKeySpec; import net.i2p.data.Signature; import net.i2p.data.SigningPrivateKey; import net.i2p.data.SigningPublicKey; import net.i2p.util.LHMCache; import net.i2p.util.NativeBigInteger; /** * Utilities for Signing keys and Signatures * * @since 0.9.9, public since 0.9.12 */ public final class SigUtil { private static final Map<SigningPublicKey, ECPublicKey> _ECPubkeyCache = new LHMCache<SigningPublicKey, ECPublicKey>(64); private static final Map<SigningPrivateKey, ECPrivateKey> _ECPrivkeyCache = new LHMCache<SigningPrivateKey, ECPrivateKey>(16); private static final Map<SigningPublicKey, EdDSAPublicKey> _EdPubkeyCache = new LHMCache<SigningPublicKey, EdDSAPublicKey>(64); private static final Map<SigningPrivateKey, EdDSAPrivateKey> _EdPrivkeyCache = new LHMCache<SigningPrivateKey, EdDSAPrivateKey>(16); private SigUtil() {} /** * @return JAVA key! */ public static PublicKey toJavaKey(SigningPublicKey pk) throws GeneralSecurityException { switch (pk.getType().getBaseAlgorithm()) { case DSA: return toJavaDSAKey(pk); case EC: return toJavaECKey(pk); case EdDSA: return toJavaEdDSAKey(pk); case RSA: return toJavaRSAKey(pk); default: throw new IllegalArgumentException(); } } /** * @return JAVA key! */ public static PrivateKey toJavaKey(SigningPrivateKey pk) throws GeneralSecurityException { switch (pk.getType().getBaseAlgorithm()) { case DSA: return toJavaDSAKey(pk); case EC: return toJavaECKey(pk); case EdDSA: return toJavaEdDSAKey(pk); case RSA: return toJavaRSAKey(pk); default: throw new IllegalArgumentException(); } } /** * Use if SigType is unknown. * For efficiency, use fromJavakey(pk, type) if type is known. * * @param pk JAVA key! * @throws IllegalArgumentException on unknown type * @since 0.9.18 */ public static SigningPublicKey fromJavaKey(PublicKey pk) throws GeneralSecurityException { if (pk instanceof DSAPublicKey) { return fromJavaKey((DSAPublicKey) pk); } if (pk instanceof ECPublicKey) { ECPublicKey k = (ECPublicKey) pk; AlgorithmParameterSpec spec = k.getParams(); SigType type; if (spec.equals(SigType.ECDSA_SHA256_P256.getParams())) type = SigType.ECDSA_SHA256_P256; else if (spec.equals(SigType.ECDSA_SHA384_P384.getParams())) type = SigType.ECDSA_SHA384_P384; else if (spec.equals(SigType.ECDSA_SHA512_P521.getParams())) type = SigType.ECDSA_SHA512_P521; else throw new IllegalArgumentException("Unknown EC type"); return fromJavaKey(k, type); } if (pk instanceof EdDSAPublicKey) { return fromJavaKey((EdDSAPublicKey) pk, SigType.EdDSA_SHA512_Ed25519); } if (pk instanceof RSAPublicKey) { RSAPublicKey k = (RSAPublicKey) pk; int sz = k.getModulus().bitLength(); SigType type; if (sz <= ((RSAKeyGenParameterSpec) SigType.RSA_SHA256_2048.getParams()).getKeysize()) type = SigType.RSA_SHA256_2048; else if (sz <= ((RSAKeyGenParameterSpec) SigType.RSA_SHA384_3072.getParams()).getKeysize()) type = SigType.RSA_SHA384_3072; else if (sz <= ((RSAKeyGenParameterSpec) SigType.RSA_SHA512_4096.getParams()).getKeysize()) type = SigType.RSA_SHA512_4096; else throw new IllegalArgumentException("Unknown RSA type"); return fromJavaKey(k, type); } throw new IllegalArgumentException("Unknown type: " + pk.getClass()); } /** * Use if SigType is known. * * @param pk JAVA key! */ public static SigningPublicKey fromJavaKey(PublicKey pk, SigType type) throws GeneralSecurityException { switch (type.getBaseAlgorithm()) { case DSA: return fromJavaKey((DSAPublicKey) pk); case EC: return fromJavaKey((ECPublicKey) pk, type); case EdDSA: return fromJavaKey((EdDSAPublicKey) pk, type); case RSA: return fromJavaKey((RSAPublicKey) pk, type); default: throw new IllegalArgumentException("Unknown type: " + type); } } /** * Use if SigType is unknown. * For efficiency, use fromJavakey(pk, type) if type is known. * * @param pk JAVA key! * @throws IllegalArgumentException on unknown type * @since 0.9.18 */ public static SigningPrivateKey fromJavaKey(PrivateKey pk) throws GeneralSecurityException { if (pk instanceof DSAPrivateKey) { return fromJavaKey((DSAPrivateKey) pk); } if (pk instanceof ECPrivateKey) { ECPrivateKey k = (ECPrivateKey) pk; AlgorithmParameterSpec spec = k.getParams(); SigType type; if (spec.equals(SigType.ECDSA_SHA256_P256.getParams())) type = SigType.ECDSA_SHA256_P256; else if (spec.equals(SigType.ECDSA_SHA384_P384.getParams())) type = SigType.ECDSA_SHA384_P384; else if (spec.equals(SigType.ECDSA_SHA512_P521.getParams())) type = SigType.ECDSA_SHA512_P521; else throw new IllegalArgumentException("Unknown EC type"); return fromJavaKey(k, type); } if (pk instanceof EdDSAPrivateKey) { return fromJavaKey((EdDSAPrivateKey) pk, SigType.EdDSA_SHA512_Ed25519); } if (pk instanceof RSAPrivateKey) { RSAPrivateKey k = (RSAPrivateKey) pk; int sz = k.getModulus().bitLength(); SigType type; if (sz <= ((RSAKeyGenParameterSpec) SigType.RSA_SHA256_2048.getParams()).getKeysize()) type = SigType.RSA_SHA256_2048; else if (sz <= ((RSAKeyGenParameterSpec) SigType.RSA_SHA384_3072.getParams()).getKeysize()) type = SigType.RSA_SHA384_3072; else if (sz <= ((RSAKeyGenParameterSpec) SigType.RSA_SHA512_4096.getParams()).getKeysize()) type = SigType.RSA_SHA512_4096; else throw new IllegalArgumentException("Unknown RSA type"); return fromJavaKey(k, type); } throw new IllegalArgumentException("Unknown type: " + pk.getClass()); } /** * Use if SigType is known. * * @param pk JAVA key! */ public static SigningPrivateKey fromJavaKey(PrivateKey pk, SigType type) throws GeneralSecurityException { switch (type.getBaseAlgorithm()) { case DSA: return fromJavaKey((DSAPrivateKey) pk); case EC: return fromJavaKey((ECPrivateKey) pk, type); case EdDSA: return fromJavaKey((EdDSAPrivateKey) pk, type); case RSA: return fromJavaKey((RSAPrivateKey) pk, type); default: throw new IllegalArgumentException("Unknown type: " + type); } } /** * @return JAVA key! */ public static ECPublicKey toJavaECKey(SigningPublicKey pk) throws GeneralSecurityException { ECPublicKey rv; synchronized (_ECPubkeyCache) { rv = _ECPubkeyCache.get(pk); } if (rv != null) return rv; rv = cvtToJavaECKey(pk); synchronized (_ECPubkeyCache) { _ECPubkeyCache.put(pk, rv); } return rv; } /** * @return JAVA key! */ public static ECPrivateKey toJavaECKey(SigningPrivateKey pk) throws GeneralSecurityException { ECPrivateKey rv; synchronized (_ECPrivkeyCache) { rv = _ECPrivkeyCache.get(pk); } if (rv != null) return rv; rv = cvtToJavaECKey(pk); synchronized (_ECPrivkeyCache) { _ECPrivkeyCache.put(pk, rv); } return rv; } private static ECPublicKey cvtToJavaECKey(SigningPublicKey pk) throws GeneralSecurityException { SigType type = pk.getType(); BigInteger[] xy = split(pk.getData()); ECPoint w = new ECPoint(xy[0], xy[1]); // see ECConstants re: casting ECPublicKeySpec ks = new ECPublicKeySpec(w, (ECParameterSpec) type.getParams()); KeyFactory kf = KeyFactory.getInstance("EC"); return (ECPublicKey) kf.generatePublic(ks); } private static ECPrivateKey cvtToJavaECKey(SigningPrivateKey pk) throws GeneralSecurityException { SigType type = pk.getType(); byte[] b = pk.getData(); BigInteger s = new NativeBigInteger(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(); byte[] b = combine(x, y, len); 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 JAVA EdDSA public key! * @since 0.9.15 */ public static EdDSAPublicKey toJavaEdDSAKey(SigningPublicKey pk) throws GeneralSecurityException { EdDSAPublicKey rv; synchronized (_EdPubkeyCache) { rv = _EdPubkeyCache.get(pk); } if (rv != null) return rv; rv = cvtToJavaEdDSAKey(pk); synchronized (_EdPubkeyCache) { _EdPubkeyCache.put(pk, rv); } return rv; } /** * @return JAVA EdDSA private key! * @since 0.9.15 */ public static EdDSAPrivateKey toJavaEdDSAKey(SigningPrivateKey pk) throws GeneralSecurityException { EdDSAPrivateKey rv; synchronized (_EdPrivkeyCache) { rv = _EdPrivkeyCache.get(pk); } if (rv != null) return rv; rv = cvtToJavaEdDSAKey(pk); synchronized (_EdPrivkeyCache) { _EdPrivkeyCache.put(pk, rv); } return rv; } /** * @since 0.9.15 */ private static EdDSAPublicKey cvtToJavaEdDSAKey(SigningPublicKey pk) throws GeneralSecurityException { try { return new EdDSAPublicKey(new EdDSAPublicKeySpec( pk.getData(), (EdDSAParameterSpec) pk.getType().getParams())); } catch (IllegalArgumentException iae) { throw new InvalidKeyException(iae); } } /** * @since 0.9.15 */ private static EdDSAPrivateKey cvtToJavaEdDSAKey(SigningPrivateKey pk) throws GeneralSecurityException { try { return new EdDSAPrivateKey(new EdDSAPrivateKeySpec( pk.getData(), (EdDSAParameterSpec) pk.getType().getParams())); } catch (IllegalArgumentException iae) { throw new InvalidKeyException(iae); } } /** * @since 0.9.15 */ public static SigningPublicKey fromJavaKey(EdDSAPublicKey pk, SigType type) throws GeneralSecurityException { return new SigningPublicKey(type, pk.getAbyte()); } /** * @since 0.9.15 */ public static SigningPrivateKey fromJavaKey(EdDSAPrivateKey pk, SigType type) throws GeneralSecurityException { return new SigningPrivateKey(type, pk.getSeed()); } public static DSAPublicKey toJavaDSAKey(SigningPublicKey pk) throws GeneralSecurityException { KeyFactory kf = KeyFactory.getInstance("DSA"); // y p q g KeySpec ks = new DSAPublicKeySpec(new NativeBigInteger(1, pk.getData()), CryptoConstants.dsap, CryptoConstants.dsaq, CryptoConstants.dsag); return (DSAPublicKey) kf.generatePublic(ks); } public static DSAPrivateKey toJavaDSAKey(SigningPrivateKey pk) throws GeneralSecurityException { KeyFactory kf = KeyFactory.getInstance("DSA"); // x p q g KeySpec ks = new DSAPrivateKeySpec(new NativeBigInteger(1, pk.getData()), CryptoConstants.dsap, CryptoConstants.dsaq, CryptoConstants.dsag); return (DSAPrivateKey) kf.generatePrivate(ks); } public static SigningPublicKey fromJavaKey(DSAPublicKey pk) throws GeneralSecurityException { BigInteger y = pk.getY(); SigType type = SigType.DSA_SHA1; int len = type.getPubkeyLen(); byte[] by = rectify(y, len); return new SigningPublicKey(type, by); } public static SigningPrivateKey fromJavaKey(DSAPrivateKey pk) throws GeneralSecurityException { BigInteger x = pk.getX(); SigType type = SigType.DSA_SHA1; int len = type.getPrivkeyLen(); byte[] bx = rectify(x, len); return new SigningPrivateKey(type, bx); } /** * @deprecated unused */ public static RSAPublicKey toJavaRSAKey(SigningPublicKey pk) throws GeneralSecurityException { SigType type = pk.getType(); KeyFactory kf = KeyFactory.getInstance("RSA"); BigInteger n = new NativeBigInteger(1, pk.getData()); BigInteger e = ((RSAKeyGenParameterSpec)type.getParams()).getPublicExponent(); // modulus exponent KeySpec ks = new RSAPublicKeySpec(n, e); return (RSAPublicKey) kf.generatePublic(ks); } /** * */ public static RSAPrivateKey toJavaRSAKey(SigningPrivateKey pk) throws GeneralSecurityException { KeyFactory kf = KeyFactory.getInstance("RSA"); // private key is modulus (pubkey) + exponent BigInteger[] nd = split(pk.getData()); // modulus exponent KeySpec ks = new RSAPrivateKeySpec(nd[0], nd[1]); return (RSAPrivateKey) kf.generatePrivate(ks); } /** * */ public static SigningPublicKey fromJavaKey(RSAPublicKey pk, SigType type) throws GeneralSecurityException { BigInteger n = pk.getModulus(); int len = type.getPubkeyLen(); byte[] bn = rectify(n, len); return new SigningPublicKey(type, bn); } /** * @deprecated unused */ public static SigningPrivateKey fromJavaKey(RSAPrivateKey pk, SigType type) throws GeneralSecurityException { // private key is modulus (pubkey) + exponent BigInteger n = pk.getModulus(); BigInteger d = pk.getPrivateExponent(); byte[] b = combine(n, d, type.getPrivkeyLen()); return new SigningPrivateKey(type, b); } /** * @return ASN.1 representation */ public static byte[] toJavaSig(Signature sig) { // RSA and EdDSA sigs are not ASN encoded if (sig.getType().getBaseAlgorithm() == SigAlgo.RSA || sig.getType().getBaseAlgorithm() == SigAlgo.EdDSA) return sig.getData(); 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 { // RSA and EdDSA sigs are not ASN encoded if (type.getBaseAlgorithm() == SigAlgo.RSA || type.getBaseAlgorithm() == SigAlgo.EdDSA) return new Signature(type, asn); 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.getBaseAlgorithm().getName(); 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.getBaseAlgorithm().getName(); 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) {} } } /** * Split a byte array into two BigIntegers * @param b length must be even * @return array of two BigIntegers * @since 0.9.9 */ private static NativeBigInteger[] split(byte[] b) { if ((b.length & 0x01) != 0) throw new IllegalArgumentException("length must be even"); int sublen = b.length / 2; byte[] bx = new byte[sublen]; byte[] by = new byte[sublen]; System.arraycopy(b, 0, bx, 0, sublen); System.arraycopy(b, sublen, by, 0, sublen); NativeBigInteger x = new NativeBigInteger(1, bx); NativeBigInteger y = new NativeBigInteger(1, by); return new NativeBigInteger[] {x, y}; } /** * Combine two BigIntegers of nominal length = len / 2 * @return array of exactly len bytes * @since 0.9.9 */ private static byte[] combine(BigInteger x, BigInteger y, int len) throws InvalidKeyException { if ((len & 0x01) != 0) throw new InvalidKeyException("length must be even"); 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 b; } /** * @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 *<pre> * 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 *</pre> * * 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. * * @param sig length must be even * @throws IllegalArgumentException if too big * @since 0.8.7, moved to SigUtil in 0.9.9 */ private static byte[] sigBytesToASN1(byte[] sig) { BigInteger[] rs = split(sig); return sigBytesToASN1(rs[0], rs[1]); } /** * http://download.oracle.com/javase/1.5.0/docs/guide/security/CryptoSpec.html *<pre> * 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 *</pre> * * r and s are always non-negative. * * Only supports sigs up to about 65530 bytes. See code to fix BER encoding for this before you * add a SigType with bigger signatures. * * @throws IllegalArgumentException if too big * @since 0.9.25, split out from sigBytesToASN1(byte[]) */ public static byte[] sigBytesToASN1(BigInteger r, BigInteger s) { int extra = 4; byte[] rb = r.toByteArray(); if (rb.length > 127) { extra++; if (rb.length > 255) extra++; } byte[] sb = s.toByteArray(); if (sb.length > 127) { extra++; if (sb.length > 255) extra++; } int seqlen = rb.length + sb.length + extra; int totlen = seqlen + 2; if (seqlen > 127) { totlen++; if (seqlen > 255) totlen++; } byte[] rv = new byte[totlen]; int idx = 0; rv[idx++] = 0x30; idx = intToASN1(rv, idx, seqlen); rv[idx++] = 0x02; idx = intToASN1(rv, idx, rb.length); System.arraycopy(rb, 0, rv, idx, rb.length); idx += rb.length; rv[idx++] = 0x02; idx = intToASN1(rv, idx, 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; } /** * Output an length or integer value in ASN.1 * Does NOT output the tag e.g. 0x02 / 0x30 * * @param val 0-65535 * @return the new index * @since 0.9.25 */ public static int intToASN1(byte[] d, int idx, int val) { if (val < 0 || val > 65535) throw new IllegalArgumentException("fixme length " + val); if (val > 127) { if (val > 255) { d[idx++] = (byte) 0x82; d[idx++] = (byte) (val >> 8); } else { d[idx++] = (byte) 0x81; } } d[idx++] = (byte) val; return idx; } /** * See above. * Only supports sigs up to about 65530 bytes. See code to fix BER encoding for bigger than that. * * @param len must be even, twice the nominal length of each BigInteger * @return len bytes, call split() on the result to get two BigIntegers * @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) { if ((rlen & 0xff) == 0x81) { rlen = asn[++idx] & 0xff; } else if ((rlen & 0xff) == 0x82) { rlen = asn[++idx] & 0xff; rlen <<= 8; rlen |= asn[++idx] & 0xff; } else { throw new SignatureException("FIXME R length > 65535"); } } 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; if (asn[idx] != 0x02) throw new SignatureException("asn[s] = " + (asn[idx] & 0xff)); int slen = asn[++idx]; if ((slen & 0x80) != 0) { if ((slen & 0xff) == 0x81) { slen = asn[++idx] & 0xff; } else if ((slen & 0xff) == 0x82) { slen = asn[++idx] & 0xff; slen <<= 8; slen |= asn[++idx] & 0xff; } else { throw new SignatureException("FIXME S length > 65535"); } } if ((asn[++idx] & 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, idx + 1, rv, sublen, sublen); else System.arraycopy(asn, idx, rv, len - slen, slen); //System.out.println("post from asn1\n" + net.i2p.util.HexDump.dump(rv)); return rv; } /** * See above. * Only supports sigs up to about 65530 bytes. See code to fix BER encoding for bigger than that. * * @param len nominal length of each BigInteger * @return two BigIntegers * @since 0.9.25 */ public static NativeBigInteger[] aSN1ToBigInteger(byte[] asn, int len) throws SignatureException { byte[] sig = aSN1ToSigBytes(asn, len * 2); return split(sig); } public static void clearCaches() { synchronized(_ECPubkeyCache) { _ECPubkeyCache.clear(); } synchronized(_ECPrivkeyCache) { _ECPrivkeyCache.clear(); } synchronized(_EdPubkeyCache) { _EdPubkeyCache.clear(); } synchronized(_EdPrivkeyCache) { _EdPrivkeyCache.clear(); } } }