Add support for hybrid forward secrecy

This commit is contained in:
Rhys Weatherley 2016-10-08 19:28:53 +10:00
parent 4bc27fefce
commit 683b9b2315
3 changed files with 584 additions and 48 deletions

View File

@ -37,12 +37,15 @@ public class HandshakeState implements Destroyable {
private boolean isInitiator;
private DHState localKeyPair;
private DHState localEphemeral;
private DHState localHybrid;
private DHState remotePublicKey;
private DHState remoteEphemeral;
private DHState remoteHybrid;
private DHState fixedEphemeral;
private DHState fixedHybrid;
private int action;
private int requirements;
private byte[] pattern;
private short[] pattern;
private int patternIndex;
private byte[] preSharedKey;
private byte[] prologue;
@ -150,6 +153,7 @@ public class HandshakeState implements Destroyable {
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"))
@ -157,7 +161,7 @@ public class HandshakeState implements Destroyable {
pattern = Pattern.lookup(patternId);
if (pattern == null)
throw new IllegalArgumentException("Handshake pattern is not recognized");
byte flags = pattern[0];
short flags = pattern[0];
int extraReqs = 0;
if ((flags & Pattern.FLAG_REMOTE_REQUIRED) != 0 && patternId.length() > 1)
extraReqs |= FALLBACK_POSSIBLE;
@ -165,6 +169,17 @@ 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)
@ -182,10 +197,14 @@ public class HandshakeState implements Destroyable {
localKeyPair = Noise.createDH(dh);
if ((flags & Pattern.FLAG_LOCAL_EPHEMERAL) != 0)
localEphemeral = Noise.createDH(dh);
if ((flags & Pattern.FLAG_LOCAL_HYBRID) != 0)
localHybrid = Noise.createDH(hybrid);
if ((flags & Pattern.FLAG_REMOTE_STATIC) != 0)
remotePublicKey = Noise.createDH(dh);
if ((flags & Pattern.FLAG_REMOTE_EPHEMERAL) != 0)
remoteEphemeral = Noise.createDH(dh);
if ((flags & Pattern.FLAG_REMOTE_HYBRID) != 0)
remoteHybrid = Noise.createDH(hybrid);
}
/**
@ -403,6 +422,33 @@ public class HandshakeState implements Destroyable {
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];
@ -468,6 +514,8 @@ public class HandshakeState implements Destroyable {
symmetric.mixPublicKey(localKeyPair);
if ((requirements & FALLBACK_PREMSG) != 0) {
symmetric.mixPublicKey(remoteEphemeral);
if (remoteHybrid != null)
symmetric.mixPublicKey(remoteHybrid);
if (preSharedKey != null)
symmetric.mixPublicKeyIntoCK(remoteEphemeral);
}
@ -478,6 +526,8 @@ public class HandshakeState implements Destroyable {
symmetric.mixPublicKey(remotePublicKey);
if ((requirements & FALLBACK_PREMSG) != 0) {
symmetric.mixPublicKey(localEphemeral);
if (localHybrid != null)
symmetric.mixPublicKey(localHybrid);
if (preSharedKey != null)
symmetric.mixPublicKeyIntoCK(localEphemeral);
}
@ -576,7 +626,7 @@ public class HandshakeState implements Destroyable {
throw new UnsupportedOperationException("Previous handshake pattern does not support fallback");
// Check that "patternName" supports fallback.
byte[] newPattern = Pattern.lookup(patternName);
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");
@ -612,12 +662,16 @@ public class HandshakeState implements Destroyable {
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;
@ -625,7 +679,7 @@ public class HandshakeState implements Destroyable {
action = NO_ACTION;
pattern = newPattern;
patternIndex = 1;
byte flags = pattern[0];
short flags = pattern[0];
if (!isInitiator) {
// Reverse the pattern flags so that the responder is "local".
flags = Pattern.reverseFlags(flags);
@ -718,7 +772,7 @@ public class HandshakeState implements Destroyable {
action = SPLIT;
break;
}
byte token = pattern[patternIndex++];
short token = pattern[patternIndex++];
if (token == Pattern.FLIP_DIR) {
// Change directions, so this message is complete and the
// next action is "read message".
@ -801,6 +855,35 @@ public class HandshakeState implements Destroyable {
}
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 (fixedHybrid == null)
localHybrid.generateKeyPair(); // FIXME: dependent keys
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.
@ -877,7 +960,7 @@ public class HandshakeState implements Destroyable {
action = SPLIT;
break;
}
byte token = pattern[patternIndex++];
short token = pattern[patternIndex++];
if (token == Pattern.FLIP_DIR) {
// Change directions, so this message is complete and the
// next action is "write message".
@ -968,6 +1051,34 @@ public class HandshakeState implements Destroyable {
}
break;
case Pattern.F:
{
// Decrypt and read the remote hybrid ephemeral key.
if (remoteHybrid == null)
throw new IllegalStateException("Pattern definition error");
len = remoteHybrid.getPublicKeyLength(); // TODO: Dependent keys
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.
@ -1065,12 +1176,18 @@ public class HandshakeState implements Destroyable {
localKeyPair.destroy();
if (localEphemeral != null)
localEphemeral.destroy();
if (localHybrid != null)
localHybrid.destroy();
if (remotePublicKey != null)
remotePublicKey.destroy();
if (remoteEphemeral != null)
remoteEphemeral.destroy();
if (remoteHybrid != null)
remoteHybrid.destroy();
if (fixedEphemeral != null)
fixedEphemeral.destroy();
if (fixedHybrid != null)
fixedHybrid.destroy();
if (preSharedKey != null)
Noise.destroy(preSharedKey);
if (prologue != null)
@ -1089,7 +1206,7 @@ public class HandshakeState implements Destroyable {
*
* @return The set of requirements for the handshake.
*/
private static int computeRequirements(byte flags, String prefix, int role, boolean isFallback)
private static int computeRequirements(short flags, String prefix, int role, boolean isFallback)
{
int requirements = 0;
if ((flags & Pattern.FLAG_LOCAL_STATIC) != 0) {

View File

@ -30,25 +30,31 @@ class Pattern {
private Pattern() {}
// Token codes.
public static final byte S = 1;
public static final byte E = 2;
public static final byte EE = 3;
public static final byte ES = 4;
public static final byte SE = 5;
public static final byte SS = 6;
public static final byte FLIP_DIR = 7;
public static final short S = 1;
public static final short E = 2;
public static final short EE = 3;
public static final short ES = 4;
public static final short SE = 5;
public static final short SS = 6;
public static final short F = 7;
public static final short FF = 8;
public static final short FLIP_DIR = 255;
// Pattern flag bits.
public static final byte FLAG_LOCAL_STATIC = 0x01;
public static final byte FLAG_LOCAL_EPHEMERAL = 0x02;
public static final byte FLAG_LOCAL_REQUIRED = 0x04;
public static final byte FLAG_LOCAL_EPHEM_REQ = 0x08;
public static final byte FLAG_REMOTE_STATIC = 0x10;
public static final byte FLAG_REMOTE_EPHEMERAL = 0x20;
public static final byte FLAG_REMOTE_REQUIRED = 0x40;
public static final byte FLAG_REMOTE_EPHEM_REQ = (byte)0x80;
public static final short FLAG_LOCAL_STATIC = 0x0001;
public static final short FLAG_LOCAL_EPHEMERAL = 0x0002;
public static final short FLAG_LOCAL_REQUIRED = 0x0004;
public static final short FLAG_LOCAL_EPHEM_REQ = 0x0008;
public static final short FLAG_LOCAL_HYBRID = 0x0010;
public static final short FLAG_LOCAL_HYBRID_REQ = 0x0020;
public static final short FLAG_REMOTE_STATIC = 0x0100;
public static final short FLAG_REMOTE_EPHEMERAL = 0x0200;
public static final short FLAG_REMOTE_REQUIRED = 0x0400;
public static final short FLAG_REMOTE_EPHEM_REQ = 0x0800;
public static final short FLAG_REMOTE_HYBRID = 0x1000;
public static final short FLAG_REMOTE_HYBRID_REQ = 0x2000;
private static final byte[] noise_pattern_N = {
private static final short[] noise_pattern_N = {
FLAG_LOCAL_EPHEMERAL |
FLAG_REMOTE_STATIC |
FLAG_REMOTE_REQUIRED,
@ -57,7 +63,7 @@ class Pattern {
ES
};
private static final byte[] noise_pattern_K = {
private static final short[] noise_pattern_K = {
FLAG_LOCAL_STATIC |
FLAG_LOCAL_EPHEMERAL |
FLAG_LOCAL_REQUIRED |
@ -69,7 +75,7 @@ class Pattern {
SS
};
private static final byte[] noise_pattern_X = {
private static final short[] noise_pattern_X = {
FLAG_LOCAL_STATIC |
FLAG_LOCAL_EPHEMERAL |
FLAG_REMOTE_STATIC |
@ -81,7 +87,7 @@ class Pattern {
SS
};
private static final byte[] noise_pattern_NN = {
private static final short[] noise_pattern_NN = {
FLAG_LOCAL_EPHEMERAL |
FLAG_REMOTE_EPHEMERAL,
@ -91,7 +97,7 @@ class Pattern {
EE
};
private static final byte[] noise_pattern_NK = {
private static final short[] noise_pattern_NK = {
FLAG_LOCAL_EPHEMERAL |
FLAG_REMOTE_STATIC |
FLAG_REMOTE_EPHEMERAL |
@ -104,7 +110,7 @@ class Pattern {
EE
};
private static final byte[] noise_pattern_NX = {
private static final short[] noise_pattern_NX = {
FLAG_LOCAL_EPHEMERAL |
FLAG_REMOTE_STATIC |
FLAG_REMOTE_EPHEMERAL,
@ -117,7 +123,7 @@ class Pattern {
ES
};
private static final byte[] noise_pattern_XN = {
private static final short[] noise_pattern_XN = {
FLAG_LOCAL_STATIC |
FLAG_LOCAL_EPHEMERAL |
FLAG_REMOTE_EPHEMERAL,
@ -131,7 +137,7 @@ class Pattern {
SE
};
private static final byte[] noise_pattern_XK = {
private static final short[] noise_pattern_XK = {
FLAG_LOCAL_STATIC |
FLAG_LOCAL_EPHEMERAL |
FLAG_REMOTE_STATIC |
@ -148,7 +154,7 @@ class Pattern {
SE
};
private static final byte[] noise_pattern_XX = {
private static final short[] noise_pattern_XX = {
FLAG_LOCAL_STATIC |
FLAG_LOCAL_EPHEMERAL |
FLAG_REMOTE_STATIC |
@ -165,7 +171,7 @@ class Pattern {
SE
};
private static final byte[] noise_pattern_KN = {
private static final short[] noise_pattern_KN = {
FLAG_LOCAL_STATIC |
FLAG_LOCAL_EPHEMERAL |
FLAG_LOCAL_REQUIRED |
@ -178,7 +184,7 @@ class Pattern {
SE
};
private static final byte[] noise_pattern_KK = {
private static final short[] noise_pattern_KK = {
FLAG_LOCAL_STATIC |
FLAG_LOCAL_EPHEMERAL |
FLAG_LOCAL_REQUIRED |
@ -195,7 +201,7 @@ class Pattern {
SE
};
private static final byte[] noise_pattern_KX = {
private static final short[] noise_pattern_KX = {
FLAG_LOCAL_STATIC |
FLAG_LOCAL_EPHEMERAL |
FLAG_LOCAL_REQUIRED |
@ -211,7 +217,7 @@ class Pattern {
ES
};
private static final byte[] noise_pattern_IN = {
private static final short[] noise_pattern_IN = {
FLAG_LOCAL_STATIC |
FLAG_LOCAL_EPHEMERAL |
FLAG_REMOTE_EPHEMERAL,
@ -224,7 +230,7 @@ class Pattern {
SE
};
private static final byte[] noise_pattern_IK = {
private static final short[] noise_pattern_IK = {
FLAG_LOCAL_STATIC |
FLAG_LOCAL_EPHEMERAL |
FLAG_REMOTE_STATIC |
@ -241,7 +247,7 @@ class Pattern {
SE
};
private static final byte[] noise_pattern_IX = {
private static final short[] noise_pattern_IX = {
FLAG_LOCAL_STATIC |
FLAG_LOCAL_EPHEMERAL |
FLAG_REMOTE_STATIC |
@ -257,7 +263,7 @@ class Pattern {
ES
};
private static final byte[] noise_pattern_XXfallback = {
private static final short[] noise_pattern_XXfallback = {
FLAG_LOCAL_STATIC |
FLAG_LOCAL_EPHEMERAL |
FLAG_REMOTE_STATIC |
@ -273,7 +279,7 @@ class Pattern {
ES
};
private static final byte[] noise_pattern_Xnoidh = {
private static final short[] noise_pattern_Xnoidh = {
FLAG_LOCAL_STATIC |
FLAG_LOCAL_EPHEMERAL |
FLAG_REMOTE_STATIC |
@ -285,7 +291,7 @@ class Pattern {
SS
};
private static final byte[] noise_pattern_NXnoidh = {
private static final short[] noise_pattern_NXnoidh = {
FLAG_LOCAL_EPHEMERAL |
FLAG_REMOTE_STATIC |
FLAG_REMOTE_EPHEMERAL,
@ -298,7 +304,7 @@ class Pattern {
ES
};
private static final byte[] noise_pattern_XXnoidh = {
private static final short[] noise_pattern_XXnoidh = {
FLAG_LOCAL_STATIC |
FLAG_LOCAL_EPHEMERAL |
FLAG_REMOTE_STATIC |
@ -315,7 +321,7 @@ class Pattern {
SE
};
private static final byte[] noise_pattern_KXnoidh = {
private static final short[] noise_pattern_KXnoidh = {
FLAG_LOCAL_STATIC |
FLAG_LOCAL_EPHEMERAL |
FLAG_LOCAL_REQUIRED |
@ -331,7 +337,7 @@ class Pattern {
ES
};
private static final byte[] noise_pattern_IKnoidh = {
private static final short[] noise_pattern_IKnoidh = {
FLAG_LOCAL_STATIC |
FLAG_LOCAL_EPHEMERAL |
FLAG_REMOTE_STATIC |
@ -348,7 +354,7 @@ class Pattern {
SE
};
private static final byte[] noise_pattern_IXnoidh = {
private static final short[] noise_pattern_IXnoidh = {
FLAG_LOCAL_STATIC |
FLAG_LOCAL_EPHEMERAL |
FLAG_REMOTE_STATIC |
@ -364,13 +370,374 @@ class Pattern {
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.
*
* @param name The name of the pattern.
* @return The pattern description or null.
*/
public static byte[] lookup(String name)
public static short[] lookup(String name)
{
if (name.equals("N"))
return noise_pattern_N;
@ -416,6 +783,42 @@ class Pattern {
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;
}
@ -425,8 +828,8 @@ class Pattern {
* @param flags The flags, assuming that the initiator is "local".
* @return The reversed flags, with the responder now being "local".
*/
public static byte reverseFlags(byte flags)
public static short reverseFlags(short flags)
{
return (byte)(((flags >> 4) & 0x0F) | ((flags << 4) & 0xF0));
return (short)(((flags >> 8) & 0x00FF) | ((flags << 8) & 0xFF00));
}
}

View File

@ -73,17 +73,20 @@ public class VectorTests {
public String name;
public String pattern;
public String dh;
public String hybrid;
public String cipher;
public String hash;
public String fallback_pattern;
public byte[] init_prologue;
public byte[] init_ephemeral;
public byte[] init_hybrid;
public byte[] init_static;
public byte[] init_remote_static;
public byte[] init_psk;
public byte[] init_ssk;
public byte[] resp_prologue;
public byte[] resp_ephemeral;
public byte[] resp_hybrid;
public byte[] resp_static;
public byte[] resp_remote_static;
public byte[] resp_psk;
@ -130,6 +133,8 @@ public class VectorTests {
initiator.getLocalKeyPair().setPrivateKey(vec.init_static, 0);
if (vec.init_remote_static != null)
initiator.getRemotePublicKey().setPublicKey(vec.init_remote_static, 0);
if (vec.init_hybrid != null)
initiator.getFixedHybridKey().setPrivateKey(vec.init_hybrid, 0);
if (vec.init_ephemeral != null)
initiator.getFixedEphemeralKey().setPrivateKey(vec.init_ephemeral, 0);
if (vec.init_psk != null)
@ -146,6 +151,8 @@ public class VectorTests {
if (vec.pattern.length() != 1)
responder.getFixedEphemeralKey().setPrivateKey(vec.resp_ephemeral, 0);
}
if (vec.resp_hybrid != null)
responder.getFixedHybridKey().setPrivateKey(vec.resp_hybrid, 0);
if (vec.resp_psk != null)
responder.setPreSharedKey(vec.resp_psk, 0, vec.resp_psk.length);
@ -299,6 +306,8 @@ public class VectorTests {
vec.pattern = reader.nextString();
else if (name.equals("dh"))
vec.dh = reader.nextString();
else if (name.equals("hybrid"))
vec.hybrid = reader.nextString();
else if (name.equals("cipher"))
vec.cipher = reader.nextString();
else if (name.equals("hash"))
@ -309,6 +318,8 @@ public class VectorTests {
vec.init_prologue = DatatypeConverter.parseHexBinary(reader.nextString());
else if (name.equals("init_ephemeral"))
vec.init_ephemeral = DatatypeConverter.parseHexBinary(reader.nextString());
else if (name.equals("init_hybrid_ephemeral"))
vec.init_hybrid = DatatypeConverter.parseHexBinary(reader.nextString());
else if (name.equals("init_static"))
vec.init_static = DatatypeConverter.parseHexBinary(reader.nextString());
else if (name.equals("init_remote_static"))
@ -321,6 +332,8 @@ public class VectorTests {
vec.resp_prologue = DatatypeConverter.parseHexBinary(reader.nextString());
else if (name.equals("resp_ephemeral"))
vec.resp_ephemeral = DatatypeConverter.parseHexBinary(reader.nextString());
else if (name.equals("resp_hybrid_ephemeral"))
vec.resp_hybrid = DatatypeConverter.parseHexBinary(reader.nextString());
else if (name.equals("resp_static"))
vec.resp_static = DatatypeConverter.parseHexBinary(reader.nextString());
else if (name.equals("resp_remote_static"))
@ -362,7 +375,10 @@ public class VectorTests {
String protocolName = "Noise";
if (vec.init_psk != null || vec.resp_psk != null)
protocolName += "PSK";
protocolName += "_" + vec.pattern + "_" + vec.dh + "_" + vec.cipher + "_" + vec.hash;
String dh = vec.dh;
if (vec.hybrid != null)
dh = dh + "+" + vec.hybrid;
protocolName += "_" + vec.pattern + "_" + dh + "_" + vec.cipher + "_" + vec.hash;
if (vec.name == null)
vec.name = protocolName;