Path: blob/master/libs/tomcrypt/src/misc/pkcs5/pkcs_5_1.c
5972 views
/* LibTomCrypt, modular cryptographic library -- Tom St Denis1*2* LibTomCrypt is a library that provides various cryptographic3* algorithms in a highly modular and flexible manner.4*5* The library is free for all purposes without any express6* guarantee it works.7*/8#include "tomcrypt.h"910/**11@file pkcs_5_1.c12PKCS #5, Algorithm #1, Tom St Denis13*/14#ifdef LTC_PKCS_515/**16Execute PKCS #5 v1 in strict or OpenSSL EVP_BytesToKey()-compat mode.1718PKCS#5 v1 specifies that the output key length can be no larger than19the hash output length. OpenSSL unilaterally extended that by repeating20the hash process on a block-by-block basis for as long as needed to make21bigger keys. If you want to be compatible with KDF for e.g. "openssl enc",22you'll want that.2324If you want strict PKCS behavior, turn openssl_compat off. Or (more25likely), use one of the convenience functions below.2627@param password The password (or key)28@param password_len The length of the password (octet)29@param salt The salt (or nonce) which is 8 octets long30@param iteration_count The PKCS #5 v1 iteration count31@param hash_idx The index of the hash desired32@param out [out] The destination for this algorithm33@param outlen [in/out] The max size and resulting size of the algorithm output34@param openssl_compat [in] Whether or not to grow the key to the buffer size ala OpenSSL35@return CRYPT_OK if successful36*/37static int _pkcs_5_alg1_common(const unsigned char *password,38unsigned long password_len,39const unsigned char *salt,40int iteration_count, int hash_idx,41unsigned char *out, unsigned long *outlen,42int openssl_compat)43{44int err;45unsigned long x;46hash_state *md;47unsigned char *buf;48/* Storage vars in case we need to support > hashsize (OpenSSL compat) */49unsigned long block = 0, iter;50/* How many bytes to put in the outbut buffer (convenience calc) */51unsigned long outidx = 0, nb = 0;5253LTC_ARGCHK(password != NULL);54LTC_ARGCHK(salt != NULL);55LTC_ARGCHK(out != NULL);56LTC_ARGCHK(outlen != NULL);5758/* test hash IDX */59if ((err = hash_is_valid(hash_idx)) != CRYPT_OK) {60return err;61}6263/* allocate memory */64md = XMALLOC(sizeof(hash_state));65buf = XMALLOC(MAXBLOCKSIZE);66if (md == NULL || buf == NULL) {67if (md != NULL) {68XFREE(md);69}70if (buf != NULL) {71XFREE(buf);72}73return CRYPT_MEM;74}7576while(block * hash_descriptor[hash_idx].hashsize < *outlen) {7778/* hash initial (maybe previous hash) + password + salt */79if ((err = hash_descriptor[hash_idx].init(md)) != CRYPT_OK) {80goto LBL_ERR;81}82/* in OpenSSL mode, we first hash the previous result for blocks 2-n */83if (openssl_compat && block) {84if ((err = hash_descriptor[hash_idx].process(md, buf, hash_descriptor[hash_idx].hashsize)) != CRYPT_OK) {85goto LBL_ERR;86}87}88if ((err = hash_descriptor[hash_idx].process(md, password, password_len)) != CRYPT_OK) {89goto LBL_ERR;90}91if ((err = hash_descriptor[hash_idx].process(md, salt, 8)) != CRYPT_OK) {92goto LBL_ERR;93}94if ((err = hash_descriptor[hash_idx].done(md, buf)) != CRYPT_OK) {95goto LBL_ERR;96}9798iter = iteration_count;99while (--iter) {100/* code goes here. */101x = MAXBLOCKSIZE;102if ((err = hash_memory(hash_idx, buf, hash_descriptor[hash_idx].hashsize, buf, &x)) != CRYPT_OK) {103goto LBL_ERR;104}105}106107/* limit the size of the copy to however many bytes we have left in108the output buffer (and how many bytes we have to copy) */109outidx = block*hash_descriptor[hash_idx].hashsize;110nb = hash_descriptor[hash_idx].hashsize;111if(outidx+nb > *outlen)112nb = *outlen - outidx;113if(nb > 0)114XMEMCPY(out+outidx, buf, nb);115116block++;117if (!openssl_compat)118break;119}120/* In strict mode, we always return the hashsize, in compat we filled it121as much as was requested, so we leave it alone. */122if(!openssl_compat)123*outlen = hash_descriptor[hash_idx].hashsize;124125err = CRYPT_OK;126LBL_ERR:127#ifdef LTC_CLEAN_STACK128zeromem(buf, MAXBLOCKSIZE);129zeromem(md, sizeof(hash_state));130#endif131132XFREE(buf);133XFREE(md);134135return err;136}137138/**139Execute PKCS #5 v1 - Strict mode (no OpenSSL-compatible extension)140@param password The password (or key)141@param password_len The length of the password (octet)142@param salt The salt (or nonce) which is 8 octets long143@param iteration_count The PKCS #5 v1 iteration count144@param hash_idx The index of the hash desired145@param out [out] The destination for this algorithm146@param outlen [in/out] The max size and resulting size of the algorithm output147@return CRYPT_OK if successful148*/149int pkcs_5_alg1(const unsigned char *password, unsigned long password_len,150const unsigned char *salt,151int iteration_count, int hash_idx,152unsigned char *out, unsigned long *outlen)153{154return _pkcs_5_alg1_common(password, password_len, salt, iteration_count,155hash_idx, out, outlen, 0);156}157158/**159Execute PKCS #5 v1 - OpenSSL-extension-compatible mode160161Use this one if you need to derive keys as "openssl enc" does by default.162OpenSSL (for better or worse), uses MD5 as the hash and iteration_count=1.163@param password The password (or key)164@param password_len The length of the password (octet)165@param salt The salt (or nonce) which is 8 octets long166@param iteration_count The PKCS #5 v1 iteration count167@param hash_idx The index of the hash desired168@param out [out] The destination for this algorithm169@param outlen [in/out] The max size and resulting size of the algorithm output170@return CRYPT_OK if successful171*/172int pkcs_5_alg1_openssl(const unsigned char *password,173unsigned long password_len,174const unsigned char *salt,175int iteration_count, int hash_idx,176unsigned char *out, unsigned long *outlen)177{178return _pkcs_5_alg1_common(password, password_len, salt, iteration_count,179hash_idx, out, outlen, 1);180}181182#endif183184185