summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorKen Raeburn <raeburn@mit.edu>2003-04-13 13:03:22 +0000
committerKen Raeburn <raeburn@mit.edu>2003-04-13 13:03:22 +0000
commit3afe75ddbc7bf4b1ae6df23a531c0f57ce266f12 (patch)
treee123e490de5b1e6136f52f701522a3a0dc6c219d /src
parentc042a565116a44e1c9e11ff179f41ec72cd3e5cb (diff)
downloadkrb5-3afe75ddbc7bf4b1ae6df23a531c0f57ce266f12.tar.gz
krb5-3afe75ddbc7bf4b1ae6df23a531c0f57ce266f12.tar.xz
krb5-3afe75ddbc7bf4b1ae6df23a531c0f57ce266f12.zip
Finish implementation of CBC+CTS decryption and truncated HMAC for AES.
Fix memory management bugs. ticket: 1418 status: open git-svn-id: svn://anonsvn.mit.edu/krb5/trunk@15351 dc483132-0cff-0310-8789-dd5450dbe970
Diffstat (limited to 'src')
-rw-r--r--src/lib/crypto/ChangeLog9
-rw-r--r--src/lib/crypto/dk/ChangeLog15
-rw-r--r--src/lib/crypto/dk/dk.h19
-rw-r--r--src/lib/crypto/dk/dk_decrypt.c51
-rw-r--r--src/lib/crypto/dk/dk_encrypt.c172
-rw-r--r--src/lib/crypto/enc_provider/ChangeLog11
-rw-r--r--src/lib/crypto/enc_provider/aes.c78
-rw-r--r--src/lib/crypto/etypes.c4
-rw-r--r--src/lib/crypto/pbkdf2.c25
9 files changed, 348 insertions, 36 deletions
diff --git a/src/lib/crypto/ChangeLog b/src/lib/crypto/ChangeLog
index 6f73ddf627..1db5612524 100644
--- a/src/lib/crypto/ChangeLog
+++ b/src/lib/crypto/ChangeLog
@@ -1,3 +1,12 @@
+2003-04-13 Ken Raeburn <raeburn@mit.edu>
+
+ * pbkdf2.c (krb5int_pbkdf2): Provide a temporary buffer for the
+ output from F, if the remaining space in the output buffer isn't
+ big enough. Free the temporary buffers before returning.
+
+ * etypes.c (krb5_enctypes_list): Use krb5int_aes_encrypt_length,
+ and krb5int_aes_dk_encrypt, and krb5int_aes_dk_decrypt for AES.
+
2003-03-06 Alexandra Ellwood <lxs@mit.edu>
* prng.c: use Unix randomness sources on Mac OS X.
diff --git a/src/lib/crypto/dk/ChangeLog b/src/lib/crypto/dk/ChangeLog
index 9ed3a8de9e..4edfaabee3 100644
--- a/src/lib/crypto/dk/ChangeLog
+++ b/src/lib/crypto/dk/ChangeLog
@@ -1,3 +1,18 @@
+2003-04-13 Ken Raeburn <raeburn@mit.edu>
+
+ * dk_decrypt.c (krb5_dk_decrypt_maybe_trunc_hmac): Renamed from
+ krb5_dk_decrypt, made static, added extra HMACSIZE argument to
+ indicate size of HMAC. Cast byte values to char to silence
+ compiler warning.
+ (krb5_dk_decrypt): Call it.
+ (krb5int_aes_dk_decrypt): New function.
+ * dk_encrypt.c (krb5_dk_encrypt): Cast byte values to char to
+ silence compiler warning.
+ (krb5int_aes_encrypt_length, trunc_hmac, krb5int_aes_dk_encrypt):
+ New functions.
+ * dk.h (krb5int_aes_encrypt_length, krb5int_aes_dk_encrypt,
+ krb5int_aes_dk_decrypt): Declare.
+
2003-03-04 Ken Raeburn <raeburn@mit.edu>
* stringtokey.c (krb5int_dk_string_to_key): Renamed from
diff --git a/src/lib/crypto/dk/dk.h b/src/lib/crypto/dk/dk.h
index 0171016171..a224167ea1 100644
--- a/src/lib/crypto/dk/dk.h
+++ b/src/lib/crypto/dk/dk.h
@@ -38,6 +38,18 @@ krb5_error_code krb5_dk_encrypt
const krb5_data *ivec,
const krb5_data *input, krb5_data *output);
+void krb5int_aes_encrypt_length
+(const struct krb5_enc_provider *enc,
+ const struct krb5_hash_provider *hash,
+ size_t input, size_t *length);
+
+krb5_error_code krb5int_aes_dk_encrypt
+(const struct krb5_enc_provider *enc,
+ const struct krb5_hash_provider *hash,
+ const krb5_keyblock *key, krb5_keyusage usage,
+ const krb5_data *ivec,
+ const krb5_data *input, krb5_data *output);
+
krb5_error_code krb5_dk_decrypt
(const struct krb5_enc_provider *enc,
const struct krb5_hash_provider *hash,
@@ -45,6 +57,13 @@ krb5_error_code krb5_dk_decrypt
const krb5_data *ivec, const krb5_data *input,
krb5_data *arg_output);
+krb5_error_code krb5int_aes_dk_decrypt
+(const struct krb5_enc_provider *enc,
+ const struct krb5_hash_provider *hash,
+ const krb5_keyblock *key, krb5_keyusage usage,
+ const krb5_data *ivec, const krb5_data *input,
+ krb5_data *arg_output);
+
krb5_error_code krb5int_dk_string_to_key
(const struct krb5_enc_provider *enc,
const krb5_data *string, const krb5_data *salt,
diff --git a/src/lib/crypto/dk/dk_decrypt.c b/src/lib/crypto/dk/dk_decrypt.c
index adc4d2348f..5f35fa6ace 100644
--- a/src/lib/crypto/dk/dk_decrypt.c
+++ b/src/lib/crypto/dk/dk_decrypt.c
@@ -29,6 +29,16 @@
#define K5CLENGTH 5 /* 32 bit net byte order integer + one byte seed */
+static krb5_error_code
+krb5_dk_decrypt_maybe_trunc_hmac(const struct krb5_enc_provider *enc,
+ const struct krb5_hash_provider *hash,
+ const krb5_keyblock *key,
+ krb5_keyusage usage,
+ const krb5_data *ivec,
+ const krb5_data *input,
+ krb5_data *output,
+ size_t hmacsize);
+
krb5_error_code
krb5_dk_decrypt(enc, hash, key, usage, ivec, input, output)
const struct krb5_enc_provider *enc;
@@ -39,6 +49,36 @@ krb5_dk_decrypt(enc, hash, key, usage, ivec, input, output)
const krb5_data *input;
krb5_data *output;
{
+ return krb5_dk_decrypt_maybe_trunc_hmac(enc, hash, key, usage,
+ ivec, input, output, 0);
+}
+
+krb5_error_code
+krb5int_aes_dk_decrypt(enc, hash, key, usage, ivec, input, output)
+ const struct krb5_enc_provider *enc;
+ const struct krb5_hash_provider *hash;
+ const krb5_keyblock *key;
+ krb5_keyusage usage;
+ const krb5_data *ivec;
+ const krb5_data *input;
+ krb5_data *output;
+{
+ return krb5_dk_decrypt_maybe_trunc_hmac(enc, hash, key, usage,
+ ivec, input, output, 96 / 8);
+}
+
+static krb5_error_code
+krb5_dk_decrypt_maybe_trunc_hmac(enc, hash, key, usage, ivec, input, output,
+ hmacsize)
+ const struct krb5_enc_provider *enc;
+ const struct krb5_hash_provider *hash;
+ const krb5_keyblock *key;
+ krb5_keyusage usage;
+ const krb5_data *ivec;
+ const krb5_data *input;
+ krb5_data *output;
+ size_t hmacsize;
+{
krb5_error_code ret;
size_t hashsize, blocksize, keybytes, keylength, enclen, plainlen;
unsigned char *plaindata, *kedata, *kidata, *cksum, *cn;
@@ -52,7 +92,12 @@ krb5_dk_decrypt(enc, hash, key, usage, ivec, input, output)
(*(enc->block_size))(&blocksize);
(*(enc->keysize))(&keybytes, &keylength);
- enclen = input->length - hashsize;
+ if (hmacsize == 0)
+ hmacsize = hashsize;
+ else if (hmacsize > hashsize)
+ return KRB5KRB_AP_ERR_BAD_INTEGRITY;
+
+ enclen = input->length - hmacsize;
if ((kedata = (unsigned char *) malloc(keylength)) == NULL)
return(ENOMEM);
@@ -87,7 +132,7 @@ krb5_dk_decrypt(enc, hash, key, usage, ivec, input, output)
d1.data[2] = (usage>>8)&0xff;
d1.data[3] = usage&0xff;
- d1.data[4] = 0xAA;
+ d1.data[4] = (char) 0xAA;
if ((ret = krb5_derive_key(enc, key, &ke, &d1)) != 0)
goto cleanup;
@@ -121,7 +166,7 @@ krb5_dk_decrypt(enc, hash, key, usage, ivec, input, output)
if ((ret = krb5_hmac(hash, &ki, 1, &d2, &d1)) != 0)
goto cleanup;
- if (memcmp(cksum, input->data+enclen, hashsize) != 0) {
+ if (memcmp(cksum, input->data+enclen, hmacsize) != 0) {
ret = KRB5KRB_AP_ERR_BAD_INTEGRITY;
goto cleanup;
}
diff --git a/src/lib/crypto/dk/dk_encrypt.c b/src/lib/crypto/dk/dk_encrypt.c
index eb9fe5fa37..7ff7d878f4 100644
--- a/src/lib/crypto/dk/dk_encrypt.c
+++ b/src/lib/crypto/dk/dk_encrypt.c
@@ -108,7 +108,7 @@ krb5_dk_encrypt(enc, hash, key, usage, ivec, input, output)
d1.data[2] = (usage>>8)&0xff;
d1.data[3] = usage&0xff;
- d1.data[4] = 0xAA;
+ d1.data[4] = (char) 0xAA;
if ((ret = krb5_derive_key(enc, key, &ke, &d1)))
goto cleanup;
@@ -177,6 +177,176 @@ cleanup:
return(ret);
}
+/* Not necessarily "AES", per se, but "a CBC+CTS mode block cipher
+ with a 96-bit truncated HMAC". */
+void
+krb5int_aes_encrypt_length(enc, hash, inputlen, length)
+ const struct krb5_enc_provider *enc;
+ const struct krb5_hash_provider *hash;
+ size_t inputlen;
+ size_t *length;
+{
+ size_t blocksize, hashsize;
+
+ (*(enc->block_size))(&blocksize);
+ hashsize = 96 / 8;
+
+ /* No roundup, since CTS requires no padding once we've hit the
+ block size. */
+ *length = blocksize+inputlen + hashsize;
+}
+
+static krb5_error_code
+trunc_hmac (const struct krb5_hash_provider *hash,
+ const krb5_keyblock *ki, int num,
+ const krb5_data *input, const krb5_data *output)
+{
+ size_t hashsize;
+ krb5_data tmp;
+ krb5_error_code ret;
+
+ (hash->hash_size)(&hashsize);
+ if (hashsize < output->length)
+ return KRB5_CRYPTO_INTERNAL;
+ tmp.length = hashsize;
+ tmp.data = malloc(hashsize);
+ if (tmp.data == NULL)
+ return errno;
+ ret = krb5_hmac(hash, ki, num, input, &tmp);
+ if (ret == 0)
+ memcpy(output->data, tmp.data, output->length);
+ memset(tmp.data, 0, hashsize);
+ free(tmp.data);
+ return ret;
+}
+
+krb5_error_code
+krb5int_aes_dk_encrypt(enc, hash, key, usage, ivec, input, output)
+ const struct krb5_enc_provider *enc;
+ const struct krb5_hash_provider *hash;
+ const krb5_keyblock *key;
+ krb5_keyusage usage;
+ const krb5_data *ivec;
+ const krb5_data *input;
+ krb5_data *output;
+{
+ size_t blocksize, keybytes, keylength, plainlen, enclen;
+ krb5_error_code ret;
+ unsigned char constantdata[K5CLENGTH];
+ krb5_data d1, d2;
+ unsigned char *plaintext, *kedata, *kidata, *cn;
+ krb5_keyblock ke, ki;
+
+ /* allocate and set up plaintext and to-be-derived keys */
+
+ (*(enc->block_size))(&blocksize);
+ (*(enc->keysize))(&keybytes, &keylength);
+ plainlen = blocksize+input->length;
+
+ krb5int_aes_encrypt_length(enc, hash, input->length, &enclen);
+
+ /* key->length, ivec will be tested in enc->encrypt */
+
+ if (output->length < enclen)
+ return(KRB5_BAD_MSIZE);
+
+ if ((kedata = (unsigned char *) malloc(keylength)) == NULL)
+ return(ENOMEM);
+ if ((kidata = (unsigned char *) malloc(keylength)) == NULL) {
+ free(kedata);
+ return(ENOMEM);
+ }
+ if ((plaintext = (unsigned char *) malloc(plainlen)) == NULL) {
+ free(kidata);
+ free(kedata);
+ return(ENOMEM);
+ }
+
+ ke.contents = kedata;
+ ke.length = keylength;
+ ki.contents = kidata;
+ ki.length = keylength;
+
+ /* derive the keys */
+
+ d1.data = constantdata;
+ d1.length = K5CLENGTH;
+
+ d1.data[0] = (usage>>24)&0xff;
+ d1.data[1] = (usage>>16)&0xff;
+ d1.data[2] = (usage>>8)&0xff;
+ d1.data[3] = usage&0xff;
+
+ d1.data[4] = (char) 0xAA;
+
+ if ((ret = krb5_derive_key(enc, key, &ke, &d1)))
+ goto cleanup;
+
+ d1.data[4] = 0x55;
+
+ if ((ret = krb5_derive_key(enc, key, &ki, &d1)))
+ goto cleanup;
+
+ /* put together the plaintext */
+
+ d1.length = blocksize;
+ d1.data = plaintext;
+
+ if ((ret = krb5_c_random_make_octets(/* XXX */ 0, &d1)))
+ goto cleanup;
+
+ memcpy(plaintext+blocksize, input->data, input->length);
+
+ /* Ciphertext stealing; there should be no more. */
+ if (plainlen != blocksize + input->length)
+ abort();
+
+ /* encrypt the plaintext */
+
+ d1.length = plainlen;
+ d1.data = plaintext;
+
+ d2.length = plainlen;
+ d2.data = output->data;
+
+ if ((ret = ((*(enc->encrypt))(&ke, ivec, &d1, &d2))))
+ goto cleanup;
+
+ if (ivec != NULL && ivec->length == blocksize)
+ cn = d2.data + d2.length - blocksize;
+ else
+ cn = NULL;
+
+ /* hash the plaintext */
+
+ d2.length = enclen - plainlen;
+ d2.data = output->data+plainlen;
+ if (d2.length != 96 / 8)
+ abort();
+
+ if ((ret = trunc_hmac(hash, &ki, 1, &d1, &d2))) {
+ memset(d2.data, 0, d2.length);
+ goto cleanup;
+ }
+
+ /* update ivec */
+ if (cn != NULL)
+ memcpy(ivec->data, cn, blocksize);
+
+ /* ret is set correctly by the prior call */
+
+cleanup:
+ memset(kedata, 0, keylength);
+ memset(kidata, 0, keylength);
+ memset(plaintext, 0, plainlen);
+
+ free(plaintext);
+ free(kidata);
+ free(kedata);
+
+ return(ret);
+}
+
#ifdef ATHENA_DES3_KLUDGE
void
krb5_marc_dk_encrypt_length(enc, hash, inputlen, length)
diff --git a/src/lib/crypto/enc_provider/ChangeLog b/src/lib/crypto/enc_provider/ChangeLog
index 08a614e967..f954f7fa22 100644
--- a/src/lib/crypto/enc_provider/ChangeLog
+++ b/src/lib/crypto/enc_provider/ChangeLog
@@ -1,3 +1,14 @@
+2003-04-13 Ken Raeburn <raeburn@mit.edu>
+
+ * aes.c (enc): Replaced function with a macro.
+ (dec): New macro.
+ (krb5int_aes_encrypt): Use enc and dec. Delete unused variable
+ OFFSET.
+ (krb5int_aes_decrypt): Renamed from k5_aes_dencrypt, implemented
+ decryption, made non-static.
+ (krb5int_enc_aes128, krb5int_enc_aes256): Use new name for
+ krb5int_aes_decrypt.
+
2003-03-04 Ken Raeburn <raeburn@mit.edu>
* aes.c (krb5int_aes_init_state): Implement.
diff --git a/src/lib/crypto/enc_provider/aes.c b/src/lib/crypto/enc_provider/aes.c
index d3dc2a5a73..013a688eb1 100644
--- a/src/lib/crypto/enc_provider/aes.c
+++ b/src/lib/crypto/enc_provider/aes.c
@@ -52,23 +52,8 @@ static void printd (const char *descr, krb5_data *d) {
}
printf("\n");
}
-static void enc(char *out, const char *in, aes_ctx *ctx)
-{
- if (aes_enc_blk(in, out, ctx) != aes_good)
- abort();
-#if 0
- {
- krb5_data e_in, e_out;
- e_in.data = in;
- e_out.data = out;
- e_in.length = e_out.length = BLOCK_SIZE;
- printf("encrypting [[\n");
- printd("input block", &e_in);
- printd("output block", &e_out);
- printf("]]\n");
- }
-#endif
-}
+#define enc(OUT, IN, CTX) (aes_enc_blk((IN),(OUT),(CTX)) == aes_good ? (void) 0 : abort())
+#define dec(OUT, IN, CTX) (aes_dec_blk((IN),(OUT),(CTX)) == aes_good ? (void) 0 : abort())
static void xorblock(char *out, const char *in)
{
@@ -83,7 +68,6 @@ krb5int_aes_encrypt(const krb5_keyblock *key, const krb5_data *ivec,
{
aes_ctx ctx;
unsigned char tmp[BLOCK_SIZE], tmp2[BLOCK_SIZE], tmp3[BLOCK_SIZE];
- int offset;
int nblocks = 0, blockno;
/* CHECK_SIZES; */
@@ -100,8 +84,7 @@ krb5int_aes_encrypt(const krb5_keyblock *key, const krb5_data *ivec,
if (nblocks == 1) {
/* XXX Used for DK function. */
- if (aes_enc_blk(input->data, output->data, &ctx) != aes_good)
- abort();
+ enc(output->data, input->data, &ctx);
} else {
int nleft;
@@ -112,7 +95,6 @@ krb5int_aes_encrypt(const krb5_keyblock *key, const krb5_data *ivec,
/* Set up for next block. */
memcpy(tmp, tmp2, BLOCK_SIZE);
- offset += BLOCK_SIZE;
}
/* Do final CTS step for last two blocks (the second of which
may or may not be incomplete). */
@@ -132,18 +114,60 @@ krb5int_aes_encrypt(const krb5_keyblock *key, const krb5_data *ivec,
return 0;
}
-static krb5_error_code
-k5_aes_decrypt(const krb5_keyblock *key, const krb5_data *ivec,
- const krb5_data *input, krb5_data *output)
+krb5_error_code
+krb5int_aes_decrypt(const krb5_keyblock *key, const krb5_data *ivec,
+ const krb5_data *input, krb5_data *output)
{
aes_ctx ctx;
+ unsigned char tmp[BLOCK_SIZE], tmp2[BLOCK_SIZE], tmp3[BLOCK_SIZE];
+ int nblocks = 0, blockno;
CHECK_SIZES;
if (aes_dec_key(key->contents, key->length, &ctx) != aes_good)
abort();
- abort();
+ if (ivec)
+ memcpy(tmp, ivec->data, BLOCK_SIZE);
+ else
+ memset(tmp, 0, BLOCK_SIZE);
+
+ nblocks = (input->length + BLOCK_SIZE - 1) / BLOCK_SIZE;
+
+ if (nblocks == 1) {
+ if (input->length < BLOCK_SIZE)
+ abort();
+ dec(output->data, input->data, &ctx);
+ } else {
+ int nleft;
+
+ for (blockno = 0; blockno < nblocks - 2; blockno++) {
+ dec(tmp2, input->data + blockno * BLOCK_SIZE, &ctx);
+ xorblock(tmp2, tmp);
+ memcpy(output->data + blockno * BLOCK_SIZE, tmp2, BLOCK_SIZE);
+ memcpy(tmp, input->data + blockno * BLOCK_SIZE, BLOCK_SIZE);
+ }
+ /* Do last two blocks, the second of which (next-to-last block
+ of plaintext) may be incomplete. */
+ dec(tmp2, input->data + (nblocks - 2) * BLOCK_SIZE, &ctx);
+ /* Set tmp3 to last ciphertext block, padded. */
+ memset(tmp3, 0, sizeof(tmp3));
+ memcpy(tmp3, input->data + (nblocks - 1) * BLOCK_SIZE,
+ input->length - (nblocks - 1) * BLOCK_SIZE);
+ /* Set tmp2 to last (possibly partial) plaintext block, and
+ save it. */
+ xorblock(tmp2, tmp3);
+ memcpy(output->data + (nblocks - 1) * BLOCK_SIZE, tmp2,
+ input->length - (nblocks - 1) * BLOCK_SIZE);
+ /* Maybe keep the trailing part, and copy in the last
+ ciphertext block. */
+ memcpy(tmp2, tmp3, input->length - (nblocks - 1) * BLOCK_SIZE);
+ /* Decrypt, to get next to last plaintext block xor previous
+ ciphertext. */
+ dec(tmp3, tmp2, &ctx);
+ xorblock(tmp3, tmp);
+ memcpy(output->data + (nblocks - 2) * BLOCK_SIZE, tmp3, BLOCK_SIZE);
+ }
return 0;
}
@@ -178,7 +202,7 @@ const struct krb5_enc_provider krb5int_enc_aes128 = {
aes_block_size,
aes128_keysize,
krb5int_aes_encrypt,
- k5_aes_decrypt,
+ krb5int_aes_decrypt,
k5_aes_make_key,
krb5int_aes_init_state,
krb5int_default_free_state
@@ -188,7 +212,7 @@ const struct krb5_enc_provider krb5int_enc_aes256 = {
aes_block_size,
aes256_keysize,
krb5int_aes_encrypt,
- k5_aes_decrypt,
+ krb5int_aes_decrypt,
k5_aes_make_key,
krb5int_aes_init_state,
krb5int_default_free_state
diff --git a/src/lib/crypto/etypes.c b/src/lib/crypto/etypes.c
index 1cc570cd8f..da234070ca 100644
--- a/src/lib/crypto/etypes.c
+++ b/src/lib/crypto/etypes.c
@@ -125,12 +125,12 @@ const struct krb5_keytypes krb5_enctypes_list[] = {
{ ENCTYPE_AES128_CTS_HMAC_SHA1_96,
"aes128-cts-hmac-sha1-96", "AES-128 CTS mode with 96-bit SHA-1 HMAC",
&krb5int_enc_aes128, &krb5int_hash_sha1,
- krb5_dk_encrypt_length, krb5_dk_encrypt, krb5_dk_decrypt,
+ krb5int_aes_encrypt_length, krb5int_aes_dk_encrypt, krb5int_aes_dk_decrypt,
krb5int_aes_string_to_key },
{ ENCTYPE_AES256_CTS_HMAC_SHA1_96,
"aes256-cts-hmac-sha1-96", "AES-256 CTS mode with 96-bit SHA-1 HMAC",
&krb5int_enc_aes256, &krb5int_hash_sha1,
- krb5_dk_encrypt_length, krb5_dk_encrypt, krb5_dk_decrypt,
+ krb5int_aes_encrypt_length, krb5int_aes_dk_encrypt, krb5int_aes_dk_decrypt,
krb5int_aes_string_to_key },
#ifdef ATHENA_DES3_KLUDGE
diff --git a/src/lib/crypto/pbkdf2.c b/src/lib/crypto/pbkdf2.c
index d8a3f8b589..165e4cf6ab 100644
--- a/src/lib/crypto/pbkdf2.c
+++ b/src/lib/crypto/pbkdf2.c
@@ -158,6 +158,7 @@ krb5int_pbkdf2 (krb5_error_code (*prf)(krb5_keyblock *, krb5_data *,
{
int l, r, i;
char *utmp1, *utmp2;
+ char utmp3[20]; /* XXX length shouldn't be hardcoded! */
if (output->length == 0 || hlen == 0)
abort();
@@ -169,7 +170,13 @@ krb5int_pbkdf2 (krb5_error_code (*prf)(krb5_keyblock *, krb5_data *,
r = output->length - (l - 1) * hlen;
utmp1 = /*output + dklen; */ malloc(hlen);
+ if (utmp1 == NULL)
+ return errno;
utmp2 = /*utmp1 + hlen; */ malloc(salt->length + 4 + hlen);
+ if (utmp2 == NULL) {
+ free(utmp1);
+ return errno;
+ }
/* Step 3. */
for (i = 1; i <= l; i++) {
@@ -177,11 +184,21 @@ krb5int_pbkdf2 (krb5_error_code (*prf)(krb5_keyblock *, krb5_data *,
int j;
#endif
krb5_error_code err;
+ char *out;
- err = F(output->data + (i-1) * hlen, utmp1, utmp2, prf, hlen,
- pass, salt, count, i);
- if (err)
+ if (i == l)
+ out = utmp3;
+ else
+ out = output->data + (i-1) * hlen;
+ err = F(out, utmp1, utmp2, prf, hlen, pass, salt, count, i);
+ if (err) {
+ free(utmp1);
+ free(utmp2);
return err;
+ }
+ if (i == l)
+ memcpy(output->data + (i-1) * hlen, utmp3,
+ output->length - (i-1) * hlen);
#if 0
printf("after F(%d), @%p:\n", i, output->data);
@@ -190,6 +207,8 @@ krb5int_pbkdf2 (krb5_error_code (*prf)(krb5_keyblock *, krb5_data *,
printf ("\n");
#endif
}
+ free(utmp1);
+ free(utmp2);
return 0;
}