forked from I2P_Developers/i2p.i2p
Crypto: Implement blinding (proposal 123)
Add sig type 11 for blinded keys
This commit is contained in:
@ -19,6 +19,7 @@ import net.i2p.data.SigningPublicKey;
|
||||
public final class Blinding {
|
||||
|
||||
private static final SigType TYPE = SigType.EdDSA_SHA512_Ed25519;
|
||||
private static final SigType TYPER = SigType.RedDSA_SHA512_Ed25519;
|
||||
|
||||
private Blinding() {}
|
||||
|
||||
@ -26,17 +27,19 @@ public final class Blinding {
|
||||
* Only for SigType EdDSA_SHA512_Ed25519.
|
||||
*
|
||||
* @param key must be SigType EdDSA_SHA512_Ed25519
|
||||
* @param alpha the secret data
|
||||
* @throws UnsupportedOperationException unless supported
|
||||
* @param alpha must be SigType RedDSA_SHA512_Ed25519
|
||||
* @return SigType RedDSA_SHA512_Ed25519
|
||||
* @throws UnsupportedOperationException unless supported SigTypes
|
||||
* @throws IllegalArgumentException on bad inputs
|
||||
*/
|
||||
public static SigningPublicKey blind(SigningPublicKey key, SigningPrivateKey alpha) {
|
||||
if (key.getType() != TYPE && alpha.getType() != TYPE)
|
||||
if (key.getType() != TYPE || alpha.getType() != TYPER)
|
||||
throw new UnsupportedOperationException();
|
||||
try {
|
||||
EdDSAPublicKey jk = SigUtil.toJavaEdDSAKey(key);
|
||||
EdDSAPrivateKey ajk = SigUtil.toJavaEdDSAKey(alpha);
|
||||
EdDSAPublicKey bjk = EdDSABlinding.blind(jk, ajk);
|
||||
return SigUtil.fromJavaKey(bjk, TYPE);
|
||||
return SigUtil.fromJavaKey(bjk, TYPER);
|
||||
} catch (GeneralSecurityException gse) {
|
||||
throw new IllegalArgumentException(gse);
|
||||
}
|
||||
@ -46,17 +49,19 @@ public final class Blinding {
|
||||
* Only for SigType EdDSA_SHA512_Ed25519.
|
||||
*
|
||||
* @param key must be SigType EdDSA_SHA512_Ed25519
|
||||
* @param alpha the secret data
|
||||
* @throws UnsupportedOperationException unless supported
|
||||
* @param alpha must be SigType RedDSA_SHA512_Ed25519
|
||||
* @return SigType RedDSA_SHA512_Ed25519
|
||||
* @throws UnsupportedOperationException unless supported SigTypes
|
||||
* @throws IllegalArgumentException on bad inputs
|
||||
*/
|
||||
public static SigningPrivateKey blind(SigningPrivateKey key, SigningPrivateKey alpha) {
|
||||
if (key.getType() != TYPE && alpha.getType() != TYPE)
|
||||
if (key.getType() != TYPE || alpha.getType() != TYPER)
|
||||
throw new UnsupportedOperationException();
|
||||
try {
|
||||
EdDSAPrivateKey jk = SigUtil.toJavaEdDSAKey(key);
|
||||
EdDSAPrivateKey ajk = SigUtil.toJavaEdDSAKey(alpha);
|
||||
EdDSAPrivateKey bjk = EdDSABlinding.blind(jk, ajk);
|
||||
return SigUtil.fromJavaKey(bjk, TYPE);
|
||||
return SigUtil.fromJavaKey(bjk, TYPER);
|
||||
} catch (GeneralSecurityException gse) {
|
||||
throw new IllegalArgumentException(gse);
|
||||
}
|
||||
@ -65,12 +70,14 @@ public final class Blinding {
|
||||
/**
|
||||
* Only for SigType EdDSA_SHA512_Ed25519.
|
||||
*
|
||||
* @param key must be SigType EdDSA_SHA512_Ed25519
|
||||
* @param alpha the secret data
|
||||
* @throws UnsupportedOperationException unless supported
|
||||
* @param key must be SigType RedDSA_SHA512_Ed25519
|
||||
* @param alpha must be SigType RedDSA_SHA512_Ed25519
|
||||
* @return SigType EdDSA_SHA512_Ed25519
|
||||
* @throws UnsupportedOperationException unless supported SigTypes
|
||||
* @throws IllegalArgumentException on bad inputs
|
||||
*/
|
||||
public static SigningPrivateKey unblind(SigningPrivateKey key, SigningPrivateKey alpha) {
|
||||
if (key.getType() != TYPE && alpha.getType() != TYPE)
|
||||
if (key.getType() != TYPER || alpha.getType() != TYPER)
|
||||
throw new UnsupportedOperationException();
|
||||
try {
|
||||
EdDSAPrivateKey bjk = SigUtil.toJavaEdDSAKey(key);
|
||||
@ -81,22 +88,39 @@ public final class Blinding {
|
||||
throw new IllegalArgumentException(gse);
|
||||
}
|
||||
}
|
||||
|
||||
/******
|
||||
public static void main(String args[]) throws Exception {
|
||||
SimpleDataStructure[] keys = KeyGenerator.getInstance().generateSigningKeys(TYPE);
|
||||
net.i2p.data.SimpleDataStructure[] keys = KeyGenerator.getInstance().generateSigningKeys(TYPE);
|
||||
SigningPublicKey pub = (SigningPublicKey) keys[0];
|
||||
SigningPrivateKey priv = (SigningPrivateKey) keys[1];
|
||||
byte[] b = new byte[32];
|
||||
byte[] b = new byte[64];
|
||||
net.i2p.I2PAppContext.getGlobalContext().random().nextBytes(b);
|
||||
Hash h = new Hash(b);
|
||||
SigningPublicKey bpub = blind(pub, h);
|
||||
SigningPrivateKey bpriv = blind(priv, h);
|
||||
SigningPublicKey bpub2 = bpriv.toPublic();
|
||||
boolean ok = bpub2.equals(bpub);
|
||||
System.out.println("Blinding test passed? " + ok);
|
||||
SigningPrivateKey priv2 = unblind(bpriv, h);
|
||||
ok = priv2.equals(priv);
|
||||
System.out.println("Unblinding test passed? " + ok);
|
||||
b = EdDSABlinding.reduce(b);
|
||||
SigningPrivateKey alpha = new SigningPrivateKey(TYPER, b);
|
||||
SigningPublicKey bpub = null;
|
||||
try {
|
||||
bpub = blind(pub, alpha);
|
||||
} catch (Exception e) {
|
||||
System.out.println("Blinding pubkey test failed");
|
||||
e.printStackTrace();
|
||||
}
|
||||
SigningPrivateKey bpriv = null;
|
||||
try {
|
||||
bpriv = blind(priv, alpha);
|
||||
} catch (Exception e) {
|
||||
System.out.println("Blinding privkey test failed");
|
||||
e.printStackTrace();
|
||||
}
|
||||
if (bpub != null && bpriv != null) {
|
||||
SigningPublicKey bpub2 = bpriv.toPublic();
|
||||
boolean ok = bpub2.equals(bpub);
|
||||
System.out.println("Blinding test passed? " + ok);
|
||||
// unimplemented
|
||||
//SigningPrivateKey priv2 = unblind(bpriv, alpha);
|
||||
//ok = priv2.equals(priv);
|
||||
//System.out.println("Unblinding test passed? " + ok);
|
||||
}
|
||||
}
|
||||
******/
|
||||
}
|
||||
|
@ -65,6 +65,17 @@ public enum SigType {
|
||||
EdDSA_SHA512_Ed25519ph(8, 32, 32, 64, 64, SigAlgo.EdDSA, "SHA-512", "NonewithEdDSA",
|
||||
EdDSANamedCurveTable.getByName("ed25519-sha-512"), "1.3.101.101", "0.9.25"),
|
||||
|
||||
// 9 and 10 reserved for GOST - see proposal 134
|
||||
|
||||
/**
|
||||
* Blinded version of EdDSA, use for encrypted LS2
|
||||
* Pubkey 32 bytes; privkey 32 bytes; hash 64 bytes; sig 64 bytes
|
||||
*
|
||||
* @since 0.9.39
|
||||
*/
|
||||
RedDSA_SHA512_Ed25519(11, 32, 32, 64, 64, SigAlgo.EdDSA, "SHA-512", "SHA512withEdDSA",
|
||||
EdDSANamedCurveTable.getByName("ed25519-sha-512"), "1.3.101.101", "0.9.39"),
|
||||
|
||||
;
|
||||
|
||||
// TESTING....................
|
||||
@ -295,6 +306,8 @@ public enum SigType {
|
||||
return EdDSA_SHA512_Ed25519;
|
||||
if (uc.equals("EDDSA_SHA512_ED25519PH"))
|
||||
return EdDSA_SHA512_Ed25519ph;
|
||||
if (uc.equals("REDDSA_SHA512_ED25519"))
|
||||
return RedDSA_SHA512_Ed25519;
|
||||
return valueOf(uc);
|
||||
} catch (IllegalArgumentException iae) {
|
||||
try {
|
||||
|
@ -369,8 +369,16 @@ public final class SigUtil {
|
||||
private static EdDSAPrivateKey cvtToJavaEdDSAKey(SigningPrivateKey pk)
|
||||
throws GeneralSecurityException {
|
||||
try {
|
||||
return new EdDSAPrivateKey(new EdDSAPrivateKeySpec(
|
||||
pk.getData(), (EdDSAParameterSpec) pk.getType().getParams()));
|
||||
EdDSAParameterSpec paramspec = (EdDSAParameterSpec) pk.getType().getParams();
|
||||
EdDSAPrivateKeySpec pkspec;
|
||||
SigType type = pk.getType();
|
||||
if (type == SigType.EdDSA_SHA512_Ed25519)
|
||||
pkspec = new EdDSAPrivateKeySpec(pk.getData(), paramspec);
|
||||
else if (type == SigType.RedDSA_SHA512_Ed25519)
|
||||
pkspec = new EdDSAPrivateKeySpec(pk.getData(), null, paramspec);
|
||||
else
|
||||
throw new InvalidKeyException();
|
||||
return new EdDSAPrivateKey(pkspec);
|
||||
} catch (IllegalArgumentException iae) {
|
||||
throw new InvalidKeyException(iae);
|
||||
}
|
||||
@ -389,7 +397,14 @@ public final class SigUtil {
|
||||
*/
|
||||
public static SigningPrivateKey fromJavaKey(EdDSAPrivateKey pk, SigType type)
|
||||
throws GeneralSecurityException {
|
||||
return new SigningPrivateKey(type, pk.getSeed());
|
||||
byte[] data;
|
||||
if (type == SigType.EdDSA_SHA512_Ed25519)
|
||||
data = pk.getSeed();
|
||||
else if (type == SigType.RedDSA_SHA512_Ed25519)
|
||||
data = pk.geta();
|
||||
else
|
||||
throw new IllegalArgumentException();
|
||||
return new SigningPrivateKey(type, data);
|
||||
}
|
||||
|
||||
public static DSAPublicKey toJavaDSAKey(SigningPublicKey pk)
|
||||
|
@ -1,5 +1,16 @@
|
||||
package net.i2p.crypto.eddsa;
|
||||
|
||||
import java.math.BigInteger;
|
||||
|
||||
import net.i2p.crypto.eddsa.math.Field;
|
||||
import net.i2p.crypto.eddsa.math.GroupElement;
|
||||
import net.i2p.crypto.eddsa.math.ScalarOps;
|
||||
import net.i2p.crypto.eddsa.math.bigint.BigIntegerLittleEndianEncoding;
|
||||
import net.i2p.crypto.eddsa.math.bigint.BigIntegerScalarOps;
|
||||
import net.i2p.crypto.eddsa.spec.EdDSANamedCurveTable;
|
||||
import net.i2p.crypto.eddsa.spec.EdDSAPrivateKeySpec;
|
||||
import net.i2p.crypto.eddsa.spec.EdDSAPublicKeySpec;
|
||||
|
||||
/**
|
||||
* Utilities for Blinding EdDSA keys.
|
||||
* PRELIMINARY - Subject to change - see proposal 123
|
||||
@ -8,6 +19,10 @@ package net.i2p.crypto.eddsa;
|
||||
*/
|
||||
public final class EdDSABlinding {
|
||||
|
||||
private static final byte[] ONE = Utils.hexToBytes("0100000000000000000000000000000000000000000000000000000000000000");
|
||||
private static final Field FIELD = EdDSANamedCurveTable.getByName("Ed25519").getCurve().getField();
|
||||
private static final BigInteger ORDER = new BigInteger("2").pow(252).add(new BigInteger("27742317777372353535851937790883648493"));
|
||||
|
||||
private EdDSABlinding() {}
|
||||
|
||||
/**
|
||||
@ -18,8 +33,19 @@ public final class EdDSABlinding {
|
||||
* @throws UnsupportedOperationException unless supported
|
||||
*/
|
||||
public static EdDSAPublicKey blind(EdDSAPublicKey key, EdDSAPrivateKey alpha) {
|
||||
// TODO, test only
|
||||
return key;
|
||||
GroupElement a = key.getA();
|
||||
GroupElement aa = alpha.getA();
|
||||
// Add the two public keys together.
|
||||
GroupElement d = a.add(aa.toCached());
|
||||
EdDSAPublicKeySpec pubKey = new EdDSAPublicKeySpec(d, key.getParams());
|
||||
EdDSAPublicKey rv = new EdDSAPublicKey(pubKey);
|
||||
//System.out.println("Adding pubkey\n" +
|
||||
// net.i2p.util.HexDump.dump(key.getAbyte()) +
|
||||
// "\nplus privkey\n" +
|
||||
// net.i2p.util.HexDump.dump(alpha.geta()) +
|
||||
// "\nequals\n" +
|
||||
// net.i2p.util.HexDump.dump(rv.getAbyte()));
|
||||
return rv;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -30,19 +56,46 @@ public final class EdDSABlinding {
|
||||
* @throws UnsupportedOperationException unless supported
|
||||
*/
|
||||
public static EdDSAPrivateKey blind(EdDSAPrivateKey key, EdDSAPrivateKey alpha) {
|
||||
// TODO, test only
|
||||
return key;
|
||||
byte[] a = key.geta();
|
||||
byte[] aa = alpha.geta();
|
||||
Field f = key.getParams().getCurve().getField();
|
||||
BigIntegerLittleEndianEncoding enc = new BigIntegerLittleEndianEncoding();
|
||||
enc.setField(f);
|
||||
ScalarOps sc = new BigIntegerScalarOps(f, ORDER);
|
||||
// Add the two private keys together.
|
||||
// just for now, since we don't have a pure add.
|
||||
byte[] d = sc.multiplyAndAdd(ONE, a, aa);
|
||||
//System.out.println("Adding privkeys\n" +
|
||||
// net.i2p.util.HexDump.dump(a) +
|
||||
// "\nplus\n" +
|
||||
// net.i2p.util.HexDump.dump(aa) +
|
||||
// "\nequals\n" +
|
||||
// net.i2p.util.HexDump.dump(d));
|
||||
EdDSAPrivateKeySpec privKey = new EdDSAPrivateKeySpec(d, null, key.getParams());
|
||||
return new EdDSAPrivateKey(privKey);
|
||||
}
|
||||
|
||||
/**
|
||||
* Only for SigType EdDSA_SHA512_Ed25519.
|
||||
* Unimplemented, probably not needed except for testing.
|
||||
*
|
||||
* @param key must be SigType EdDSA_SHA512_Ed25519
|
||||
* @param alpha generated from hash of secret data
|
||||
* @throws UnsupportedOperationException unless supported
|
||||
*/
|
||||
public static EdDSAPrivateKey unblind(EdDSAPrivateKey key, EdDSAPrivateKey alpha) {
|
||||
// TODO, test only
|
||||
return key;
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
/**
|
||||
* Use to generate alpha
|
||||
*
|
||||
* @param b 64 bytes little endian of random
|
||||
* @return 32 bytes little endian mod l
|
||||
*/
|
||||
public static byte[] reduce(byte[] b) {
|
||||
if (b.length != 64)
|
||||
throw new IllegalArgumentException();
|
||||
ScalarOps sc = new BigIntegerScalarOps(FIELD, ORDER);
|
||||
return sc.reduce(b);
|
||||
}
|
||||
}
|
||||
|
@ -83,11 +83,41 @@ public class EdDSAPrivateKeySpec implements KeySpec {
|
||||
A = spec.getB().scalarMultiply(a);
|
||||
}
|
||||
|
||||
/**
|
||||
* No validation of any parameters other than a.
|
||||
* getSeed() and getH() will return null if this constructor is used.
|
||||
*
|
||||
* @param a must be "clamped" (for Ed) or reduced mod l (for Red)
|
||||
* @param A if null, will be derived from a.
|
||||
* @throws IllegalArgumentException if a not clamped or reduced
|
||||
* @since 0.9.39
|
||||
*/
|
||||
public EdDSAPrivateKeySpec(byte[] a, GroupElement A, EdDSAParameterSpec spec) {
|
||||
this(null, null, a, A, spec);
|
||||
}
|
||||
|
||||
/**
|
||||
* No validation of any parameters other than a.
|
||||
*
|
||||
* @param seed may be null
|
||||
* @param h may be null
|
||||
* @param a must be "clamped" (for Ed) or reduced mod l (for Red)
|
||||
* @param A if null, will be derived from a.
|
||||
* @throws IllegalArgumentException if a not clamped or reduced
|
||||
*/
|
||||
public EdDSAPrivateKeySpec(byte[] seed, byte[] h, byte[] a, GroupElement A, EdDSAParameterSpec spec) {
|
||||
/**
|
||||
// TODO if we move RedDSA to a different spec
|
||||
int bd8m1 = (spec.getCurve().getField().getb() / 8) - 1;
|
||||
if ((a[0] & 0x07) != 0 ||
|
||||
(a[bd8m1] & 0xc0) != 0x40)
|
||||
throw new IllegalArgumentException("a not clamped: a[0]=0x" + Integer.toString(a[0] & 0xff, 16) +
|
||||
" a[31]=0x" + Integer.toString(a[31] & 0xff, 16));
|
||||
**/
|
||||
this.seed = seed;
|
||||
this.h = h;
|
||||
this.a = a;
|
||||
this.A = A;
|
||||
this.A = (A != null) ? A : spec.getB().scalarMultiply(a);
|
||||
this.spec = spec;
|
||||
}
|
||||
|
||||
|
Reference in New Issue
Block a user