pkcs5_pbkdf2.c revision 1.1
1/* $OpenBSD: pkcs5_pbkdf2.c,v 1.1 2012/09/06 19:41:59 tedu Exp $ */ 2 3/*- 4 * Copyright (c) 2008 Damien Bergamini <damien.bergamini@free.fr> 5 * 6 * Permission to use, copy, modify, and distribute this software for any 7 * purpose with or without fee is hereby granted, provided that the above 8 * copyright notice and this permission notice appear in all copies. 9 * 10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 15 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 16 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17 */ 18 19#include <sys/types.h> 20#include <sys/param.h> 21 22#include <string.h> 23#include <limits.h> 24#include <stdlib.h> 25#include <util.h> 26 27#include <sha1.h> 28 29 30/* #define PBKDF2_MAIN */ 31 32/* 33 * HMAC-SHA-1 (from RFC 2202). 34 */ 35static void 36hmac_sha1(const u_int8_t *text, size_t text_len, const u_int8_t *key, 37 size_t key_len, u_int8_t digest[SHA1_DIGEST_LENGTH]) 38{ 39 SHA1_CTX ctx; 40 u_int8_t k_pad[SHA1_BLOCK_LENGTH]; 41 u_int8_t tk[SHA1_DIGEST_LENGTH]; 42 int i; 43 44 if (key_len > SHA1_BLOCK_LENGTH) { 45 SHA1Init(&ctx); 46 SHA1Update(&ctx, key, key_len); 47 SHA1Final(tk, &ctx); 48 49 key = tk; 50 key_len = SHA1_DIGEST_LENGTH; 51 } 52 53 bzero(k_pad, sizeof k_pad); 54 bcopy(key, k_pad, key_len); 55 for (i = 0; i < SHA1_BLOCK_LENGTH; i++) 56 k_pad[i] ^= 0x36; 57 58 SHA1Init(&ctx); 59 SHA1Update(&ctx, k_pad, SHA1_BLOCK_LENGTH); 60 SHA1Update(&ctx, text, text_len); 61 SHA1Final(digest, &ctx); 62 63 bzero(k_pad, sizeof k_pad); 64 bcopy(key, k_pad, key_len); 65 for (i = 0; i < SHA1_BLOCK_LENGTH; i++) 66 k_pad[i] ^= 0x5c; 67 68 SHA1Init(&ctx); 69 SHA1Update(&ctx, k_pad, SHA1_BLOCK_LENGTH); 70 SHA1Update(&ctx, digest, SHA1_DIGEST_LENGTH); 71 SHA1Final(digest, &ctx); 72} 73 74/* 75 * Password-Based Key Derivation Function 2 (PKCS #5 v2.0). 76 * Code based on IEEE Std 802.11-2007, Annex H.4.2. 77 */ 78int 79pkcs5_pbkdf2(const char *pass, size_t pass_len, const char *salt, size_t salt_len, 80 u_int8_t *key, size_t key_len, u_int rounds) 81{ 82 u_int8_t *asalt, obuf[SHA1_DIGEST_LENGTH]; 83 u_int8_t d1[SHA1_DIGEST_LENGTH], d2[SHA1_DIGEST_LENGTH]; 84 u_int i, j; 85 u_int count; 86 size_t r; 87 88 if (rounds < 1 || key_len == 0) 89 return -1; 90 if (salt_len == 0 || salt_len > SIZE_MAX - 4) 91 return -1; 92 if ((asalt = malloc(salt_len + 4)) == NULL) 93 return -1; 94 95 memcpy(asalt, salt, salt_len); 96 97 for (count = 1; key_len > 0; count++) { 98 asalt[salt_len + 0] = (count >> 24) & 0xff; 99 asalt[salt_len + 1] = (count >> 16) & 0xff; 100 asalt[salt_len + 2] = (count >> 8) & 0xff; 101 asalt[salt_len + 3] = count & 0xff; 102 hmac_sha1(asalt, salt_len + 4, pass, pass_len, d1); 103 memcpy(obuf, d1, sizeof(obuf)); 104 105 for (i = 1; i < rounds; i++) { 106 hmac_sha1(d1, sizeof(d1), pass, pass_len, d2); 107 memcpy(d1, d2, sizeof(d1)); 108 for (j = 0; j < sizeof(obuf); j++) 109 obuf[j] ^= d1[j]; 110 } 111 112 r = MIN(key_len, SHA1_DIGEST_LENGTH); 113 memcpy(key, obuf, r); 114 key += r; 115 key_len -= r; 116 }; 117 bzero(asalt, salt_len + 4); 118 free(asalt); 119 bzero(d1, sizeof(d1)); 120 bzero(d2, sizeof(d2)); 121 bzero(obuf, sizeof(obuf)); 122 123 return 0; 124} 125 126#ifdef PBKDF2_MAIN 127struct test_vector { 128 u_int rounds; 129 const char *pass; 130 const char *salt; 131 const char expected[32]; 132}; 133 134/* 135 * Test vectors from RFC 3962 136 */ 137struct test_vector test_vectors[] = { 138 { 139 1, 140 "password", 141 "ATHENA.MIT.EDUraeburn", 142 { 143 0xcd, 0xed, 0xb5, 0x28, 0x1b, 0xb2, 0xf8, 0x01, 144 0x56, 0x5a, 0x11, 0x22, 0xb2, 0x56, 0x35, 0x15, 145 0x0a, 0xd1, 0xf7, 0xa0, 0x4b, 0xb9, 0xf3, 0xa3, 146 0x33, 0xec, 0xc0, 0xe2, 0xe1, 0xf7, 0x08, 0x37 147 }, 148 }, { 149 2, 150 "password", 151 "ATHENA.MIT.EDUraeburn", 152 { 153 0x01, 0xdb, 0xee, 0x7f, 0x4a, 0x9e, 0x24, 0x3e, 154 0x98, 0x8b, 0x62, 0xc7, 0x3c, 0xda, 0x93, 0x5d, 155 0xa0, 0x53, 0x78, 0xb9, 0x32, 0x44, 0xec, 0x8f, 156 0x48, 0xa9, 0x9e, 0x61, 0xad, 0x79, 0x9d, 0x86 157 }, 158 }, { 159 1200, 160 "password", 161 "ATHENA.MIT.EDUraeburn", 162 { 163 0x5c, 0x08, 0xeb, 0x61, 0xfd, 0xf7, 0x1e, 0x4e, 164 0x4e, 0xc3, 0xcf, 0x6b, 0xa1, 0xf5, 0x51, 0x2b, 165 0xa7, 0xe5, 0x2d, 0xdb, 0xc5, 0xe5, 0x14, 0x2f, 166 0x70, 0x8a, 0x31, 0xe2, 0xe6, 0x2b, 0x1e, 0x13 167 }, 168 }, { 169 5, 170 "password", 171 "\0224VxxV4\022", /* 0x1234567878563412 */ 172 { 173 0xd1, 0xda, 0xa7, 0x86, 0x15, 0xf2, 0x87, 0xe6, 174 0xa1, 0xc8, 0xb1, 0x20, 0xd7, 0x06, 0x2a, 0x49, 175 0x3f, 0x98, 0xd2, 0x03, 0xe6, 0xbe, 0x49, 0xa6, 176 0xad, 0xf4, 0xfa, 0x57, 0x4b, 0x6e, 0x64, 0xee 177 }, 178 }, { 179 1200, 180 "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX" 181 "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX", 182 "pass phrase equals block size", 183 { 184 0x13, 0x9c, 0x30, 0xc0, 0x96, 0x6b, 0xc3, 0x2b, 185 0xa5, 0x5f, 0xdb, 0xf2, 0x12, 0x53, 0x0a, 0xc9, 186 0xc5, 0xec, 0x59, 0xf1, 0xa4, 0x52, 0xf5, 0xcc, 187 0x9a, 0xd9, 0x40, 0xfe, 0xa0, 0x59, 0x8e, 0xd1 188 }, 189 }, { 190 1200, 191 "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX" 192 "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX", 193 "pass phrase exceeds block size", 194 { 195 0x9c, 0xca, 0xd6, 0xd4, 0x68, 0x77, 0x0c, 0xd5, 196 0x1b, 0x10, 0xe6, 0xa6, 0x87, 0x21, 0xbe, 0x61, 197 0x1a, 0x8b, 0x4d, 0x28, 0x26, 0x01, 0xdb, 0x3b, 198 0x36, 0xbe, 0x92, 0x46, 0x91, 0x5e, 0xc8, 0x2a 199 }, 200 }, { 201 50, 202 "\360\235\204\236", /* g-clef (0xf09d849e) */ 203 "EXAMPLE.COMpianist", 204 { 205 0x6b, 0x9c, 0xf2, 0x6d, 0x45, 0x45, 0x5a, 0x43, 206 0xa5, 0xb8, 0xbb, 0x27, 0x6a, 0x40, 0x3b, 0x39, 207 0xe7, 0xfe, 0x37, 0xa0, 0xc4, 0x1e, 0x02, 0xc2, 208 0x81, 0xff, 0x30, 0x69, 0xe1, 0xe9, 0x4f, 0x52 209 }, 210 } 211}; 212#define NVECS (sizeof(test_vectors) / sizeof(*test_vectors)) 213 214#include <stdio.h> 215#include <err.h> 216 217static void 218printhex(const char *s, const u_int8_t *buf, size_t len) 219{ 220 size_t i; 221 222 printf("%s: ", s); 223 for (i = 0; i < len; i++) 224 printf("%02x", buf[i]); 225 printf("\n"); 226 fflush(stdout); 227} 228 229int 230main(int argc, char **argv) 231{ 232 u_int i, j; 233 u_char result[32]; 234 struct test_vector *vec; 235 236 for (i = 0; i < NVECS; i++) { 237 vec = &test_vectors[i]; 238 printf("vector %u\n", i); 239 for (j = 1; j < sizeof(result); j += 3) { 240 if (pkcs5_pbkdf2(vec->pass, strlen(vec->pass), 241 vec->salt, strlen(vec->salt), 242 result, j, vec->rounds) != 0) 243 errx(1, "pbkdf2 failed"); 244 if (memcmp(result, vec->expected, j) != 0) { 245 printhex(" got", result, j); 246 printhex("want", vec->expected, j); 247 return 1; 248 } 249 } 250 } 251 return 0; 252} 253#endif /* PBKDF2_MAIN */ 254