Add OpenSSL-compatible PKCS#5v1 KDF, demo of OpenSSL-compatible aes-256-cbc command.
This commit is contained in:
parent
bbe54053ec
commit
c7d6c3ad28
13
crypt.tex
13
crypt.tex
@ -5070,6 +5070,8 @@ In order to securely handle user passwords for the purposes of creating session
|
||||
is made up of two algorithms, Algorithm One and Algorithm Two. Algorithm One is the older fairly limited algorithm which has been implemented
|
||||
for completeness. Algorithm Two is a bit more modern and more flexible to work with.
|
||||
|
||||
The OpenSSL project implemented an extension to Algorithm One that allows for arbitrary keylengths; we have a compatible implementation described below.
|
||||
|
||||
\subsection{Algorithm One}
|
||||
Algorithm One accepts as input a password, an 8--byte salt, and an iteration counter. The iteration counter is meant to act as delay for
|
||||
people trying to brute force guess the password. The higher the iteration counter the longer the delay. This algorithm also requires a hash
|
||||
@ -5092,6 +5094,17 @@ on the password. The \textit{hash\_idx} is the index of the hash you wish to us
|
||||
The output of length up to \textit{outlen} is stored in \textit{out}. If \textit{outlen} is initially larger than the size of the hash functions output
|
||||
it is set to the number of bytes stored. If it is smaller than not all of the hash output is stored in \textit{out}.
|
||||
|
||||
\index{pkcs\_5\_alg1\_openssl()}
|
||||
\begin{alltt}
|
||||
int pkcs_5_alg1_openssl(const unsigned char *password,
|
||||
unsigned long password_len,
|
||||
const unsigned char *salt,
|
||||
int iteration_count,
|
||||
int hash_idx,
|
||||
unsigned char *out,
|
||||
unsigned long *outlen)
|
||||
\end{alltt}
|
||||
As above, but we generate as many bytes as requested in outlen per the OpenSSL extension to Algorithm One. If you are trying to be compatible with OpenSSL's EVP\_BytesToKey() or the "openssl enc" command line (or variants such as perl's Crypt::CBC), then use this function with MD5 as your hash (ick!) and iteration\_count=1 (double-ick!!).
|
||||
\subsection{Algorithm Two}
|
||||
|
||||
Algorithm Two is the recommended algorithm for this task. It allows variable length salts, and can produce outputs larger than the
|
||||
|
381
demos/openssl-enc.c
Normal file
381
demos/openssl-enc.c
Normal file
@ -0,0 +1,381 @@
|
||||
/*
|
||||
* Demo to do the rough equivalent of:
|
||||
*
|
||||
* openssl enc -aes-256-cbc -pass pass:foobar -in infile -out outfile -p
|
||||
*
|
||||
* Compilation:
|
||||
*
|
||||
* $(CC) -I /path/to/headers -L .../libs \
|
||||
* -o openssl-enc \
|
||||
* openssl-enc.c -ltomcrypt
|
||||
*
|
||||
* Usage:
|
||||
*
|
||||
* ./openssl-enc <enc|dec> infile outfile "passphrase" [salt]
|
||||
*
|
||||
* If provided, the salt must be EXACTLY a 16-char hex string.
|
||||
*
|
||||
* Demo is an example of:
|
||||
*
|
||||
* - (When decrypting) yanking salt out of the OpenSSL "Salted__..." header
|
||||
* - OpenSSL-compatible key derivation (in OpenSSL's modified PKCS#5v1 approach)
|
||||
* - Grabbing an Initialization Vector from the key generator
|
||||
* - Performing simple block encryption using AES
|
||||
* - PKCS#7-type padding (which hopefully can get ripped out of this demo and
|
||||
* made a libtomcrypt thing someday).
|
||||
*
|
||||
* This program is free for all purposes without any express guarantee it
|
||||
* works. If you really want to see a license here, assume the WTFPL :-)
|
||||
*
|
||||
* BJ Black, bblack@barracuda.com, https://wjblack.com
|
||||
*
|
||||
* BUGS:
|
||||
* Passing a password on a command line is a HORRIBLE idea. Don't use
|
||||
* this program for serious work!
|
||||
*/
|
||||
|
||||
#include <tomcrypt.h>
|
||||
|
||||
#ifndef LTC_RIJNDAEL
|
||||
#error Cannot compile this demo; Rijndael (AES) required
|
||||
#endif
|
||||
#ifndef LTC_CBC_MODE
|
||||
#error Cannot compile this demo; CBC mode required
|
||||
#endif
|
||||
#ifndef LTC_PKCS_5
|
||||
#error Cannot compile this demo; PKCS5 required
|
||||
#endif
|
||||
#ifndef LTC_RNG_GET_BYTES
|
||||
#error Cannot compile this demo; random generator required
|
||||
#endif
|
||||
|
||||
/* OpenSSL by default only runs one hash round */
|
||||
#define OPENSSL_ITERATIONS 1
|
||||
/* Use aes-256-cbc, so 256 bits of key, 128 of IV */
|
||||
#define KEY_LENGTH (256>>3)
|
||||
#define IV_LENGTH (128>>3)
|
||||
/* PKCS#5v1 requires exactly an 8-byte salt */
|
||||
#define SALT_LENGTH 8
|
||||
/* The header OpenSSL puts on an encrypted file */
|
||||
static char salt_header[] = { 'S', 'a', 'l', 't', 'e', 'd', '_', '_' };
|
||||
|
||||
#include <errno.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
/* A simple way to handle the possibility that a block may increase in size
|
||||
after padding. */
|
||||
union paddable {
|
||||
char unpad[1024];
|
||||
char pad[1024+MAXBLOCKSIZE];
|
||||
};
|
||||
|
||||
/*
|
||||
* Print usage and exit with a bad status (and perror() if any errno).
|
||||
*
|
||||
* Input: argv[0] and the error string
|
||||
* Output: <no return>
|
||||
* Side Effects: print messages and barf (does exit(3))
|
||||
*/
|
||||
void barf(char *pname, char *err)
|
||||
{
|
||||
printf("Usage: %s <enc|dec> infile outfile [salt]\n", pname);
|
||||
printf("\n");
|
||||
printf(" # encrypts infile->outfile, random salt\n");
|
||||
printf(" %s enc infile outfile \"passphrase\"\n", pname);
|
||||
printf("\n");
|
||||
printf(" # encrypts infile->outfile, salt from cmdline\n");
|
||||
printf(" %s enc infile outfile pass 0123456789abcdef\n", pname);
|
||||
printf("\n");
|
||||
printf(" # decrypts infile->outfile, pulls salt from infile\n");
|
||||
printf(" %s dec infile outfile pass\n", pname);
|
||||
printf("\n");
|
||||
printf(" # decrypts infile->outfile, salt specified\n");
|
||||
printf(" # (don't try to read the salt from infile)\n");
|
||||
printf(" %s dec infile outfile pass 0123456789abcdef"
|
||||
"\n", pname);
|
||||
printf("\n");
|
||||
printf("Application Error: %s\n", err);
|
||||
if(errno)
|
||||
perror(" System Error");
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
/*
|
||||
* Parse a salt value passed in on the cmdline.
|
||||
*
|
||||
* Input: string passed in and a buf to put it in (exactly 8 bytes!)
|
||||
* Output: CRYPT_OK if parsed OK, CRYPT_ERROR if not
|
||||
* Side Effects: none
|
||||
*/
|
||||
int parse_hex_salt(unsigned char *in, unsigned char *out)
|
||||
{
|
||||
int idx;
|
||||
for(idx=0; idx<SALT_LENGTH; idx++)
|
||||
if(sscanf(in+idx*2, "%02hhx", out+idx) != 1)
|
||||
return CRYPT_ERROR;
|
||||
return CRYPT_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
* Parse the Salted__[+8 bytes] from an OpenSSL-compatible file header.
|
||||
*
|
||||
* Input: file to read from and a to put the salt in (exactly 8 bytes!)
|
||||
* Output: CRYPT_OK if parsed OK, CRYPT_ERROR if not
|
||||
* Side Effects: infile's read pointer += 16
|
||||
*/
|
||||
int parse_openssl_header(FILE *in, unsigned char *out)
|
||||
{
|
||||
unsigned char tmp[SALT_LENGTH];
|
||||
if(fread(tmp, 1, sizeof(tmp), in) != sizeof(tmp))
|
||||
return CRYPT_ERROR;
|
||||
if(memcmp(tmp, salt_header, sizeof(tmp)))
|
||||
return CRYPT_ERROR;
|
||||
if(fread(tmp, 1, sizeof(tmp), in) != sizeof(tmp))
|
||||
return CRYPT_ERROR;
|
||||
memcpy(out, tmp, sizeof(tmp));
|
||||
return CRYPT_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
* Dump a hexed stream of bytes (convenience func).
|
||||
*
|
||||
* Input: buf to read from, length
|
||||
* Output: none
|
||||
* Side Effects: bytes printed as a hex blob, no lf at the end
|
||||
*/
|
||||
void dump_bytes(unsigned char *in, unsigned long len)
|
||||
{
|
||||
unsigned long idx;
|
||||
for(idx=0; idx<len; idx++)
|
||||
printf("%02hhX", *(in+idx));
|
||||
}
|
||||
|
||||
/*
|
||||
* Pad or unpad a message using PKCS#7 padding.
|
||||
* Padding will add 1-(blocksize) bytes and unpadding will remove that amount.
|
||||
* Set is_padding to 1 to pad, 0 to unpad.
|
||||
*
|
||||
* Input: paddable buffer, size read, block length of cipher, mode
|
||||
* Output: none
|
||||
* Side Effects: bytes printed as a hex blob, no lf at the end
|
||||
*/
|
||||
size_t pkcs7_pad(union paddable *buf, size_t nb, int block_length,
|
||||
int is_padding)
|
||||
{
|
||||
unsigned char padval;
|
||||
off_t idx;
|
||||
|
||||
if(is_padding) {
|
||||
/* We are PADDING this block (and therefore adding bytes) */
|
||||
/* The pad value in PKCS#7 is the number of bytes remaining in
|
||||
the block, so for a 16-byte block and 3 bytes left, it's
|
||||
0x030303. In the oddball case where nb is an exact multiple
|
||||
multiple of block_length, set the padval to blocksize (i.e.
|
||||
add one full block) */
|
||||
padval = (unsigned char) (block_length - (nb % block_length));
|
||||
padval = padval ? padval : block_length;
|
||||
|
||||
XMEMSET(buf->pad+nb, padval, padval);
|
||||
return nb+padval;
|
||||
} else {
|
||||
/* We are UNPADDING this block (and removing bytes)
|
||||
We really just need to verify that the pad bytes are correct,
|
||||
so start at the end of the string and work backwards. */
|
||||
|
||||
/* Figure out what the padlength should be by looking at the
|
||||
last byte */
|
||||
idx = nb-1;
|
||||
padval = buf->pad[idx];
|
||||
|
||||
/* padval must be nonzero and <= block length */
|
||||
if(padval <= 0 || padval > block_length)
|
||||
return -1;
|
||||
|
||||
/* First byte's accounted for; do the rest */
|
||||
idx--;
|
||||
|
||||
while(idx >= nb-padval)
|
||||
if(buf->pad[idx] != padval)
|
||||
return -1;
|
||||
else
|
||||
idx--;
|
||||
|
||||
/* If we got here, the pad checked out, so return a smaller
|
||||
number of bytes than nb (basically where we left off+1) */
|
||||
return idx+1;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Perform an encrypt/decrypt operation to/from files using AES+CBC+PKCS7 pad.
|
||||
* Set encrypt to 1 to encrypt, 0 to decrypt.
|
||||
*
|
||||
* Input: in/out files, key, iv, and mode
|
||||
* Output: CRYPT_OK if no error
|
||||
* Side Effects: bytes slurped from infile, pushed to outfile, fds updated.
|
||||
*/
|
||||
int do_crypt(FILE *infd, FILE *outfd, unsigned char *key, unsigned char *iv,
|
||||
int encrypt)
|
||||
{
|
||||
union paddable inbuf, outbuf;
|
||||
int cipher, ret;
|
||||
symmetric_CBC cbc;
|
||||
size_t nb;
|
||||
|
||||
/* Register your cipher! */
|
||||
cipher = register_cipher(&aes_desc);
|
||||
if(cipher == -1)
|
||||
return CRYPT_INVALID_CIPHER;
|
||||
|
||||
/* Start a CBC session with cipher/key/val params */
|
||||
ret = cbc_start(cipher, iv, key, KEY_LENGTH, 0, &cbc);
|
||||
if( ret != CRYPT_OK )
|
||||
return -1;
|
||||
|
||||
do {
|
||||
/* Get bytes from the source */
|
||||
nb = fread(inbuf.unpad, 1, sizeof(inbuf.unpad), infd);
|
||||
if(!nb)
|
||||
return encrypt ? CRYPT_OK : CRYPT_ERROR;
|
||||
|
||||
/* Barf if we got a read error */
|
||||
if(ferror(infd))
|
||||
return CRYPT_ERROR;
|
||||
|
||||
if(encrypt) {
|
||||
/* We're encrypting, so pad first (if at EOF) and then
|
||||
crypt */
|
||||
if(feof(infd))
|
||||
nb = pkcs7_pad(&inbuf, nb,
|
||||
aes_desc.block_length, 1);
|
||||
|
||||
ret = cbc_encrypt(inbuf.pad, outbuf.pad, nb, &cbc);
|
||||
if(ret != CRYPT_OK)
|
||||
return ret;
|
||||
|
||||
} else {
|
||||
/* We're decrypting, so decrypt and then unpad if at
|
||||
EOF */
|
||||
ret = cbc_decrypt(inbuf.unpad, outbuf.unpad, nb, &cbc);
|
||||
if( ret != CRYPT_OK )
|
||||
return ret;
|
||||
|
||||
if( feof(infd) )
|
||||
nb = pkcs7_pad(&outbuf, nb,
|
||||
aes_desc.block_length, 0);
|
||||
if(nb < 0)
|
||||
/* The file didn't decrypt correctly */
|
||||
return CRYPT_ERROR;
|
||||
|
||||
}
|
||||
|
||||
/* Push bytes to outfile */
|
||||
if(fwrite(outbuf.unpad, 1, nb, outfd) != nb)
|
||||
return CRYPT_ERROR;
|
||||
|
||||
} while(!feof(infd));
|
||||
|
||||
/* Close up */
|
||||
cbc_done(&cbc);
|
||||
|
||||
return CRYPT_OK;
|
||||
}
|
||||
|
||||
/* Convenience macro for the various barfable places below */
|
||||
#define BARF(a) { \
|
||||
if(infd) fclose(infd); \
|
||||
if(outfd) { fclose(outfd); remove(argv[3]); } \
|
||||
barf(argv[0], a); \
|
||||
}
|
||||
/*
|
||||
* The main routine. Mostly validate cmdline params, open files, run the KDF,
|
||||
* and do the crypt.
|
||||
*/
|
||||
int main(int argc, char *argv[]) {
|
||||
unsigned char salt[SALT_LENGTH];
|
||||
FILE *infd = NULL, *outfd = NULL;
|
||||
int encrypt = -1;
|
||||
int hash = -1;
|
||||
int ret;
|
||||
unsigned char keyiv[KEY_LENGTH + IV_LENGTH];
|
||||
unsigned long keyivlen = (KEY_LENGTH + IV_LENGTH);
|
||||
unsigned char *key, *iv;
|
||||
|
||||
/* Check proper number of cmdline args */
|
||||
if(argc < 5 || argc > 6)
|
||||
BARF("Invalid number of arguments");
|
||||
|
||||
/* Check proper mode of operation */
|
||||
if (!strncmp(argv[1], "enc", sizeof("enc")))
|
||||
encrypt = 1;
|
||||
else if(!strncmp(argv[1], "dec", sizeof("dec")))
|
||||
encrypt = 0;
|
||||
else
|
||||
BARF("Bad command name");
|
||||
|
||||
/* Check we can open infile/outfile */
|
||||
infd = fopen(argv[2], "rb");
|
||||
if(infd == NULL)
|
||||
BARF("Could not open infile");
|
||||
outfd = fopen(argv[3], "wb");
|
||||
if(outfd == NULL)
|
||||
BARF("Could not open outfile");
|
||||
|
||||
/* Get the salt from wherever */
|
||||
if(argc == 6) {
|
||||
/* User-provided */
|
||||
if(parse_hex_salt((unsigned char*) argv[5], salt) != CRYPT_OK)
|
||||
BARF("Bad user-specified salt");
|
||||
} else if(!strncmp(argv[1], "enc", sizeof("enc"))) {
|
||||
/* Encrypting; get from RNG */
|
||||
if(rng_get_bytes(salt, sizeof(salt), NULL) != sizeof(salt))
|
||||
BARF("Not enough random data");
|
||||
} else {
|
||||
/* Parse from infile (decrypt only) */
|
||||
if(parse_openssl_header(infd, salt) != CRYPT_OK)
|
||||
BARF("Invalid OpenSSL header in infile");
|
||||
}
|
||||
|
||||
/* Fetch the MD5 hasher for PKCS#5 */
|
||||
hash = register_hash(&md5_desc);
|
||||
if(hash == -1)
|
||||
BARF("Could not register MD5 hash");
|
||||
|
||||
/* Set things to a sane initial state */
|
||||
zeromem(keyiv, sizeof(keyiv));
|
||||
key = keyiv + 0; /* key comes first */
|
||||
iv = keyiv + KEY_LENGTH; /* iv comes next */
|
||||
|
||||
/* Run the key derivation from the provided passphrase. This gets us
|
||||
the key and iv. */
|
||||
ret = pkcs_5_alg1_openssl(argv[4], strlen(argv[4]), salt,
|
||||
OPENSSL_ITERATIONS, hash, keyiv, &keyivlen );
|
||||
if(ret != CRYPT_OK)
|
||||
BARF("Could not derive key/iv from passphrase");
|
||||
|
||||
/* Display the salt/key/iv like OpenSSL cmdline does when -p */
|
||||
printf("salt="); dump_bytes(salt, sizeof(salt)); printf("\n");
|
||||
printf("key="); dump_bytes(key, KEY_LENGTH); printf("\n");
|
||||
printf("iv ="); dump_bytes(iv, IV_LENGTH ); printf("\n");
|
||||
|
||||
/* If we're encrypting, write the salt header as OpenSSL does */
|
||||
if(!strncmp(argv[1], "enc", sizeof("enc"))) {
|
||||
if(fwrite(salt_header, 1, sizeof(salt_header), outfd) !=
|
||||
sizeof(salt_header) )
|
||||
BARF("Error writing salt header to outfile");
|
||||
if(fwrite(salt, 1, sizeof(salt), outfd) != sizeof(salt))
|
||||
BARF("Error writing salt to outfile");
|
||||
}
|
||||
|
||||
/* At this point, the files are open, the salt has been figured out,
|
||||
and we're ready to pump data through crypt. */
|
||||
|
||||
/* Do the crypt operation */
|
||||
if(do_crypt(infd, outfd, key, iv, encrypt) != CRYPT_OK)
|
||||
BARF("Error during crypt operation");
|
||||
|
||||
/* Clean up */
|
||||
fclose(infd); fclose(outfd);
|
||||
return 0;
|
||||
}
|
@ -76,6 +76,14 @@ int pkcs_5_alg1(const unsigned char *password, unsigned long password_len,
|
||||
int iteration_count, int hash_idx,
|
||||
unsigned char *out, unsigned long *outlen);
|
||||
|
||||
/* Algorithm #1 - OpenSSL-compatible variant for arbitrarily-long keys.
|
||||
Compatible with EVP_BytesToKey() */
|
||||
int pkcs_5_alg1_openssl(const unsigned char *password,
|
||||
unsigned long password_len,
|
||||
const unsigned char *salt,
|
||||
int iteration_count, int hash_idx,
|
||||
unsigned char *out, unsigned long *outlen);
|
||||
|
||||
/* Algorithm #2 (new) */
|
||||
int pkcs_5_alg2(const unsigned char *password, unsigned long password_len,
|
||||
const unsigned char *salt, unsigned long salt_len,
|
||||
|
@ -16,7 +16,17 @@
|
||||
*/
|
||||
#ifdef LTC_PKCS_5
|
||||
/**
|
||||
Execute PKCS #5 v1
|
||||
Execute PKCS #5 v1 in strict or OpenSSL EVP_BytesToKey()-compat mode.
|
||||
|
||||
PKCS#5 v1 specifies that the output key length can be no larger than
|
||||
the hash output length. OpenSSL unilaterally extended that by repeating
|
||||
the hash process on a block-by-block basis for as long as needed to make
|
||||
bigger keys. If you want to be compatible with KDF for e.g. "openssl enc",
|
||||
you'll want that.
|
||||
|
||||
If you want strict PKCS behavior, turn openssl_compat off. Or (more
|
||||
likely), use one of the convenience functions below.
|
||||
|
||||
@param password The password (or key)
|
||||
@param password_len The length of the password (octet)
|
||||
@param salt The salt (or nonce) which is 8 octets long
|
||||
@ -24,17 +34,24 @@
|
||||
@param hash_idx The index of the hash desired
|
||||
@param out [out] The destination for this algorithm
|
||||
@param outlen [in/out] The max size and resulting size of the algorithm output
|
||||
@param openssl_compat [in] Whether or not to grow the key to the buffer size ala OpenSSL
|
||||
@return CRYPT_OK if successful
|
||||
*/
|
||||
int pkcs_5_alg1(const unsigned char *password, unsigned long password_len,
|
||||
const unsigned char *salt,
|
||||
int iteration_count, int hash_idx,
|
||||
unsigned char *out, unsigned long *outlen)
|
||||
static int _pkcs_5_alg1_common(const unsigned char *password,
|
||||
unsigned long password_len,
|
||||
const unsigned char *salt,
|
||||
int iteration_count, int hash_idx,
|
||||
unsigned char *out, unsigned long *outlen,
|
||||
int openssl_compat)
|
||||
{
|
||||
int err;
|
||||
unsigned long x;
|
||||
hash_state *md;
|
||||
unsigned char *buf;
|
||||
/* Storage vars in case we need to support > hashsize (OpenSSL compat) */
|
||||
unsigned long block = 0, iter;
|
||||
/* How many bytes to put in the outbut buffer (convenience calc) */
|
||||
unsigned long outidx = 0, nb = 0;
|
||||
|
||||
LTC_ARGCHK(password != NULL);
|
||||
LTC_ARGCHK(salt != NULL);
|
||||
@ -59,33 +76,55 @@ int pkcs_5_alg1(const unsigned char *password, unsigned long password_len,
|
||||
return CRYPT_MEM;
|
||||
}
|
||||
|
||||
/* hash initial password + salt */
|
||||
if ((err = hash_descriptor[hash_idx].init(md)) != CRYPT_OK) {
|
||||
goto LBL_ERR;
|
||||
}
|
||||
if ((err = hash_descriptor[hash_idx].process(md, password, password_len)) != CRYPT_OK) {
|
||||
goto LBL_ERR;
|
||||
}
|
||||
if ((err = hash_descriptor[hash_idx].process(md, salt, 8)) != CRYPT_OK) {
|
||||
goto LBL_ERR;
|
||||
}
|
||||
if ((err = hash_descriptor[hash_idx].done(md, buf)) != CRYPT_OK) {
|
||||
goto LBL_ERR;
|
||||
}
|
||||
while(block * hash_descriptor[hash_idx].hashsize < *outlen) {
|
||||
|
||||
while (--iteration_count) {
|
||||
/* code goes here. */
|
||||
x = MAXBLOCKSIZE;
|
||||
if ((err = hash_memory(hash_idx, buf, hash_descriptor[hash_idx].hashsize, buf, &x)) != CRYPT_OK) {
|
||||
goto LBL_ERR;
|
||||
/* hash initial (maybe previous hash) + password + salt */
|
||||
if ((err = hash_descriptor[hash_idx].init(md)) != CRYPT_OK) {
|
||||
goto LBL_ERR;
|
||||
}
|
||||
/* in OpenSSL mode, we first hash the previous result for blocks 2-n */
|
||||
if (openssl_compat && block) {
|
||||
if ((err = hash_descriptor[hash_idx].process(md, buf, hash_descriptor[hash_idx].hashsize)) != CRYPT_OK) {
|
||||
goto LBL_ERR;
|
||||
}
|
||||
}
|
||||
if ((err = hash_descriptor[hash_idx].process(md, password, password_len)) != CRYPT_OK) {
|
||||
goto LBL_ERR;
|
||||
}
|
||||
if ((err = hash_descriptor[hash_idx].process(md, salt, 8)) != CRYPT_OK) {
|
||||
goto LBL_ERR;
|
||||
}
|
||||
if ((err = hash_descriptor[hash_idx].done(md, buf)) != CRYPT_OK) {
|
||||
goto LBL_ERR;
|
||||
}
|
||||
}
|
||||
|
||||
/* copy upto outlen bytes */
|
||||
for (x = 0; x < hash_descriptor[hash_idx].hashsize && x < *outlen; x++) {
|
||||
out[x] = buf[x];
|
||||
iter = iteration_count;
|
||||
while (--iter) {
|
||||
/* code goes here. */
|
||||
x = MAXBLOCKSIZE;
|
||||
if ((err = hash_memory(hash_idx, buf, hash_descriptor[hash_idx].hashsize, buf, &x)) != CRYPT_OK) {
|
||||
goto LBL_ERR;
|
||||
}
|
||||
}
|
||||
|
||||
/* limit the size of the copy to however many bytes we have left in
|
||||
the output buffer (and how many bytes we have to copy) */
|
||||
outidx = block*hash_descriptor[hash_idx].hashsize;
|
||||
nb = hash_descriptor[hash_idx].hashsize;
|
||||
if(outidx+nb > *outlen)
|
||||
nb = *outlen - outidx;
|
||||
if(nb > 0)
|
||||
XMEMCPY(out+outidx, buf, nb);
|
||||
|
||||
block++;
|
||||
if (!openssl_compat)
|
||||
break;
|
||||
}
|
||||
*outlen = x;
|
||||
/* In strict mode, we always return the hashsize, in compat we filled it
|
||||
as much as was requested, so we leave it alone. */
|
||||
if(!openssl_compat)
|
||||
*outlen = hash_descriptor[hash_idx].hashsize;
|
||||
|
||||
err = CRYPT_OK;
|
||||
LBL_ERR:
|
||||
#ifdef LTC_CLEAN_STACK
|
||||
@ -99,6 +138,50 @@ LBL_ERR:
|
||||
return err;
|
||||
}
|
||||
|
||||
/**
|
||||
Execute PKCS #5 v1 - Strict mode (no OpenSSL-compatible extension)
|
||||
@param password The password (or key)
|
||||
@param password_len The length of the password (octet)
|
||||
@param salt The salt (or nonce) which is 8 octets long
|
||||
@param iteration_count The PKCS #5 v1 iteration count
|
||||
@param hash_idx The index of the hash desired
|
||||
@param out [out] The destination for this algorithm
|
||||
@param outlen [in/out] The max size and resulting size of the algorithm output
|
||||
@return CRYPT_OK if successful
|
||||
*/
|
||||
int pkcs_5_alg1(const unsigned char *password, unsigned long password_len,
|
||||
const unsigned char *salt,
|
||||
int iteration_count, int hash_idx,
|
||||
unsigned char *out, unsigned long *outlen)
|
||||
{
|
||||
return _pkcs_5_alg1_common(password, password_len, salt, iteration_count,
|
||||
hash_idx, out, outlen, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
Execute PKCS #5 v1 - OpenSSL-extension-compatible mode
|
||||
|
||||
Use this one if you need to derive keys as "openssl enc" does by default.
|
||||
OpenSSL (for better or worse), uses MD5 as the hash and iteration_count=1.
|
||||
@param password The password (or key)
|
||||
@param password_len The length of the password (octet)
|
||||
@param salt The salt (or nonce) which is 8 octets long
|
||||
@param iteration_count The PKCS #5 v1 iteration count
|
||||
@param hash_idx The index of the hash desired
|
||||
@param out [out] The destination for this algorithm
|
||||
@param outlen [in/out] The max size and resulting size of the algorithm output
|
||||
@return CRYPT_OK if successful
|
||||
*/
|
||||
int pkcs_5_alg1_openssl(const unsigned char *password,
|
||||
unsigned long password_len,
|
||||
const unsigned char *salt,
|
||||
int iteration_count, int hash_idx,
|
||||
unsigned char *out, unsigned long *outlen)
|
||||
{
|
||||
return _pkcs_5_alg1_common(password, password_len, salt, iteration_count,
|
||||
hash_idx, out, outlen, 1);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
/* $Source$ */
|
||||
|
Loading…
Reference in New Issue
Block a user