From 683b9b23152dbec511540c75e1f41c4d7b60a306 Mon Sep 17 00:00:00 2001 From: Rhys Weatherley Date: Sat, 8 Oct 2016 19:28:53 +1000 Subject: [PATCH] Add support for hybrid forward secrecy --- .../noise/protocol/HandshakeState.java | 131 ++++- .../southernstorm/noise/protocol/Pattern.java | 483 ++++++++++++++++-- .../noise/tests/VectorTests.java | 18 +- 3 files changed, 584 insertions(+), 48 deletions(-) diff --git a/NoiseJava/src/com/southernstorm/noise/protocol/HandshakeState.java b/NoiseJava/src/com/southernstorm/noise/protocol/HandshakeState.java index b1f6c98..ac3d3ba 100644 --- a/NoiseJava/src/com/southernstorm/noise/protocol/HandshakeState.java +++ b/NoiseJava/src/com/southernstorm/noise/protocol/HandshakeState.java @@ -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) { diff --git a/NoiseJava/src/com/southernstorm/noise/protocol/Pattern.java b/NoiseJava/src/com/southernstorm/noise/protocol/Pattern.java index eb9fa6a..157af6a 100644 --- a/NoiseJava/src/com/southernstorm/noise/protocol/Pattern.java +++ b/NoiseJava/src/com/southernstorm/noise/protocol/Pattern.java @@ -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)); } } diff --git a/NoiseJavaTests/src/com/southernstorm/noise/tests/VectorTests.java b/NoiseJavaTests/src/com/southernstorm/noise/tests/VectorTests.java index 323d75c..2dd50c8 100644 --- a/NoiseJavaTests/src/com/southernstorm/noise/tests/VectorTests.java +++ b/NoiseJavaTests/src/com/southernstorm/noise/tests/VectorTests.java @@ -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;