forked from I2P_Developers/i2p.i2p
Crypto: Noise modifications to support ratchet:
- Add IK support - Add generic key factory support - Add method to get ephemeral key - Add method to get encoded ephemeral key - Add clone() support - Add back ChaCha debug support
This commit is contained in:
@ -29,7 +29,7 @@ import com.southernstorm.noise.protocol.Destroyable;
|
|||||||
/**
|
/**
|
||||||
* Simple implementation of the Poly1305 message authenticator.
|
* Simple implementation of the Poly1305 message authenticator.
|
||||||
*/
|
*/
|
||||||
public final class Poly1305 implements Destroyable {
|
public final class Poly1305 implements Destroyable, Cloneable {
|
||||||
|
|
||||||
// The 130-bit intermediate values are broken up into five 26-bit words.
|
// The 130-bit intermediate values are broken up into five 26-bit words.
|
||||||
private final byte[] nonce;
|
private final byte[] nonce;
|
||||||
@ -324,4 +324,13 @@ public final class Poly1305 implements Destroyable {
|
|||||||
Arrays.fill(c, 0);
|
Arrays.fill(c, 0);
|
||||||
Arrays.fill(t, (long)0);
|
Arrays.fill(t, (long)0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* I2P
|
||||||
|
* @since 0.9.44
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public Poly1305 clone() throws CloneNotSupportedException {
|
||||||
|
return (Poly1305) super.clone();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -41,6 +41,10 @@ public class ChaChaPolyCipherState implements CipherState {
|
|||||||
private final byte[] polyKey;
|
private final byte[] polyKey;
|
||||||
private long n;
|
private long n;
|
||||||
private boolean haskey;
|
private boolean haskey;
|
||||||
|
// Debug only
|
||||||
|
private byte[] initialKey;
|
||||||
|
|
||||||
|
private static final boolean DEBUG = false;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructs a new cipher state for the "ChaChaPoly" algorithm.
|
* Constructs a new cipher state for the "ChaChaPoly" algorithm.
|
||||||
@ -55,6 +59,20 @@ public class ChaChaPolyCipherState implements CipherState {
|
|||||||
haskey = false;
|
haskey = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Copy constructor for cloning
|
||||||
|
* @since 0.9.44
|
||||||
|
*/
|
||||||
|
protected ChaChaPolyCipherState(ChaChaPolyCipherState o) throws CloneNotSupportedException {
|
||||||
|
poly = o.poly.clone();
|
||||||
|
input = Arrays.copyOf(o.input, o.input.length);
|
||||||
|
output = Arrays.copyOf(o.output, o.output.length);
|
||||||
|
polyKey = Arrays.copyOf(o.polyKey, o.polyKey.length);
|
||||||
|
n = o.n;
|
||||||
|
haskey = o.haskey;
|
||||||
|
initialKey = o.initialKey;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void destroy() {
|
public void destroy() {
|
||||||
poly.destroy();
|
poly.destroy();
|
||||||
@ -80,6 +98,10 @@ public class ChaChaPolyCipherState implements CipherState {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void initializeKey(byte[] key, int offset) {
|
public void initializeKey(byte[] key, int offset) {
|
||||||
|
if (DEBUG) {
|
||||||
|
initialKey = new byte[32];
|
||||||
|
System.arraycopy(key, 0, initialKey, 0, 32);
|
||||||
|
}
|
||||||
ChaChaCore.initKey256(input, key, offset);
|
ChaChaCore.initKey256(input, key, offset);
|
||||||
n = 0;
|
n = 0;
|
||||||
haskey = true;
|
haskey = true;
|
||||||
@ -249,6 +271,15 @@ public class ChaChaPolyCipherState implements CipherState {
|
|||||||
n = nonce;
|
n = nonce;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* I2P
|
||||||
|
* @since 0.9.44
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public ChaChaPolyCipherState clone() throws CloneNotSupportedException {
|
||||||
|
return new ChaChaPolyCipherState(this);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* I2P debug
|
* I2P debug
|
||||||
*/
|
*/
|
||||||
@ -258,6 +289,15 @@ public class ChaChaPolyCipherState implements CipherState {
|
|||||||
buf.append(" Cipher State:\n" +
|
buf.append(" Cipher State:\n" +
|
||||||
" nonce: ");
|
" nonce: ");
|
||||||
buf.append(n);
|
buf.append(n);
|
||||||
|
// I2P debug
|
||||||
|
if (DEBUG) {
|
||||||
|
buf.append("\n" +
|
||||||
|
" init key: ");
|
||||||
|
if (haskey)
|
||||||
|
buf.append(net.i2p.data.Base64.encode(initialKey));
|
||||||
|
else
|
||||||
|
buf.append("null");
|
||||||
|
}
|
||||||
buf.append("\n poly key: ");
|
buf.append("\n poly key: ");
|
||||||
if (haskey)
|
if (haskey)
|
||||||
buf.append(net.i2p.data.Base64.encode(polyKey));
|
buf.append(net.i2p.data.Base64.encode(polyKey));
|
||||||
|
@ -33,7 +33,7 @@ import javax.crypto.ShortBufferException;
|
|||||||
* will create two CipherState objects for encrypting packets sent to
|
* will create two CipherState objects for encrypting packets sent to
|
||||||
* the other party, and decrypting packets received from the other party.
|
* the other party, and decrypting packets received from the other party.
|
||||||
*/
|
*/
|
||||||
public interface CipherState extends Destroyable {
|
public interface CipherState extends Destroyable, Cloneable {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the Noise protocol name for this cipher.
|
* Gets the Noise protocol name for this cipher.
|
||||||
@ -155,4 +155,10 @@ public interface CipherState extends Destroyable {
|
|||||||
* value goes backwards then security may be compromised.
|
* value goes backwards then security may be compromised.
|
||||||
*/
|
*/
|
||||||
void setNonce(long nonce);
|
void setNonce(long nonce);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* I2P
|
||||||
|
* @since 0.9.44
|
||||||
|
*/
|
||||||
|
public CipherState clone() throws CloneNotSupportedException;
|
||||||
}
|
}
|
||||||
|
@ -26,23 +26,25 @@ import java.util.Arrays;
|
|||||||
|
|
||||||
import com.southernstorm.noise.crypto.x25519.Curve25519;
|
import com.southernstorm.noise.crypto.x25519.Curve25519;
|
||||||
|
|
||||||
|
import net.i2p.crypto.KeyFactory;
|
||||||
import net.i2p.crypto.KeyPair;
|
import net.i2p.crypto.KeyPair;
|
||||||
import net.i2p.router.transport.crypto.X25519KeyFactory;
|
import net.i2p.router.crypto.ratchet.Elg2KeyPair;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Implementation of the Curve25519 algorithm for the Noise protocol.
|
* Implementation of the Curve25519 algorithm for the Noise protocol.
|
||||||
*/
|
*/
|
||||||
class Curve25519DHState implements DHState {
|
class Curve25519DHState implements DHState, Cloneable {
|
||||||
|
|
||||||
private final byte[] publicKey;
|
private final byte[] publicKey;
|
||||||
private final byte[] privateKey;
|
private final byte[] privateKey;
|
||||||
private int mode;
|
private int mode;
|
||||||
private final X25519KeyFactory _xdh;
|
private final KeyFactory _xdh;
|
||||||
|
private byte[] encodedPublicKey;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructs a new Diffie-Hellman object for Curve25519.
|
* Constructs a new Diffie-Hellman object for Curve25519.
|
||||||
*/
|
*/
|
||||||
public Curve25519DHState(X25519KeyFactory xdh)
|
public Curve25519DHState(KeyFactory xdh)
|
||||||
{
|
{
|
||||||
publicKey = new byte [32];
|
publicKey = new byte [32];
|
||||||
privateKey = new byte [32];
|
privateKey = new byte [32];
|
||||||
@ -80,6 +82,11 @@ class Curve25519DHState implements DHState {
|
|||||||
KeyPair kp = _xdh.getKeys();
|
KeyPair kp = _xdh.getKeys();
|
||||||
System.arraycopy(kp.getPrivate().getData(), 0, privateKey, 0, 32);
|
System.arraycopy(kp.getPrivate().getData(), 0, privateKey, 0, 32);
|
||||||
System.arraycopy(kp.getPublic().getData(), 0, publicKey, 0, 32);
|
System.arraycopy(kp.getPublic().getData(), 0, publicKey, 0, 32);
|
||||||
|
if (kp instanceof Elg2KeyPair) {
|
||||||
|
Elg2KeyPair ekp = (Elg2KeyPair) kp;
|
||||||
|
encodedPublicKey = new byte[32];
|
||||||
|
System.arraycopy(ekp.getEncoded(), 0, encodedPublicKey, 0, 32);
|
||||||
|
}
|
||||||
mode = 0x03;
|
mode = 0x03;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -111,6 +118,10 @@ class Curve25519DHState implements DHState {
|
|||||||
public void setToNullPublicKey() {
|
public void setToNullPublicKey() {
|
||||||
Arrays.fill(publicKey, (byte)0);
|
Arrays.fill(publicKey, (byte)0);
|
||||||
Arrays.fill(privateKey, (byte)0);
|
Arrays.fill(privateKey, (byte)0);
|
||||||
|
if (encodedPublicKey != null) {
|
||||||
|
Arrays.fill(encodedPublicKey, (byte)0);
|
||||||
|
encodedPublicKey = null;
|
||||||
|
}
|
||||||
mode = 0x01;
|
mode = 0x01;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -118,6 +129,10 @@ class Curve25519DHState implements DHState {
|
|||||||
public void clearKey() {
|
public void clearKey() {
|
||||||
Noise.destroy(publicKey);
|
Noise.destroy(publicKey);
|
||||||
Noise.destroy(privateKey);
|
Noise.destroy(privateKey);
|
||||||
|
if (encodedPublicKey != null) {
|
||||||
|
Noise.destroy(encodedPublicKey);
|
||||||
|
encodedPublicKey = null;
|
||||||
|
}
|
||||||
mode = 0;
|
mode = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -141,6 +156,26 @@ class Curve25519DHState implements DHState {
|
|||||||
return temp == 0;
|
return temp == 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* I2P
|
||||||
|
* @since 0.9.44
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public boolean hasEncodedPublicKey() {
|
||||||
|
return encodedPublicKey != null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* I2P
|
||||||
|
* @since 0.9.44
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public void getEncodedPublicKey(byte[] key, int offset) {
|
||||||
|
if (encodedPublicKey == null)
|
||||||
|
throw new IllegalStateException();
|
||||||
|
System.arraycopy(encodedPublicKey, 0, key, offset, 32);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void calculate(byte[] sharedKey, int offset, DHState publicDH) {
|
public void calculate(byte[] sharedKey, int offset, DHState publicDH) {
|
||||||
if (!(publicDH instanceof Curve25519DHState))
|
if (!(publicDH instanceof Curve25519DHState))
|
||||||
@ -159,4 +194,13 @@ class Curve25519DHState implements DHState {
|
|||||||
System.arraycopy(dh.publicKey, 0, publicKey, 0, 32);
|
System.arraycopy(dh.publicKey, 0, publicKey, 0, 32);
|
||||||
mode = dh.mode;
|
mode = dh.mode;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* I2P
|
||||||
|
* @since 0.9.44
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public Curve25519DHState clone() throws CloneNotSupportedException {
|
||||||
|
return (Curve25519DHState) super.clone();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -25,7 +25,7 @@ package com.southernstorm.noise.protocol;
|
|||||||
/**
|
/**
|
||||||
* Interface to a Diffie-Hellman algorithm for the Noise protocol.
|
* Interface to a Diffie-Hellman algorithm for the Noise protocol.
|
||||||
*/
|
*/
|
||||||
public interface DHState extends Destroyable {
|
public interface DHState extends Destroyable, Cloneable {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the Noise protocol name for this Diffie-Hellman algorithm.
|
* Gets the Noise protocol name for this Diffie-Hellman algorithm.
|
||||||
@ -132,6 +132,26 @@ public interface DHState extends Destroyable {
|
|||||||
*/
|
*/
|
||||||
boolean isNullPublicKey();
|
boolean isNullPublicKey();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Determine if this object contains an optional encoded public key.
|
||||||
|
*
|
||||||
|
* @return Returns true if this object contains an encoded public key,
|
||||||
|
* or false if the public key has not yet been set.
|
||||||
|
*
|
||||||
|
* @since 0.9.44
|
||||||
|
*/
|
||||||
|
boolean hasEncodedPublicKey();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the public key associated with this object.
|
||||||
|
*
|
||||||
|
* @param key The buffer to copy the public key to.
|
||||||
|
* @param offset The first offset in the key buffer to copy to.
|
||||||
|
*
|
||||||
|
* @since 0.9.44
|
||||||
|
*/
|
||||||
|
void getEncodedPublicKey(byte[] key, int offset);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Performs a Diffie-Hellman calculation with this object as the private key.
|
* Performs a Diffie-Hellman calculation with this object as the private key.
|
||||||
*
|
*
|
||||||
@ -153,4 +173,10 @@ public interface DHState extends Destroyable {
|
|||||||
* the same type as this object.
|
* the same type as this object.
|
||||||
*/
|
*/
|
||||||
void copyFrom(DHState other);
|
void copyFrom(DHState other);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* I2P
|
||||||
|
* @since 0.9.44
|
||||||
|
*/
|
||||||
|
public DHState clone() throws CloneNotSupportedException;
|
||||||
}
|
}
|
||||||
|
@ -28,12 +28,12 @@ import java.util.Arrays;
|
|||||||
import javax.crypto.BadPaddingException;
|
import javax.crypto.BadPaddingException;
|
||||||
import javax.crypto.ShortBufferException;
|
import javax.crypto.ShortBufferException;
|
||||||
|
|
||||||
import net.i2p.router.transport.crypto.X25519KeyFactory;
|
import net.i2p.crypto.KeyFactory;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Interface to a Noise handshake.
|
* Interface to a Noise handshake.
|
||||||
*/
|
*/
|
||||||
public class HandshakeState implements Destroyable {
|
public class HandshakeState implements Destroyable, Cloneable {
|
||||||
|
|
||||||
private final SymmetricState symmetric;
|
private final SymmetricState symmetric;
|
||||||
private final boolean isInitiator;
|
private final boolean isInitiator;
|
||||||
@ -128,36 +128,53 @@ public class HandshakeState implements Destroyable {
|
|||||||
private static final int FALLBACK_POSSIBLE = 0x40;
|
private static final int FALLBACK_POSSIBLE = 0x40;
|
||||||
|
|
||||||
public static final String protocolName = "Noise_XKaesobfse+hs2+hs3_25519_ChaChaPoly_SHA256";
|
public static final String protocolName = "Noise_XKaesobfse+hs2+hs3_25519_ChaChaPoly_SHA256";
|
||||||
|
public static final String protocolName2 = "Noise_IKelg2+hs2_25519_ChaChaPoly_SHA256";
|
||||||
private static final String prefix;
|
private static final String prefix;
|
||||||
private static final String patternId;
|
private final String patternId;
|
||||||
|
public static final String PATTERN_ID_XK = "XK";
|
||||||
|
public static final String PATTERN_ID_IK = "IK";
|
||||||
private static String dh;
|
private static String dh;
|
||||||
private static final String cipher;
|
private static final String cipher;
|
||||||
private static final String hash;
|
private static final String hash;
|
||||||
private static final short[] pattern;
|
private final short[] pattern;
|
||||||
|
private static final short[] PATTERN_XK;
|
||||||
|
private static final short[] PATTERN_IK;
|
||||||
|
|
||||||
static {
|
static {
|
||||||
// Parse the protocol name into its components.
|
// Parse the protocol name into its components.
|
||||||
|
// XK
|
||||||
String[] components = protocolName.split("_");
|
String[] components = protocolName.split("_");
|
||||||
if (components.length != 5)
|
if (components.length != 5)
|
||||||
throw new IllegalArgumentException("Protocol name must have 5 components");
|
throw new IllegalArgumentException("Protocol name must have 5 components");
|
||||||
prefix = components[0];
|
prefix = components[0];
|
||||||
patternId = components[1].substring(0, 2);
|
String id = components[1].substring(0, 2);
|
||||||
|
if (!PATTERN_ID_XK.equals(id))
|
||||||
|
throw new IllegalArgumentException();
|
||||||
dh = components[2];
|
dh = components[2];
|
||||||
cipher = components[3];
|
cipher = components[3];
|
||||||
hash = components[4];
|
hash = components[4];
|
||||||
if (!prefix.equals("Noise") && !prefix.equals("NoisePSK"))
|
if (!prefix.equals("Noise") && !prefix.equals("NoisePSK"))
|
||||||
throw new IllegalArgumentException("Prefix must be Noise or NoisePSK");
|
throw new IllegalArgumentException("Prefix must be Noise or NoisePSK");
|
||||||
pattern = Pattern.lookup(patternId);
|
PATTERN_XK = Pattern.lookup(id);
|
||||||
if (pattern == null)
|
if (PATTERN_XK == null)
|
||||||
throw new IllegalArgumentException("Handshake pattern is not recognized");
|
throw new IllegalArgumentException("Handshake pattern is not recognized");
|
||||||
if (!dh.equals("25519"))
|
if (!dh.equals("25519"))
|
||||||
throw new IllegalArgumentException("Unknown Noise DH algorithm name: " + dh);
|
throw new IllegalArgumentException("Unknown Noise DH algorithm name: " + dh);
|
||||||
|
// IK
|
||||||
|
components = protocolName2.split("_");
|
||||||
|
id = components[1].substring(0, 2);
|
||||||
|
if (!PATTERN_ID_IK.equals(id))
|
||||||
|
throw new IllegalArgumentException();
|
||||||
|
PATTERN_IK = Pattern.lookup(id);
|
||||||
|
if (PATTERN_IK == null)
|
||||||
|
throw new IllegalArgumentException("Handshake pattern is not recognized");
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a new Noise handshake.
|
* Creates a new Noise handshake.
|
||||||
* Noise protocol name is hardcoded.
|
* Noise protocol name is hardcoded.
|
||||||
*
|
*
|
||||||
|
* @param patternId XK or IK
|
||||||
* @param role The role, HandshakeState.INITIATOR or HandshakeState.RESPONDER.
|
* @param role The role, HandshakeState.INITIATOR or HandshakeState.RESPONDER.
|
||||||
* @param xdh The key pair factory for ephemeral keys
|
* @param xdh The key pair factory for ephemeral keys
|
||||||
*
|
*
|
||||||
@ -167,8 +184,15 @@ public class HandshakeState implements Destroyable {
|
|||||||
* @throws NoSuchAlgorithmException One of the cryptographic algorithms
|
* @throws NoSuchAlgorithmException One of the cryptographic algorithms
|
||||||
* that is specified in the protocolName is not supported.
|
* that is specified in the protocolName is not supported.
|
||||||
*/
|
*/
|
||||||
public HandshakeState(int role, X25519KeyFactory xdh) throws NoSuchAlgorithmException
|
public HandshakeState(String patternId, int role, KeyFactory xdh) throws NoSuchAlgorithmException
|
||||||
{
|
{
|
||||||
|
this.patternId = patternId;
|
||||||
|
if (patternId.equals(PATTERN_ID_XK))
|
||||||
|
pattern = PATTERN_XK;
|
||||||
|
else if (patternId.equals(PATTERN_ID_IK))
|
||||||
|
pattern = PATTERN_IK;
|
||||||
|
else
|
||||||
|
throw new IllegalArgumentException("Handshake pattern is not recognized");
|
||||||
short flags = pattern[0];
|
short flags = pattern[0];
|
||||||
int extraReqs = 0;
|
int extraReqs = 0;
|
||||||
if ((flags & Pattern.FLAG_REMOTE_REQUIRED) != 0 && patternId.length() > 1)
|
if ((flags & Pattern.FLAG_REMOTE_REQUIRED) != 0 && patternId.length() > 1)
|
||||||
@ -183,7 +207,7 @@ public class HandshakeState implements Destroyable {
|
|||||||
throw new IllegalArgumentException("Role must be initiator or responder");
|
throw new IllegalArgumentException("Role must be initiator or responder");
|
||||||
|
|
||||||
// Initialize this object. This will also create the cipher and hash objects.
|
// Initialize this object. This will also create the cipher and hash objects.
|
||||||
symmetric = new SymmetricState(cipher, hash);
|
symmetric = new SymmetricState(cipher, hash, patternId);
|
||||||
isInitiator = (role == INITIATOR);
|
isInitiator = (role == INITIATOR);
|
||||||
action = NO_ACTION;
|
action = NO_ACTION;
|
||||||
requirements = extraReqs | computeRequirements(flags, prefix, role, false);
|
requirements = extraReqs | computeRequirements(flags, prefix, role, false);
|
||||||
@ -201,6 +225,27 @@ public class HandshakeState implements Destroyable {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Copy constructor for cloning
|
||||||
|
* @since 0.9.44
|
||||||
|
*/
|
||||||
|
protected HandshakeState(HandshakeState o) throws CloneNotSupportedException {
|
||||||
|
// everything is shallow copied except for symmetric state
|
||||||
|
symmetric = o.symmetric.clone();
|
||||||
|
isInitiator = o.isInitiator;
|
||||||
|
localKeyPair = o.localKeyPair;
|
||||||
|
localEphemeral = o.localEphemeral;
|
||||||
|
remotePublicKey = o.remotePublicKey;
|
||||||
|
remoteEphemeral = o.remoteEphemeral;
|
||||||
|
action = o.action;
|
||||||
|
if (action == SPLIT || action == COMPLETE)
|
||||||
|
throw new CloneNotSupportedException("clone after NSR");
|
||||||
|
requirements = o.requirements;
|
||||||
|
patternIndex = o.patternIndex;
|
||||||
|
patternId = o.patternId;
|
||||||
|
pattern = o.pattern;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the name of the Noise protocol.
|
* Gets the name of the Noise protocol.
|
||||||
*
|
*
|
||||||
@ -231,6 +276,19 @@ public class HandshakeState implements Destroyable {
|
|||||||
return localKeyPair;
|
return localKeyPair;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the keypair object for the local ephemeral key.
|
||||||
|
*
|
||||||
|
* I2P
|
||||||
|
*
|
||||||
|
* @return The keypair, or null if a local ephemeral key is not required or has not been generated.
|
||||||
|
* @since 0.9.44
|
||||||
|
*/
|
||||||
|
public DHState getLocalEphemeralKeyPair()
|
||||||
|
{
|
||||||
|
return localEphemeral;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Determine if this handshake requires a local static key.
|
* Determine if this handshake requires a local static key.
|
||||||
*
|
*
|
||||||
@ -534,6 +592,13 @@ public class HandshakeState implements Destroyable {
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case Pattern.SS:
|
||||||
|
{
|
||||||
|
// DH operation with initiator and responder static keys.
|
||||||
|
mixDH(localKeyPair, remotePublicKey);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
{
|
{
|
||||||
// Unknown token code. Abort.
|
// Unknown token code. Abort.
|
||||||
@ -691,6 +756,13 @@ public class HandshakeState implements Destroyable {
|
|||||||
mixDH(localEphemeral, remotePublicKey);
|
mixDH(localEphemeral, remotePublicKey);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case Pattern.SS:
|
||||||
|
{
|
||||||
|
// DH operation with initiator and responder static keys.
|
||||||
|
mixDH(localKeyPair, remotePublicKey);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
{
|
{
|
||||||
@ -844,13 +916,25 @@ public class HandshakeState implements Destroyable {
|
|||||||
return symmetric.getChainingKey();
|
return symmetric.getChainingKey();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* I2P
|
||||||
|
* Must be called before both eph. keys set.
|
||||||
|
* @since 0.9.44
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public synchronized HandshakeState clone() throws CloneNotSupportedException {
|
||||||
|
return new HandshakeState(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* I2P debug
|
* I2P debug
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
StringBuilder buf = new StringBuilder();
|
StringBuilder buf = new StringBuilder(256);
|
||||||
buf.append("Handshake State:\n");
|
buf.append(patternId);
|
||||||
|
buf.append(" Handshake State:\n");
|
||||||
buf.append(symmetric.toString());
|
buf.append(symmetric.toString());
|
||||||
|
|
||||||
byte[] tmp = new byte[32];
|
byte[] tmp = new byte[32];
|
||||||
|
@ -71,6 +71,23 @@ class Pattern {
|
|||||||
SE
|
SE
|
||||||
};
|
};
|
||||||
|
|
||||||
|
private static final short[] noise_pattern_IK = {
|
||||||
|
FLAG_LOCAL_STATIC |
|
||||||
|
FLAG_LOCAL_EPHEMERAL |
|
||||||
|
FLAG_REMOTE_STATIC |
|
||||||
|
FLAG_REMOTE_EPHEMERAL |
|
||||||
|
FLAG_REMOTE_REQUIRED,
|
||||||
|
|
||||||
|
E,
|
||||||
|
ES,
|
||||||
|
S,
|
||||||
|
SS,
|
||||||
|
FLIP_DIR,
|
||||||
|
E,
|
||||||
|
EE,
|
||||||
|
SE
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Look up the description information for a pattern.
|
* Look up the description information for a pattern.
|
||||||
*
|
*
|
||||||
@ -81,6 +98,8 @@ class Pattern {
|
|||||||
{
|
{
|
||||||
if (name.equals("XK"))
|
if (name.equals("XK"))
|
||||||
return noise_pattern_XK;
|
return noise_pattern_XK;
|
||||||
|
else if (name.equals("IK"))
|
||||||
|
return noise_pattern_IK;
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -34,32 +34,42 @@ import javax.crypto.ShortBufferException;
|
|||||||
/**
|
/**
|
||||||
* Symmetric state for helping manage a Noise handshake.
|
* Symmetric state for helping manage a Noise handshake.
|
||||||
*/
|
*/
|
||||||
class SymmetricState implements Destroyable {
|
class SymmetricState implements Destroyable, Cloneable {
|
||||||
|
|
||||||
// precalculated hash of the Noise name
|
// precalculated hash of the Noise name
|
||||||
private static final byte[] INIT_HASH;
|
private static final byte[] INIT_HASH_XK;
|
||||||
|
private static final byte[] INIT_HASH_IK;
|
||||||
|
|
||||||
static {
|
static {
|
||||||
|
INIT_HASH_XK = initHash(HandshakeState.protocolName);
|
||||||
|
INIT_HASH_IK = initHash(HandshakeState.protocolName2);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @since 0.9.44
|
||||||
|
*/
|
||||||
|
private static byte[] initHash(String protocolName) {
|
||||||
byte[] protocolNameBytes;
|
byte[] protocolNameBytes;
|
||||||
try {
|
try {
|
||||||
protocolNameBytes = HandshakeState.protocolName.getBytes("UTF-8");
|
protocolNameBytes = protocolName.getBytes("UTF-8");
|
||||||
} catch (UnsupportedEncodingException e) {
|
} catch (UnsupportedEncodingException e) {
|
||||||
// If UTF-8 is not supported, then we are definitely in trouble!
|
// If UTF-8 is not supported, then we are definitely in trouble!
|
||||||
throw new UnsupportedOperationException("UTF-8 encoding is not supported");
|
throw new UnsupportedOperationException("UTF-8 encoding is not supported");
|
||||||
}
|
}
|
||||||
INIT_HASH = new byte[32];
|
byte[] rv = new byte[32];
|
||||||
if (protocolNameBytes.length <= 32) {
|
if (protocolNameBytes.length <= 32) {
|
||||||
System.arraycopy(protocolNameBytes, 0, INIT_HASH, 0, protocolNameBytes.length);
|
System.arraycopy(protocolNameBytes, 0, rv, 0, protocolNameBytes.length);
|
||||||
Arrays.fill(INIT_HASH, protocolNameBytes.length, 32, (byte)0);
|
Arrays.fill(rv, protocolNameBytes.length, 32, (byte)0);
|
||||||
} else {
|
} else {
|
||||||
try {
|
try {
|
||||||
MessageDigest hash = Noise.createHash("SHA256");
|
MessageDigest hash = Noise.createHash("SHA256");
|
||||||
hash.update(protocolNameBytes, 0, protocolNameBytes.length);
|
hash.update(protocolNameBytes, 0, protocolNameBytes.length);
|
||||||
hash.digest(INIT_HASH, 0, 32);
|
hash.digest(rv, 0, 32);
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
throw new IllegalStateException(e);
|
throw new IllegalStateException(e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
return rv;
|
||||||
}
|
}
|
||||||
|
|
||||||
private final CipherState cipher;
|
private final CipherState cipher;
|
||||||
@ -78,7 +88,7 @@ class SymmetricState implements Destroyable {
|
|||||||
* @throws NoSuchAlgorithmException The cipher or hash algorithm in the
|
* @throws NoSuchAlgorithmException The cipher or hash algorithm in the
|
||||||
* protocol name is not supported.
|
* protocol name is not supported.
|
||||||
*/
|
*/
|
||||||
public SymmetricState(String cipherName, String hashName) throws NoSuchAlgorithmException
|
public SymmetricState(String cipherName, String hashName, String patternId) throws NoSuchAlgorithmException
|
||||||
{
|
{
|
||||||
cipher = Noise.createCipher(cipherName);
|
cipher = Noise.createCipher(cipherName);
|
||||||
hash = Noise.createHash(hashName);
|
hash = Noise.createHash(hashName);
|
||||||
@ -87,10 +97,29 @@ class SymmetricState implements Destroyable {
|
|||||||
h = new byte [hashLength];
|
h = new byte [hashLength];
|
||||||
prev_h = new byte [hashLength];
|
prev_h = new byte [hashLength];
|
||||||
|
|
||||||
System.arraycopy(INIT_HASH, 0, h, 0, hashLength);
|
byte[] initHash;
|
||||||
|
if (patternId.equals(HandshakeState.PATTERN_ID_XK))
|
||||||
|
initHash = INIT_HASH_XK;
|
||||||
|
else if (patternId.equals(HandshakeState.PATTERN_ID_IK))
|
||||||
|
initHash = INIT_HASH_IK;
|
||||||
|
else
|
||||||
|
throw new IllegalArgumentException("Handshake pattern is not recognized");
|
||||||
|
System.arraycopy(initHash, 0, h, 0, hashLength);
|
||||||
System.arraycopy(h, 0, ck, 0, hashLength);
|
System.arraycopy(h, 0, ck, 0, hashLength);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Copy constructor for cloning
|
||||||
|
* @since 0.9.44
|
||||||
|
*/
|
||||||
|
protected SymmetricState(SymmetricState o) throws CloneNotSupportedException {
|
||||||
|
cipher = o.cipher.clone();
|
||||||
|
hash = (MessageDigest) o.hash.clone();
|
||||||
|
ck = Arrays.copyOf(o.ck, o.ck.length);
|
||||||
|
h = Arrays.copyOf(o.h, o.h.length);
|
||||||
|
prev_h = Arrays.copyOf(o.prev_h, o.prev_h.length);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the name of the Noise protocol.
|
* Gets the name of the Noise protocol.
|
||||||
*
|
*
|
||||||
@ -482,6 +511,15 @@ class SymmetricState implements Destroyable {
|
|||||||
return rv;
|
return rv;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* I2P
|
||||||
|
* @since 0.9.44
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public SymmetricState clone() throws CloneNotSupportedException {
|
||||||
|
return new SymmetricState(this);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* I2P debug
|
* I2P debug
|
||||||
*/
|
*/
|
||||||
|
@ -4,6 +4,7 @@ import java.util.concurrent.LinkedBlockingQueue;
|
|||||||
|
|
||||||
import net.i2p.I2PAppContext;
|
import net.i2p.I2PAppContext;
|
||||||
import net.i2p.crypto.EncType;
|
import net.i2p.crypto.EncType;
|
||||||
|
import net.i2p.crypto.KeyFactory;
|
||||||
import net.i2p.crypto.KeyPair;
|
import net.i2p.crypto.KeyPair;
|
||||||
import net.i2p.data.PrivateKey;
|
import net.i2p.data.PrivateKey;
|
||||||
import net.i2p.data.PublicKey;
|
import net.i2p.data.PublicKey;
|
||||||
@ -19,7 +20,7 @@ import net.i2p.util.SystemVersion;
|
|||||||
*
|
*
|
||||||
* @since 0.9.36 from DHSessionKeyFactory.PrecalcRunner
|
* @since 0.9.36 from DHSessionKeyFactory.PrecalcRunner
|
||||||
*/
|
*/
|
||||||
public class X25519KeyFactory extends I2PThread {
|
public class X25519KeyFactory extends I2PThread implements KeyFactory {
|
||||||
|
|
||||||
private final I2PAppContext _context;
|
private final I2PAppContext _context;
|
||||||
private final Log _log;
|
private final Log _log;
|
||||||
|
@ -682,7 +682,7 @@ class InboundEstablishState extends EstablishBase implements NTCP2Payload.Payloa
|
|||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
_handshakeState = new HandshakeState(HandshakeState.RESPONDER, _transport.getXDHFactory());
|
_handshakeState = new HandshakeState(HandshakeState.PATTERN_ID_XK, HandshakeState.RESPONDER, _transport.getXDHFactory());
|
||||||
} catch (GeneralSecurityException gse) {
|
} catch (GeneralSecurityException gse) {
|
||||||
throw new IllegalStateException("bad proto", gse);
|
throw new IllegalStateException("bad proto", gse);
|
||||||
}
|
}
|
||||||
|
@ -106,7 +106,7 @@ class OutboundNTCP2State implements EstablishState {
|
|||||||
_state = State.OB_INIT;
|
_state = State.OB_INIT;
|
||||||
_tmp = new byte[TOTAL1_MAX];
|
_tmp = new byte[TOTAL1_MAX];
|
||||||
try {
|
try {
|
||||||
_handshakeState = new HandshakeState(HandshakeState.INITIATOR, _transport.getXDHFactory());
|
_handshakeState = new HandshakeState(HandshakeState.PATTERN_ID_XK, HandshakeState.INITIATOR, _transport.getXDHFactory());
|
||||||
} catch (GeneralSecurityException gse) {
|
} catch (GeneralSecurityException gse) {
|
||||||
throw new IllegalStateException("bad proto", gse);
|
throw new IllegalStateException("bad proto", gse);
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user