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 {
|
public final class Blinding {
|
||||||
|
|
||||||
private static final SigType TYPE = SigType.EdDSA_SHA512_Ed25519;
|
private static final SigType TYPE = SigType.EdDSA_SHA512_Ed25519;
|
||||||
|
private static final SigType TYPER = SigType.RedDSA_SHA512_Ed25519;
|
||||||
|
|
||||||
private Blinding() {}
|
private Blinding() {}
|
||||||
|
|
||||||
@ -26,17 +27,19 @@ public final class Blinding {
|
|||||||
* Only for SigType EdDSA_SHA512_Ed25519.
|
* Only for SigType EdDSA_SHA512_Ed25519.
|
||||||
*
|
*
|
||||||
* @param key must be SigType EdDSA_SHA512_Ed25519
|
* @param key must be SigType EdDSA_SHA512_Ed25519
|
||||||
* @param alpha the secret data
|
* @param alpha must be SigType RedDSA_SHA512_Ed25519
|
||||||
* @throws UnsupportedOperationException unless supported
|
* @return SigType RedDSA_SHA512_Ed25519
|
||||||
|
* @throws UnsupportedOperationException unless supported SigTypes
|
||||||
|
* @throws IllegalArgumentException on bad inputs
|
||||||
*/
|
*/
|
||||||
public static SigningPublicKey blind(SigningPublicKey key, SigningPrivateKey alpha) {
|
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();
|
throw new UnsupportedOperationException();
|
||||||
try {
|
try {
|
||||||
EdDSAPublicKey jk = SigUtil.toJavaEdDSAKey(key);
|
EdDSAPublicKey jk = SigUtil.toJavaEdDSAKey(key);
|
||||||
EdDSAPrivateKey ajk = SigUtil.toJavaEdDSAKey(alpha);
|
EdDSAPrivateKey ajk = SigUtil.toJavaEdDSAKey(alpha);
|
||||||
EdDSAPublicKey bjk = EdDSABlinding.blind(jk, ajk);
|
EdDSAPublicKey bjk = EdDSABlinding.blind(jk, ajk);
|
||||||
return SigUtil.fromJavaKey(bjk, TYPE);
|
return SigUtil.fromJavaKey(bjk, TYPER);
|
||||||
} catch (GeneralSecurityException gse) {
|
} catch (GeneralSecurityException gse) {
|
||||||
throw new IllegalArgumentException(gse);
|
throw new IllegalArgumentException(gse);
|
||||||
}
|
}
|
||||||
@ -46,17 +49,19 @@ public final class Blinding {
|
|||||||
* Only for SigType EdDSA_SHA512_Ed25519.
|
* Only for SigType EdDSA_SHA512_Ed25519.
|
||||||
*
|
*
|
||||||
* @param key must be SigType EdDSA_SHA512_Ed25519
|
* @param key must be SigType EdDSA_SHA512_Ed25519
|
||||||
* @param alpha the secret data
|
* @param alpha must be SigType RedDSA_SHA512_Ed25519
|
||||||
* @throws UnsupportedOperationException unless supported
|
* @return SigType RedDSA_SHA512_Ed25519
|
||||||
|
* @throws UnsupportedOperationException unless supported SigTypes
|
||||||
|
* @throws IllegalArgumentException on bad inputs
|
||||||
*/
|
*/
|
||||||
public static SigningPrivateKey blind(SigningPrivateKey key, SigningPrivateKey alpha) {
|
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();
|
throw new UnsupportedOperationException();
|
||||||
try {
|
try {
|
||||||
EdDSAPrivateKey jk = SigUtil.toJavaEdDSAKey(key);
|
EdDSAPrivateKey jk = SigUtil.toJavaEdDSAKey(key);
|
||||||
EdDSAPrivateKey ajk = SigUtil.toJavaEdDSAKey(alpha);
|
EdDSAPrivateKey ajk = SigUtil.toJavaEdDSAKey(alpha);
|
||||||
EdDSAPrivateKey bjk = EdDSABlinding.blind(jk, ajk);
|
EdDSAPrivateKey bjk = EdDSABlinding.blind(jk, ajk);
|
||||||
return SigUtil.fromJavaKey(bjk, TYPE);
|
return SigUtil.fromJavaKey(bjk, TYPER);
|
||||||
} catch (GeneralSecurityException gse) {
|
} catch (GeneralSecurityException gse) {
|
||||||
throw new IllegalArgumentException(gse);
|
throw new IllegalArgumentException(gse);
|
||||||
}
|
}
|
||||||
@ -65,12 +70,14 @@ public final class Blinding {
|
|||||||
/**
|
/**
|
||||||
* Only for SigType EdDSA_SHA512_Ed25519.
|
* Only for SigType EdDSA_SHA512_Ed25519.
|
||||||
*
|
*
|
||||||
* @param key must be SigType EdDSA_SHA512_Ed25519
|
* @param key must be SigType RedDSA_SHA512_Ed25519
|
||||||
* @param alpha the secret data
|
* @param alpha must be SigType RedDSA_SHA512_Ed25519
|
||||||
* @throws UnsupportedOperationException unless supported
|
* @return SigType EdDSA_SHA512_Ed25519
|
||||||
|
* @throws UnsupportedOperationException unless supported SigTypes
|
||||||
|
* @throws IllegalArgumentException on bad inputs
|
||||||
*/
|
*/
|
||||||
public static SigningPrivateKey unblind(SigningPrivateKey key, SigningPrivateKey alpha) {
|
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();
|
throw new UnsupportedOperationException();
|
||||||
try {
|
try {
|
||||||
EdDSAPrivateKey bjk = SigUtil.toJavaEdDSAKey(key);
|
EdDSAPrivateKey bjk = SigUtil.toJavaEdDSAKey(key);
|
||||||
@ -81,22 +88,39 @@ public final class Blinding {
|
|||||||
throw new IllegalArgumentException(gse);
|
throw new IllegalArgumentException(gse);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/******
|
/******
|
||||||
public static void main(String args[]) throws Exception {
|
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];
|
SigningPublicKey pub = (SigningPublicKey) keys[0];
|
||||||
SigningPrivateKey priv = (SigningPrivateKey) keys[1];
|
SigningPrivateKey priv = (SigningPrivateKey) keys[1];
|
||||||
byte[] b = new byte[32];
|
byte[] b = new byte[64];
|
||||||
net.i2p.I2PAppContext.getGlobalContext().random().nextBytes(b);
|
net.i2p.I2PAppContext.getGlobalContext().random().nextBytes(b);
|
||||||
Hash h = new Hash(b);
|
b = EdDSABlinding.reduce(b);
|
||||||
SigningPublicKey bpub = blind(pub, h);
|
SigningPrivateKey alpha = new SigningPrivateKey(TYPER, b);
|
||||||
SigningPrivateKey bpriv = blind(priv, h);
|
SigningPublicKey bpub = null;
|
||||||
SigningPublicKey bpub2 = bpriv.toPublic();
|
try {
|
||||||
boolean ok = bpub2.equals(bpub);
|
bpub = blind(pub, alpha);
|
||||||
System.out.println("Blinding test passed? " + ok);
|
} catch (Exception e) {
|
||||||
SigningPrivateKey priv2 = unblind(bpriv, h);
|
System.out.println("Blinding pubkey test failed");
|
||||||
ok = priv2.equals(priv);
|
e.printStackTrace();
|
||||||
System.out.println("Unblinding test passed? " + ok);
|
}
|
||||||
|
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",
|
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"),
|
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....................
|
// TESTING....................
|
||||||
@ -295,6 +306,8 @@ public enum SigType {
|
|||||||
return EdDSA_SHA512_Ed25519;
|
return EdDSA_SHA512_Ed25519;
|
||||||
if (uc.equals("EDDSA_SHA512_ED25519PH"))
|
if (uc.equals("EDDSA_SHA512_ED25519PH"))
|
||||||
return EdDSA_SHA512_Ed25519ph;
|
return EdDSA_SHA512_Ed25519ph;
|
||||||
|
if (uc.equals("REDDSA_SHA512_ED25519"))
|
||||||
|
return RedDSA_SHA512_Ed25519;
|
||||||
return valueOf(uc);
|
return valueOf(uc);
|
||||||
} catch (IllegalArgumentException iae) {
|
} catch (IllegalArgumentException iae) {
|
||||||
try {
|
try {
|
||||||
|
@ -369,8 +369,16 @@ public final class SigUtil {
|
|||||||
private static EdDSAPrivateKey cvtToJavaEdDSAKey(SigningPrivateKey pk)
|
private static EdDSAPrivateKey cvtToJavaEdDSAKey(SigningPrivateKey pk)
|
||||||
throws GeneralSecurityException {
|
throws GeneralSecurityException {
|
||||||
try {
|
try {
|
||||||
return new EdDSAPrivateKey(new EdDSAPrivateKeySpec(
|
EdDSAParameterSpec paramspec = (EdDSAParameterSpec) pk.getType().getParams();
|
||||||
pk.getData(), (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) {
|
} catch (IllegalArgumentException iae) {
|
||||||
throw new InvalidKeyException(iae);
|
throw new InvalidKeyException(iae);
|
||||||
}
|
}
|
||||||
@ -389,7 +397,14 @@ public final class SigUtil {
|
|||||||
*/
|
*/
|
||||||
public static SigningPrivateKey fromJavaKey(EdDSAPrivateKey pk, SigType type)
|
public static SigningPrivateKey fromJavaKey(EdDSAPrivateKey pk, SigType type)
|
||||||
throws GeneralSecurityException {
|
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)
|
public static DSAPublicKey toJavaDSAKey(SigningPublicKey pk)
|
||||||
|
@ -1,5 +1,16 @@
|
|||||||
package net.i2p.crypto.eddsa;
|
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.
|
* Utilities for Blinding EdDSA keys.
|
||||||
* PRELIMINARY - Subject to change - see proposal 123
|
* PRELIMINARY - Subject to change - see proposal 123
|
||||||
@ -8,6 +19,10 @@ package net.i2p.crypto.eddsa;
|
|||||||
*/
|
*/
|
||||||
public final class EdDSABlinding {
|
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() {}
|
private EdDSABlinding() {}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -18,8 +33,19 @@ public final class EdDSABlinding {
|
|||||||
* @throws UnsupportedOperationException unless supported
|
* @throws UnsupportedOperationException unless supported
|
||||||
*/
|
*/
|
||||||
public static EdDSAPublicKey blind(EdDSAPublicKey key, EdDSAPrivateKey alpha) {
|
public static EdDSAPublicKey blind(EdDSAPublicKey key, EdDSAPrivateKey alpha) {
|
||||||
// TODO, test only
|
GroupElement a = key.getA();
|
||||||
return key;
|
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
|
* @throws UnsupportedOperationException unless supported
|
||||||
*/
|
*/
|
||||||
public static EdDSAPrivateKey blind(EdDSAPrivateKey key, EdDSAPrivateKey alpha) {
|
public static EdDSAPrivateKey blind(EdDSAPrivateKey key, EdDSAPrivateKey alpha) {
|
||||||
// TODO, test only
|
byte[] a = key.geta();
|
||||||
return key;
|
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 key must be SigType EdDSA_SHA512_Ed25519
|
||||||
* @param alpha generated from hash of secret data
|
* @param alpha generated from hash of secret data
|
||||||
* @throws UnsupportedOperationException unless supported
|
* @throws UnsupportedOperationException unless supported
|
||||||
*/
|
*/
|
||||||
public static EdDSAPrivateKey unblind(EdDSAPrivateKey key, EdDSAPrivateKey alpha) {
|
public static EdDSAPrivateKey unblind(EdDSAPrivateKey key, EdDSAPrivateKey alpha) {
|
||||||
// TODO, test only
|
throw new UnsupportedOperationException();
|
||||||
return key;
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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);
|
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) {
|
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.seed = seed;
|
||||||
this.h = h;
|
this.h = h;
|
||||||
this.a = a;
|
this.a = a;
|
||||||
this.A = A;
|
this.A = (A != null) ? A : spec.getB().scalarMultiply(a);
|
||||||
this.spec = spec;
|
this.spec = spec;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user