diff options
author | Martin Willi <martin@strongswan.org> | 2008-05-08 14:51:37 +0000 |
---|---|---|
committer | Martin Willi <martin@strongswan.org> | 2008-05-08 14:51:37 +0000 |
commit | 0f074a4344f002fa3f1440fbcdfc5b28ce0b5afb (patch) | |
tree | 019d9b9fe1f38e4f1f42f84e6eb9dd8107beb5ae | |
parent | affd7a90bade50f5194ef730ecf3a7810cecac5a (diff) | |
download | strongswan-0f074a4344f002fa3f1440fbcdfc5b28ce0b5afb.tar.bz2 strongswan-0f074a4344f002fa3f1440fbcdfc5b28ce0b5afb.tar.xz |
implemented append mode for xcbc, testcase
-rw-r--r-- | src/charon/plugins/unit_tester/tests/test_aes.c | 61 | ||||
-rw-r--r-- | src/libstrongswan/plugins/xcbc/xcbc.c | 138 |
2 files changed, 163 insertions, 36 deletions
diff --git a/src/charon/plugins/unit_tester/tests/test_aes.c b/src/charon/plugins/unit_tester/tests/test_aes.c index 5b69dc25d..06e891d83 100644 --- a/src/charon/plugins/unit_tester/tests/test_aes.c +++ b/src/charon/plugins/unit_tester/tests/test_aes.c @@ -178,7 +178,7 @@ static bool do_xcbc_test(u_int8_t *key, size_t keylen, u_int8_t *mac, prf_t *prf; u_int8_t res[16]; - prf = lib->crypto->create_prf(lib->crypto, PRF_AES128_CBC); + prf = lib->crypto->create_prf(lib->crypto, PRF_AES128_XCBC); if (!prf) { return FALSE; @@ -403,6 +403,65 @@ bool test_aes_xcbc() { return FALSE; } + + + /* Test Case #10 : AES-XCBC-MAC-96 with 32-byte input using append mode + * Key (K) : 000102030405060708090a0b0c0d0e0f + * Message (M) : 000102030405060708090a0b0c0d0e0f10111213141516171819 + * 1a1b1c1d1e1f + * AES-XCBC-MAC : f54f0ec8d2b9f3d36807734bd5283fd4 + * AES-XCBC-MAC-96: f54f0ec8d2b9f3d36807734b + */ + u_char key10[] = { + 0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07, + 0x08,0x09,0x0a,0x0b,0x0c,0x0d,0x0e,0x0f + }; + u_char plain10[] = { + 0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07, + 0x08,0x09,0x0a,0x0b,0x0c,0x0d,0x0e,0x0f, + 0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17, + 0x18,0x19,0x1a,0x1b,0x1c,0x1d,0x1e,0x1f + }; + u_char mac10[] = { + 0xf5,0x4f,0x0e,0xc8,0xd2,0xb9,0xf3,0xd3, + 0x68,0x07,0x73,0x4b,0xd5,0x28,0x3f,0xd4 + }; + int i; + prf_t *prf = lib->crypto->create_prf(lib->crypto, PRF_AES128_XCBC); + u_char res[16]; + if (!prf) + { + return FALSE; + } + prf->set_key(prf, chunk_create(key10, sizeof(key10))); + for (i = 0; i < 4; i++) + { /* bytes 0 - 3, 1 byte at once */ + prf->get_bytes(prf, chunk_create(plain10 + i, 1), NULL); + } + for (i = 4; i < 5; i+=8) + { /* bytes 4 - 11, at once */ + prf->get_bytes(prf, chunk_create(plain10 + i, 8), NULL); + } + for (i = 12; i < 24; i+=4) + { /* bytes 12 - 23, in blocks of 4 */ + prf->get_bytes(prf, chunk_create(plain10 + i, 4), NULL); + } + for (i = 0; i < 4; i++) + { /* 4 zero blobs */ + prf->get_bytes(prf, chunk_create(NULL, 0), NULL); + } + for (i = 24; i < 25; i+=8) + { /* bytes 24 - 32, at once */ + prf->get_bytes(prf, chunk_create(plain10 + i, 8), res); + } + if (!memeq(res, mac10, 16)) + { + DBG1(DBG_CFG, "expected %b\ngot %b", mac10, 16, res, 16); + prf->destroy(prf); + return FALSE; + } + prf->destroy(prf); + return TRUE; } diff --git a/src/libstrongswan/plugins/xcbc/xcbc.c b/src/libstrongswan/plugins/xcbc/xcbc.c index dc1398950..ab37eca40 100644 --- a/src/libstrongswan/plugins/xcbc/xcbc.c +++ b/src/libstrongswan/plugins/xcbc/xcbc.c @@ -53,57 +53,96 @@ struct private_xcbc_t { * k3 */ u_int8_t *k3; + + /** + * E + */ + u_int8_t *e; + + /** + * remaining, unprocessed bytes in append mode + */ + u_int8_t *remaining; + + /** + * number of bytes in remaining + */ + int remaining_bytes; + + /** + * TRUE if we have zero bytes to xcbc in final() + */ + bool zero; }; /** - * Implementation of xcbc_t.get_mac. + * xcbc supplied data, but do not run final operation */ -static void get_mac(private_xcbc_t *this, chunk_t data, u_int8_t *e) +static void update(private_xcbc_t *this, chunk_t data) { - int n, i, padding; - u_int8_t *m; chunk_t iv; - if (e == NULL) + if (data.len) { - DBG1("XCBC append mode not implemented!"); - /* TODO: append mode */ - return; + this->zero = FALSE; } - n = data.len / this->b; - padding = data.len % this->b; - if (padding || data.len == 0) - { /* do an additional block if we have padding or zero-length data */ - n++; + if (this->remaining_bytes + data.len <= this->b) + { /* no complete block, just copy into remaining */ + memcpy(this->remaining + this->remaining_bytes, data.ptr, data.len); + this->remaining_bytes += data.len; + return; } + iv = chunk_alloca(this->b); memset(iv.ptr, 0, iv.len); - m = data.ptr; - - /* (2) Define E[0] = 0x00000000000000000000000000000000 */ - memset(e, 0, this->b); /* (3) For each block M[i], where i = 1 ... n-1: - * XOR M[i] with E[i-1], then encrypt the result with Key K1, - * yielding E[i]. - */ - for (i = 1; i < n; i++) + * XOR M[i] with E[i-1], then encrypt the result with Key K1, + * yielding E[i]. + */ + + /* append data to remaining bytes, process block M[1] */ + memcpy(this->remaining + this->remaining_bytes, data.ptr, + this->b - this->remaining_bytes); + data = chunk_skip(data, this->b - this->remaining_bytes); + memxor(this->e, this->remaining, this->b); + this->k1->encrypt(this->k1, chunk_create(this->e, this->b), iv, NULL); + + /* process blocks M[2] ... M[n-1] */ + while (data.len > this->b) { - memxor(e, m + (i - 1) * this->b, this->b); - this->k1->encrypt(this->k1, chunk_create(e, this->b), iv, NULL); + memcpy(this->remaining, data.ptr, this->b); + data = chunk_skip(data, this->b); + memxor(this->e, this->remaining, this->b); + this->k1->encrypt(this->k1, chunk_create(this->e, this->b), iv, NULL); } + /* store remaining bytes of block M[n] */ + memcpy(this->remaining, data.ptr, data.len); + this->remaining_bytes = data.len; +} + +/** + * run last round, data is in this->e + */ +static void final(private_xcbc_t *this, u_int8_t *out) +{ + chunk_t iv; + + iv = chunk_alloca(this->b); + memset(iv.ptr, 0, iv.len); + /* (4) For block M[n]: */ - if (data.len && padding == 0) + if (this->remaining_bytes == this->b && !this->zero) { /* a) If the blocksize of M[n] is 128 bits: * XOR M[n] with E[n-1] and Key K2, then encrypt the result with * Key K1, yielding E[n]. */ - memxor(e, m + (i - 1) * this->b, this->b); - memxor(e, this->k2, this->b); - this->k1->encrypt(this->k1, chunk_create(e, this->b), iv, NULL); + memxor(this->e, this->remaining, this->b); + memxor(this->e, this->k2, this->b); + this->k1->encrypt(this->k1, chunk_create(this->e, this->b), iv, NULL); } else { @@ -113,19 +152,41 @@ static void get_mac(private_xcbc_t *this, chunk_t data, u_int8_t *e) * "0" bits (possibly none) required to increase M[n]'s * blocksize to 128 bits. */ - u_int8_t *mn = alloca(this->b); - memcpy(mn, m + (n - 1) * this->b, padding); - mn[padding] = 0x80; - while (++padding < this->b) + if (this->remaining_bytes < this->b) { - mn[padding] = 0x00; + this->remaining[this->remaining_bytes] = 0x80; + while (++this->remaining_bytes < this->b) + { + this->remaining[this->remaining_bytes] = 0x00; + } } /* ii) XOR M[n] with E[n-1] and Key K3, then encrypt the result * with Key K1, yielding E[n]. */ - memxor(e, mn, this->b); - memxor(e, this->k3, this->b); - this->k1->encrypt(this->k1, chunk_create(e, this->b), iv, NULL); + memxor(this->e, this->remaining, this->b); + memxor(this->e, this->k3, this->b); + this->k1->encrypt(this->k1, chunk_create(this->e, this->b), iv, NULL); + } + + memcpy(out, this->e, this->b); + + /* (2) Define E[0] = 0x00000000000000000000000000000000 */ + memset(this->e, 0, this->b); + this->remaining_bytes = 0; + this->zero = TRUE; +} + +/** + * Implementation of xcbc_t.get_mac. + */ +static void get_mac(private_xcbc_t *this, chunk_t data, u_int8_t *out) +{ + /* update E, do not process last block */ + update(this, data); + + if (out) + { /* if not in append mode, process last block and output result */ + final(this, out); } } @@ -192,6 +253,8 @@ static void destroy(private_xcbc_t *this) this->k1->destroy(this->k1); free(this->k2); free(this->k3); + free(this->e); + free(this->remaining); free(this); } @@ -225,6 +288,11 @@ xcbc_t *xcbc_create(encryption_algorithm_t algo, size_t key_size) this->k1 = crypter; this->k2 = malloc(this->b); this->k3 = malloc(this->b); + this->e = malloc(this->b); + memset(this->e, 0, this->b); + this->remaining = malloc(this->b); + this->remaining_bytes = 0; + this->zero = TRUE; return &this->xcbc; } |