diff options
Diffstat (limited to 'netwerk/srtp/src/crypto/hash')
-rw-r--r-- | netwerk/srtp/src/crypto/hash/auth.c | 183 | ||||
-rw-r--r-- | netwerk/srtp/src/crypto/hash/hmac.c | 268 | ||||
-rw-r--r-- | netwerk/srtp/src/crypto/hash/null_auth.c | 162 | ||||
-rw-r--r-- | netwerk/srtp/src/crypto/hash/sha1.c | 405 |
4 files changed, 1018 insertions, 0 deletions
diff --git a/netwerk/srtp/src/crypto/hash/auth.c b/netwerk/srtp/src/crypto/hash/auth.c new file mode 100644 index 000000000..aaf0269c7 --- /dev/null +++ b/netwerk/srtp/src/crypto/hash/auth.c @@ -0,0 +1,183 @@ +/* + * auth.c + * + * some bookkeeping functions for authentication functions + * + * David A. McGrew + * Cisco Systems, Inc. + */ + +/* + * + * Copyright (c) 2001-2006, Cisco Systems, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided + * with the distribution. + * + * Neither the name of the Cisco Systems, Inc. nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#include "auth.h" + +/* the debug module for authentiation */ + +debug_module_t mod_auth = { + 0, /* debugging is off by default */ + "auth func" /* printable name for module */ +}; + + +int +auth_get_key_length(const auth_t *a) { + return a->key_len; +} + +int +auth_get_tag_length(const auth_t *a) { + return a->out_len; +} + +int +auth_get_prefix_length(const auth_t *a) { + return a->prefix_len; +} + +int +auth_type_get_ref_count(const auth_type_t *at) { + return at->ref_count; +} + +/* + * auth_type_test() tests an auth function of type ct against + * test cases provided in a list test_data of values of key, data, and tag + * that is known to be good + */ + +/* should be big enough for most occasions */ +#define SELF_TEST_TAG_BUF_OCTETS 32 + +err_status_t +auth_type_test(const auth_type_t *at, const auth_test_case_t *test_data) { + const auth_test_case_t *test_case = test_data; + auth_t *a; + err_status_t status; + uint8_t tag[SELF_TEST_TAG_BUF_OCTETS]; + int i, case_num = 0; + + debug_print(mod_auth, "running self-test for auth function %s", + at->description); + + /* + * check to make sure that we have at least one test case, and + * return an error if we don't - we need to be paranoid here + */ + if (test_case == NULL) + return err_status_cant_check; + + /* loop over all test cases */ + while (test_case != NULL) { + + /* check test case parameters */ + if (test_case->tag_length_octets > SELF_TEST_TAG_BUF_OCTETS) + return err_status_bad_param; + + /* allocate auth */ + status = auth_type_alloc(at, &a, test_case->key_length_octets, + test_case->tag_length_octets); + if (status) + return status; + + /* initialize auth */ + status = auth_init(a, test_case->key); + if (status) { + auth_dealloc(a); + return status; + } + + /* zeroize tag then compute */ + octet_string_set_to_zero(tag, test_case->tag_length_octets); + status = auth_compute(a, test_case->data, + test_case->data_length_octets, tag); + if (status) { + auth_dealloc(a); + return status; + } + + debug_print(mod_auth, "key: %s", + octet_string_hex_string(test_case->key, + test_case->key_length_octets)); + debug_print(mod_auth, "data: %s", + octet_string_hex_string(test_case->data, + test_case->data_length_octets)); + debug_print(mod_auth, "tag computed: %s", + octet_string_hex_string(tag, test_case->tag_length_octets)); + debug_print(mod_auth, "tag expected: %s", + octet_string_hex_string(test_case->tag, + test_case->tag_length_octets)); + + /* check the result */ + status = err_status_ok; + for (i=0; i < test_case->tag_length_octets; i++) + if (tag[i] != test_case->tag[i]) { + status = err_status_algo_fail; + debug_print(mod_auth, "test case %d failed", case_num); + debug_print(mod_auth, " (mismatch at octet %d)", i); + } + if (status) { + auth_dealloc(a); + return err_status_algo_fail; + } + + /* deallocate the auth function */ + status = auth_dealloc(a); + if (status) + return status; + + /* + * the auth function passed the test case, so move on to the next test + * case in the list; if NULL, we'll quit and return an OK + */ + test_case = test_case->next_test_case; + ++case_num; + } + + return err_status_ok; +} + + +/* + * auth_type_self_test(at) performs auth_type_test on at's internal + * list of test data. + */ + +err_status_t +auth_type_self_test(const auth_type_t *at) { + return auth_type_test(at, at->test_data); +} + diff --git a/netwerk/srtp/src/crypto/hash/hmac.c b/netwerk/srtp/src/crypto/hash/hmac.c new file mode 100644 index 000000000..4f389fe18 --- /dev/null +++ b/netwerk/srtp/src/crypto/hash/hmac.c @@ -0,0 +1,268 @@ +/* + * hmac.c + * + * implementation of hmac auth_type_t + * + * David A. McGrew + * Cisco Systems, Inc. + */ +/* + * + * Copyright(c) 2001-2006 Cisco Systems, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided + * with the distribution. + * + * Neither the name of the Cisco Systems, Inc. nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#include "hmac.h" +#include "alloc.h" + +/* the debug module for authentiation */ + +debug_module_t mod_hmac = { + 0, /* debugging is off by default */ + "hmac sha-1" /* printable name for module */ +}; + + +err_status_t +hmac_alloc(auth_t **a, int key_len, int out_len) { + extern auth_type_t hmac; + uint8_t *pointer; + + debug_print(mod_hmac, "allocating auth func with key length %d", key_len); + debug_print(mod_hmac, " tag length %d", out_len); + + /* + * check key length - note that we don't support keys larger + * than 20 bytes yet + */ + if (key_len > 20) + return err_status_bad_param; + + /* check output length - should be less than 20 bytes */ + if (out_len > 20) + return err_status_bad_param; + + /* allocate memory for auth and hmac_ctx_t structures */ + pointer = (uint8_t*)crypto_alloc(sizeof(hmac_ctx_t) + sizeof(auth_t)); + if (pointer == NULL) + return err_status_alloc_fail; + + /* set pointers */ + *a = (auth_t *)pointer; + (*a)->type = &hmac; + (*a)->state = pointer + sizeof(auth_t); + (*a)->out_len = out_len; + (*a)->key_len = key_len; + (*a)->prefix_len = 0; + + /* increment global count of all hmac uses */ + hmac.ref_count++; + + return err_status_ok; +} + +err_status_t +hmac_dealloc(auth_t *a) { + extern auth_type_t hmac; + + /* zeroize entire state*/ + octet_string_set_to_zero((uint8_t *)a, + sizeof(hmac_ctx_t) + sizeof(auth_t)); + + /* free memory */ + crypto_free(a); + + /* decrement global count of all hmac uses */ + hmac.ref_count--; + + return err_status_ok; +} + +err_status_t +hmac_init(hmac_ctx_t *state, const uint8_t *key, int key_len) { + int i; + uint8_t ipad[64]; + + /* + * check key length - note that we don't support keys larger + * than 20 bytes yet + */ + if (key_len > 20) + return err_status_bad_param; + + /* + * set values of ipad and opad by exoring the key into the + * appropriate constant values + */ + for (i=0; i < key_len; i++) { + ipad[i] = key[i] ^ 0x36; + state->opad[i] = key[i] ^ 0x5c; + } + /* set the rest of ipad, opad to constant values */ + for ( ; i < 64; i++) { + ipad[i] = 0x36; + ((uint8_t *)state->opad)[i] = 0x5c; + } + + debug_print(mod_hmac, "ipad: %s", octet_string_hex_string(ipad, 64)); + + /* initialize sha1 context */ + sha1_init(&state->init_ctx); + + /* hash ipad ^ key */ + sha1_update(&state->init_ctx, ipad, 64); + memcpy(&state->ctx, &state->init_ctx, sizeof(sha1_ctx_t)); + + return err_status_ok; +} + +err_status_t +hmac_start(hmac_ctx_t *state) { + + memcpy(&state->ctx, &state->init_ctx, sizeof(sha1_ctx_t)); + + return err_status_ok; +} + +err_status_t +hmac_update(hmac_ctx_t *state, const uint8_t *message, int msg_octets) { + + debug_print(mod_hmac, "input: %s", + octet_string_hex_string(message, msg_octets)); + + /* hash message into sha1 context */ + sha1_update(&state->ctx, message, msg_octets); + + return err_status_ok; +} + +err_status_t +hmac_compute(hmac_ctx_t *state, const void *message, + int msg_octets, int tag_len, uint8_t *result) { + uint32_t hash_value[5]; + uint32_t H[5]; + int i; + + /* check tag length, return error if we can't provide the value expected */ + if (tag_len > 20) + return err_status_bad_param; + + /* hash message, copy output into H */ + hmac_update(state, (const uint8_t*)message, msg_octets); + sha1_final(&state->ctx, H); + + /* + * note that we don't need to debug_print() the input, since the + * function hmac_update() already did that for us + */ + debug_print(mod_hmac, "intermediate state: %s", + octet_string_hex_string((uint8_t *)H, 20)); + + /* re-initialize hash context */ + sha1_init(&state->ctx); + + /* hash opad ^ key */ + sha1_update(&state->ctx, (uint8_t *)state->opad, 64); + + /* hash the result of the inner hash */ + sha1_update(&state->ctx, (uint8_t *)H, 20); + + /* the result is returned in the array hash_value[] */ + sha1_final(&state->ctx, hash_value); + + /* copy hash_value to *result */ + for (i=0; i < tag_len; i++) + result[i] = ((uint8_t *)hash_value)[i]; + + debug_print(mod_hmac, "output: %s", + octet_string_hex_string((uint8_t *)hash_value, tag_len)); + + return err_status_ok; +} + + +/* begin test case 0 */ + +uint8_t +hmac_test_case_0_key[20] = { + 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, + 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, + 0x0b, 0x0b, 0x0b, 0x0b +}; + +uint8_t +hmac_test_case_0_data[8] = { + 0x48, 0x69, 0x20, 0x54, 0x68, 0x65, 0x72, 0x65 /* "Hi There" */ +}; + +uint8_t +hmac_test_case_0_tag[20] = { + 0xb6, 0x17, 0x31, 0x86, 0x55, 0x05, 0x72, 0x64, + 0xe2, 0x8b, 0xc0, 0xb6, 0xfb, 0x37, 0x8c, 0x8e, + 0xf1, 0x46, 0xbe, 0x00 +}; + +auth_test_case_t +hmac_test_case_0 = { + 20, /* octets in key */ + hmac_test_case_0_key, /* key */ + 8, /* octets in data */ + hmac_test_case_0_data, /* data */ + 20, /* octets in tag */ + hmac_test_case_0_tag, /* tag */ + NULL /* pointer to next testcase */ +}; + +/* end test case 0 */ + +char hmac_description[] = "hmac sha-1 authentication function"; + +/* + * auth_type_t hmac is the hmac metaobject + */ + +auth_type_t +hmac = { + (auth_alloc_func) hmac_alloc, + (auth_dealloc_func) hmac_dealloc, + (auth_init_func) hmac_init, + (auth_compute_func) hmac_compute, + (auth_update_func) hmac_update, + (auth_start_func) hmac_start, + (char *) hmac_description, + (int) 0, /* instance count */ + (auth_test_case_t *) &hmac_test_case_0, + (debug_module_t *) &mod_hmac, + (auth_type_id_t) HMAC_SHA1 +}; + diff --git a/netwerk/srtp/src/crypto/hash/null_auth.c b/netwerk/srtp/src/crypto/hash/null_auth.c new file mode 100644 index 000000000..103444bc5 --- /dev/null +++ b/netwerk/srtp/src/crypto/hash/null_auth.c @@ -0,0 +1,162 @@ +/* + * null_auth.c + * + * implements the do-nothing auth algorithm + * + * David A. McGrew + * Cisco Systems, Inc. + * + */ + +/* + * + * Copyright (c) 2001-2006, Cisco Systems, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided + * with the distribution. + * + * Neither the name of the Cisco Systems, Inc. nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + + +#include "null_auth.h" +#include "alloc.h" + +/* null_auth uses the auth debug module */ + +extern debug_module_t mod_auth; + +err_status_t +null_auth_alloc(auth_t **a, int key_len, int out_len) { + extern auth_type_t null_auth; + uint8_t *pointer; + + debug_print(mod_auth, "allocating auth func with key length %d", key_len); + debug_print(mod_auth, " tag length %d", out_len); + + /* allocate memory for auth and null_auth_ctx_t structures */ + pointer = (uint8_t*)crypto_alloc(sizeof(null_auth_ctx_t) + sizeof(auth_t)); + if (pointer == NULL) + return err_status_alloc_fail; + + /* set pointers */ + *a = (auth_t *)pointer; + (*a)->type = &null_auth; + (*a)->state = pointer + sizeof (auth_t); + (*a)->out_len = out_len; + (*a)->prefix_len = out_len; + (*a)->key_len = key_len; + + /* increment global count of all null_auth uses */ + null_auth.ref_count++; + + return err_status_ok; +} + +err_status_t +null_auth_dealloc(auth_t *a) { + extern auth_type_t null_auth; + + /* zeroize entire state*/ + octet_string_set_to_zero((uint8_t *)a, + sizeof(null_auth_ctx_t) + sizeof(auth_t)); + + /* free memory */ + crypto_free(a); + + /* decrement global count of all null_auth uses */ + null_auth.ref_count--; + + return err_status_ok; +} + +err_status_t +null_auth_init(null_auth_ctx_t *state, const uint8_t *key, int key_len) { + + /* accept any length of key, and do nothing */ + + return err_status_ok; +} + +err_status_t +null_auth_compute(null_auth_ctx_t *state, uint8_t *message, + int msg_octets, int tag_len, uint8_t *result) { + + return err_status_ok; +} + +err_status_t +null_auth_update(null_auth_ctx_t *state, uint8_t *message, + int msg_octets) { + + return err_status_ok; +} + +err_status_t +null_auth_start(null_auth_ctx_t *state) { + return err_status_ok; +} + +/* + * auth_type_t - defines description, test case, and null_auth + * metaobject + */ + +/* begin test case 0 */ + +auth_test_case_t +null_auth_test_case_0 = { + 0, /* octets in key */ + NULL, /* key */ + 0, /* octets in data */ + NULL, /* data */ + 0, /* octets in tag */ + NULL, /* tag */ + NULL /* pointer to next testcase */ +}; + +/* end test case 0 */ + +char null_auth_description[] = "null authentication function"; + +auth_type_t +null_auth = { + (auth_alloc_func) null_auth_alloc, + (auth_dealloc_func) null_auth_dealloc, + (auth_init_func) null_auth_init, + (auth_compute_func) null_auth_compute, + (auth_update_func) null_auth_update, + (auth_start_func) null_auth_start, + (char *) null_auth_description, + (int) 0, /* instance count */ + (auth_test_case_t *) &null_auth_test_case_0, + (debug_module_t *) NULL, + (auth_type_id_t) NULL_AUTH +}; + diff --git a/netwerk/srtp/src/crypto/hash/sha1.c b/netwerk/srtp/src/crypto/hash/sha1.c new file mode 100644 index 000000000..b9a8d1050 --- /dev/null +++ b/netwerk/srtp/src/crypto/hash/sha1.c @@ -0,0 +1,405 @@ +/* + * sha1.c + * + * an implementation of the Secure Hash Algorithm v.1 (SHA-1), + * specified in FIPS 180-1 + * + * David A. McGrew + * Cisco Systems, Inc. + */ + +/* + * + * Copyright (c) 2001-2006, Cisco Systems, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided + * with the distribution. + * + * Neither the name of the Cisco Systems, Inc. nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + + +#include "sha1.h" + +debug_module_t mod_sha1 = { + 0, /* debugging is off by default */ + "sha-1" /* printable module name */ +}; + +/* SN == Rotate left N bits */ +#define S1(X) ((X << 1) | (X >> 31)) +#define S5(X) ((X << 5) | (X >> 27)) +#define S30(X) ((X << 30) | (X >> 2)) + +#define f0(B,C,D) ((B & C) | (~B & D)) +#define f1(B,C,D) (B ^ C ^ D) +#define f2(B,C,D) ((B & C) | (B & D) | (C & D)) +#define f3(B,C,D) (B ^ C ^ D) + +/* + * nota bene: the variable K0 appears in the curses library, so we + * give longer names to these variables to avoid spurious warnings + * on systems that uses curses + */ + +uint32_t SHA_K0 = 0x5A827999; /* Kt for 0 <= t <= 19 */ +uint32_t SHA_K1 = 0x6ED9EBA1; /* Kt for 20 <= t <= 39 */ +uint32_t SHA_K2 = 0x8F1BBCDC; /* Kt for 40 <= t <= 59 */ +uint32_t SHA_K3 = 0xCA62C1D6; /* Kt for 60 <= t <= 79 */ + +void +sha1(const uint8_t *msg, int octets_in_msg, uint32_t hash_value[5]) { + sha1_ctx_t ctx; + + sha1_init(&ctx); + sha1_update(&ctx, msg, octets_in_msg); + sha1_final(&ctx, hash_value); + +} + +/* + * sha1_core(M, H) computes the core compression function, where M is + * the next part of the message (in network byte order) and H is the + * intermediate state { H0, H1, ...} (in host byte order) + * + * this function does not do any of the padding required in the + * complete SHA1 function + * + * this function is used in the SEAL 3.0 key setup routines + * (crypto/cipher/seal.c) + */ + +void +sha1_core(const uint32_t M[16], uint32_t hash_value[5]) { + uint32_t H0; + uint32_t H1; + uint32_t H2; + uint32_t H3; + uint32_t H4; + uint32_t W[80]; + uint32_t A, B, C, D, E, TEMP; + int t; + + /* copy hash_value into H0, H1, H2, H3, H4 */ + H0 = hash_value[0]; + H1 = hash_value[1]; + H2 = hash_value[2]; + H3 = hash_value[3]; + H4 = hash_value[4]; + + /* copy/xor message into array */ + + W[0] = be32_to_cpu(M[0]); + W[1] = be32_to_cpu(M[1]); + W[2] = be32_to_cpu(M[2]); + W[3] = be32_to_cpu(M[3]); + W[4] = be32_to_cpu(M[4]); + W[5] = be32_to_cpu(M[5]); + W[6] = be32_to_cpu(M[6]); + W[7] = be32_to_cpu(M[7]); + W[8] = be32_to_cpu(M[8]); + W[9] = be32_to_cpu(M[9]); + W[10] = be32_to_cpu(M[10]); + W[11] = be32_to_cpu(M[11]); + W[12] = be32_to_cpu(M[12]); + W[13] = be32_to_cpu(M[13]); + W[14] = be32_to_cpu(M[14]); + W[15] = be32_to_cpu(M[15]); + TEMP = W[13] ^ W[8] ^ W[2] ^ W[0]; W[16] = S1(TEMP); + TEMP = W[14] ^ W[9] ^ W[3] ^ W[1]; W[17] = S1(TEMP); + TEMP = W[15] ^ W[10] ^ W[4] ^ W[2]; W[18] = S1(TEMP); + TEMP = W[16] ^ W[11] ^ W[5] ^ W[3]; W[19] = S1(TEMP); + TEMP = W[17] ^ W[12] ^ W[6] ^ W[4]; W[20] = S1(TEMP); + TEMP = W[18] ^ W[13] ^ W[7] ^ W[5]; W[21] = S1(TEMP); + TEMP = W[19] ^ W[14] ^ W[8] ^ W[6]; W[22] = S1(TEMP); + TEMP = W[20] ^ W[15] ^ W[9] ^ W[7]; W[23] = S1(TEMP); + TEMP = W[21] ^ W[16] ^ W[10] ^ W[8]; W[24] = S1(TEMP); + TEMP = W[22] ^ W[17] ^ W[11] ^ W[9]; W[25] = S1(TEMP); + TEMP = W[23] ^ W[18] ^ W[12] ^ W[10]; W[26] = S1(TEMP); + TEMP = W[24] ^ W[19] ^ W[13] ^ W[11]; W[27] = S1(TEMP); + TEMP = W[25] ^ W[20] ^ W[14] ^ W[12]; W[28] = S1(TEMP); + TEMP = W[26] ^ W[21] ^ W[15] ^ W[13]; W[29] = S1(TEMP); + TEMP = W[27] ^ W[22] ^ W[16] ^ W[14]; W[30] = S1(TEMP); + TEMP = W[28] ^ W[23] ^ W[17] ^ W[15]; W[31] = S1(TEMP); + + /* process the remainder of the array */ + for (t=32; t < 80; t++) { + TEMP = W[t-3] ^ W[t-8] ^ W[t-14] ^ W[t-16]; + W[t] = S1(TEMP); + } + + A = H0; B = H1; C = H2; D = H3; E = H4; + + for (t=0; t < 20; t++) { + TEMP = S5(A) + f0(B,C,D) + E + W[t] + SHA_K0; + E = D; D = C; C = S30(B); B = A; A = TEMP; + } + for ( ; t < 40; t++) { + TEMP = S5(A) + f1(B,C,D) + E + W[t] + SHA_K1; + E = D; D = C; C = S30(B); B = A; A = TEMP; + } + for ( ; t < 60; t++) { + TEMP = S5(A) + f2(B,C,D) + E + W[t] + SHA_K2; + E = D; D = C; C = S30(B); B = A; A = TEMP; + } + for ( ; t < 80; t++) { + TEMP = S5(A) + f3(B,C,D) + E + W[t] + SHA_K3; + E = D; D = C; C = S30(B); B = A; A = TEMP; + } + + hash_value[0] = H0 + A; + hash_value[1] = H1 + B; + hash_value[2] = H2 + C; + hash_value[3] = H3 + D; + hash_value[4] = H4 + E; + + return; +} + +void +sha1_init(sha1_ctx_t *ctx) { + + /* initialize state vector */ + ctx->H[0] = 0x67452301; + ctx->H[1] = 0xefcdab89; + ctx->H[2] = 0x98badcfe; + ctx->H[3] = 0x10325476; + ctx->H[4] = 0xc3d2e1f0; + + /* indicate that message buffer is empty */ + ctx->octets_in_buffer = 0; + + /* reset message bit-count to zero */ + ctx->num_bits_in_msg = 0; + +} + +void +sha1_update(sha1_ctx_t *ctx, const uint8_t *msg, int octets_in_msg) { + int i; + uint8_t *buf = (uint8_t *)ctx->M; + + /* update message bit-count */ + ctx->num_bits_in_msg += octets_in_msg * 8; + + /* loop over 16-word blocks of M */ + while (octets_in_msg > 0) { + + if (octets_in_msg + ctx->octets_in_buffer >= 64) { + + /* + * copy words of M into msg buffer until that buffer is full, + * converting them into host byte order as needed + */ + octets_in_msg -= (64 - ctx->octets_in_buffer); + for (i=ctx->octets_in_buffer; i < 64; i++) + buf[i] = *msg++; + ctx->octets_in_buffer = 0; + + /* process a whole block */ + + debug_print(mod_sha1, "(update) running sha1_core()", NULL); + + sha1_core(ctx->M, ctx->H); + + } else { + + debug_print(mod_sha1, "(update) not running sha1_core()", NULL); + + for (i=ctx->octets_in_buffer; + i < (ctx->octets_in_buffer + octets_in_msg); i++) + buf[i] = *msg++; + ctx->octets_in_buffer += octets_in_msg; + octets_in_msg = 0; + } + + } + +} + +/* + * sha1_final(ctx, output) computes the result for ctx and copies it + * into the twenty octets located at *output + */ + +void +sha1_final(sha1_ctx_t *ctx, uint32_t *output) { + uint32_t A, B, C, D, E, TEMP; + uint32_t W[80]; + int i, t; + + /* + * process the remaining octets_in_buffer, padding and terminating as + * necessary + */ + { + int tail = ctx->octets_in_buffer % 4; + + /* copy/xor message into array */ + for (i=0; i < (ctx->octets_in_buffer+3)/4; i++) + W[i] = be32_to_cpu(ctx->M[i]); + + /* set the high bit of the octet immediately following the message */ + switch (tail) { + case (3): + W[i-1] = (be32_to_cpu(ctx->M[i-1]) & 0xffffff00) | 0x80; + W[i] = 0x0; + break; + case (2): + W[i-1] = (be32_to_cpu(ctx->M[i-1]) & 0xffff0000) | 0x8000; + W[i] = 0x0; + break; + case (1): + W[i-1] = (be32_to_cpu(ctx->M[i-1]) & 0xff000000) | 0x800000; + W[i] = 0x0; + break; + case (0): + W[i] = 0x80000000; + break; + } + + /* zeroize remaining words */ + for (i++ ; i < 15; i++) + W[i] = 0x0; + + /* + * if there is room at the end of the word array, then set the + * last word to the bit-length of the message; otherwise, set that + * word to zero and then we need to do one more run of the + * compression algo. + */ + if (ctx->octets_in_buffer < 56) + W[15] = ctx->num_bits_in_msg; + else if (ctx->octets_in_buffer < 60) + W[15] = 0x0; + + /* process the word array */ + for (t=16; t < 80; t++) { + TEMP = W[t-3] ^ W[t-8] ^ W[t-14] ^ W[t-16]; + W[t] = S1(TEMP); + } + + A = ctx->H[0]; + B = ctx->H[1]; + C = ctx->H[2]; + D = ctx->H[3]; + E = ctx->H[4]; + + for (t=0; t < 20; t++) { + TEMP = S5(A) + f0(B,C,D) + E + W[t] + SHA_K0; + E = D; D = C; C = S30(B); B = A; A = TEMP; + } + for ( ; t < 40; t++) { + TEMP = S5(A) + f1(B,C,D) + E + W[t] + SHA_K1; + E = D; D = C; C = S30(B); B = A; A = TEMP; + } + for ( ; t < 60; t++) { + TEMP = S5(A) + f2(B,C,D) + E + W[t] + SHA_K2; + E = D; D = C; C = S30(B); B = A; A = TEMP; + } + for ( ; t < 80; t++) { + TEMP = S5(A) + f3(B,C,D) + E + W[t] + SHA_K3; + E = D; D = C; C = S30(B); B = A; A = TEMP; + } + + ctx->H[0] += A; + ctx->H[1] += B; + ctx->H[2] += C; + ctx->H[3] += D; + ctx->H[4] += E; + + } + + debug_print(mod_sha1, "(final) running sha1_core()", NULL); + + if (ctx->octets_in_buffer >= 56) { + + debug_print(mod_sha1, "(final) running sha1_core() again", NULL); + + /* we need to do one final run of the compression algo */ + + /* + * set initial part of word array to zeros, and set the + * final part to the number of bits in the message + */ + for (i=0; i < 15; i++) + W[i] = 0x0; + W[15] = ctx->num_bits_in_msg; + + /* process the word array */ + for (t=16; t < 80; t++) { + TEMP = W[t-3] ^ W[t-8] ^ W[t-14] ^ W[t-16]; + W[t] = S1(TEMP); + } + + A = ctx->H[0]; + B = ctx->H[1]; + C = ctx->H[2]; + D = ctx->H[3]; + E = ctx->H[4]; + + for (t=0; t < 20; t++) { + TEMP = S5(A) + f0(B,C,D) + E + W[t] + SHA_K0; + E = D; D = C; C = S30(B); B = A; A = TEMP; + } + for ( ; t < 40; t++) { + TEMP = S5(A) + f1(B,C,D) + E + W[t] + SHA_K1; + E = D; D = C; C = S30(B); B = A; A = TEMP; + } + for ( ; t < 60; t++) { + TEMP = S5(A) + f2(B,C,D) + E + W[t] + SHA_K2; + E = D; D = C; C = S30(B); B = A; A = TEMP; + } + for ( ; t < 80; t++) { + TEMP = S5(A) + f3(B,C,D) + E + W[t] + SHA_K3; + E = D; D = C; C = S30(B); B = A; A = TEMP; + } + + ctx->H[0] += A; + ctx->H[1] += B; + ctx->H[2] += C; + ctx->H[3] += D; + ctx->H[4] += E; + } + + /* copy result into output buffer */ + output[0] = be32_to_cpu(ctx->H[0]); + output[1] = be32_to_cpu(ctx->H[1]); + output[2] = be32_to_cpu(ctx->H[2]); + output[3] = be32_to_cpu(ctx->H[3]); + output[4] = be32_to_cpu(ctx->H[4]); + + /* indicate that message buffer in context is empty */ + ctx->octets_in_buffer = 0; + + return; +} + + + |