forked from I2P_Developers/i2p.i2p
Crypto: RedDSAEngine and generateAlpha() for Encrypted LS2
This commit is contained in:
@ -1,10 +1,16 @@
|
||||
package net.i2p.crypto;
|
||||
|
||||
import java.security.GeneralSecurityException;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.Locale;
|
||||
import java.util.TimeZone;
|
||||
|
||||
import net.i2p.I2PAppContext;
|
||||
import net.i2p.crypto.eddsa.EdDSABlinding;
|
||||
import net.i2p.crypto.eddsa.EdDSAPrivateKey;
|
||||
import net.i2p.crypto.eddsa.EdDSAPublicKey;
|
||||
import net.i2p.data.DataHelper;
|
||||
import net.i2p.data.Destination;
|
||||
import net.i2p.data.Hash;
|
||||
import net.i2p.data.SigningPrivateKey;
|
||||
import net.i2p.data.SigningPublicKey;
|
||||
@ -20,6 +26,15 @@ public final class Blinding {
|
||||
|
||||
private static final SigType TYPE = SigType.EdDSA_SHA512_Ed25519;
|
||||
private static final SigType TYPER = SigType.RedDSA_SHA512_Ed25519;
|
||||
private static final String INFO = "i2pblinding1";
|
||||
|
||||
// following copied from RouterKeyGenerator
|
||||
private static final String FORMAT = "yyyyMMdd";
|
||||
private static final int LENGTH = FORMAT.length();
|
||||
private static final SimpleDateFormat _fmt = new SimpleDateFormat(FORMAT, Locale.US);
|
||||
static {
|
||||
_fmt.setTimeZone(TimeZone.getTimeZone("GMT"));
|
||||
}
|
||||
|
||||
private Blinding() {}
|
||||
|
||||
@ -89,6 +104,40 @@ public final class Blinding {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Only for SigType EdDSA_SHA512_Ed25519.
|
||||
*
|
||||
* @param dest spk must be SigType EdDSA_SHA512_Ed25519
|
||||
* @param secret may be null or zero-length
|
||||
* @return SigType RedDSA_SHA512_Ed25519
|
||||
* @throws UnsupportedOperationException unless supported SigTypes
|
||||
* @throws IllegalArgumentException on bad inputs
|
||||
* @since 0.9.39
|
||||
*/
|
||||
public static SigningPrivateKey generateAlpha(I2PAppContext ctx, Destination dest, String secret) {
|
||||
long now = ctx.clock().now();
|
||||
String modVal;
|
||||
synchronized(_fmt) {
|
||||
modVal = _fmt.format(now);
|
||||
}
|
||||
if (modVal.length() != LENGTH)
|
||||
throw new IllegalStateException();
|
||||
byte[] mod = DataHelper.getASCII(modVal);
|
||||
byte[] data;
|
||||
if (secret != null && secret.length() > 0) {
|
||||
data = new byte[LENGTH + secret.length()];
|
||||
System.arraycopy(mod, 0, data, 0, LENGTH);
|
||||
System.arraycopy(DataHelper.getASCII(secret), 0, data, LENGTH, secret.length());
|
||||
} else {
|
||||
data = mod;
|
||||
}
|
||||
HKDF hkdf = new HKDF(ctx);
|
||||
byte[] out = new byte[64];
|
||||
hkdf.calculate(dest.getHash().getData(), data, INFO, out, out, 32);
|
||||
byte[] b = EdDSABlinding.reduce(out);
|
||||
return new SigningPrivateKey(TYPER, b);
|
||||
}
|
||||
|
||||
/******
|
||||
public static void main(String args[]) throws Exception {
|
||||
net.i2p.data.SimpleDataStructure[] keys = KeyGenerator.getInstance().generateSigningKeys(TYPE);
|
||||
|
@ -44,6 +44,7 @@ import java.security.interfaces.RSAKey;
|
||||
import net.i2p.I2PAppContext;
|
||||
import net.i2p.crypto.eddsa.EdDSAEngine;
|
||||
import net.i2p.crypto.eddsa.EdDSAKey;
|
||||
import net.i2p.crypto.eddsa.RedDSAEngine;
|
||||
import net.i2p.data.Hash;
|
||||
import net.i2p.data.Signature;
|
||||
import net.i2p.data.SigningPrivateKey;
|
||||
@ -520,7 +521,8 @@ public final class DSAEngine {
|
||||
boolean rv;
|
||||
if (type.getBaseAlgorithm() == SigAlgo.EdDSA) {
|
||||
// take advantage of one-shot mode
|
||||
EdDSAEngine jsig = new EdDSAEngine(type.getDigestInstance());
|
||||
MessageDigest md = type.getDigestInstance();
|
||||
EdDSAEngine jsig = (type == SigType.RedDSA_SHA512_Ed25519) ? new RedDSAEngine(md) : new EdDSAEngine(md);
|
||||
jsig.initVerify(pubKey);
|
||||
rv = jsig.verifyOneShot(data, offset, len, sigbytes);
|
||||
} else {
|
||||
@ -573,7 +575,7 @@ public final class DSAEngine {
|
||||
if (type.getBaseAlgorithm() == SigAlgo.EdDSA) {
|
||||
// take advantage of one-shot mode
|
||||
// Ignore algo, EdDSAKey includes a hash specification.
|
||||
EdDSAEngine jsig = new EdDSAEngine();
|
||||
EdDSAEngine jsig = (type == SigType.RedDSA_SHA512_Ed25519) ? new RedDSAEngine() : new EdDSAEngine();
|
||||
jsig.initVerify(pubKey);
|
||||
rv = jsig.verifyOneShot(hash.getData(), sigbytes);
|
||||
} else {
|
||||
@ -621,7 +623,8 @@ public final class DSAEngine {
|
||||
byte[] sigbytes;
|
||||
if (type.getBaseAlgorithm() == SigAlgo.EdDSA) {
|
||||
// take advantage of one-shot mode
|
||||
EdDSAEngine jsig = new EdDSAEngine(type.getDigestInstance());
|
||||
MessageDigest md = type.getDigestInstance();
|
||||
EdDSAEngine jsig = (type == SigType.RedDSA_SHA512_Ed25519) ? new RedDSAEngine(md) : new EdDSAEngine(md);
|
||||
jsig.initSign(privKey);
|
||||
sigbytes = jsig.signOneShot(data, offset, len);
|
||||
} else {
|
||||
@ -669,7 +672,7 @@ public final class DSAEngine {
|
||||
if (type.getBaseAlgorithm() == SigAlgo.EdDSA) {
|
||||
// take advantage of one-shot mode
|
||||
// Ignore algo, EdDSAKey includes a hash specification.
|
||||
EdDSAEngine jsig = new EdDSAEngine();
|
||||
EdDSAEngine jsig = (type == SigType.RedDSA_SHA512_Ed25519) ? new RedDSAEngine() : new EdDSAEngine();
|
||||
jsig.initSign(privKey);
|
||||
sigbytes = jsig.signOneShot(hash.getData());
|
||||
} else {
|
||||
|
@ -55,10 +55,10 @@ import net.i2p.crypto.eddsa.math.ScalarOps;
|
||||
* @author str4d
|
||||
*
|
||||
*/
|
||||
public final class EdDSAEngine extends Signature {
|
||||
public class EdDSAEngine extends Signature {
|
||||
public static final String SIGNATURE_ALGORITHM = "NONEwithEdDSA";
|
||||
|
||||
private MessageDigest digest;
|
||||
protected MessageDigest digest;
|
||||
private ByteArrayOutputStream baos;
|
||||
private EdDSAKey key;
|
||||
private boolean oneShotMode;
|
||||
@ -129,7 +129,7 @@ public final class EdDSAEngine extends Signature {
|
||||
}
|
||||
}
|
||||
|
||||
private void digestInitSign(EdDSAPrivateKey privKey) {
|
||||
protected void digestInitSign(EdDSAPrivateKey privKey) {
|
||||
// Preparing for hash
|
||||
// r = H(h_b,...,h_2b-1,M)
|
||||
int b = privKey.getParams().getCurve().getField().getb();
|
||||
|
70
core/java/src/net/i2p/crypto/eddsa/RedDSAEngine.java
Normal file
70
core/java/src/net/i2p/crypto/eddsa/RedDSAEngine.java
Normal file
@ -0,0 +1,70 @@
|
||||
package net.i2p.crypto.eddsa;
|
||||
|
||||
import java.security.MessageDigest;
|
||||
|
||||
import net.i2p.util.RandomSource;
|
||||
|
||||
/**
|
||||
* Signing and verification for REdDSA using SHA-512 and the Ed25519 curve.
|
||||
* Ref: Zcash Protocol Specification, Version 2018.0-beta-33 [Overwinter+Sapling]
|
||||
* Sections 4.1.6.1, 4.1.6.2, 5.4.6
|
||||
*
|
||||
*<p>
|
||||
* The EdDSA sign and verify algorithms do not interact well with
|
||||
* the Java Signature API, as one or more update() methods must be
|
||||
* called before sign() or verify(). Using the standard API,
|
||||
* this implementation must copy and buffer all data passed in
|
||||
* via update().
|
||||
*</p><p>
|
||||
* This implementation offers two ways to avoid this copying,
|
||||
* but only if all data to be signed or verified is available
|
||||
* in a single byte array.
|
||||
*</p><p>
|
||||
*Option 1:
|
||||
*</p><ol>
|
||||
*<li>Call initSign() or initVerify() as usual.
|
||||
*</li><li>Call setParameter(ONE_SHOT_MODE)
|
||||
*</li><li>Call update(byte[]) or update(byte[], int, int) exactly once
|
||||
*</li><li>Call sign() or verify() as usual.
|
||||
*</li><li>If doing additional one-shot signs or verifies with this object, you must
|
||||
* call setParameter(ONE_SHOT_MODE) each time
|
||||
*</li></ol>
|
||||
*
|
||||
*<p>
|
||||
*Option 2:
|
||||
*</p><ol>
|
||||
*<li>Call initSign() or initVerify() as usual.
|
||||
*</li><li>Call one of the signOneShot() or verifyOneShot() methods.
|
||||
*</li><li>If doing additional one-shot signs or verifies with this object,
|
||||
* just call signOneShot() or verifyOneShot() again.
|
||||
*</li></ol>
|
||||
*
|
||||
* @since 0.9.39
|
||||
*/
|
||||
public final class RedDSAEngine extends EdDSAEngine {
|
||||
|
||||
/**
|
||||
* No specific EdDSA-internal hash requested, allows any EdDSA key.
|
||||
*/
|
||||
public RedDSAEngine() {
|
||||
super();
|
||||
}
|
||||
|
||||
/**
|
||||
* Specific EdDSA-internal hash requested, only matching keys will be allowed.
|
||||
* @param digest the hash algorithm that keys must have to sign or verify.
|
||||
*/
|
||||
public RedDSAEngine(MessageDigest digest) {
|
||||
super(digest);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void digestInitSign(EdDSAPrivateKey privKey) {
|
||||
// Preparing for hash
|
||||
// r = H(T, pubkey, M)
|
||||
byte[] t = new byte[digest.getDigestLength() + 16];
|
||||
RandomSource.getInstance().nextBytes(t);
|
||||
digest.update(t);
|
||||
digest.update(privKey.getAbyte());
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user