]> err.no Git - yubikey-personalization/blob - ykpbkdf2.c
Merge tag 'v1.15.1'
[yubikey-personalization] / ykpbkdf2.c
1 /* -*- mode:C; c-file-style: "bsd" -*- */
2 /* Copyright (c) 2008-2013 Yubico AB
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions are
7  * met:
8  *
9  *     * Redistributions of source code must retain the above copyright
10  *       notice, this list of conditions and the following disclaimer.
11  *
12  *     * Redistributions in binary form must reproduce the above
13  *       copyright notice, this list of conditions and the following
14  *       disclaimer in the documentation and/or other materials provided
15  *       with the distribution.
16  *
17  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
18  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
19  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
20  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
21  * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
22  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
23  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
27  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28  */
29
30 #include <string.h>
31
32 #include <ykpbkdf2.h>
33
34 #include "sha.h"
35
36 int yk_hmac_sha1(const char *key, size_t key_len,
37                      const char *text, size_t text_len,
38                      uint8_t *output, size_t output_size)
39 {
40         if (output_size < SHA1HashSize)
41                 return 0;
42
43         if (hmac(SHA1,
44                  (const unsigned char *)text, (int)text_len,
45                  (const unsigned char *)key, (int)key_len,
46                  output))
47                 return 0;
48         return 1;
49 }
50
51 int yk_pbkdf2(const char *passphrase,
52               const unsigned char *salt, size_t salt_len,
53               unsigned int iterations,
54               unsigned char *dk, size_t dklen,
55               YK_PRF_METHOD *prf_method)
56 {
57         size_t l = ((dklen - 1 + prf_method->output_size)
58                     / prf_method->output_size);
59 #if 0 /* r for "rest" is unused but may be interesting in the future */
60         size_t r = dklen - ((l - 1) * prf_method->output_size);
61 #endif
62
63         unsigned int block_count;
64
65         memset(dk, 0, dklen);
66
67         for (block_count = 1; block_count <= l; block_count++) {
68                 unsigned char block[256]; /* A big chunk, that's 2048 bits */
69                 size_t block_len;
70                 unsigned int iteration;
71                 size_t i;
72
73                 memcpy(block, salt, salt_len);
74                 block[salt_len + 0] = (block_count & 0xff000000) >> 24;
75                 block[salt_len + 1] = (block_count & 0x00ff0000) >> 16;
76                 block[salt_len + 2] = (block_count & 0x0000ff00) >>  8;
77                 block[salt_len + 3] = (block_count & 0x000000ff) >>  0;
78                 block_len = salt_len + 4;
79
80                 for (iteration = 0; iteration < iterations; iteration++) {
81                         if (!prf_method->prf_fn(passphrase, strlen(passphrase),
82                                                 (char *)block, block_len,
83                                                 block, sizeof(block)))
84                                 return 0;
85                         block_len = prf_method->output_size;
86                         for(i = 0; i < dklen; i++) {
87                                 dk[i] ^= block[i];
88                         }
89                 }
90
91                 if (block_len > dklen)
92                         block_len = dklen; /* This happens in the last block */
93                 dk += block_len;
94                 dklen -= block_len;
95         }
96         return 1;
97 }