commit d63d9d56a0da3a51aa7ec599635ec8a02ab0c8cb
Author: George Kadianakis <desnacked(a)gmail.com>
Date: Wed May 25 02:13:37 2011 +0200
Implemented iterated hashing and updated the protocol spec.
---
doc/protocol-spec.txt | 28 ++++++++++++++++++----------
src/protocols/obfs2.c | 21 ++++++++++++++++++++-
src/protocols/obfs2.h | 1 +
3 files changed, 39 insertions(+), 11 deletions(-)
diff --git a/doc/protocol-spec.txt b/doc/protocol-spec.txt
index 9a7d4fa..0f9edf9 100644
--- a/doc/protocol-spec.txt
+++ b/doc/protocol-spec.txt
@@ -27,9 +27,10 @@ The Twobfuscator
s[:n] is the first n bytes of s.
s[n:] is the last n bytes of s.
- MAGIC_VALUE is 0x2BF5CA7E
- SEED_LENGTH is 16
- MAX_PADDING is 8192
+ MAGIC_VALUE is 0x2BF5CA7E
+ SEED_LENGTH is 16
+ MAX_PADDING is 8192
+ HASH_ITERATIONS is 100000
KEYLEN is the length of the key used by E_K(s) -- that is, 16.
IVLEN is the length of the IV used by E_K(s) -- that is, 16
@@ -38,6 +39,9 @@ The Twobfuscator
MAC(s, x) = H(s | x | s)
+ Let n = HASH_ITERATIONS through section '2. Key establishment phase.'.
+ Then, H^n(x) is H(x) called iteratively n times.
+
A "byte" is an 8-bit octet.
We require that HASHLEN >= KEYLEN + IVLEN
@@ -49,12 +53,14 @@ The Twobfuscator
a padding key as follows. The initiator generates:
INIT_SEED = SR(SEED_LENGTH)
- INIT_PAD_KEY = MAC("Initiator obfuscation padding", INIT_SEED)[:KEYLEN]
+ INIT_PAD_TEMP = MAC("Initiator obfuscation padding", INIT_SEED)[:KEYLEN]
+ INIT_PAD_KEY = H^n(INIT_PAD_TEMP)
And the responder generates:
RESP_SEED = SR(SEED_LENGTH)
- RESP_PAD_KEY = MAC("Responder obfuscation padding", INIT_SEED)[:KEYLEN]
+ RESP_PAD_TEMP = MAC("Responder obfuscation padding", INIT_SEED)[:KEYLEN]
+ RESP_PAD_KEY = H^n(RESP_PAD_TEMP)
Each then generates a random number PADLEN in range from 0 through
MAX_PADDING (inclusive), and sends:
@@ -73,10 +79,12 @@ The Twobfuscator
INIT_SECRET = MAC("Initiator obfuscated data", INIT_SEED|RESP_SEED)
RESP_SECRET = MAC("Responder obfuscated data", INIT_SEED|RESP_SEED)
- INIT_KEY = INIT_SECRET[:KEYLEN]
- INIT_IV = INIT_SECRET[KEYLEN:]
- RESP_KEY = RESP_SECRET[:KEYLEN]
- RESP_IV = RESP_SECRET[KEYLEN:]
+ INIT_MASTER_KEY = H^n(INIT_SECRET)
+ RESP_MASTER_KEY = H^n(RESP_SECRET)
+ INIT_KEY = INIT_MASTER_KEY[:KEYLEN]
+ INIT_IV = INIT_MASTER_KEY[KEYLEN:]
+ RESP_KEY = RESP_MASTER_KEY[:KEYLEN]
+ RESP_IV = RESP_MASTER_KEY[KEYLEN:]
The INIT_KEY value keys a stream cipher used to encrypt values from
initiator to responder thereafter. The stream cipher's IV is
@@ -89,5 +97,5 @@ The Twobfuscator
Optionally, if the client and server share a secret value SECRET,
they can replace the MAC function with:
- MAC(s,x) = MAC(s | x | SECRET | s)
+ MAC(s,x) = H(s | x | SECRET | s)
diff --git a/src/protocols/obfs2.c b/src/protocols/obfs2.c
index 3490d0e..6221bb2 100644
--- a/src/protocols/obfs2.c
+++ b/src/protocols/obfs2.c
@@ -72,10 +72,12 @@ static crypt_t *
derive_key(void *s, const char *keytype)
{
obfs2_state_t *state = s;
-
crypt_t *cryptstate;
uchar buf[SHA256_LENGTH];
digest_t *c = digest_new();
+ digest_t *d;
+ int i;
+
digest_update(c, (uchar*)keytype, strlen(keytype));
if (seed_nonzero(state->initiator_seed))
digest_update(c, state->initiator_seed, OBFUSCATE_SEED_LENGTH);
@@ -85,6 +87,13 @@ derive_key(void *s, const char *keytype)
digest_update(c, state->secret_seed, SHARED_SECRET_LENGTH);
digest_update(c, (uchar*)keytype, strlen(keytype));
digest_getdigest(c, buf, sizeof(buf));
+
+ for (i=0; i < OBFUSCATE_HASH_ITERATIONS; i++) {
+ d = digest_new();
+ digest_update(d, buf, sizeof(buf));
+ digest_getdigest(d, buf, sizeof(buf));
+ }
+
cryptstate = crypt_new(buf, 16);
crypt_set_iv(cryptstate, buf+16, 16);
memset(buf, 0, sizeof(buf));
@@ -101,6 +110,9 @@ derive_padding_key(void *s, const uchar *seed,
crypt_t *cryptstate;
uchar buf[SHA256_LENGTH];
digest_t *c = digest_new();
+ digest_t *d;
+ int i;
+
digest_update(c, (uchar*)keytype, strlen(keytype));
if (seed_nonzero(seed))
digest_update(c, seed, OBFUSCATE_SEED_LENGTH);
@@ -108,6 +120,13 @@ derive_padding_key(void *s, const uchar *seed,
digest_update(c, state->secret_seed, OBFUSCATE_SEED_LENGTH);
digest_update(c, (uchar*)keytype, strlen(keytype));
digest_getdigest(c, buf, sizeof(buf));
+
+ for (i=0; i < OBFUSCATE_HASH_ITERATIONS; i++) {
+ d = digest_new();
+ digest_update(d, buf, sizeof(buf));
+ digest_getdigest(d, buf, sizeof(buf));
+ }
+
cryptstate = crypt_new(buf, 16);
crypt_set_iv(cryptstate, buf+16, 16);
memset(buf, 0, 16);
diff --git a/src/protocols/obfs2.h b/src/protocols/obfs2.h
index 1f9f31d..0d70144 100644
--- a/src/protocols/obfs2.h
+++ b/src/protocols/obfs2.h
@@ -36,6 +36,7 @@ void *obfs2_new(struct protocol_t *proto_struct,
#define OBFUSCATE_SEED_LENGTH 16
#define OBFUSCATE_MAX_PADDING 8192
#define OBFUSCATE_ZERO_SEED "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
+#define OBFUSCATE_HASH_ITERATIONS 100000
#define INITIATOR_PAD_TYPE "Initiator obfuscation padding"
#define RESPONDER_PAD_TYPE "Responder obfuscation padding"