1 /* LibTomCrypt, modular cryptographic library -- Tom St Denis
3 * LibTomCrypt is a library that provides various cryptographic
4 * algorithms in a highly modular and flexible manner.
6 * The library is free for all purposes without any express
13 PKCS #5, Algorithm #1, Tom St Denis
17 Execute PKCS #5 v1 in strict or OpenSSL EVP_BytesToKey()-compat mode.
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",
25 If you want strict PKCS behavior, turn openssl_compat off. Or (more
26 likely), use one of the convenience functions below.
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
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,
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;
54 LTC_ARGCHK(password != NULL);
55 LTC_ARGCHK(salt != NULL);
56 LTC_ARGCHK(out != NULL);
57 LTC_ARGCHK(outlen != NULL);
60 if ((err = hash_is_valid(hash_idx)) != CRYPT_OK) {
65 md = XMALLOC(sizeof(hash_state));
66 buf = XMALLOC(MAXBLOCKSIZE);
67 if (md == NULL || buf == NULL) {
77 while(block * hash_descriptor[hash_idx].hashsize < *outlen) {
79 /* hash initial (maybe previous hash) + password + salt */
80 if ((err = hash_descriptor[hash_idx].init(md)) != CRYPT_OK) {
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) {
89 if ((err = hash_descriptor[hash_idx].process(md, password, password_len)) != CRYPT_OK) {
92 if ((err = hash_descriptor[hash_idx].process(md, salt, 8)) != CRYPT_OK) {
95 if ((err = hash_descriptor[hash_idx].done(md, buf)) != CRYPT_OK) {
99 iter = iteration_count;
101 /* code goes here. */
103 if ((err = hash_memory(hash_idx, buf, hash_descriptor[hash_idx].hashsize, buf, &x)) != CRYPT_OK) {
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;
115 XMEMCPY(out+outidx, buf, nb);
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. */
124 *outlen = hash_descriptor[hash_idx].hashsize;
128 #ifdef LTC_CLEAN_STACK
129 zeromem(buf, MAXBLOCKSIZE);
130 zeromem(md, sizeof(hash_state));
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
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)
155 return _pkcs_5_alg1_common(password, password_len, salt, iteration_count,
156 hash_idx, out, outlen, 0);
160 Execute PKCS #5 v1 - OpenSSL-extension-compatible mode
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
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)
179 return _pkcs_5_alg1_common(password, password_len, salt, iteration_count,
180 hash_idx, out, outlen, 1);
185 /* ref: $Format:%D$ */
186 /* git commit: $Format:%H$ */
187 /* commit time: $Format:%ai$ */