]> pd.if.org Git - zpackage/blob - libtomcrypt/src/misc/pkcs5/pkcs_5_1.c
commit files needed for zpm-fetchurl
[zpackage] / libtomcrypt / src / misc / pkcs5 / pkcs_5_1.c
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 #include "tomcrypt.h"
10
11 /**
12    @file pkcs_5_1.c
13    PKCS #5, Algorithm #1, Tom St Denis
14 */
15 #ifdef LTC_PKCS_5
16 /**
17    Execute PKCS #5 v1 in strict or OpenSSL EVP_BytesToKey()-compat mode.
18
19    PKCS#5 v1 specifies that the output key length can be no larger than
20    the hash output length.  OpenSSL unilaterally extended that by repeating
21    the hash process on a block-by-block basis for as long as needed to make
22    bigger keys.  If you want to be compatible with KDF for e.g. "openssl enc",
23    you'll want that.
24
25    If you want strict PKCS behavior, turn openssl_compat off.  Or (more
26    likely), use one of the convenience functions below.
27
28    @param password         The password (or key)
29    @param password_len     The length of the password (octet)
30    @param salt             The salt (or nonce) which is 8 octets long
31    @param iteration_count  The PKCS #5 v1 iteration count
32    @param hash_idx         The index of the hash desired
33    @param out              [out] The destination for this algorithm
34    @param outlen           [in/out] The max size and resulting size of the algorithm output
35    @param openssl_compat   [in] Whether or not to grow the key to the buffer size ala OpenSSL
36    @return CRYPT_OK if successful
37 */
38 static int _pkcs_5_alg1_common(const unsigned char *password,
39                        unsigned long password_len,
40                        const unsigned char *salt,
41                        int iteration_count,  int hash_idx,
42                        unsigned char *out,   unsigned long *outlen,
43                        int openssl_compat)
44 {
45    int err;
46    unsigned long x;
47    hash_state    *md;
48    unsigned char *buf;
49    /* Storage vars in case we need to support > hashsize (OpenSSL compat) */
50    unsigned long block = 0, iter;
51    /* How many bytes to put in the outbut buffer (convenience calc) */
52    unsigned long outidx = 0, nb = 0;
53
54    LTC_ARGCHK(password != NULL);
55    LTC_ARGCHK(salt     != NULL);
56    LTC_ARGCHK(out      != NULL);
57    LTC_ARGCHK(outlen   != NULL);
58
59    /* test hash IDX */
60    if ((err = hash_is_valid(hash_idx)) != CRYPT_OK) {
61       return err;
62    }
63
64    /* allocate memory */
65    md  = XMALLOC(sizeof(hash_state));
66    buf = XMALLOC(MAXBLOCKSIZE);
67    if (md == NULL || buf == NULL) {
68       if (md != NULL) {
69          XFREE(md);
70       }
71       if (buf != NULL) {
72          XFREE(buf);
73       }
74       return CRYPT_MEM;
75    }
76
77    while(block * hash_descriptor[hash_idx].hashsize < *outlen) {
78
79       /* hash initial (maybe previous hash) + password + salt */
80       if ((err = hash_descriptor[hash_idx].init(md)) != CRYPT_OK) {
81           goto LBL_ERR;
82       }
83       /* in OpenSSL mode, we first hash the previous result for blocks 2-n */
84       if (openssl_compat && block) {
85           if ((err = hash_descriptor[hash_idx].process(md, buf, hash_descriptor[hash_idx].hashsize)) != CRYPT_OK) {
86               goto LBL_ERR;
87           }
88       }
89       if ((err = hash_descriptor[hash_idx].process(md, password, password_len)) != CRYPT_OK) {
90           goto LBL_ERR;
91       }
92       if ((err = hash_descriptor[hash_idx].process(md, salt, 8)) != CRYPT_OK) {
93           goto LBL_ERR;
94       }
95       if ((err = hash_descriptor[hash_idx].done(md, buf)) != CRYPT_OK) {
96           goto LBL_ERR;
97       }
98
99       iter = iteration_count;
100       while (--iter) {
101          /* code goes here. */
102          x = MAXBLOCKSIZE;
103          if ((err = hash_memory(hash_idx, buf, hash_descriptor[hash_idx].hashsize, buf, &x)) != CRYPT_OK) {
104             goto LBL_ERR;
105          }
106       }
107
108       /* limit the size of the copy to however many bytes we have left in
109          the output buffer (and how many bytes we have to copy) */
110       outidx = block*hash_descriptor[hash_idx].hashsize;
111       nb = hash_descriptor[hash_idx].hashsize;
112       if(outidx+nb > *outlen)
113           nb = *outlen - outidx;
114       if(nb > 0)
115           XMEMCPY(out+outidx, buf, nb);
116
117       block++;
118       if (!openssl_compat)
119           break;
120    }
121    /* In strict mode, we always return the hashsize, in compat we filled it
122       as much as was requested, so we leave it alone. */
123    if(!openssl_compat)
124       *outlen = hash_descriptor[hash_idx].hashsize;
125
126    err = CRYPT_OK;
127 LBL_ERR:
128 #ifdef LTC_CLEAN_STACK
129    zeromem(buf, MAXBLOCKSIZE);
130    zeromem(md, sizeof(hash_state));
131 #endif
132
133    XFREE(buf);
134    XFREE(md);
135
136    return err;
137 }
138
139 /**
140    Execute PKCS #5 v1 - Strict mode (no OpenSSL-compatible extension)
141    @param password         The password (or key)
142    @param password_len     The length of the password (octet)
143    @param salt             The salt (or nonce) which is 8 octets long
144    @param iteration_count  The PKCS #5 v1 iteration count
145    @param hash_idx         The index of the hash desired
146    @param out              [out] The destination for this algorithm
147    @param outlen           [in/out] The max size and resulting size of the algorithm output
148    @return CRYPT_OK if successful
149 */
150 int pkcs_5_alg1(const unsigned char *password, unsigned long password_len,
151                 const unsigned char *salt,
152                 int iteration_count,  int hash_idx,
153                 unsigned char *out,   unsigned long *outlen)
154 {
155    return _pkcs_5_alg1_common(password, password_len, salt, iteration_count,
156                              hash_idx, out, outlen, 0);
157 }
158
159 /**
160    Execute PKCS #5 v1 - OpenSSL-extension-compatible mode
161
162    Use this one if you need to derive keys as "openssl enc" does by default.
163    OpenSSL (for better or worse), uses MD5 as the hash and iteration_count=1.
164    @param password         The password (or key)
165    @param password_len     The length of the password (octet)
166    @param salt             The salt (or nonce) which is 8 octets long
167    @param iteration_count  The PKCS #5 v1 iteration count
168    @param hash_idx         The index of the hash desired
169    @param out              [out] The destination for this algorithm
170    @param outlen           [in/out] The max size and resulting size of the algorithm output
171    @return CRYPT_OK if successful
172 */
173 int pkcs_5_alg1_openssl(const unsigned char *password,
174                         unsigned long password_len,
175                         const unsigned char *salt,
176                         int iteration_count,  int hash_idx,
177                         unsigned char *out,   unsigned long *outlen)
178 {
179    return _pkcs_5_alg1_common(password, password_len, salt, iteration_count,
180                              hash_idx, out, outlen, 1);
181 }
182
183 #endif
184
185 /* ref:         $Format:%D$ */
186 /* git commit:  $Format:%H$ */
187 /* commit time: $Format:%ai$ */