1/* LibTomCrypt, modular cryptographic library -- Tom St Denis
2 *
3 * LibTomCrypt is a library that provides various cryptographic
4 * algorithms in a highly modular and flexible manner.
5 *
6 * The library is free for all purposes without any express
7 * guarantee it works.
8 *
9 * Tom St Denis, tomstdenis@gmail.com, http://libtomcrypt.com
10 */
11#include <tomcrypt.h>
12
13/**
14   @file pkcs_5_2.c
15   PKCS #5, Algorithm #2, Tom St Denis
16*/
17#ifdef PKCS_5
18
19/**
20   Execute PKCS #5 v2
21   @param password          The input password (or key)
22   @param password_len      The length of the password (octets)
23   @param salt              The salt (or nonce)
24   @param salt_len          The length of the salt (octets)
25   @param iteration_count   # of iterations desired for PKCS #5 v2 [read specs for more]
26   @param hash_idx          The index of the hash desired
27   @param out               [out] The destination for this algorithm
28   @param outlen            [in/out] The max size and resulting size of the algorithm output
29   @return CRYPT_OK if successful
30*/
31int pkcs_5_alg2(const unsigned char *password, unsigned long password_len,
32                const unsigned char *salt,     unsigned long salt_len,
33                int iteration_count,           int hash_idx,
34                unsigned char *out,            unsigned long *outlen)
35{
36   int err, itts;
37   ulong32  blkno;
38   unsigned long stored, left, x, y;
39   unsigned char *buf[2];
40   hmac_state    *hmac;
41
42   LTC_ARGCHK(password != NULL);
43   LTC_ARGCHK(salt     != NULL);
44   LTC_ARGCHK(out      != NULL);
45   LTC_ARGCHK(outlen   != NULL);
46
47   /* test hash IDX */
48   if ((err = hash_is_valid(hash_idx)) != CRYPT_OK) {
49      return err;
50   }
51
52   buf[0] = XMALLOC(MAXBLOCKSIZE * 2);
53   hmac   = XMALLOC(sizeof(hmac_state));
54   if (hmac == NULL || buf[0] == NULL) {
55      if (hmac != NULL) {
56         XFREE(hmac);
57      }
58      if (buf[0] != NULL) {
59         XFREE(buf[0]);
60      }
61      return CRYPT_MEM;
62   }
63   /* buf[1] points to the second block of MAXBLOCKSIZE bytes */
64   buf[1] = buf[0] + MAXBLOCKSIZE;
65
66   left   = *outlen;
67   blkno  = 1;
68   stored = 0;
69   while (left != 0) {
70       /* process block number blkno */
71       zeromem(buf[0], MAXBLOCKSIZE*2);
72
73       /* store current block number and increment for next pass */
74       STORE32H(blkno, buf[1]);
75       ++blkno;
76
77       /* get PRF(P, S||int(blkno)) */
78       if ((err = hmac_init(hmac, hash_idx, password, password_len)) != CRYPT_OK) {
79          goto LBL_ERR;
80       }
81       if ((err = hmac_process(hmac, salt, salt_len)) != CRYPT_OK) {
82          goto LBL_ERR;
83       }
84       if ((err = hmac_process(hmac, buf[1], 4)) != CRYPT_OK) {
85          goto LBL_ERR;
86       }
87       x = MAXBLOCKSIZE;
88       if ((err = hmac_done(hmac, buf[0], &x)) != CRYPT_OK) {
89          goto LBL_ERR;
90       }
91
92       /* now compute repeated and XOR it in buf[1] */
93       XMEMCPY(buf[1], buf[0], x);
94       for (itts = 1; itts < iteration_count; ++itts) {
95           if ((err = hmac_memory(hash_idx, password, password_len, buf[0], x, buf[0], &x)) != CRYPT_OK) {
96              goto LBL_ERR;
97           }
98           for (y = 0; y < x; y++) {
99               buf[1][y] ^= buf[0][y];
100           }
101       }
102
103       /* now emit upto x bytes of buf[1] to output */
104       for (y = 0; y < x && left != 0; ++y) {
105           out[stored++] = buf[1][y];
106           --left;
107       }
108   }
109   *outlen = stored;
110
111   err = CRYPT_OK;
112LBL_ERR:
113#ifdef LTC_CLEAN_STACK
114   zeromem(buf[0], MAXBLOCKSIZE*2);
115   zeromem(hmac, sizeof(hmac_state));
116#endif
117
118   XFREE(hmac);
119   XFREE(buf[0]);
120
121   return err;
122}
123
124#endif
125
126
127/* $Source: /cvs/libtom/libtomcrypt/src/misc/pkcs5/pkcs_5_2.c,v $ */
128/* $Revision: 1.5 $ */
129/* $Date: 2006/03/31 14:15:35 $ */
130