forked from I2P_Developers/i2p.i2p
NTCP2: Noise library changes:
Use key factory for key pair generation Hardcode Noise name and compute first hash in advance Expose mixHash method so we can process message 1 and 2 padding Add method to get chaining key and hash for siphash key generation Remove unused patterns, methods, code Debug and speed test code Finals
This commit is contained in:
@@ -40,22 +40,22 @@ public final class Curve25519 {
|
||||
// Numbers modulo 2^255 - 19 are broken up into ten 26-bit words.
|
||||
private static final int NUM_LIMBS_255BIT = 10;
|
||||
private static final int NUM_LIMBS_510BIT = 20;
|
||||
private int[] x_1;
|
||||
private int[] x_2;
|
||||
private int[] x_3;
|
||||
private int[] z_2;
|
||||
private int[] z_3;
|
||||
private int[] A;
|
||||
private int[] B;
|
||||
private int[] C;
|
||||
private int[] D;
|
||||
private int[] E;
|
||||
private int[] AA;
|
||||
private int[] BB;
|
||||
private int[] DA;
|
||||
private int[] CB;
|
||||
private long[] t1;
|
||||
private int[] t2;
|
||||
private final int[] x_1;
|
||||
private final int[] x_2;
|
||||
private final int[] x_3;
|
||||
private final int[] z_2;
|
||||
private final int[] z_3;
|
||||
private final int[] A;
|
||||
private final int[] B;
|
||||
private final int[] C;
|
||||
private final int[] D;
|
||||
private final int[] E;
|
||||
private final int[] AA;
|
||||
private final int[] BB;
|
||||
private final int[] DA;
|
||||
private final int[] CB;
|
||||
private final long[] t1;
|
||||
private final int[] t2;
|
||||
|
||||
/**
|
||||
* Constructs the temporary state holder for Curve25519 evaluation.
|
||||
@@ -188,7 +188,7 @@ public final class Curve25519 {
|
||||
}
|
||||
|
||||
// At this point "x" will either be the answer or it will be the
|
||||
// answer plus (2^255 - 19). Perform a trial subtraction to
|
||||
// answer plus (2^255 - 19). Perform a trial subtraction to
|
||||
// complete the reduction process.
|
||||
reduceQuick(result);
|
||||
}
|
||||
|
||||
@@ -32,12 +32,12 @@ import com.southernstorm.noise.protocol.Destroyable;
|
||||
public final class Poly1305 implements Destroyable {
|
||||
|
||||
// The 130-bit intermediate values are broken up into five 26-bit words.
|
||||
private byte[] nonce;
|
||||
private byte[] block;
|
||||
private int[] h;
|
||||
private int[] r;
|
||||
private int[] c;
|
||||
private long[] t;
|
||||
private final byte[] nonce;
|
||||
private final byte[] block;
|
||||
private final int[] h;
|
||||
private final int[] r;
|
||||
private final int[] c;
|
||||
private final long[] t;
|
||||
private int posn;
|
||||
|
||||
/**
|
||||
@@ -319,9 +319,9 @@ public final class Poly1305 implements Destroyable {
|
||||
public void destroy() {
|
||||
Arrays.fill(nonce, (byte)0);
|
||||
Arrays.fill(block, (byte)0);
|
||||
Arrays.fill(h, (int)0);
|
||||
Arrays.fill(r, (int)0);
|
||||
Arrays.fill(c, (int)0);
|
||||
Arrays.fill(h, 0);
|
||||
Arrays.fill(r, 0);
|
||||
Arrays.fill(c, 0);
|
||||
Arrays.fill(t, (long)0);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -33,14 +33,16 @@ import com.southernstorm.noise.crypto.Poly1305;
|
||||
/**
|
||||
* Implements the ChaChaPoly cipher for Noise.
|
||||
*/
|
||||
class ChaChaPolyCipherState implements CipherState {
|
||||
public class ChaChaPolyCipherState implements CipherState {
|
||||
|
||||
private Poly1305 poly;
|
||||
private int[] input;
|
||||
private int[] output;
|
||||
private byte[] polyKey;
|
||||
long n;
|
||||
private final Poly1305 poly;
|
||||
private final int[] input;
|
||||
private final int[] output;
|
||||
private final byte[] polyKey;
|
||||
private long n;
|
||||
private boolean haskey;
|
||||
// I2P debug to be removed
|
||||
private byte[] initialKey;
|
||||
|
||||
/**
|
||||
* Constructs a new cipher state for the "ChaChaPoly" algorithm.
|
||||
@@ -80,6 +82,9 @@ class ChaChaPolyCipherState implements CipherState {
|
||||
|
||||
@Override
|
||||
public void initializeKey(byte[] key, int offset) {
|
||||
// I2P debug to be removed
|
||||
initialKey = new byte[32];
|
||||
System.arraycopy(key, 0, initialKey, 0, 32);
|
||||
ChaChaCore.initKey256(input, key, offset);
|
||||
n = 0;
|
||||
haskey = true;
|
||||
@@ -287,4 +292,39 @@ class ChaChaPolyCipherState implements CipherState {
|
||||
public void setNonce(long nonce) {
|
||||
n = nonce;
|
||||
}
|
||||
|
||||
/**
|
||||
* I2P debug to be removed
|
||||
* @return null if none yet
|
||||
*/
|
||||
public byte[] getKey() {
|
||||
if (!haskey)
|
||||
return null;
|
||||
return initialKey;
|
||||
}
|
||||
|
||||
/**
|
||||
* I2P debug
|
||||
*/
|
||||
@Override
|
||||
public String toString() {
|
||||
StringBuilder buf = new StringBuilder();
|
||||
buf.append(" Cipher State:\n" +
|
||||
" nonce: ");
|
||||
buf.append(n);
|
||||
buf.append("\n" +
|
||||
" init key: ");
|
||||
// I2P debug to be removed
|
||||
if (haskey)
|
||||
buf.append(net.i2p.data.Base64.encode(initialKey));
|
||||
else
|
||||
buf.append("null");
|
||||
buf.append("\n poly key: ");
|
||||
if (haskey)
|
||||
buf.append(net.i2p.data.Base64.encode(polyKey));
|
||||
else
|
||||
buf.append("null");
|
||||
buf.append('\n');
|
||||
return buf.toString();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -155,4 +155,9 @@ public interface CipherState extends Destroyable {
|
||||
* value goes backwards then security may be compromised.
|
||||
*/
|
||||
void setNonce(long nonce);
|
||||
|
||||
/**
|
||||
* I2P debug to be removed
|
||||
*/
|
||||
public byte[] getKey();
|
||||
}
|
||||
|
||||
@@ -69,10 +69,7 @@ public final class CipherStatePair implements Destroyable {
|
||||
*/
|
||||
public void senderOnly()
|
||||
{
|
||||
if (recv != null) {
|
||||
recv.destroy();
|
||||
recv = null;
|
||||
}
|
||||
recv.destroy();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -82,10 +79,7 @@ public final class CipherStatePair implements Destroyable {
|
||||
*/
|
||||
public void receiverOnly()
|
||||
{
|
||||
if (send != null) {
|
||||
send.destroy();
|
||||
send = null;
|
||||
}
|
||||
send.destroy();
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -22,27 +22,32 @@
|
||||
|
||||
package com.southernstorm.noise.protocol;
|
||||
|
||||
import java.security.KeyPair;
|
||||
import java.util.Arrays;
|
||||
|
||||
import com.southernstorm.noise.crypto.Curve25519;
|
||||
|
||||
import net.i2p.router.transport.crypto.X25519KeyFactory;
|
||||
|
||||
/**
|
||||
* Implementation of the Curve25519 algorithm for the Noise protocol.
|
||||
*/
|
||||
class Curve25519DHState implements DHState {
|
||||
|
||||
private byte[] publicKey;
|
||||
private byte[] privateKey;
|
||||
private final byte[] publicKey;
|
||||
private final byte[] privateKey;
|
||||
private int mode;
|
||||
private final X25519KeyFactory _xdh;
|
||||
|
||||
/**
|
||||
* Constructs a new Diffie-Hellman object for Curve25519.
|
||||
*/
|
||||
public Curve25519DHState()
|
||||
public Curve25519DHState(X25519KeyFactory xdh)
|
||||
{
|
||||
publicKey = new byte [32];
|
||||
privateKey = new byte [32];
|
||||
mode = 0;
|
||||
_xdh = xdh;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -72,8 +77,9 @@ class Curve25519DHState implements DHState {
|
||||
|
||||
@Override
|
||||
public void generateKeyPair() {
|
||||
Noise.random(privateKey);
|
||||
Curve25519.eval(publicKey, 0, privateKey, null);
|
||||
KeyPair kp = _xdh.getKeys();
|
||||
System.arraycopy(kp.getPrivate().getEncoded(), 0, privateKey, 0, 32);
|
||||
System.arraycopy(kp.getPublic().getEncoded(), 0, publicKey, 0, 32);
|
||||
mode = 0x03;
|
||||
}
|
||||
|
||||
|
||||
@@ -28,13 +28,15 @@ import java.util.Arrays;
|
||||
import javax.crypto.BadPaddingException;
|
||||
import javax.crypto.ShortBufferException;
|
||||
|
||||
import net.i2p.router.transport.crypto.X25519KeyFactory;
|
||||
|
||||
/**
|
||||
* Interface to a Noise handshake.
|
||||
*/
|
||||
public class HandshakeState implements Destroyable {
|
||||
|
||||
private SymmetricState symmetric;
|
||||
private boolean isInitiator;
|
||||
private final SymmetricState symmetric;
|
||||
private final boolean isInitiator;
|
||||
private DHState localKeyPair;
|
||||
private DHState localEphemeral;
|
||||
private DHState localHybrid;
|
||||
@@ -44,11 +46,12 @@ public class HandshakeState implements Destroyable {
|
||||
private DHState fixedEphemeral;
|
||||
private DHState fixedHybrid;
|
||||
private int action;
|
||||
private int requirements;
|
||||
private short[] pattern;
|
||||
private final int requirements;
|
||||
private int patternIndex;
|
||||
private byte[] preSharedKey;
|
||||
private byte[] prologue;
|
||||
// not supported
|
||||
private static final byte[] preSharedKey = null;
|
||||
// not supported
|
||||
private static final byte[] prologue = null;
|
||||
|
||||
/**
|
||||
* Enumerated value that indicates that the handshake object
|
||||
@@ -132,11 +135,39 @@ public class HandshakeState implements Destroyable {
|
||||
*/
|
||||
private static final int FALLBACK_POSSIBLE = 0x40;
|
||||
|
||||
public static final String protocolName = "Noise_XKaesobfse+hs2+hs3_25519_ChaChaPoly_SHA256";
|
||||
private static final String prefix;
|
||||
private static final String patternId;
|
||||
private static String dh;
|
||||
private static final String cipher;
|
||||
private static final String hash;
|
||||
private static final short[] pattern;
|
||||
|
||||
static {
|
||||
// Parse the protocol name into its components.
|
||||
String[] components = protocolName.split("_");
|
||||
if (components.length != 5)
|
||||
throw new IllegalArgumentException("Protocol name must have 5 components");
|
||||
prefix = components[0];
|
||||
patternId = components[1].substring(0, 2);
|
||||
dh = components[2];
|
||||
cipher = components[3];
|
||||
hash = components[4];
|
||||
if (!prefix.equals("Noise") && !prefix.equals("NoisePSK"))
|
||||
throw new IllegalArgumentException("Prefix must be Noise or NoisePSK");
|
||||
pattern = Pattern.lookup(patternId);
|
||||
if (pattern == null)
|
||||
throw new IllegalArgumentException("Handshake pattern is not recognized");
|
||||
if (!dh.equals("25519"))
|
||||
throw new IllegalArgumentException("Unknown Noise DH algorithm name: " + dh);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new Noise handshake.
|
||||
* Noise protocol name is hardcoded.
|
||||
*
|
||||
* @param protocolName The name of the Noise protocol.
|
||||
* @param role The role, HandshakeState.INITIATOR or HandshakeState.RESPONDER.
|
||||
* @param xdh The key pair factory for ephemeral keys
|
||||
*
|
||||
* @throws IllegalArgumentException The protocolName is not
|
||||
* formatted correctly, or the role is not recognized.
|
||||
@@ -144,23 +175,8 @@ public class HandshakeState implements Destroyable {
|
||||
* @throws NoSuchAlgorithmException One of the cryptographic algorithms
|
||||
* that is specified in the protocolName is not supported.
|
||||
*/
|
||||
public HandshakeState(String protocolName, int role) throws NoSuchAlgorithmException
|
||||
public HandshakeState(int role, X25519KeyFactory xdh) throws NoSuchAlgorithmException
|
||||
{
|
||||
// Parse the protocol name into its components.
|
||||
String[] components = protocolName.split("_");
|
||||
if (components.length != 5)
|
||||
throw new IllegalArgumentException("Protocol name must have 5 components");
|
||||
String prefix = components[0];
|
||||
String patternId = components[1];
|
||||
String dh = components[2];
|
||||
String hybrid = null;
|
||||
String cipher = components[3];
|
||||
String hash = components[4];
|
||||
if (!prefix.equals("Noise") && !prefix.equals("NoisePSK"))
|
||||
throw new IllegalArgumentException("Prefix must be Noise or NoisePSK");
|
||||
pattern = Pattern.lookup(patternId);
|
||||
if (pattern == null)
|
||||
throw new IllegalArgumentException("Handshake pattern is not recognized");
|
||||
short flags = pattern[0];
|
||||
int extraReqs = 0;
|
||||
if ((flags & Pattern.FLAG_REMOTE_REQUIRED) != 0 && patternId.length() > 1)
|
||||
@@ -169,24 +185,13 @@ public class HandshakeState implements Destroyable {
|
||||
// Reverse the pattern flags so that the responder is "local".
|
||||
flags = Pattern.reverseFlags(flags);
|
||||
}
|
||||
int index = dh.indexOf('+');
|
||||
if (index != -1) {
|
||||
// The DH name has two components: regular and hybrid.
|
||||
hybrid = dh.substring(index + 1);
|
||||
dh = dh.substring(0, index);
|
||||
if ((flags & Pattern.FLAG_LOCAL_HYBRID) == 0 || (flags & Pattern.FLAG_REMOTE_HYBRID) == 0)
|
||||
throw new IllegalArgumentException("Hybrid function specified for non-hybrid pattern");
|
||||
} else {
|
||||
if ((flags & Pattern.FLAG_LOCAL_HYBRID) != 0 || (flags & Pattern.FLAG_REMOTE_HYBRID) != 0)
|
||||
throw new IllegalArgumentException("Hybrid function not specified for hybrid pattern");
|
||||
}
|
||||
|
||||
// Check that the role is correctly specified.
|
||||
if (role != INITIATOR && role != RESPONDER)
|
||||
throw new IllegalArgumentException("Role must be initiator or responder");
|
||||
|
||||
// Initialize this object. This will also create the cipher and hash objects.
|
||||
symmetric = new SymmetricState(protocolName, cipher, hash);
|
||||
symmetric = new SymmetricState(cipher, hash);
|
||||
isInitiator = (role == INITIATOR);
|
||||
action = NO_ACTION;
|
||||
requirements = extraReqs | computeRequirements(flags, prefix, role, false);
|
||||
@@ -194,28 +199,14 @@ public class HandshakeState implements Destroyable {
|
||||
|
||||
// Create the DH objects that we will need later.
|
||||
if ((flags & Pattern.FLAG_LOCAL_STATIC) != 0)
|
||||
localKeyPair = Noise.createDH(dh);
|
||||
localKeyPair = new Curve25519DHState(xdh);
|
||||
if ((flags & Pattern.FLAG_LOCAL_EPHEMERAL) != 0)
|
||||
localEphemeral = Noise.createDH(dh);
|
||||
if ((flags & Pattern.FLAG_LOCAL_HYBRID) != 0)
|
||||
localHybrid = Noise.createDH(hybrid);
|
||||
localEphemeral = new Curve25519DHState(xdh);
|
||||
if ((flags & Pattern.FLAG_REMOTE_STATIC) != 0)
|
||||
remotePublicKey = Noise.createDH(dh);
|
||||
remotePublicKey = new Curve25519DHState(xdh);
|
||||
if ((flags & Pattern.FLAG_REMOTE_EPHEMERAL) != 0)
|
||||
remoteEphemeral = Noise.createDH(dh);
|
||||
if ((flags & Pattern.FLAG_REMOTE_HYBRID) != 0)
|
||||
remoteHybrid = Noise.createDH(hybrid);
|
||||
remoteEphemeral = new Curve25519DHState(xdh);
|
||||
|
||||
// We cannot use hybrid algorithms like New Hope for ephemeral or static keys,
|
||||
// as the unbalanced nature of the algorithm only works with "f" and "ff" tokens.
|
||||
if (localKeyPair instanceof DHStateHybrid)
|
||||
throw new NoSuchAlgorithmException("Cannot use '" + localKeyPair.getDHName() + "' for static keys");
|
||||
if (localEphemeral instanceof DHStateHybrid)
|
||||
throw new NoSuchAlgorithmException("Cannot use '" + localEphemeral.getDHName() + "' for ephemeral keys");
|
||||
if (remotePublicKey instanceof DHStateHybrid)
|
||||
throw new NoSuchAlgorithmException("Cannot use '" + remotePublicKey.getDHName() + "' for static keys");
|
||||
if (remoteEphemeral instanceof DHStateHybrid)
|
||||
throw new NoSuchAlgorithmException("Cannot use '" + remoteEphemeral.getDHName() + "' for ephemeral keys");
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -237,91 +228,6 @@ public class HandshakeState implements Destroyable {
|
||||
{
|
||||
return isInitiator ? INITIATOR : RESPONDER;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine if this handshake needs a pre-shared key value
|
||||
* and one has not been configured yet.
|
||||
*
|
||||
* @return true if a pre-shared key is needed; false if not.
|
||||
*/
|
||||
public boolean needsPreSharedKey()
|
||||
{
|
||||
if (preSharedKey != null)
|
||||
return false;
|
||||
else
|
||||
return (requirements & PSK_REQUIRED) != 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine if this object has already been configured with a
|
||||
* pre-shared key.
|
||||
*
|
||||
* @return true if the pre-shared key has already been configured;
|
||||
* false if one is not needed or it has not been configured yet.
|
||||
*/
|
||||
public boolean hasPreSharedKey()
|
||||
{
|
||||
return preSharedKey != null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the pre-shared key for this handshake.
|
||||
*
|
||||
* @param key Buffer containing the pre-shared key value.
|
||||
* @param offset Offset into the buffer of the first byte of the key.
|
||||
* @param length The length of the pre-shared key, which must be 32.
|
||||
*
|
||||
* @throws IllegalArgumentException The length is not 32.
|
||||
*
|
||||
* @throws UnsupportedOperationException Pre-shared keys are not
|
||||
* supported for this handshake type.
|
||||
*
|
||||
* @throws IllegalStateException The handshake has already started,
|
||||
* so the pre-shared key can no longer be set.
|
||||
*/
|
||||
public void setPreSharedKey(byte[] key, int offset, int length)
|
||||
{
|
||||
if (length != 32) {
|
||||
throw new IllegalArgumentException
|
||||
("Pre-shared keys must be 32 bytes in length");
|
||||
}
|
||||
if ((requirements & PSK_REQUIRED) == 0) {
|
||||
throw new UnsupportedOperationException
|
||||
("Pre-shared keys are not supported for this handshake");
|
||||
}
|
||||
if (action != NO_ACTION) {
|
||||
throw new IllegalStateException
|
||||
("Handshake has already started; cannot set pre-shared key");
|
||||
}
|
||||
if (preSharedKey != null) {
|
||||
Noise.destroy(preSharedKey);
|
||||
preSharedKey = null;
|
||||
}
|
||||
preSharedKey = Noise.copySubArray(key, offset, length);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the prologue for this handshake.
|
||||
*
|
||||
* @param prologue Buffer containing the prologue value.
|
||||
* @param offset Offset into the buffer of the first byte of the prologue.
|
||||
* @param length The length of the prologue in bytes.
|
||||
*
|
||||
* @throws IllegalStateException The handshake has already started,
|
||||
* so the prologue can no longer be set.
|
||||
*/
|
||||
public void setPrologue(byte[] prologue, int offset, int length)
|
||||
{
|
||||
if (action != NO_ACTION) {
|
||||
throw new IllegalStateException
|
||||
("Handshake has already started; cannot set prologue");
|
||||
}
|
||||
if (this.prologue != null) {
|
||||
Noise.destroy(this.prologue);
|
||||
this.prologue = null;
|
||||
}
|
||||
this.prologue = Noise.copySubArray(prologue, offset, length);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the keypair object for the local static key.
|
||||
@@ -406,60 +312,6 @@ public class HandshakeState implements Destroyable {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the DHState object containing a fixed local ephemeral
|
||||
* key value for this handshake.
|
||||
*
|
||||
* @return The fixed ephemeral key object, or null if a local
|
||||
* ephemeral key is not required by this handshake.
|
||||
*
|
||||
* This function is intended for testing only. It can be used
|
||||
* to establish a fixed ephemeral key for test vectors. This
|
||||
* function should not be used in real applications.
|
||||
*/
|
||||
public DHState getFixedEphemeralKey()
|
||||
{
|
||||
if (fixedEphemeral != null)
|
||||
return fixedEphemeral;
|
||||
if (localEphemeral == null)
|
||||
return null;
|
||||
try {
|
||||
fixedEphemeral = Noise.createDH(localEphemeral.getDHName());
|
||||
} catch (NoSuchAlgorithmException e) {
|
||||
// This shouldn't happen - the local ephemeral key would
|
||||
// have already been created with the same name!
|
||||
fixedEphemeral = null;
|
||||
}
|
||||
return fixedEphemeral;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the DHState object containing a fixed local hybrid
|
||||
* key value for this handshake.
|
||||
*
|
||||
* @return The fixed hybrid key object, or null if a local
|
||||
* hybrid key is not required by this handshake.
|
||||
*
|
||||
* This function is intended for testing only. It can be used
|
||||
* to establish a fixed hybrid key for test vectors. This
|
||||
* function should not be used in real applications.
|
||||
*/
|
||||
public DHState getFixedHybridKey()
|
||||
{
|
||||
if (fixedHybrid != null)
|
||||
return fixedHybrid;
|
||||
if (localHybrid == null)
|
||||
return null;
|
||||
try {
|
||||
fixedHybrid = Noise.createDH(localHybrid.getDHName());
|
||||
} catch (NoSuchAlgorithmException e) {
|
||||
// This shouldn't happen - the local hybrid key would
|
||||
// have already been created with the same name!
|
||||
fixedHybrid = null;
|
||||
}
|
||||
return fixedHybrid;
|
||||
}
|
||||
|
||||
// Empty value for when the prologue is not supplied.
|
||||
private static final byte[] emptyPrologue = new byte [0];
|
||||
|
||||
@@ -481,7 +333,7 @@ public class HandshakeState implements Destroyable {
|
||||
* @see #getAction()
|
||||
* @see #writeMessage(byte[], int, byte[], int, int)
|
||||
* @see #readMessage(byte[], int, int, byte[], int)
|
||||
* @see #fallback()
|
||||
* see #fallback()
|
||||
*/
|
||||
public void start()
|
||||
{
|
||||
@@ -504,10 +356,6 @@ public class HandshakeState implements Destroyable {
|
||||
if (remotePublicKey == null || !remotePublicKey.hasPublicKey())
|
||||
throw new IllegalStateException("Remote static key required");
|
||||
}
|
||||
if ((requirements & PSK_REQUIRED) != 0) {
|
||||
if (preSharedKey == null)
|
||||
throw new IllegalStateException("Pre-shared key required");
|
||||
}
|
||||
|
||||
// Hash the prologue value.
|
||||
if (prologue != null)
|
||||
@@ -515,10 +363,6 @@ public class HandshakeState implements Destroyable {
|
||||
else
|
||||
symmetric.mixHash(emptyPrologue, 0, 0);
|
||||
|
||||
// Hash the pre-shared key into the chaining key and handshake hash.
|
||||
if (preSharedKey != null)
|
||||
symmetric.mixPreSharedKey(preSharedKey);
|
||||
|
||||
// Mix the pre-supplied public keys into the handshake hash.
|
||||
if (isInitiator) {
|
||||
if ((requirements & LOCAL_PREMSG) != 0)
|
||||
@@ -553,151 +397,6 @@ public class HandshakeState implements Destroyable {
|
||||
action = READ_MESSAGE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Falls back to the "XXfallback" handshake pattern.
|
||||
*
|
||||
* This function is intended used to help implement the "Noise Pipes" protocol.
|
||||
* It resets a HandshakeState object with the original handshake pattern
|
||||
* (usually "IK"), converting it into an object with the handshake pattern
|
||||
* "XXfallback". Information from the previous session such as the local
|
||||
* keypair, the initiator's ephemeral key, the prologue value, and the
|
||||
* pre-shared key, are passed to the new session.
|
||||
*
|
||||
* Once the fallback has been initiated, the application can set
|
||||
* new values for the handshake parameters if the values from the
|
||||
* previous session do not apply. For example, the application may
|
||||
* use a different prologue for the fallback than for the original
|
||||
* session.
|
||||
*
|
||||
* After setting any new parameters, the application calls start()
|
||||
* again to restart the handshake from where it left off before the fallback.
|
||||
*
|
||||
* Note that this function reverses the roles of initiator and responder.
|
||||
*
|
||||
* @throws UnsupportedOperationException The current handshake pattern
|
||||
* is not compatible with "XXfallback".
|
||||
*
|
||||
* @throws IllegalStateException The previous protocol has not started
|
||||
* or it has not reached the fallback position yet.
|
||||
*
|
||||
* @throws NoSuchAlgorithmException One of the cryptographic algorithms
|
||||
* that is specified in the new protocolName is not supported.
|
||||
*
|
||||
* @see #start()
|
||||
*/
|
||||
public void fallback() throws NoSuchAlgorithmException
|
||||
{
|
||||
fallback("XXfallback");
|
||||
}
|
||||
|
||||
/**
|
||||
* Falls back to another handshake pattern.
|
||||
*
|
||||
* @param patternName The name of the pattern to fall back to;
|
||||
* e.g. "XXfallback", "NXfallback", etc.
|
||||
*
|
||||
* This function resets a HandshakeState object with the original
|
||||
* handshake pattern, and converts it into an object with the new handshake
|
||||
* patternName. Information from the previous session such as the local
|
||||
* keypair, the initiator's ephemeral key, the prologue value, and the
|
||||
* pre-shared key, are passed to the new session.
|
||||
*
|
||||
* Once the fallback has been initiated, the application can set
|
||||
* new values for the handshake parameters if the values from the
|
||||
* previous session do not apply. For example, the application may
|
||||
* use a different prologue for the fallback than for the original
|
||||
* session.
|
||||
*
|
||||
* After setting any new parameters, the application calls start()
|
||||
* again to restart the handshake from where it left off before the fallback.
|
||||
*
|
||||
* The new pattern may have greater key requirements than the original;
|
||||
* for example changing from "NK" from "XXfallback" requires that the
|
||||
* initiator's static public key be set. The application is responsible for
|
||||
* setting any extra keys before calling start().
|
||||
*
|
||||
* Note that this function reverses the roles of initiator and responder.
|
||||
*
|
||||
* @throws UnsupportedOperationException The current handshake pattern
|
||||
* is not compatible with the patternName, or patternName is not a
|
||||
* fallback pattern.
|
||||
*
|
||||
* @throws IllegalStateException The previous protocol has not started
|
||||
* or it has not reached the fallback position yet.
|
||||
*
|
||||
* @throws NoSuchAlgorithmException One of the cryptographic algorithms
|
||||
* that is specified in the new protocolName is not supported.
|
||||
*
|
||||
* @see #start()
|
||||
*/
|
||||
public void fallback(String patternName) throws NoSuchAlgorithmException
|
||||
{
|
||||
// The original pattern must end in "K" for fallback to be possible.
|
||||
if ((requirements & FALLBACK_POSSIBLE) == 0)
|
||||
throw new UnsupportedOperationException("Previous handshake pattern does not support fallback");
|
||||
|
||||
// Check that "patternName" supports fallback.
|
||||
short[] newPattern = Pattern.lookup(patternName);
|
||||
if (newPattern == null || (newPattern[0] & Pattern.FLAG_REMOTE_EPHEM_REQ) == 0)
|
||||
throw new UnsupportedOperationException("New pattern is not a fallback pattern");
|
||||
|
||||
// The initiator should be waiting for a return message from the
|
||||
// responder, and the responder should have failed on the first
|
||||
// handshake message from the initiator. We also allow the
|
||||
// responder to fallback after processing the first message
|
||||
// successfully; it decides to always fall back anyway.
|
||||
if (isInitiator) {
|
||||
if ((action != FAILED && action != READ_MESSAGE) || !localEphemeral.hasPublicKey())
|
||||
throw new IllegalStateException("Initiator cannot fall back from this state");
|
||||
} else {
|
||||
if ((action != FAILED && action != WRITE_MESSAGE) || !remoteEphemeral.hasPublicKey())
|
||||
throw new IllegalStateException("Responder cannot fall back from this state");
|
||||
}
|
||||
|
||||
// Format a new protocol name for the fallback variant
|
||||
// and recreate the SymmetricState object.
|
||||
String[] components = symmetric.getProtocolName().split("_");
|
||||
components[1] = patternName;
|
||||
StringBuilder builder = new StringBuilder();
|
||||
builder.append(components[0]);
|
||||
for (int index = 1; index < components.length; ++index) {
|
||||
builder.append('_');
|
||||
builder.append(components[index]);
|
||||
}
|
||||
String name = builder.toString();
|
||||
SymmetricState newSymmetric = new SymmetricState(name, components[3], components[4]);
|
||||
symmetric.destroy();
|
||||
symmetric = newSymmetric;
|
||||
|
||||
// Convert the HandshakeState to the "XXfallback" pattern.
|
||||
if (isInitiator) {
|
||||
if (remoteEphemeral != null)
|
||||
remoteEphemeral.clearKey();
|
||||
if (remoteHybrid != null)
|
||||
remoteHybrid.clearKey();
|
||||
if (remotePublicKey != null)
|
||||
remotePublicKey.clearKey();
|
||||
isInitiator = false;
|
||||
} else {
|
||||
if (localEphemeral != null)
|
||||
localEphemeral.clearKey();
|
||||
if (localHybrid != null)
|
||||
localHybrid.clearKey();
|
||||
if ((newPattern[0] & Pattern.FLAG_REMOTE_REQUIRED) == 0 && remotePublicKey != null)
|
||||
remotePublicKey.clearKey();
|
||||
isInitiator = true;
|
||||
}
|
||||
action = NO_ACTION;
|
||||
pattern = newPattern;
|
||||
patternIndex = 1;
|
||||
short flags = pattern[0];
|
||||
if (!isInitiator) {
|
||||
// Reverse the pattern flags so that the responder is "local".
|
||||
flags = Pattern.reverseFlags(flags);
|
||||
}
|
||||
requirements = computeRequirements(flags, components[0], isInitiator ? INITIATOR : RESPONDER, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the next action that the application should perform for
|
||||
* the handshake part of the protocol.
|
||||
@@ -795,9 +494,9 @@ public class HandshakeState implements Destroyable {
|
||||
switch (token) {
|
||||
case Pattern.E:
|
||||
{
|
||||
// Generate a local ephemeral keypair and add the public
|
||||
// key to the message. If we are running fixed vector tests,
|
||||
// then the ephemeral key may have already been provided.
|
||||
// Generate a local ephemeral keypair and add the public
|
||||
// key to the message. If we are running fixed vector tests,
|
||||
// then the ephemeral key may have already been provided.
|
||||
if (localEphemeral == null)
|
||||
throw new IllegalStateException("Pattern definition error");
|
||||
if (fixedEphemeral == null)
|
||||
@@ -811,7 +510,7 @@ public class HandshakeState implements Destroyable {
|
||||
symmetric.mixHash(message, messagePosn, len);
|
||||
|
||||
// If the protocol is using pre-shared keys, then also mix
|
||||
// the local ephemeral key into the chaining key.
|
||||
// the local ephemeral key into the chaining key.
|
||||
if (preSharedKey != null)
|
||||
symmetric.mixKey(message, messagePosn, len);
|
||||
messagePosn += len;
|
||||
@@ -820,7 +519,7 @@ public class HandshakeState implements Destroyable {
|
||||
|
||||
case Pattern.S:
|
||||
{
|
||||
// Encrypt the local static public key and add it to the message.
|
||||
// Encrypt the local static public key and add it to the message.
|
||||
if (localKeyPair == null)
|
||||
throw new IllegalStateException("Pattern definition error");
|
||||
len = localKeyPair.getPublicKeyLength();
|
||||
@@ -859,52 +558,6 @@ public class HandshakeState implements Destroyable {
|
||||
}
|
||||
break;
|
||||
|
||||
case Pattern.SS:
|
||||
{
|
||||
// DH operation with initiator and responder static keys.
|
||||
mixDH(localKeyPair, remotePublicKey);
|
||||
}
|
||||
break;
|
||||
|
||||
case Pattern.F:
|
||||
{
|
||||
// Generate a local hybrid keypair and add the public
|
||||
// key to the message. If we are running fixed vector tests,
|
||||
// then a fixed hybrid key may have already been provided.
|
||||
if (localHybrid == null)
|
||||
throw new IllegalStateException("Pattern definition error");
|
||||
if (localHybrid instanceof DHStateHybrid) {
|
||||
// The DH object is something like New Hope which needs to
|
||||
// generate keys relative to the other party's public key.
|
||||
DHStateHybrid hybrid = (DHStateHybrid)localHybrid;
|
||||
if (fixedHybrid == null)
|
||||
hybrid.generateKeyPair(remoteHybrid);
|
||||
else
|
||||
hybrid.copyFrom(fixedHybrid, remoteHybrid);
|
||||
} else {
|
||||
if (fixedHybrid == null)
|
||||
localHybrid.generateKeyPair();
|
||||
else
|
||||
localHybrid.copyFrom(fixedHybrid);
|
||||
}
|
||||
len = localHybrid.getPublicKeyLength();
|
||||
if (space < len)
|
||||
throw new ShortBufferException();
|
||||
macLen = symmetric.getMACLength();
|
||||
if (space < (len + macLen))
|
||||
throw new ShortBufferException();
|
||||
localHybrid.getPublicKey(message, messagePosn);
|
||||
messagePosn += symmetric.encryptAndHash(message, messagePosn, message, messagePosn, len);
|
||||
}
|
||||
break;
|
||||
|
||||
case Pattern.FF:
|
||||
{
|
||||
// DH operation with initiator and responder hybrid keys.
|
||||
mixDH(localHybrid, remoteHybrid);
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
{
|
||||
// Unknown token code. Abort.
|
||||
@@ -993,7 +646,7 @@ public class HandshakeState implements Destroyable {
|
||||
switch (token) {
|
||||
case Pattern.E:
|
||||
{
|
||||
// Save the remote ephemeral key and hash it.
|
||||
// Save the remote ephemeral key and hash it.
|
||||
if (remoteEphemeral == null)
|
||||
throw new IllegalStateException("Pattern definition error");
|
||||
len = remoteEphemeral.getPublicKeyLength();
|
||||
@@ -1002,15 +655,15 @@ public class HandshakeState implements Destroyable {
|
||||
symmetric.mixHash(message, messageOffset, len);
|
||||
remoteEphemeral.setPublicKey(message, messageOffset);
|
||||
if (remoteEphemeral.isNullPublicKey()) {
|
||||
// The remote ephemeral key is null, which means that it is
|
||||
// not contributing anything to the security of the session
|
||||
// and is in fact downgrading the security to "none at all"
|
||||
// in some of the message patterns. Reject all such keys.
|
||||
// The remote ephemeral key is null, which means that it is
|
||||
// not contributing anything to the security of the session
|
||||
// and is in fact downgrading the security to "none at all"
|
||||
// in some of the message patterns. Reject all such keys.
|
||||
throw new BadPaddingException("Null remote public key");
|
||||
}
|
||||
|
||||
// If the protocol is using pre-shared keys, then also mix
|
||||
// the remote ephemeral key into the chaining key.
|
||||
// the remote ephemeral key into the chaining key.
|
||||
if (preSharedKey != null)
|
||||
symmetric.mixKey(message, messageOffset, len);
|
||||
messageOffset += len;
|
||||
@@ -1065,47 +718,6 @@ public class HandshakeState implements Destroyable {
|
||||
}
|
||||
break;
|
||||
|
||||
case Pattern.SS:
|
||||
{
|
||||
// DH operation with initiator and responder static keys.
|
||||
mixDH(localKeyPair, remotePublicKey);
|
||||
}
|
||||
break;
|
||||
|
||||
case Pattern.F:
|
||||
{
|
||||
// Decrypt and read the remote hybrid ephemeral key.
|
||||
if (remoteHybrid == null)
|
||||
throw new IllegalStateException("Pattern definition error");
|
||||
if (remoteHybrid instanceof DHStateHybrid) {
|
||||
// The DH object is something like New Hope. The public key
|
||||
// length may need to change based on whether we already have
|
||||
// generated a local hybrid keypair or not.
|
||||
((DHStateHybrid)remoteHybrid).specifyPeer(localHybrid);
|
||||
}
|
||||
len = remoteHybrid.getPublicKeyLength();
|
||||
macLen = symmetric.getMACLength();
|
||||
if (space < (len + macLen))
|
||||
throw new ShortBufferException();
|
||||
byte[] temp = new byte [len];
|
||||
try {
|
||||
if (symmetric.decryptAndHash(message, messageOffset, temp, 0, len + macLen) != len)
|
||||
throw new ShortBufferException();
|
||||
remoteHybrid.setPublicKey(temp, 0);
|
||||
} finally {
|
||||
Noise.destroy(temp);
|
||||
}
|
||||
messageOffset += len + macLen;
|
||||
}
|
||||
break;
|
||||
|
||||
case Pattern.FF:
|
||||
{
|
||||
// DH operation with initiator and responder hybrid keys.
|
||||
mixDH(localHybrid, remoteHybrid);
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
{
|
||||
// Unknown token code. Abort.
|
||||
@@ -1235,7 +847,7 @@ public class HandshakeState implements Destroyable {
|
||||
*/
|
||||
private static int computeRequirements(short flags, String prefix, int role, boolean isFallback)
|
||||
{
|
||||
int requirements = 0;
|
||||
int requirements = 0;
|
||||
if ((flags & Pattern.FLAG_LOCAL_STATIC) != 0) {
|
||||
requirements |= LOCAL_REQUIRED;
|
||||
}
|
||||
@@ -1252,9 +864,83 @@ public class HandshakeState implements Destroyable {
|
||||
if (isFallback)
|
||||
requirements |= FALLBACK_PREMSG;
|
||||
}
|
||||
if (prefix.equals("NoisePSK")) {
|
||||
requirements |= PSK_REQUIRED;
|
||||
}
|
||||
return requirements;
|
||||
}
|
||||
|
||||
/**
|
||||
* I2P for mixing in padding in messages 1 and 2
|
||||
*/
|
||||
public void mixHash(byte[] data, int offset, int length) {
|
||||
symmetric.mixHash(data, offset, length);
|
||||
}
|
||||
|
||||
/**
|
||||
* I2P for getting chaining key for siphash calc
|
||||
* @return a copy
|
||||
*/
|
||||
public byte[] getChainingKey() {
|
||||
return symmetric.getChainingKey();
|
||||
}
|
||||
|
||||
/**
|
||||
* I2P for getting current hash for siphash calculation
|
||||
* @return NOT a copy, do not modify
|
||||
*/
|
||||
public byte[] getHash() {
|
||||
return symmetric.getHandshakeHash();
|
||||
}
|
||||
|
||||
/**
|
||||
* I2P debug
|
||||
*/
|
||||
@Override
|
||||
public String toString() {
|
||||
StringBuilder buf = new StringBuilder();
|
||||
buf.append("Handshake State:\n");
|
||||
buf.append(symmetric.toString());
|
||||
|
||||
byte[] tmp = new byte[32];
|
||||
|
||||
DHState dh = localKeyPair;
|
||||
buf.append("Local static public key (s) : ");
|
||||
if (dh != null && dh.hasPublicKey()) {
|
||||
dh.getPublicKey(tmp, 0);
|
||||
buf.append(net.i2p.data.Base64.encode(tmp));
|
||||
} else {
|
||||
buf.append("null");
|
||||
}
|
||||
buf.append('\n');
|
||||
|
||||
dh = remotePublicKey;
|
||||
buf.append("Remote static public key (rs) : ");
|
||||
if (dh != null && dh.hasPublicKey()) {
|
||||
dh.getPublicKey(tmp, 0);
|
||||
buf.append(net.i2p.data.Base64.encode(tmp));
|
||||
} else {
|
||||
buf.append("null");
|
||||
}
|
||||
buf.append('\n');
|
||||
|
||||
dh = localEphemeral;
|
||||
buf.append("Local ephemeral public key (e) : ");
|
||||
if (dh != null && dh.hasPublicKey()) {
|
||||
dh.getPublicKey(tmp, 0);
|
||||
buf.append(net.i2p.data.Base64.encode(tmp));
|
||||
} else {
|
||||
buf.append("null");
|
||||
}
|
||||
buf.append('\n');
|
||||
|
||||
dh = remoteEphemeral;
|
||||
buf.append("Remote ephemeral public key (re) : ");
|
||||
if (dh != null && dh.hasPublicKey()) {
|
||||
dh.getPublicKey(tmp, 0);
|
||||
buf.append(net.i2p.data.Base64.encode(tmp));
|
||||
} else {
|
||||
buf.append("null");
|
||||
}
|
||||
buf.append('\n');
|
||||
|
||||
return buf.toString();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -29,11 +29,6 @@ import java.util.Arrays;
|
||||
|
||||
import javax.crypto.BadPaddingException;
|
||||
|
||||
import com.southernstorm.noise.crypto.Blake2bMessageDigest;
|
||||
import com.southernstorm.noise.crypto.Blake2sMessageDigest;
|
||||
import com.southernstorm.noise.crypto.SHA256MessageDigest;
|
||||
import com.southernstorm.noise.crypto.SHA512MessageDigest;
|
||||
|
||||
/**
|
||||
* Utility functions for the Noise protocol library.
|
||||
*/
|
||||
@@ -44,57 +39,6 @@ public final class Noise {
|
||||
*/
|
||||
public static final int MAX_PACKET_LEN = 65535;
|
||||
|
||||
private static SecureRandom random = new SecureRandom();
|
||||
|
||||
/**
|
||||
* Generates random data using the system random number generator.
|
||||
*
|
||||
* @param data The data buffer to fill with random data.
|
||||
*/
|
||||
public static void random(byte[] data)
|
||||
{
|
||||
random.nextBytes(data);
|
||||
}
|
||||
|
||||
private static boolean forceFallbacks = false;
|
||||
|
||||
/**
|
||||
* Force the use of plain Java fallback crypto implementations.
|
||||
*
|
||||
* @param force Set to true for force fallbacks, false to
|
||||
* try to use the system implementation before falling back.
|
||||
*
|
||||
* This function is intended for testing purposes to toggle between
|
||||
* the system JCA/JCE implementations and the plain Java fallback
|
||||
* reference implementations.
|
||||
*/
|
||||
public static void setForceFallbacks(boolean force)
|
||||
{
|
||||
forceFallbacks = force;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a Diffie-Hellman object from its Noise protocol name.
|
||||
*
|
||||
* @param name The name of the DH algorithm; e.g. "25519", "448", etc.
|
||||
*
|
||||
* @return The Diffie-Hellman object if the name is recognized.
|
||||
*
|
||||
* @throws NoSuchAlgorithmException The name is not recognized as a
|
||||
* valid Noise protocol name, or there is no cryptography provider
|
||||
* in the system that implements the algorithm.
|
||||
*/
|
||||
public static DHState createDH(String name) throws NoSuchAlgorithmException
|
||||
{
|
||||
if (name.equals("25519"))
|
||||
return new Curve25519DHState();
|
||||
if (name.equals("448"))
|
||||
return new Curve448DHState();
|
||||
if (name.equals("NewHope"))
|
||||
return new NewHopeDHState();
|
||||
throw new NoSuchAlgorithmException("Unknown Noise DH algorithm name: " + name);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a cipher object from its Noise protocol name.
|
||||
*
|
||||
@@ -108,20 +52,7 @@ public final class Noise {
|
||||
*/
|
||||
public static CipherState createCipher(String name) throws NoSuchAlgorithmException
|
||||
{
|
||||
if (name.equals("AESGCM")) {
|
||||
if (forceFallbacks)
|
||||
return new AESGCMFallbackCipherState();
|
||||
// "AES/GCM/NoPadding" exists in some recent JDK's but it is flaky
|
||||
// to use and not easily back-portable to older Android versions.
|
||||
// We instead emulate AESGCM on top of "AES/CTR/NoPadding".
|
||||
try {
|
||||
return new AESGCMOnCtrCipherState();
|
||||
} catch (NoSuchAlgorithmException e1) {
|
||||
// Could not find anything useful in the JCA/JCE so
|
||||
// use the pure Java fallback implementation instead.
|
||||
return new AESGCMFallbackCipherState();
|
||||
}
|
||||
} else if (name.equals("ChaChaPoly")) {
|
||||
if (name.equals("ChaChaPoly")) {
|
||||
return new ChaChaPolyCipherState();
|
||||
}
|
||||
throw new NoSuchAlgorithmException("Unknown Noise cipher algorithm name: " + name);
|
||||
@@ -145,41 +76,9 @@ public final class Noise {
|
||||
// The only algorithm that is required to be implemented by a
|
||||
// JDK is "SHA-256", although "SHA-512" is fairly common as well.
|
||||
if (name.equals("SHA256")) {
|
||||
if (forceFallbacks)
|
||||
return new SHA256MessageDigest();
|
||||
try {
|
||||
return MessageDigest.getInstance("SHA-256");
|
||||
} catch (NoSuchAlgorithmException e) {
|
||||
return new SHA256MessageDigest();
|
||||
}
|
||||
} else if (name.equals("SHA512")) {
|
||||
if (forceFallbacks)
|
||||
return new SHA512MessageDigest();
|
||||
try {
|
||||
return MessageDigest.getInstance("SHA-512");
|
||||
} catch (NoSuchAlgorithmException e) {
|
||||
return new SHA512MessageDigest();
|
||||
}
|
||||
} else if (name.equals("BLAKE2b")) {
|
||||
// Bouncy Castle registers the BLAKE2b variant we
|
||||
// want under the name "BLAKE2B-512".
|
||||
if (forceFallbacks)
|
||||
return new Blake2bMessageDigest();
|
||||
try {
|
||||
return MessageDigest.getInstance("BLAKE2B-512");
|
||||
} catch (NoSuchAlgorithmException e) {
|
||||
return new Blake2bMessageDigest();
|
||||
}
|
||||
} else if (name.equals("BLAKE2s")) {
|
||||
// Bouncy Castle doesn't currently (June 2016) have an
|
||||
// implementation of BLAKE2s, but look for the most
|
||||
// obvious provider name in case one is added in the future.
|
||||
if (forceFallbacks)
|
||||
return new Blake2sMessageDigest();
|
||||
try {
|
||||
return MessageDigest.getInstance("BLAKE2S-256");
|
||||
} catch (NoSuchAlgorithmException e) {
|
||||
return new Blake2sMessageDigest();
|
||||
}
|
||||
}
|
||||
throw new NoSuchAlgorithmException("Unknown Noise hash algorithm name: " + name);
|
||||
|
||||
@@ -54,89 +54,6 @@ class Pattern {
|
||||
public static final short FLAG_REMOTE_HYBRID = 0x1000;
|
||||
public static final short FLAG_REMOTE_HYBRID_REQ = 0x2000;
|
||||
|
||||
private static final short[] noise_pattern_N = {
|
||||
FLAG_LOCAL_EPHEMERAL |
|
||||
FLAG_REMOTE_STATIC |
|
||||
FLAG_REMOTE_REQUIRED,
|
||||
|
||||
E,
|
||||
ES
|
||||
};
|
||||
|
||||
private static final short[] noise_pattern_K = {
|
||||
FLAG_LOCAL_STATIC |
|
||||
FLAG_LOCAL_EPHEMERAL |
|
||||
FLAG_LOCAL_REQUIRED |
|
||||
FLAG_REMOTE_STATIC |
|
||||
FLAG_REMOTE_REQUIRED,
|
||||
|
||||
E,
|
||||
ES,
|
||||
SS
|
||||
};
|
||||
|
||||
private static final short[] noise_pattern_X = {
|
||||
FLAG_LOCAL_STATIC |
|
||||
FLAG_LOCAL_EPHEMERAL |
|
||||
FLAG_REMOTE_STATIC |
|
||||
FLAG_REMOTE_REQUIRED,
|
||||
|
||||
E,
|
||||
ES,
|
||||
S,
|
||||
SS
|
||||
};
|
||||
|
||||
private static final short[] noise_pattern_NN = {
|
||||
FLAG_LOCAL_EPHEMERAL |
|
||||
FLAG_REMOTE_EPHEMERAL,
|
||||
|
||||
E,
|
||||
FLIP_DIR,
|
||||
E,
|
||||
EE
|
||||
};
|
||||
|
||||
private static final short[] noise_pattern_NK = {
|
||||
FLAG_LOCAL_EPHEMERAL |
|
||||
FLAG_REMOTE_STATIC |
|
||||
FLAG_REMOTE_EPHEMERAL |
|
||||
FLAG_REMOTE_REQUIRED,
|
||||
|
||||
E,
|
||||
ES,
|
||||
FLIP_DIR,
|
||||
E,
|
||||
EE
|
||||
};
|
||||
|
||||
private static final short[] noise_pattern_NX = {
|
||||
FLAG_LOCAL_EPHEMERAL |
|
||||
FLAG_REMOTE_STATIC |
|
||||
FLAG_REMOTE_EPHEMERAL,
|
||||
|
||||
E,
|
||||
FLIP_DIR,
|
||||
E,
|
||||
EE,
|
||||
S,
|
||||
ES
|
||||
};
|
||||
|
||||
private static final short[] noise_pattern_XN = {
|
||||
FLAG_LOCAL_STATIC |
|
||||
FLAG_LOCAL_EPHEMERAL |
|
||||
FLAG_REMOTE_EPHEMERAL,
|
||||
|
||||
E,
|
||||
FLIP_DIR,
|
||||
E,
|
||||
EE,
|
||||
FLIP_DIR,
|
||||
S,
|
||||
SE
|
||||
};
|
||||
|
||||
private static final short[] noise_pattern_XK = {
|
||||
FLAG_LOCAL_STATIC |
|
||||
FLAG_LOCAL_EPHEMERAL |
|
||||
@@ -154,583 +71,6 @@ class Pattern {
|
||||
SE
|
||||
};
|
||||
|
||||
private static final short[] noise_pattern_XX = {
|
||||
FLAG_LOCAL_STATIC |
|
||||
FLAG_LOCAL_EPHEMERAL |
|
||||
FLAG_REMOTE_STATIC |
|
||||
FLAG_REMOTE_EPHEMERAL,
|
||||
|
||||
E,
|
||||
FLIP_DIR,
|
||||
E,
|
||||
EE,
|
||||
S,
|
||||
ES,
|
||||
FLIP_DIR,
|
||||
S,
|
||||
SE
|
||||
};
|
||||
|
||||
private static final short[] noise_pattern_KN = {
|
||||
FLAG_LOCAL_STATIC |
|
||||
FLAG_LOCAL_EPHEMERAL |
|
||||
FLAG_LOCAL_REQUIRED |
|
||||
FLAG_REMOTE_EPHEMERAL,
|
||||
|
||||
E,
|
||||
FLIP_DIR,
|
||||
E,
|
||||
EE,
|
||||
SE
|
||||
};
|
||||
|
||||
private static final short[] noise_pattern_KK = {
|
||||
FLAG_LOCAL_STATIC |
|
||||
FLAG_LOCAL_EPHEMERAL |
|
||||
FLAG_LOCAL_REQUIRED |
|
||||
FLAG_REMOTE_STATIC |
|
||||
FLAG_REMOTE_EPHEMERAL |
|
||||
FLAG_REMOTE_REQUIRED,
|
||||
|
||||
E,
|
||||
ES,
|
||||
SS,
|
||||
FLIP_DIR,
|
||||
E,
|
||||
EE,
|
||||
SE
|
||||
};
|
||||
|
||||
private static final short[] noise_pattern_KX = {
|
||||
FLAG_LOCAL_STATIC |
|
||||
FLAG_LOCAL_EPHEMERAL |
|
||||
FLAG_LOCAL_REQUIRED |
|
||||
FLAG_REMOTE_STATIC |
|
||||
FLAG_REMOTE_EPHEMERAL,
|
||||
|
||||
E,
|
||||
FLIP_DIR,
|
||||
E,
|
||||
EE,
|
||||
SE,
|
||||
S,
|
||||
ES
|
||||
};
|
||||
|
||||
private static final short[] noise_pattern_IN = {
|
||||
FLAG_LOCAL_STATIC |
|
||||
FLAG_LOCAL_EPHEMERAL |
|
||||
FLAG_REMOTE_EPHEMERAL,
|
||||
|
||||
E,
|
||||
S,
|
||||
FLIP_DIR,
|
||||
E,
|
||||
EE,
|
||||
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
|
||||
};
|
||||
|
||||
private static final short[] noise_pattern_IX = {
|
||||
FLAG_LOCAL_STATIC |
|
||||
FLAG_LOCAL_EPHEMERAL |
|
||||
FLAG_REMOTE_STATIC |
|
||||
FLAG_REMOTE_EPHEMERAL,
|
||||
|
||||
E,
|
||||
S,
|
||||
FLIP_DIR,
|
||||
E,
|
||||
EE,
|
||||
SE,
|
||||
S,
|
||||
ES
|
||||
};
|
||||
|
||||
private static final short[] noise_pattern_XXfallback = {
|
||||
FLAG_LOCAL_STATIC |
|
||||
FLAG_LOCAL_EPHEMERAL |
|
||||
FLAG_REMOTE_STATIC |
|
||||
FLAG_REMOTE_EPHEMERAL |
|
||||
FLAG_REMOTE_EPHEM_REQ,
|
||||
|
||||
E,
|
||||
EE,
|
||||
S,
|
||||
SE,
|
||||
FLIP_DIR,
|
||||
S,
|
||||
ES
|
||||
};
|
||||
|
||||
private static final short[] noise_pattern_Xnoidh = {
|
||||
FLAG_LOCAL_STATIC |
|
||||
FLAG_LOCAL_EPHEMERAL |
|
||||
FLAG_REMOTE_STATIC |
|
||||
FLAG_REMOTE_REQUIRED,
|
||||
|
||||
E,
|
||||
S,
|
||||
ES,
|
||||
SS
|
||||
};
|
||||
|
||||
private static final short[] noise_pattern_NXnoidh = {
|
||||
FLAG_LOCAL_EPHEMERAL |
|
||||
FLAG_REMOTE_STATIC |
|
||||
FLAG_REMOTE_EPHEMERAL,
|
||||
|
||||
E,
|
||||
FLIP_DIR,
|
||||
E,
|
||||
S,
|
||||
EE,
|
||||
ES
|
||||
};
|
||||
|
||||
private static final short[] noise_pattern_XXnoidh = {
|
||||
FLAG_LOCAL_STATIC |
|
||||
FLAG_LOCAL_EPHEMERAL |
|
||||
FLAG_REMOTE_STATIC |
|
||||
FLAG_REMOTE_EPHEMERAL,
|
||||
|
||||
E,
|
||||
FLIP_DIR,
|
||||
E,
|
||||
S,
|
||||
EE,
|
||||
ES,
|
||||
FLIP_DIR,
|
||||
S,
|
||||
SE
|
||||
};
|
||||
|
||||
private static final short[] noise_pattern_KXnoidh = {
|
||||
FLAG_LOCAL_STATIC |
|
||||
FLAG_LOCAL_EPHEMERAL |
|
||||
FLAG_LOCAL_REQUIRED |
|
||||
FLAG_REMOTE_STATIC |
|
||||
FLAG_REMOTE_EPHEMERAL,
|
||||
|
||||
E,
|
||||
FLIP_DIR,
|
||||
E,
|
||||
S,
|
||||
EE,
|
||||
SE,
|
||||
ES
|
||||
};
|
||||
|
||||
private static final short[] noise_pattern_IKnoidh = {
|
||||
FLAG_LOCAL_STATIC |
|
||||
FLAG_LOCAL_EPHEMERAL |
|
||||
FLAG_REMOTE_STATIC |
|
||||
FLAG_REMOTE_EPHEMERAL |
|
||||
FLAG_REMOTE_REQUIRED,
|
||||
|
||||
E,
|
||||
S,
|
||||
ES,
|
||||
SS,
|
||||
FLIP_DIR,
|
||||
E,
|
||||
EE,
|
||||
SE
|
||||
};
|
||||
|
||||
private static final short[] noise_pattern_IXnoidh = {
|
||||
FLAG_LOCAL_STATIC |
|
||||
FLAG_LOCAL_EPHEMERAL |
|
||||
FLAG_REMOTE_STATIC |
|
||||
FLAG_REMOTE_EPHEMERAL,
|
||||
|
||||
E,
|
||||
S,
|
||||
FLIP_DIR,
|
||||
E,
|
||||
S,
|
||||
EE,
|
||||
SE,
|
||||
ES
|
||||
};
|
||||
|
||||
private static final short[] noise_pattern_NNhfs = {
|
||||
FLAG_LOCAL_EPHEMERAL |
|
||||
FLAG_LOCAL_HYBRID |
|
||||
FLAG_REMOTE_EPHEMERAL |
|
||||
FLAG_REMOTE_HYBRID,
|
||||
|
||||
E,
|
||||
F,
|
||||
FLIP_DIR,
|
||||
E,
|
||||
F,
|
||||
EE,
|
||||
FF
|
||||
};
|
||||
|
||||
private static final short[] noise_pattern_NKhfs = {
|
||||
FLAG_LOCAL_EPHEMERAL |
|
||||
FLAG_LOCAL_HYBRID |
|
||||
FLAG_REMOTE_STATIC |
|
||||
FLAG_REMOTE_EPHEMERAL |
|
||||
FLAG_REMOTE_HYBRID |
|
||||
FLAG_REMOTE_REQUIRED,
|
||||
|
||||
E,
|
||||
F,
|
||||
ES,
|
||||
FLIP_DIR,
|
||||
E,
|
||||
F,
|
||||
EE,
|
||||
FF
|
||||
};
|
||||
|
||||
private static final short[] noise_pattern_NXhfs = {
|
||||
FLAG_LOCAL_EPHEMERAL |
|
||||
FLAG_LOCAL_HYBRID |
|
||||
FLAG_REMOTE_STATIC |
|
||||
FLAG_REMOTE_EPHEMERAL |
|
||||
FLAG_REMOTE_HYBRID,
|
||||
|
||||
E,
|
||||
F,
|
||||
FLIP_DIR,
|
||||
E,
|
||||
F,
|
||||
EE,
|
||||
FF,
|
||||
S,
|
||||
ES
|
||||
};
|
||||
|
||||
private static final short[] noise_pattern_XNhfs = {
|
||||
FLAG_LOCAL_STATIC |
|
||||
FLAG_LOCAL_EPHEMERAL |
|
||||
FLAG_LOCAL_HYBRID |
|
||||
FLAG_REMOTE_EPHEMERAL |
|
||||
FLAG_REMOTE_HYBRID,
|
||||
|
||||
E,
|
||||
F,
|
||||
FLIP_DIR,
|
||||
E,
|
||||
F,
|
||||
EE,
|
||||
FF,
|
||||
FLIP_DIR,
|
||||
S,
|
||||
SE
|
||||
};
|
||||
|
||||
private static final short[] noise_pattern_XKhfs = {
|
||||
FLAG_LOCAL_STATIC |
|
||||
FLAG_LOCAL_EPHEMERAL |
|
||||
FLAG_LOCAL_HYBRID |
|
||||
FLAG_REMOTE_STATIC |
|
||||
FLAG_REMOTE_EPHEMERAL |
|
||||
FLAG_REMOTE_HYBRID |
|
||||
FLAG_REMOTE_REQUIRED,
|
||||
|
||||
E,
|
||||
F,
|
||||
ES,
|
||||
FLIP_DIR,
|
||||
E,
|
||||
F,
|
||||
EE,
|
||||
FF,
|
||||
FLIP_DIR,
|
||||
S,
|
||||
SE
|
||||
};
|
||||
|
||||
private static final short[] noise_pattern_XXhfs = {
|
||||
FLAG_LOCAL_STATIC |
|
||||
FLAG_LOCAL_EPHEMERAL |
|
||||
FLAG_LOCAL_HYBRID |
|
||||
FLAG_REMOTE_STATIC |
|
||||
FLAG_REMOTE_EPHEMERAL |
|
||||
FLAG_REMOTE_HYBRID,
|
||||
|
||||
E,
|
||||
F,
|
||||
FLIP_DIR,
|
||||
E,
|
||||
F,
|
||||
EE,
|
||||
FF,
|
||||
S,
|
||||
ES,
|
||||
FLIP_DIR,
|
||||
S,
|
||||
SE
|
||||
};
|
||||
|
||||
private static final short[] noise_pattern_KNhfs = {
|
||||
FLAG_LOCAL_STATIC |
|
||||
FLAG_LOCAL_EPHEMERAL |
|
||||
FLAG_LOCAL_REQUIRED |
|
||||
FLAG_LOCAL_HYBRID |
|
||||
FLAG_REMOTE_EPHEMERAL |
|
||||
FLAG_REMOTE_HYBRID,
|
||||
|
||||
E,
|
||||
F,
|
||||
FLIP_DIR,
|
||||
E,
|
||||
F,
|
||||
EE,
|
||||
FF,
|
||||
SE
|
||||
};
|
||||
|
||||
private static final short[] noise_pattern_KKhfs = {
|
||||
FLAG_LOCAL_STATIC |
|
||||
FLAG_LOCAL_EPHEMERAL |
|
||||
FLAG_LOCAL_REQUIRED |
|
||||
FLAG_LOCAL_HYBRID |
|
||||
FLAG_REMOTE_STATIC |
|
||||
FLAG_REMOTE_EPHEMERAL |
|
||||
FLAG_REMOTE_HYBRID |
|
||||
FLAG_REMOTE_REQUIRED,
|
||||
|
||||
E,
|
||||
F,
|
||||
ES,
|
||||
SS,
|
||||
FLIP_DIR,
|
||||
E,
|
||||
F,
|
||||
EE,
|
||||
FF,
|
||||
SE
|
||||
};
|
||||
|
||||
private static final short[] noise_pattern_KXhfs = {
|
||||
FLAG_LOCAL_STATIC |
|
||||
FLAG_LOCAL_EPHEMERAL |
|
||||
FLAG_LOCAL_REQUIRED |
|
||||
FLAG_LOCAL_HYBRID |
|
||||
FLAG_REMOTE_STATIC |
|
||||
FLAG_REMOTE_EPHEMERAL |
|
||||
FLAG_REMOTE_HYBRID,
|
||||
|
||||
E,
|
||||
F,
|
||||
FLIP_DIR,
|
||||
E,
|
||||
F,
|
||||
EE,
|
||||
FF,
|
||||
SE,
|
||||
S,
|
||||
ES
|
||||
};
|
||||
|
||||
private static final short[] noise_pattern_INhfs = {
|
||||
FLAG_LOCAL_STATIC |
|
||||
FLAG_LOCAL_EPHEMERAL |
|
||||
FLAG_LOCAL_HYBRID |
|
||||
FLAG_REMOTE_EPHEMERAL |
|
||||
FLAG_REMOTE_HYBRID,
|
||||
|
||||
E,
|
||||
F,
|
||||
S,
|
||||
FLIP_DIR,
|
||||
E,
|
||||
F,
|
||||
EE,
|
||||
FF,
|
||||
SE
|
||||
};
|
||||
|
||||
private static final short[] noise_pattern_IKhfs = {
|
||||
FLAG_LOCAL_STATIC |
|
||||
FLAG_LOCAL_EPHEMERAL |
|
||||
FLAG_LOCAL_HYBRID |
|
||||
FLAG_REMOTE_STATIC |
|
||||
FLAG_REMOTE_EPHEMERAL |
|
||||
FLAG_REMOTE_HYBRID |
|
||||
FLAG_REMOTE_REQUIRED,
|
||||
|
||||
E,
|
||||
F,
|
||||
ES,
|
||||
S,
|
||||
SS,
|
||||
FLIP_DIR,
|
||||
E,
|
||||
F,
|
||||
EE,
|
||||
FF,
|
||||
SE
|
||||
};
|
||||
|
||||
private static final short[] noise_pattern_IXhfs = {
|
||||
FLAG_LOCAL_STATIC |
|
||||
FLAG_LOCAL_EPHEMERAL |
|
||||
FLAG_LOCAL_HYBRID |
|
||||
FLAG_REMOTE_STATIC |
|
||||
FLAG_REMOTE_EPHEMERAL |
|
||||
FLAG_REMOTE_HYBRID,
|
||||
|
||||
E,
|
||||
F,
|
||||
S,
|
||||
FLIP_DIR,
|
||||
E,
|
||||
F,
|
||||
EE,
|
||||
FF,
|
||||
SE,
|
||||
S,
|
||||
ES
|
||||
};
|
||||
|
||||
private static final short[] noise_pattern_XXfallback_hfs = {
|
||||
FLAG_LOCAL_STATIC |
|
||||
FLAG_LOCAL_EPHEMERAL |
|
||||
FLAG_LOCAL_HYBRID |
|
||||
FLAG_REMOTE_STATIC |
|
||||
FLAG_REMOTE_EPHEMERAL |
|
||||
FLAG_REMOTE_EPHEM_REQ |
|
||||
FLAG_REMOTE_HYBRID |
|
||||
FLAG_REMOTE_HYBRID_REQ,
|
||||
|
||||
E,
|
||||
F,
|
||||
EE,
|
||||
FF,
|
||||
S,
|
||||
SE,
|
||||
FLIP_DIR,
|
||||
S,
|
||||
ES
|
||||
};
|
||||
|
||||
private static final short[] noise_pattern_NXnoidh_hfs = {
|
||||
FLAG_LOCAL_EPHEMERAL |
|
||||
FLAG_LOCAL_HYBRID |
|
||||
FLAG_REMOTE_STATIC |
|
||||
FLAG_REMOTE_EPHEMERAL |
|
||||
FLAG_REMOTE_HYBRID,
|
||||
|
||||
E,
|
||||
F,
|
||||
FLIP_DIR,
|
||||
E,
|
||||
F,
|
||||
S,
|
||||
EE,
|
||||
FF,
|
||||
ES
|
||||
};
|
||||
|
||||
private static final short[] noise_pattern_XXnoidh_hfs = {
|
||||
FLAG_LOCAL_STATIC |
|
||||
FLAG_LOCAL_EPHEMERAL |
|
||||
FLAG_LOCAL_HYBRID |
|
||||
FLAG_REMOTE_STATIC |
|
||||
FLAG_REMOTE_EPHEMERAL |
|
||||
FLAG_REMOTE_HYBRID,
|
||||
|
||||
E,
|
||||
F,
|
||||
FLIP_DIR,
|
||||
E,
|
||||
F,
|
||||
S,
|
||||
EE,
|
||||
FF,
|
||||
ES,
|
||||
FLIP_DIR,
|
||||
S,
|
||||
SE
|
||||
};
|
||||
|
||||
private static final short[] noise_pattern_KXnoidh_hfs = {
|
||||
FLAG_LOCAL_STATIC |
|
||||
FLAG_LOCAL_EPHEMERAL |
|
||||
FLAG_LOCAL_REQUIRED |
|
||||
FLAG_LOCAL_HYBRID |
|
||||
FLAG_REMOTE_STATIC |
|
||||
FLAG_REMOTE_EPHEMERAL |
|
||||
FLAG_REMOTE_HYBRID,
|
||||
|
||||
E,
|
||||
F,
|
||||
FLIP_DIR,
|
||||
E,
|
||||
F,
|
||||
S,
|
||||
EE,
|
||||
FF,
|
||||
SE,
|
||||
ES
|
||||
};
|
||||
|
||||
private static final short[] noise_pattern_IKnoidh_hfs = {
|
||||
FLAG_LOCAL_STATIC |
|
||||
FLAG_LOCAL_EPHEMERAL |
|
||||
FLAG_LOCAL_HYBRID |
|
||||
FLAG_REMOTE_STATIC |
|
||||
FLAG_REMOTE_EPHEMERAL |
|
||||
FLAG_REMOTE_EPHEMERAL |
|
||||
FLAG_REMOTE_HYBRID,
|
||||
|
||||
E,
|
||||
F,
|
||||
S,
|
||||
ES,
|
||||
SS,
|
||||
FLIP_DIR,
|
||||
E,
|
||||
F,
|
||||
EE,
|
||||
FF,
|
||||
SE
|
||||
};
|
||||
|
||||
private static final short[] noise_pattern_IXnoidh_hfs = {
|
||||
FLAG_LOCAL_STATIC |
|
||||
FLAG_LOCAL_EPHEMERAL |
|
||||
FLAG_LOCAL_HYBRID |
|
||||
FLAG_REMOTE_STATIC |
|
||||
FLAG_REMOTE_EPHEMERAL |
|
||||
FLAG_REMOTE_HYBRID,
|
||||
|
||||
E,
|
||||
F,
|
||||
S,
|
||||
FLIP_DIR,
|
||||
E,
|
||||
F,
|
||||
S,
|
||||
EE,
|
||||
FF,
|
||||
SE,
|
||||
ES
|
||||
};
|
||||
|
||||
/**
|
||||
* Look up the description information for a pattern.
|
||||
*
|
||||
@@ -739,86 +79,8 @@ class Pattern {
|
||||
*/
|
||||
public static short[] lookup(String name)
|
||||
{
|
||||
if (name.equals("N"))
|
||||
return noise_pattern_N;
|
||||
else if (name.equals("K"))
|
||||
return noise_pattern_K;
|
||||
else if (name.equals("X"))
|
||||
return noise_pattern_X;
|
||||
else if (name.equals("NN"))
|
||||
return noise_pattern_NN;
|
||||
else if (name.equals("NK"))
|
||||
return noise_pattern_NK;
|
||||
else if (name.equals("NX"))
|
||||
return noise_pattern_NX;
|
||||
else if (name.equals("XN"))
|
||||
return noise_pattern_XN;
|
||||
else if (name.equals("XK"))
|
||||
if (name.equals("XK"))
|
||||
return noise_pattern_XK;
|
||||
else if (name.equals("XX"))
|
||||
return noise_pattern_XX;
|
||||
else if (name.equals("KN"))
|
||||
return noise_pattern_KN;
|
||||
else if (name.equals("KK"))
|
||||
return noise_pattern_KK;
|
||||
else if (name.equals("KX"))
|
||||
return noise_pattern_KX;
|
||||
else if (name.equals("IN"))
|
||||
return noise_pattern_IN;
|
||||
else if (name.equals("IK"))
|
||||
return noise_pattern_IK;
|
||||
else if (name.equals("IX"))
|
||||
return noise_pattern_IX;
|
||||
else if (name.equals("XXfallback"))
|
||||
return noise_pattern_XXfallback;
|
||||
else if (name.equals("Xnoidh"))
|
||||
return noise_pattern_Xnoidh;
|
||||
else if (name.equals("NXnoidh"))
|
||||
return noise_pattern_NXnoidh;
|
||||
else if (name.equals("XXnoidh"))
|
||||
return noise_pattern_XXnoidh;
|
||||
else if (name.equals("KXnoidh"))
|
||||
return noise_pattern_KXnoidh;
|
||||
else if (name.equals("IKnoidh"))
|
||||
return noise_pattern_IKnoidh;
|
||||
else if (name.equals("IXnoidh"))
|
||||
return noise_pattern_IXnoidh;
|
||||
else if (name.equals("NNhfs"))
|
||||
return noise_pattern_NNhfs;
|
||||
else if (name.equals("NKhfs"))
|
||||
return noise_pattern_NKhfs;
|
||||
else if (name.equals("NXhfs"))
|
||||
return noise_pattern_NXhfs;
|
||||
else if (name.equals("XNhfs"))
|
||||
return noise_pattern_XNhfs;
|
||||
else if (name.equals("XKhfs"))
|
||||
return noise_pattern_XKhfs;
|
||||
else if (name.equals("XXhfs"))
|
||||
return noise_pattern_XXhfs;
|
||||
else if (name.equals("KNhfs"))
|
||||
return noise_pattern_KNhfs;
|
||||
else if (name.equals("KKhfs"))
|
||||
return noise_pattern_KKhfs;
|
||||
else if (name.equals("KXhfs"))
|
||||
return noise_pattern_KXhfs;
|
||||
else if (name.equals("INhfs"))
|
||||
return noise_pattern_INhfs;
|
||||
else if (name.equals("IKhfs"))
|
||||
return noise_pattern_IKhfs;
|
||||
else if (name.equals("IXhfs"))
|
||||
return noise_pattern_IXhfs;
|
||||
else if (name.equals("XXfallback+hfs"))
|
||||
return noise_pattern_XXfallback_hfs;
|
||||
else if (name.equals("NXnoidh+hfs"))
|
||||
return noise_pattern_NXnoidh_hfs;
|
||||
else if (name.equals("XXnoidh+hfs"))
|
||||
return noise_pattern_XXnoidh_hfs;
|
||||
else if (name.equals("KXnoidh+hfs"))
|
||||
return noise_pattern_KXnoidh_hfs;
|
||||
else if (name.equals("IKnoidh+hfs"))
|
||||
return noise_pattern_IKnoidh_hfs;
|
||||
else if (name.equals("IXnoidh+hfs"))
|
||||
return noise_pattern_IXnoidh_hfs;
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
@@ -36,15 +36,41 @@ import javax.crypto.ShortBufferException;
|
||||
*/
|
||||
class SymmetricState implements Destroyable {
|
||||
|
||||
private String name;
|
||||
private CipherState cipher;
|
||||
private MessageDigest hash;
|
||||
private byte[] ck;
|
||||
private byte[] h;
|
||||
private byte[] prev_h;
|
||||
// precalculated hash of the Noise name
|
||||
private static final byte[] INIT_HASH;
|
||||
|
||||
static {
|
||||
byte[] protocolNameBytes;
|
||||
try {
|
||||
protocolNameBytes = HandshakeState.protocolName.getBytes("UTF-8");
|
||||
} catch (UnsupportedEncodingException e) {
|
||||
// If UTF-8 is not supported, then we are definitely in trouble!
|
||||
throw new UnsupportedOperationException("UTF-8 encoding is not supported");
|
||||
}
|
||||
INIT_HASH = new byte[32];
|
||||
if (protocolNameBytes.length <= 32) {
|
||||
System.arraycopy(protocolNameBytes, 0, INIT_HASH, 0, protocolNameBytes.length);
|
||||
Arrays.fill(INIT_HASH, protocolNameBytes.length, 32, (byte)0);
|
||||
} else {
|
||||
try {
|
||||
MessageDigest hash = Noise.createHash("SHA256");
|
||||
hash.update(protocolNameBytes, 0, protocolNameBytes.length);
|
||||
hash.digest(INIT_HASH, 0, 32);
|
||||
} catch (Exception e) {
|
||||
throw new IllegalStateException(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private final CipherState cipher;
|
||||
private final MessageDigest hash;
|
||||
private final byte[] ck;
|
||||
private final byte[] h;
|
||||
private final byte[] prev_h;
|
||||
|
||||
/**
|
||||
* Constructs a new symmetric state object.
|
||||
* Noise protocol name is hardcoded.
|
||||
*
|
||||
* @param protocolName The name of the Noise protocol, which is assumed to be valid.
|
||||
* @param cipherName The name of the cipher within protocolName.
|
||||
@@ -53,9 +79,8 @@ class SymmetricState implements Destroyable {
|
||||
* @throws NoSuchAlgorithmException The cipher or hash algorithm in the
|
||||
* protocol name is not supported.
|
||||
*/
|
||||
public SymmetricState(String protocolName, String cipherName, String hashName) throws NoSuchAlgorithmException
|
||||
public SymmetricState(String cipherName, String hashName) throws NoSuchAlgorithmException
|
||||
{
|
||||
name = protocolName;
|
||||
cipher = Noise.createCipher(cipherName);
|
||||
hash = Noise.createHash(hashName);
|
||||
int hashLength = hash.getDigestLength();
|
||||
@@ -63,21 +88,7 @@ class SymmetricState implements Destroyable {
|
||||
h = new byte [hashLength];
|
||||
prev_h = new byte [hashLength];
|
||||
|
||||
byte[] protocolNameBytes;
|
||||
try {
|
||||
protocolNameBytes = protocolName.getBytes("UTF-8");
|
||||
} catch (UnsupportedEncodingException e) {
|
||||
// If UTF-8 is not supported, then we are definitely in trouble!
|
||||
throw new UnsupportedOperationException("UTF-8 encoding is not supported");
|
||||
}
|
||||
|
||||
if (protocolNameBytes.length <= hashLength) {
|
||||
System.arraycopy(protocolNameBytes, 0, h, 0, protocolNameBytes.length);
|
||||
Arrays.fill(h, protocolNameBytes.length, h.length, (byte)0);
|
||||
} else {
|
||||
hashOne(protocolNameBytes, 0, protocolNameBytes.length, h, 0, h.length);
|
||||
}
|
||||
|
||||
System.arraycopy(INIT_HASH, 0, h, 0, hashLength);
|
||||
System.arraycopy(h, 0, ck, 0, hashLength);
|
||||
}
|
||||
|
||||
@@ -88,7 +99,7 @@ class SymmetricState implements Destroyable {
|
||||
*/
|
||||
public String getProtocolName()
|
||||
{
|
||||
return name;
|
||||
return HandshakeState.protocolName;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -311,31 +322,11 @@ class SymmetricState implements Destroyable {
|
||||
|
||||
@Override
|
||||
public void destroy() {
|
||||
if (cipher != null) {
|
||||
cipher.destroy();
|
||||
cipher = null;
|
||||
}
|
||||
if (hash != null) {
|
||||
// The built-in fallback implementations are destroyable.
|
||||
// JCA/JCE implementations aren't, so try reset() instead.
|
||||
if (hash instanceof Destroyable)
|
||||
((Destroyable)hash).destroy();
|
||||
else
|
||||
hash.reset();
|
||||
hash = null;
|
||||
}
|
||||
if (ck != null) {
|
||||
Noise.destroy(ck);
|
||||
ck = null;
|
||||
}
|
||||
if (h != null) {
|
||||
Noise.destroy(h);
|
||||
h = null;
|
||||
}
|
||||
if (prev_h != null) {
|
||||
Noise.destroy(prev_h);
|
||||
prev_h = null;
|
||||
}
|
||||
cipher.destroy();
|
||||
hash.reset();
|
||||
Noise.destroy(ck);
|
||||
Noise.destroy(h);
|
||||
Noise.destroy(prev_h);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -481,4 +472,59 @@ class SymmetricState implements Destroyable {
|
||||
Noise.destroy(tempHash);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* I2P for getting chaining key for siphash calculation
|
||||
* @return a copy
|
||||
*/
|
||||
public byte[] getChainingKey() {
|
||||
byte[] rv = new byte[ck.length];
|
||||
System.arraycopy(ck, 0, rv, 0, ck.length);
|
||||
return rv;
|
||||
}
|
||||
|
||||
/**
|
||||
* I2P debug
|
||||
*/
|
||||
@Override
|
||||
public String toString() {
|
||||
StringBuilder buf = new StringBuilder();
|
||||
buf.append(" Symmetric State:\n" +
|
||||
" ck: ");
|
||||
buf.append(net.i2p.data.Base64.encode(ck));
|
||||
buf.append("\n" +
|
||||
" h: ");
|
||||
buf.append(net.i2p.data.Base64.encode(h));
|
||||
buf.append('\n');
|
||||
buf.append(cipher.toString());
|
||||
return buf.toString();
|
||||
}
|
||||
|
||||
/****
|
||||
private static final int LENGTH = 33;
|
||||
|
||||
public static void main(String args[]) throws Exception {
|
||||
net.i2p.I2PAppContext ctx = net.i2p.I2PAppContext.getGlobalContext();
|
||||
byte[] rand = new byte[32];
|
||||
byte[] data = new byte[LENGTH];
|
||||
byte[] out = new byte[32];
|
||||
System.out.println("Warmup");
|
||||
int RUNS = 25000;
|
||||
SymmetricState ss = new SymmetricState("ChaChaPoly", "SHA256");
|
||||
for (int i = 0; i < RUNS; i++) {
|
||||
ctx.random().nextBytes(rand);
|
||||
ctx.random().nextBytes(data);
|
||||
ss.hmac(rand, 0, 32, data, 0, LENGTH, out, 0, 32);
|
||||
}
|
||||
System.out.println("Start");
|
||||
RUNS = 500000;
|
||||
long start = System.currentTimeMillis();
|
||||
for (int i = 0; i < RUNS; i++) {
|
||||
ss.hmac(rand, 0, 32, data, 0, LENGTH, out, 0, 32);
|
||||
}
|
||||
long time = System.currentTimeMillis() - start;
|
||||
System.out.println("Time for " + RUNS + " HMAC-SHA256 computations:");
|
||||
System.out.println("Noise time (ms): " + time);
|
||||
}
|
||||
****/
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user