diff options
author | Benny Prijono <bennylp@teluu.com> | 2007-02-25 15:38:32 +0000 |
---|---|---|
committer | Benny Prijono <bennylp@teluu.com> | 2007-02-25 15:38:32 +0000 |
commit | a34fbb64e27b5075a4207318ba356349669b4f08 (patch) | |
tree | fb9705d9e0164747e4a17ba0fc723abb4abba791 /pjlib-util/src | |
parent | 3692bfe973fa350b52445119e3270199b88dfa7e (diff) |
Updated VS8 and EVC4 project with new STUN files and added SHA1, HMAC-MD5, and HMAC-SHA1 encryption
git-svn-id: http://svn.pjsip.org/repos/pjproject/trunk@1001 74dad513-b988-da41-8d7b-12977e46ad98
Diffstat (limited to 'pjlib-util/src')
-rw-r--r-- | pjlib-util/src/pjlib-util-test/encryption.c | 409 | ||||
-rw-r--r-- | pjlib-util/src/pjlib-util-test/main.c | 2 | ||||
-rw-r--r-- | pjlib-util/src/pjlib-util-test/test.c | 10 | ||||
-rw-r--r-- | pjlib-util/src/pjlib-util-test/test.h | 6 | ||||
-rw-r--r-- | pjlib-util/src/pjlib-util/hmac_md5.c | 75 | ||||
-rw-r--r-- | pjlib-util/src/pjlib-util/hmac_sha1.c | 74 | ||||
-rw-r--r-- | pjlib-util/src/pjlib-util/md5.c | 17 | ||||
-rw-r--r-- | pjlib-util/src/pjlib-util/sha1.c | 260 | ||||
-rw-r--r-- | pjlib-util/src/pjlib-util/stun_msg.c | 25 |
9 files changed, 859 insertions, 19 deletions
diff --git a/pjlib-util/src/pjlib-util-test/encryption.c b/pjlib-util/src/pjlib-util-test/encryption.c new file mode 100644 index 00000000..0c5de154 --- /dev/null +++ b/pjlib-util/src/pjlib-util-test/encryption.c @@ -0,0 +1,409 @@ +/* $Id$ */ +/* + * Copyright (C) 2003-2007 Benny Prijono <benny@prijono.org> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +#include "test.h" +#include <pjlib-util.h> +#include <pjlib.h> + + +#if INCLUDE_ENCRYPTION_TEST + +/* + * Encryption algorithm tests. + */ +#define THIS_FILE "encryption.c" + + +/* + * SHA1 test from the original sha1.c source file. + */ +static char *sha1_test_data[] = { + "abc", + "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq", + "A million repetitions of 'a'" +}; +static char *sha1_test_results[] = { + "A9993E36 4706816A BA3E2571 7850C26C 9CD0D89D", + "84983E44 1C3BD26E BAAE4AA1 F95129E5 E54670F1", + "34AA973C D4C4DAA4 F61EEB2B DBAD2731 6534016F" +}; + + +static void digest_to_hex(const pj_uint8_t digest[PJ_SHA1_DIGEST_SIZE], + char *output) +{ + int i,j; + char *c = output; + + for (i = 0; i < PJ_SHA1_DIGEST_SIZE/4; i++) { + for (j = 0; j < 4; j++) { + sprintf(c,"%02X", digest[i*4+j]); + c += 2; + } + sprintf(c, " "); + c += 1; + } + *(c - 1) = '\0'; +} + +static int sha1_test1(void) +{ + int k; + pj_sha1_context context; + pj_uint8_t digest[20]; + char output[80]; + + PJ_LOG(3, (THIS_FILE, " SHA1 test vector 1 from sha1.c..")); + + for (k = 0; k < 2; k++){ + pj_sha1_init(&context); + pj_sha1_update(&context, (pj_uint8_t*)sha1_test_data[k], + pj_ansi_strlen(sha1_test_data[k])); + pj_sha1_final(&context, digest); + digest_to_hex(digest, output); + + if (pj_ansi_strcmp(output, sha1_test_results[k])) { + PJ_LOG(3, (THIS_FILE, " incorrect hash result on k=%d", k)); + return -10; + } + } + + /* million 'a' vector we feed separately */ + pj_sha1_init(&context); + for (k = 0; k < 1000000; k++) + pj_sha1_update(&context, (pj_uint8_t*)"a", 1); + pj_sha1_final(&context, digest); + digest_to_hex(digest, output); + if (strcmp(output, sha1_test_results[2])) { + PJ_LOG(3, (THIS_FILE, " incorrect hash result!")); + return -20; + } + + /* success */ + return(0); +} + + +/* + * SHA1 test from RFC 3174 + */ +/* + * Define patterns for testing + */ +#define TEST1 "abc" +#define TEST2a "abcdbcdecdefdefgefghfghighijhi" +#define TEST2b "jkijkljklmklmnlmnomnopnopq" +#define TEST2 TEST2a TEST2b +#define TEST3 "a" +#define TEST4a "01234567012345670123456701234567" +#define TEST4b "01234567012345670123456701234567" + /* an exact multiple of 512 bits */ +#define TEST4 TEST4a TEST4b + +static char *testarray[4] = +{ + TEST1, + TEST2, + TEST3, + TEST4 +}; +static int repeatcount[4] = { 1, 1, 1000000, 10 }; +static char *resultarray[4] = +{ + "A9993E36 4706816A BA3E2571 7850C26C 9CD0D89D", + "84983E44 1C3BD26E BAAE4AA1 F95129E5 E54670F1", + "34AA973C D4C4DAA4 F61EEB2B DBAD2731 6534016F", + "DEA356A2 CDDD90C7 A7ECEDC5 EBB56393 4F460452" +}; + +static int sha1_test2(void) +{ + pj_sha1_context sha; + int i; + pj_uint8_t digest[20]; + char char_digest[64]; + + PJ_LOG(3, (THIS_FILE, " SHA1 test vector 2 from rfc 3174..")); + + for(i = 0; i < 4; ++i) { + int j; + + pj_sha1_init(&sha); + + for(j = 0; j < repeatcount[i]; ++j) { + pj_sha1_update(&sha, + (const pj_uint8_t *) testarray[i], + pj_ansi_strlen(testarray[i])); + } + + pj_sha1_final(&sha, digest); + + digest_to_hex(digest, char_digest); + if (pj_ansi_strcmp(char_digest, resultarray[i])) { + PJ_LOG(3, (THIS_FILE, " digest mismatch in test %d", i)); + return -40; + } + } + + return 0; +} + + +/* + * HMAC-MD5 and HMAC-SHA1 test vectors from RFC 2202 + */ +struct rfc2202_test +{ + char *key; + unsigned key_len; + char *input; + unsigned input_len; + char *md5_digest; + char *sha1_digest; +}; + + +struct rfc2202_test rfc2202_test_vector[] = +{ + { + "\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b", + 16, + "Hi There", + 8, + "\x92\x94\x72\x7a\x36\x38\xbb\x1c\x13\xf4\x8e\xf8\x15\x8b\xfc\x9d", + NULL + }, + { + "\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b" + "\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b", + 20, + "Hi There", + 8, + NULL, + "\xb6\x17\x31\x86\x55\x05\x72\x64\xe2\x8b\xc0\xb6\xfb\x37\x8c\x8e\xf1\x46\xbe\x00" + }, + { + "Jefe", + 4, + "what do ya want for nothing?", + 28, + "\x75\x0c\x78\x3e\x6a\xb0\xb5\x03\xea\xa8\x6e\x31\x0a\x5d\xb7\x38", + "\xef\xfc\xdf\x6a\xe5\xeb\x2f\xa2\xd2\x74\x16\xd5\xf1\x84\xdf\x9c\x25\x9a\x7c\x79" + }, + { + "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa" + "\xaa\xaa\xaa\xaa\xaa\xaa", + 16, + "\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd" + "\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd" + "\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd" + "\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd" + "\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd", + 50, + "\x56\xbe\x34\x52\x1d\x14\x4c\x88\xdb\xb8\xc7\x33\xf0\xe8\xb3\xf6", + NULL + }, + { + "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa" + "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa", + 20, + "\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd" + "\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd" + "\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd" + "\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd" + "\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd", + 50, + NULL, + "\x12\x5d\x73\x42\xb9\xac\x11\xcd\x91\xa3\x9a\xf4\x8a\xa1\x7b\x4f\x63\xf1\x75\xd3" + }, + { + "\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19", + 25, + "\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd" + "\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd" + "\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd" + "\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd" + "\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd", + 50, + "\x69\x7e\xaf\x0a\xca\x3a\x3a\xea\x3a\x75\x16\x47\x46\xff\xaa\x79", + "\x4c\x90\x07\xf4\x02\x62\x50\xc6\xbc\x84\x14\xf9\xbf\x50\xc8\x6c\x2d\x72\x35\xda" + }, + { + "\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c" + "\x0c\x0c\x0c\x0c\x0c\x0c", + 16, + "Test With Truncation", + 20, + "\x56\x46\x1e\xf2\x34\x2e\xdc\x00\xf9\xba\xb9\x95\x69\x0e\xfd\x4c", + NULL + }, + { + "\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c" + "\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c", + 20, + "Test With Truncation", + 20, + NULL, + "\x4c\x1a\x03\x42\x4b\x55\xe0\x7f\xe7\xf2\x7b\xe1\xd5\x8b\xb9\x32\x4a\x9a\x5a\x04" + }, + { + "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa" + "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa" + "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa" + "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa" + "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa" + "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa" + "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa" + "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa", + 80, + "Test Using Larger Than Block-Size Key - Hash Key First", + 54, + "\x6b\x1a\xb7\xfe\x4b\xd7\xbf\x8f\x0b\x62\xe6\xce\x61\xb9\xd0\xcd", + "\xaa\x4a\xe5\xe1\x52\x72\xd0\x0e\x95\x70\x56\x37\xce\x8a\x3b\x55\xed\x40\x21\x12" + }, + { + "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa" + "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa" + "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa" + "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa" + "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa" + "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa" + "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa" + "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa", + 80, + "Test Using Larger Than Block-Size Key and Larger Than One Block-Size Data", + 73, + "\x6f\x63\x0f\xad\x67\xcd\xa0\xee\x1f\xb1\xf5\x62\xdb\x3a\xa5\x3e", + "\xe8\xe9\x9d\x0f\x45\x23\x7d\x78\x6d\x6b\xba\xa7\x96\x5c\x78\x08\xbb\xff\x1a\x91" + } +}; + + +static int rfc2202_test(void) +{ + unsigned i; + + PJ_LOG(3, (THIS_FILE, " verifying test vectors from rfc 2202..")); + + /* Verify that test vectors are valid */ + for (i=0; i<PJ_ARRAY_SIZE(rfc2202_test_vector); ++i) { + PJ_ASSERT_RETURN(pj_ansi_strlen(rfc2202_test_vector[i].input) == + rfc2202_test_vector[i].input_len, -50); + PJ_ASSERT_RETURN(pj_ansi_strlen(rfc2202_test_vector[i].key) == + rfc2202_test_vector[i].key_len, -52); + PJ_ASSERT_RETURN(rfc2202_test_vector[i].md5_digest==NULL || + pj_ansi_strlen(rfc2202_test_vector[i].md5_digest)<=16, + -54); + PJ_ASSERT_RETURN(rfc2202_test_vector[i].sha1_digest==NULL || + pj_ansi_strlen(rfc2202_test_vector[i].sha1_digest)<=20, + -56); + } + + /* Test HMAC-MD5 */ + PJ_LOG(3, (THIS_FILE, " HMAC-MD5 test vectors from rfc 2202..")); + for (i=0; i<PJ_ARRAY_SIZE(rfc2202_test_vector); ++i) { + pj_uint8_t digest_buf[18], *digest; + + if (rfc2202_test_vector[i].md5_digest == NULL) + continue; + + digest_buf[0] = '\0'; + digest_buf[17] = '\0'; + + digest = digest_buf+1; + + pj_hmac_md5((pj_uint8_t*)rfc2202_test_vector[i].input, + rfc2202_test_vector[i].input_len, + (pj_uint8_t*)rfc2202_test_vector[i].key, + rfc2202_test_vector[i].key_len, + digest); + + /* Check for overwrites */ + if (digest_buf[0] != '\0' || digest_buf[17] != '\0') { + PJ_LOG(3, (THIS_FILE, " error: overwriting outside buffer on test %d", i)); + return -60; + } + + /* Compare digest */ + if (pj_memcmp(rfc2202_test_vector[i].md5_digest, digest, 16)) { + PJ_LOG(3, (THIS_FILE, " error: digest mismatch on test %d", i)); + return -65; + } + } + + /* Test HMAC-SHA1 */ + PJ_LOG(3, (THIS_FILE, " HMAC-SHA1 test vectors from rfc 2202..")); + for (i=0; i<PJ_ARRAY_SIZE(rfc2202_test_vector); ++i) { + pj_uint8_t digest_buf[22], *digest; + + if (rfc2202_test_vector[i].sha1_digest == NULL) + continue; + + digest_buf[0] = '\0'; + digest_buf[21] = '\0'; + + digest = digest_buf+1; + + pj_hmac_sha1((pj_uint8_t*)rfc2202_test_vector[i].input, + rfc2202_test_vector[i].input_len, + (pj_uint8_t*)rfc2202_test_vector[i].key, + rfc2202_test_vector[i].key_len, + digest); + + /* Check for overwrites */ + if (digest_buf[0] != '\0' || digest_buf[21] != '\0') { + PJ_LOG(3, (THIS_FILE, " error: overwriting outside buffer on test %d", i)); + return -70; + } + + /* Compare digest */ + if (pj_memcmp(rfc2202_test_vector[i].sha1_digest, digest, 20)) { + PJ_LOG(3, (THIS_FILE, " error: digest mismatch on test %d", i)); + return -75; + } + } + + + /* Success */ + return 0; +} + + +int encryption_test() +{ + int rc; + + rc = sha1_test1(); + if (rc != 0) + return rc; + + rc = sha1_test2(); + if (rc != 0) + return rc; + + rc = rfc2202_test(); + if (rc != 0) + return rc; + + return 0; +} + + + +#endif /* INCLUDE_ENCRYPTION_TEST */ + diff --git a/pjlib-util/src/pjlib-util-test/main.c b/pjlib-util/src/pjlib-util-test/main.c index ac48b8a4..33583e30 100644 --- a/pjlib-util/src/pjlib-util-test/main.c +++ b/pjlib-util/src/pjlib-util-test/main.c @@ -1,4 +1,4 @@ -/* $Id */ +/* $Id$ */ /* * Copyright (C) 2003-2007 Benny Prijono <benny@prijono.org> * diff --git a/pjlib-util/src/pjlib-util-test/test.c b/pjlib-util/src/pjlib-util-test/test.c index 0d1b4117..b6cc7290 100644 --- a/pjlib-util/src/pjlib-util-test/test.c +++ b/pjlib-util/src/pjlib-util-test/test.c @@ -1,4 +1,4 @@ -/* $Id */ +/* $Id$ */ /* * Copyright (C) 2003-2007 Benny Prijono <benny@prijono.org> * @@ -61,7 +61,15 @@ static int test_inner(void) pj_dump_config(); pj_caching_pool_init( &caching_pool, &pj_pool_factory_default_policy, 0 ); + +#if INCLUDE_XML_TEST DO_TEST(xml_test()); +#endif + +#if INCLUDE_ENCRYPTION_TEST + DO_TEST(encryption_test()); +#endif + on_return: return rc; diff --git a/pjlib-util/src/pjlib-util-test/test.h b/pjlib-util/src/pjlib-util-test/test.h index 9532bbd3..252b3399 100644 --- a/pjlib-util/src/pjlib-util-test/test.h +++ b/pjlib-util/src/pjlib-util-test/test.h @@ -1,4 +1,4 @@ -/* $Id */ +/* $Id$ */ /* * Copyright (C) 2003-2007 Benny Prijono <benny@prijono.org> * @@ -18,9 +18,11 @@ */ #include <pj/types.h> -#define INCLUDE_XML_TEST 1 +#define INCLUDE_XML_TEST 1 +#define INCLUDE_ENCRYPTION_TEST 1 extern int xml_test(void); +extern int encryption_test(); extern int test_main(void); extern void app_perror(const char *title, pj_status_t rc); diff --git a/pjlib-util/src/pjlib-util/hmac_md5.c b/pjlib-util/src/pjlib-util/hmac_md5.c new file mode 100644 index 00000000..d9c4e466 --- /dev/null +++ b/pjlib-util/src/pjlib-util/hmac_md5.c @@ -0,0 +1,75 @@ +/* $Id$ */ +/* + * Copyright (C) 2003-2007 Benny Prijono <benny@prijono.org> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +#include <pjlib-util/md5.h> +#include <pj/string.h> + + +/* This code is taken from RFC 2104 */ + + +PJ_DEF(void) pj_hmac_md5( const pj_uint8_t *input, unsigned input_len, + const pj_uint8_t *key, unsigned key_len, + pj_uint8_t digest[16] ) +{ + pj_md5_context context; + pj_uint8_t k_ipad[65]; + pj_uint8_t k_opad[65]; + pj_uint8_t tk[16]; + int i; + + /* if key is longer than 64 bytes reset it to key=MD5(key) */ + if (key_len > 64) { + pj_md5_context tctx; + + pj_md5_init(&tctx); + pj_md5_update(&tctx, key, key_len); + pj_md5_final(&tctx, tk); + + key = tk; + key_len = 16; + } + + /* start out by storing key in pads */ + pj_bzero( k_ipad, sizeof(k_ipad)); + pj_bzero( k_opad, sizeof(k_opad)); + pj_memcpy( k_ipad, key, key_len); + pj_memcpy( k_opad, key, key_len); + + /* XOR key with ipad and opad values */ + for (i=0; i<64; i++) { + k_ipad[i] ^= 0x36; + k_opad[i] ^= 0x5c; + } + /* + * perform inner MD5 + */ + pj_md5_init(&context); + pj_md5_update(&context, k_ipad, 64); + pj_md5_update(&context, input, input_len); + pj_md5_final(&context, digest); + + /* + * perform outer MD5 + */ + pj_md5_init(&context); + pj_md5_update(&context, k_opad, 64); + pj_md5_update(&context, digest, 16); + pj_md5_final(&context, digest); +} + diff --git a/pjlib-util/src/pjlib-util/hmac_sha1.c b/pjlib-util/src/pjlib-util/hmac_sha1.c new file mode 100644 index 00000000..127434b7 --- /dev/null +++ b/pjlib-util/src/pjlib-util/hmac_sha1.c @@ -0,0 +1,74 @@ +/* $Id$ */ +/* + * Copyright (C) 2003-2007 Benny Prijono <benny@prijono.org> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +#include <pjlib-util/hmac_sha1.h> +#include <pjlib-util/sha1.h> +#include <pj/string.h> + + +PJ_DEF(void) pj_hmac_sha1(const pj_uint8_t *input, unsigned input_len, + const pj_uint8_t *key, unsigned key_len, + pj_uint8_t digest[20] ) +{ + pj_sha1_context context; + pj_uint8_t k_ipad[65]; + pj_uint8_t k_opad[65]; + pj_uint8_t tk[20]; + int i; + + /* if key is longer than 64 bytes reset it to key=SHA1(key) */ + if (key_len > 64) { + pj_sha1_context tctx; + + pj_sha1_init(&tctx); + pj_sha1_update(&tctx, key, key_len); + pj_sha1_final(&tctx, tk); + + key = tk; + key_len = 20; + } + + /* start out by storing key in pads */ + pj_bzero( k_ipad, sizeof(k_ipad)); + pj_bzero( k_opad, sizeof(k_opad)); + pj_memcpy( k_ipad, key, key_len); + pj_memcpy( k_opad, key, key_len); + + /* XOR key with ipad and opad values */ + for (i=0; i<64; i++) { + k_ipad[i] ^= 0x36; + k_opad[i] ^= 0x5c; + } + /* + * perform inner SHA1 + */ + pj_sha1_init(&context); + pj_sha1_update(&context, k_ipad, 64); + pj_sha1_update(&context, input, input_len); + pj_sha1_final(&context, digest); + + /* + * perform outer SHA1 + */ + pj_sha1_init(&context); + pj_sha1_update(&context, k_opad, 64); + pj_sha1_update(&context, digest, 20); + pj_sha1_final(&context, digest); +} + + diff --git a/pjlib-util/src/pjlib-util/md5.c b/pjlib-util/src/pjlib-util/md5.c index d350c34d..142a4e58 100644 --- a/pjlib-util/src/pjlib-util/md5.c +++ b/pjlib-util/src/pjlib-util/md5.c @@ -1,20 +1,7 @@ /* $Id$ */ /* - * Copyright (C) 2003-2007 Benny Prijono <benny@prijono.org> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * This is the implementation of MD5 algorithm, based on the code + * written by Colin Plumb. This file is put in public domain. */ #include <pjlib-util/md5.h> #include <pj/string.h> /* pj_memcpy */ diff --git a/pjlib-util/src/pjlib-util/sha1.c b/pjlib-util/src/pjlib-util/sha1.c new file mode 100644 index 00000000..deb75162 --- /dev/null +++ b/pjlib-util/src/pjlib-util/sha1.c @@ -0,0 +1,260 @@ +/* $Id$ */ +/* + * Modified 2/07 + * By Benny Prijono <benny@prijono.org> + * Still 100% Public Domain + * + * This is the implementation of SHA-1 encryption algorithm based on + * Steve Reid work. Modified to work with PJLIB. + */ + +/* +SHA-1 in C +By Steve Reid <sreid@sea-to-sky.net> +100% Public Domain + +----------------- +Modified 7/98 +By James H. Brown <jbrown@burgoyne.com> +Still 100% Public Domain + +Corrected a problem which generated improper hash values on 16 bit machines +Routine SHA1Update changed from + void SHA1Update(SHA1_CTX* context, unsigned char* data, unsigned int +len) +to + void SHA1Update(SHA1_CTX* context, unsigned char* data, unsigned +long len) + +The 'len' parameter was declared an int which works fine on 32 bit machines. +However, on 16 bit machines an int is too small for the shifts being done +against +it. This caused the hash function to generate incorrect values if len was +greater than 8191 (8K - 1) due to the 'len << 3' on line 3 of SHA1Update(). + +Since the file IO in main() reads 16K at a time, any file 8K or larger would +be guaranteed to generate the wrong hash (e.g. Test Vector #3, a million +"a"s). + +I also changed the declaration of variables i & j in SHA1Update to +unsigned long from unsigned int for the same reason. + +These changes should make no difference to any 32 bit implementations since +an +int and a long are the same size in those environments. + +-- +I also corrected a few compiler warnings generated by Borland C. +1. Added #include <process.h> for exit() prototype +2. Removed unused variable 'j' in SHA1Final +3. Changed exit(0) to return(0) at end of main. + +ALL changes I made can be located by searching for comments containing 'JHB' +----------------- +Modified 8/98 +By Steve Reid <sreid@sea-to-sky.net> +Still 100% public domain + +1- Removed #include <process.h> and used return() instead of exit() +2- Fixed overwriting of finalcount in SHA1Final() (discovered by Chris Hall) +3- Changed email address from steve@edmweb.com to sreid@sea-to-sky.net + +----------------- +Modified 4/01 +By Saul Kravitz <Saul.Kravitz@celera.com> +Still 100% PD +Modified to run on Compaq Alpha hardware. + +----------------- +Modified 07/2002 +By Ralph Giles <giles@ghostscript.com> +Still 100% public domain +modified for use with stdint types, autoconf +code cleanup, removed attribution comments +switched SHA1Final() argument order for consistency +use SHA1_ prefix for public api +move public api to sha1.h +*/ + +/* +Test Vectors (from FIPS PUB 180-1) +"abc" + A9993E36 4706816A BA3E2571 7850C26C 9CD0D89D +"abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq" + 84983E44 1C3BD26E BAAE4AA1 F95129E5 E54670F1 +A million repetitions of "a" + 34AA973C D4C4DAA4 F61EEB2B DBAD2731 6534016F +*/ + +/* #define SHA1HANDSOFF */ +/* blp: +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include <stdio.h> +#include <string.h> + +#include "os_types.h" + +#include "sha1.h" +*/ +#include <pjlib-util/sha1.h> +#include <pj/string.h> + +#undef SHA1HANDSOFF + + +static void SHA1_Transform(pj_uint32_t state[5], const pj_uint8_t buffer[64]); + +#define rol(value, bits) (((value) << (bits)) | ((value) >> (32 - (bits)))) + +/* blk0() and blk() perform the initial expand. */ +/* I got the idea of expanding during the round function from SSLeay */ +/* FIXME: can we do this in an endian-proof way? */ +/* #ifdef WORDS_BIGENDIAN */ +#if defined(PJ_IS_BIG_ENDIAN) && PJ_IS_BIG_ENDIAN != 0 +#define blk0(i) block->l[i] +#else +#define blk0(i) (block->l[i] = (rol(block->l[i],24)&0xFF00FF00) \ + |(rol(block->l[i],8)&0x00FF00FF)) +#endif +#define blk(i) (block->l[i&15] = rol(block->l[(i+13)&15]^block->l[(i+8)&15] \ + ^block->l[(i+2)&15]^block->l[i&15],1)) + +/* (R0+R1), R2, R3, R4 are the different operations used in SHA1 */ +#define R0(v,w,x,y,z,i) z+=((w&(x^y))^y)+blk0(i)+0x5A827999+rol(v,5);w=rol(w,30); +#define R1(v,w,x,y,z,i) z+=((w&(x^y))^y)+blk(i)+0x5A827999+rol(v,5);w=rol(w,30); +#define R2(v,w,x,y,z,i) z+=(w^x^y)+blk(i)+0x6ED9EBA1+rol(v,5);w=rol(w,30); +#define R3(v,w,x,y,z,i) z+=(((w|x)&y)|(w&x))+blk(i)+0x8F1BBCDC+rol(v,5);w=rol(w,30); +#define R4(v,w,x,y,z,i) z+=(w^x^y)+blk(i)+0xCA62C1D6+rol(v,5);w=rol(w,30); + + +/* Hash a single 512-bit block. This is the core of the algorithm. */ +static void SHA1_Transform(pj_uint32_t state[5], const pj_uint8_t buffer[64]) +{ + pj_uint32_t a, b, c, d, e; + typedef union { + pj_uint8_t c[64]; + pj_uint32_t l[16]; + } CHAR64LONG16; + CHAR64LONG16* block; + +#ifdef SHA1HANDSOFF + static pj_uint8_t workspace[64]; + block = (CHAR64LONG16*)workspace; + pj_memcpy(block, buffer, 64); +#else + block = (CHAR64LONG16*)buffer; +#endif + + /* Copy context->state[] to working vars */ + a = state[0]; + b = state[1]; + c = state[2]; + d = state[3]; + e = state[4]; + + /* 4 rounds of 20 operations each. Loop unrolled. */ + R0(a,b,c,d,e, 0); R0(e,a,b,c,d, 1); R0(d,e,a,b,c, 2); R0(c,d,e,a,b, 3); + R0(b,c,d,e,a, 4); R0(a,b,c,d,e, 5); R0(e,a,b,c,d, 6); R0(d,e,a,b,c, 7); + R0(c,d,e,a,b, 8); R0(b,c,d,e,a, 9); R0(a,b,c,d,e,10); R0(e,a,b,c,d,11); + R0(d,e,a,b,c,12); R0(c,d,e,a,b,13); R0(b,c,d,e,a,14); R0(a,b,c,d,e,15); + R1(e,a,b,c,d,16); R1(d,e,a,b,c,17); R1(c,d,e,a,b,18); R1(b,c,d,e,a,19); + R2(a,b,c,d,e,20); R2(e,a,b,c,d,21); R2(d,e,a,b,c,22); R2(c,d,e,a,b,23); + R2(b,c,d,e,a,24); R2(a,b,c,d,e,25); R2(e,a,b,c,d,26); R2(d,e,a,b,c,27); + R2(c,d,e,a,b,28); R2(b,c,d,e,a,29); R2(a,b,c,d,e,30); R2(e,a,b,c,d,31); + R2(d,e,a,b,c,32); R2(c,d,e,a,b,33); R2(b,c,d,e,a,34); R2(a,b,c,d,e,35); + R2(e,a,b,c,d,36); R2(d,e,a,b,c,37); R2(c,d,e,a,b,38); R2(b,c,d,e,a,39); + R3(a,b,c,d,e,40); R3(e,a,b,c,d,41); R3(d,e,a,b,c,42); R3(c,d,e,a,b,43); + R3(b,c,d,e,a,44); R3(a,b,c,d,e,45); R3(e,a,b,c,d,46); R3(d,e,a,b,c,47); + R3(c,d,e,a,b,48); R3(b,c,d,e,a,49); R3(a,b,c,d,e,50); R3(e,a,b,c,d,51); + R3(d,e,a,b,c,52); R3(c,d,e,a,b,53); R3(b,c,d,e,a,54); R3(a,b,c,d,e,55); + R3(e,a,b,c,d,56); R3(d,e,a,b,c,57); R3(c,d,e,a,b,58); R3(b,c,d,e,a,59); + R4(a,b,c,d,e,60); R4(e,a,b,c,d,61); R4(d,e,a,b,c,62); R4(c,d,e,a,b,63); + R4(b,c,d,e,a,64); R4(a,b,c,d,e,65); R4(e,a,b,c,d,66); R4(d,e,a,b,c,67); + R4(c,d,e,a,b,68); R4(b,c,d,e,a,69); R4(a,b,c,d,e,70); R4(e,a,b,c,d,71); + R4(d,e,a,b,c,72); R4(c,d,e,a,b,73); R4(b,c,d,e,a,74); R4(a,b,c,d,e,75); + R4(e,a,b,c,d,76); R4(d,e,a,b,c,77); R4(c,d,e,a,b,78); R4(b,c,d,e,a,79); + + /* Add the working vars back into context.state[] */ + state[0] += a; + state[1] += b; + state[2] += c; + state[3] += d; + state[4] += e; + + /* Wipe variables */ + a = b = c = d = e = 0; +} + + +/* SHA1Init - Initialize new context */ +PJ_DEF(void) pj_sha1_init(pj_sha1_context* context) +{ + /* SHA1 initialization constants */ + context->state[0] = 0x67452301; + context->state[1] = 0xEFCDAB89; + context->state[2] = 0x98BADCFE; + context->state[3] = 0x10325476; + context->state[4] = 0xC3D2E1F0; + context->count[0] = context->count[1] = 0; +} + + +/* Run your data through this. */ +PJ_DEF(void) pj_sha1_update(pj_sha1_context* context, + const pj_uint8_t* data, const pj_size_t len) +{ + pj_size_t i, j; + + j = (context->count[0] >> 3) & 63; + if ((context->count[0] += len << 3) < (len << 3)) context->count[1]++; + context->count[1] += (len >> 29); + if ((j + len) > 63) { + pj_memcpy(&context->buffer[j], data, (i = 64-j)); + SHA1_Transform(context->state, context->buffer); + for ( ; i + 63 < len; i += 64) { + SHA1_Transform(context->state, data + i); + } + j = 0; + } + else i = 0; + pj_memcpy(&context->buffer[j], &data[i], len - i); + +} + + +/* Add padding and return the message digest. */ +PJ_DEF(void) pj_sha1_final(pj_sha1_context* context, + pj_uint8_t digest[PJ_SHA1_DIGEST_SIZE]) +{ + pj_uint32_t i; + pj_uint8_t finalcount[8]; + + for (i = 0; i < 8; i++) { + finalcount[i] = (unsigned char)((context->count[(i >= 4 ? 0 : 1)] + >> ((3-(i & 3)) * 8) ) & 255); /* Endian independent */ + } + pj_sha1_update(context, (pj_uint8_t *)"\200", 1); + while ((context->count[0] & 504) != 448) { + pj_sha1_update(context, (pj_uint8_t *)"\0", 1); + } + pj_sha1_update(context, finalcount, 8); /* Should cause a SHA1_Transform() */ + for (i = 0; i < PJ_SHA1_DIGEST_SIZE; i++) { + digest[i] = (pj_uint8_t) + ((context->state[i>>2] >> ((3-(i & 3)) * 8) ) & 255); + } + + /* Wipe variables */ + i = 0; + pj_memset(context->buffer, 0, 64); + pj_memset(context->state, 0, 20); + pj_memset(context->count, 0, 8); + pj_memset(finalcount, 0, 8); /* SWR */ + +#ifdef SHA1HANDSOFF /* make SHA1Transform overwrite its own static vars */ + SHA1_Transform(context->state, context->buffer); +#endif +} + diff --git a/pjlib-util/src/pjlib-util/stun_msg.c b/pjlib-util/src/pjlib-util/stun_msg.c index ec92f6b6..fbe2223c 100644 --- a/pjlib-util/src/pjlib-util/stun_msg.c +++ b/pjlib-util/src/pjlib-util/stun_msg.c @@ -1486,15 +1486,20 @@ PJ_DEF(pj_status_t) pj_stun_msg_decode(pj_pool_t *pool, PJ_DEF(pj_status_t) pj_stun_msg_encode(const pj_stun_msg *msg, pj_uint8_t *buf, unsigned buf_size, unsigned options, + const pj_str_t *password, unsigned *p_msg_len) { pj_stun_msg_hdr *hdr; pj_uint8_t *start = buf; + pj_stun_realm_attr *arealm = NULL; + pj_stun_username_attr *auname = NULL; + pj_stun_msg_integrity_attr *amsg_integrity = NULL; unsigned i; PJ_ASSERT_RETURN(msg && buf && buf_size, PJ_EINVAL); PJ_UNUSED_ARG(options); + PJ_ASSERT_RETURN(options == 0, PJ_EINVAL); /* Copy the message header part and convert the header fields to * network byte order @@ -1519,6 +1524,21 @@ PJ_DEF(pj_status_t) pj_stun_msg_encode(const pj_stun_msg *msg, attr_hdr = msg->attr[i]; + if (attr_hdr->type == PJ_STUN_ATTR_MESSAGE_INTEGRITY) { + pj_assert(amsg_integrity == NULL); + amsg_integrity = (pj_stun_msg_integrity_attr*) attr_hdr; + + /* Stop when encountering MESSAGE-INTEGRITY */ + break; + + } else if (attr_hdr->type == PJ_STUN_ATTR_USERNAME) { + pj_assert(auname == NULL); + auname = (pj_stun_username_attr*) attr_hdr; + } else if (attr_hdr->type == PJ_STUN_ATTR_REALM) { + pj_assert(arealm == NULL); + arealm = (pj_stun_realm_attr*) attr_hdr; + } + adesc = find_attr_desc(attr_hdr->type); PJ_ASSERT_RETURN(adesc != NULL, PJ_EBUG); @@ -1530,6 +1550,11 @@ PJ_DEF(pj_status_t) pj_stun_msg_encode(const pj_stun_msg *msg, buf_size -= printed; } + if (amsg_integrity != NULL) { + PJ_TODO(IMPLEMENT_MSG_INTEGRITY); + } + + /* Update the message length in the header. * Note that length is not including the 20 bytes header. */ |