From 58703ca2fe8115ede0f38b327ca6cc60fcf3bb0d Mon Sep 17 00:00:00 2001 From: Zhanna Tsitkov Date: Thu, 1 Oct 2009 22:54:27 +0000 Subject: [PATCH] Crypto modularity proj: Populae openssl/arcfour dir git-svn-id: svn://anonsvn.mit.edu/krb5/trunk@22825 dc483132-0cff-0310-8789-dd5450dbe970 --- src/lib/crypto/openssl/arcfour/arcfour-int.h | 35 ++ src/lib/crypto/openssl/arcfour/arcfour.c | 326 ++++++++++++++++++ src/lib/crypto/openssl/arcfour/arcfour.h | 43 +++ src/lib/crypto/openssl/arcfour/arcfour_aead.c | 325 +++++++++++++++++ src/lib/crypto/openssl/arcfour/arcfour_s2k.c | 59 ++++ 5 files changed, 788 insertions(+) create mode 100644 src/lib/crypto/openssl/arcfour/arcfour-int.h create mode 100644 src/lib/crypto/openssl/arcfour/arcfour.c create mode 100644 src/lib/crypto/openssl/arcfour/arcfour.h create mode 100644 src/lib/crypto/openssl/arcfour/arcfour_aead.c create mode 100644 src/lib/crypto/openssl/arcfour/arcfour_s2k.c diff --git a/src/lib/crypto/openssl/arcfour/arcfour-int.h b/src/lib/crypto/openssl/arcfour/arcfour-int.h new file mode 100644 index 000000000..d9db0be8a --- /dev/null +++ b/src/lib/crypto/openssl/arcfour/arcfour-int.h @@ -0,0 +1,35 @@ +/* + +ARCFOUR cipher (based on a cipher posted on the Usenet in Spring-95). +This cipher is widely believed and has been tested to be equivalent +with the RC4 cipher from RSA Data Security, Inc. (RC4 is a trademark +of RSA Data Security) + +*/ +#ifndef ARCFOUR_INT_H +#define ARCFOUR_INT_H + +#include "arcfour.h" +#include + +#define CONFOUNDERLENGTH 8 + +typedef struct +{ + EVP_CIPHER_CTX evp_ctx; + unsigned int x; + unsigned int y; + unsigned char state[256]; + +} ArcfourContext; + +typedef struct { + int initialized; + ArcfourContext ctx; +} ArcFourCipherState; + +krb5_keyusage krb5int_arcfour_translate_usage(krb5_keyusage usage); + +extern const char *const krb5int_arcfour_l40; + +#endif /* ARCFOUR_INT_H */ diff --git a/src/lib/crypto/openssl/arcfour/arcfour.c b/src/lib/crypto/openssl/arcfour/arcfour.c new file mode 100644 index 000000000..687f276b0 --- /dev/null +++ b/src/lib/crypto/openssl/arcfour/arcfour.c @@ -0,0 +1,326 @@ +/* + +ARCFOUR cipher (based on a cipher posted on the Usenet in Spring-95). +This cipher is widely believed and has been tested to be equivalent +with the RC4 cipher from RSA Data Security, Inc. (RC4 is a trademark +of RSA Data Security) + +*/ +#include "k5-int.h" +#include "arcfour-int.h" +#include "hash_provider/hash_provider.h" + +const char *const krb5int_arcfour_l40 = "fortybits"; + +void +krb5_arcfour_encrypt_length(const struct krb5_enc_provider *enc, + const struct krb5_hash_provider *hash, + size_t inputlen, size_t *length) +{ + size_t blocksize, hashsize; + + blocksize = enc->block_size; + hashsize = hash->hashsize; + + /* checksum + (confounder + inputlen, in even blocksize) */ + *length = hashsize + krb5_roundup(8 + inputlen, blocksize); +} + + krb5_keyusage + krb5int_arcfour_translate_usage(krb5_keyusage usage) +{ + switch (usage) { + case 1: /* AS-REQ PA-ENC-TIMESTAMP padata timestamp, */ + return 1; + case 2: /* ticket from kdc */ + return 2; + case 3: /* as-rep encrypted part */ + return 8; + case 4: /* tgs-req authz data */ + return 4; + case 5: /* tgs-req authz data in subkey */ + return 5; + case 6: /* tgs-req authenticator cksum */ + return 6; +case 7: /* tgs-req authenticator */ + return 7; + case 8: + return 8; + case 9: /* tgs-rep encrypted with subkey */ + return 9; + case 10: /* ap-rep authentication cksum */ + return 10; /* xxx Microsoft never uses this*/ + case 11: /* app-req authenticator */ + return 11; + case 12: /* app-rep encrypted part */ + return 12; + case 23: /* sign wrap token*/ + return 13; + default: + return usage; +} +} + +/* RFC 4757 */ +krb5_error_code +krb5_arcfour_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_keyblock k1, k2, k3; + krb5_data d1, d2, d3, salt, plaintext, checksum, ciphertext, confounder; + krb5_keyusage ms_usage; + size_t keylength, keybytes, blocksize, hashsize; + krb5_error_code ret; + + blocksize = enc->block_size; + keybytes = enc->keybytes; + keylength = enc->keylength; + hashsize = hash->hashsize; + + d1.length=keybytes; + d1.data=malloc(d1.length); + if (d1.data == NULL) + return (ENOMEM); + k1 = *key; + k1.length=d1.length; + k1.contents= (void *) d1.data; + + d2.length=keybytes; + d2.data=malloc(d2.length); + if (d2.data == NULL) { + free(d1.data); + return (ENOMEM); + } + k2 = *key; + k2.length=d2.length; + k2.contents=(void *) d2.data; + + d3.length=keybytes; + d3.data=malloc(d3.length); + if (d3.data == NULL) { + free(d1.data); + free(d2.data); + return (ENOMEM); + } + k3 = *key; + k3.length=d3.length; + k3.contents= (void *) d3.data; + + salt.length=14; + salt.data=malloc(salt.length); + if (salt.data == NULL) { + free(d1.data); + free(d2.data); + free(d3.data); + return (ENOMEM); + } + + /* is "input" already blocksize aligned? if it is, then we need this + step, otherwise we do not */ + plaintext.length=krb5_roundup(input->length+CONFOUNDERLENGTH,blocksize); + plaintext.data=malloc(plaintext.length); + if (plaintext.data == NULL) { + free(d1.data); + free(d2.data); + free(d3.data); + free(salt.data); + return(ENOMEM); + } + + /* setup convienient pointers into the allocated data */ + checksum.length=hashsize; + checksum.data=output->data; + ciphertext.length=krb5_roundup(input->length+CONFOUNDERLENGTH,blocksize); + ciphertext.data=output->data+hashsize; + confounder.length=CONFOUNDERLENGTH; + confounder.data=plaintext.data; + output->length = plaintext.length+hashsize; + + /* begin the encryption, computer K1 */ + ms_usage=krb5int_arcfour_translate_usage(usage); + if (key->enctype == ENCTYPE_ARCFOUR_HMAC_EXP) { + strncpy(salt.data, krb5int_arcfour_l40, salt.length); + store_32_le(ms_usage, salt.data+10); + } else { + salt.length=4; + store_32_le(ms_usage, salt.data); + } + krb5_hmac(hash, key, 1, &salt, &d1); + + memcpy(k2.contents, k1.contents, k2.length); + + if (key->enctype==ENCTYPE_ARCFOUR_HMAC_EXP) + memset(k1.contents+7, 0xab, 9); + + ret=krb5_c_random_make_octets(/* XXX */ 0, &confounder); + memcpy(plaintext.data+confounder.length, input->data, input->length); + if (ret) + goto cleanup; + + krb5_hmac(hash, &k2, 1, &plaintext, &checksum); + + krb5_hmac(hash, &k1, 1, &checksum, &d3); + + ret=(*(enc->encrypt))(&k3, ivec, &plaintext, &ciphertext); + + cleanup: + memset(d1.data, 0, d1.length); + memset(d2.data, 0, d2.length); + memset(d3.data, 0, d3.length); + memset(salt.data, 0, salt.length); + memset(plaintext.data, 0, plaintext.length); + + free(d1.data); + free(d2.data); + free(d3.data); + free(salt.data); + free(plaintext.data); + return (ret); +} + +/* This is the arcfour-hmac decryption routine */ +krb5_error_code +krb5_arcfour_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 *output) +{ + krb5_keyblock k1,k2,k3; + krb5_data d1,d2,d3,salt,ciphertext,plaintext,checksum; + krb5_keyusage ms_usage; + size_t keybytes, keylength, hashsize, blocksize; + krb5_error_code ret; + + blocksize = enc->block_size; + keybytes = enc->keybytes; + keylength = enc->keylength; + hashsize = hash->hashsize; + + d1.length=keybytes; + d1.data=malloc(d1.length); + if (d1.data == NULL) + return (ENOMEM); + k1 = *key; + k1.length=d1.length; + k1.contents= (void *) d1.data; + + d2.length=keybytes; + d2.data=malloc(d2.length); + if (d2.data == NULL) { + free(d1.data); + return (ENOMEM); + } + k2 = *key; + k2.length=d2.length; + k2.contents= (void *) d2.data; + + d3.length=keybytes; + d3.data=malloc(d3.length); + if (d3.data == NULL) { + free(d1.data); + free(d2.data); + return (ENOMEM); + } + k3 = *key; + k3.length=d3.length; + k3.contents= (void *) d3.data; + + salt.length=14; + salt.data=malloc(salt.length); + if(salt.data==NULL) { + free(d1.data); + free(d2.data); + free(d3.data); + return (ENOMEM); + } + + ciphertext.length=input->length-hashsize; + ciphertext.data=input->data+hashsize; + plaintext.length=ciphertext.length; + plaintext.data=malloc(plaintext.length); + if (plaintext.data == NULL) { + free(d1.data); + free(d2.data); + free(d3.data); + free(salt.data); + return (ENOMEM); + } + + checksum.length=hashsize; + checksum.data=input->data; + + ms_usage=krb5int_arcfour_translate_usage(usage); + + /* We may have to try two ms_usage values; see below. */ + do { + /* compute the salt */ + if (key->enctype == ENCTYPE_ARCFOUR_HMAC_EXP) { + strncpy(salt.data, krb5int_arcfour_l40, salt.length); + store_32_le(ms_usage, salt.data + 10); + } else { + salt.length = 4; + store_32_le(ms_usage, salt.data); + } + ret = krb5_hmac(hash, key, 1, &salt, &d1); + if (ret) + goto cleanup; + + memcpy(k2.contents, k1.contents, k2.length); + + if (key->enctype == ENCTYPE_ARCFOUR_HMAC_EXP) + memset(k1.contents + 7, 0xab, 9); + + ret = krb5_hmac(hash, &k1, 1, &checksum, &d3); + if (ret) + goto cleanup; + + ret = (*(enc->decrypt))(&k3, ivec, &ciphertext, &plaintext); + if (ret) + goto cleanup; + + ret = krb5_hmac(hash, &k2, 1, &plaintext, &d1); + if (ret) + goto cleanup; + + if (memcmp(checksum.data, d1.data, hashsize) != 0) { + if (ms_usage == 9) { + /* + * RFC 4757 specifies usage 8 for TGS-REP encrypted + * parts encrypted in a subkey, but the value used by MS + * is actually 9. We now use 9 to start with, but fall + * back to 8 on failure in case we are communicating + * with a KDC using the value from the RFC. + */ + ms_usage = 8; + continue; + } + ret = KRB5KRB_AP_ERR_BAD_INTEGRITY; + goto cleanup; + } + + break; + } while (1); + + memcpy(output->data, plaintext.data+CONFOUNDERLENGTH, + (plaintext.length-CONFOUNDERLENGTH)); + output->length=plaintext.length-CONFOUNDERLENGTH; + + cleanup: + memset(d1.data, 0, d1.length); + memset(d2.data, 0, d2.length); + memset(d3.data, 0, d2.length); + memset(salt.data, 0, salt.length); + memset(plaintext.data, 0, plaintext.length); + + free(d1.data); + free(d2.data); + free(d3.data); + free(salt.data); + free(plaintext.data); + return (ret); +} + diff --git a/src/lib/crypto/openssl/arcfour/arcfour.h b/src/lib/crypto/openssl/arcfour/arcfour.h new file mode 100644 index 000000000..be408febc --- /dev/null +++ b/src/lib/crypto/openssl/arcfour/arcfour.h @@ -0,0 +1,43 @@ +#ifndef ARCFOUR_H +#define ARCFOUR_H + +extern void +krb5_arcfour_encrypt_length(const struct krb5_enc_provider *, + const struct krb5_hash_provider *, + size_t, + size_t *); + +extern +krb5_error_code krb5_arcfour_encrypt(const struct krb5_enc_provider *, + const struct krb5_hash_provider *, + const krb5_keyblock *, + krb5_keyusage, + const krb5_data *, + const krb5_data *, + krb5_data *); + +extern +krb5_error_code krb5_arcfour_decrypt(const struct krb5_enc_provider *, + const struct krb5_hash_provider *, + const krb5_keyblock *, + krb5_keyusage, + const krb5_data *, + const krb5_data *, + krb5_data *); + +extern krb5_error_code krb5int_arcfour_string_to_key( + const struct krb5_enc_provider *, + const krb5_data *, + const krb5_data *, + const krb5_data *, + krb5_keyblock *); + +extern const struct krb5_enc_provider krb5int_enc_arcfour; +extern const struct krb5_aead_provider krb5int_aead_arcfour; + krb5_error_code krb5int_arcfour_prf( + const struct krb5_enc_provider *enc, + const struct krb5_hash_provider *hash, + const krb5_keyblock *key, + const krb5_data *in, krb5_data *out); + +#endif /* ARCFOUR_H */ diff --git a/src/lib/crypto/openssl/arcfour/arcfour_aead.c b/src/lib/crypto/openssl/arcfour/arcfour_aead.c new file mode 100644 index 000000000..cff7d66d6 --- /dev/null +++ b/src/lib/crypto/openssl/arcfour/arcfour_aead.c @@ -0,0 +1,325 @@ +/* + * lib/crypto/arcfour/arcfour_aead.c + * + * Copyright 2008 by the Massachusetts Institute of Technology. + * All Rights Reserved. + * + * Export of this software from the United States of America may + * require a specific license from the United States Government. + * It is the responsibility of any person or organization contemplating + * export to obtain such a license before exporting. + * + * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and + * distribute this software and its documentation for any purpose and + * without fee is hereby granted, provided that the above copyright + * notice appear in all copies and that both that copyright notice and + * this permission notice appear in supporting documentation, and that + * the name of M.I.T. not be used in advertising or publicity pertaining + * to distribution of the software without specific, written prior + * permission. Furthermore if you modify this software you must label + * your software as modified software and not distribute it in such a + * fashion that it might be confused with the original M.I.T. software. + * M.I.T. makes no representations about the suitability of + * this software for any purpose. It is provided "as is" without express + * or implied warranty. + */ + + +#include "k5-int.h" +#include "arcfour.h" +#include "arcfour-int.h" +#include "aead.h" + +/* AEAD */ + +static krb5_error_code +krb5int_arcfour_crypto_length(const struct krb5_aead_provider *aead, + const struct krb5_enc_provider *enc, + const struct krb5_hash_provider *hash, + krb5_cryptotype type, + unsigned int *length) +{ + switch (type) { + case KRB5_CRYPTO_TYPE_HEADER: + *length = hash->hashsize + CONFOUNDERLENGTH; + break; + case KRB5_CRYPTO_TYPE_PADDING: + *length = 0; + break; + case KRB5_CRYPTO_TYPE_TRAILER: + *length = 0; + break; + case KRB5_CRYPTO_TYPE_CHECKSUM: + *length = hash->hashsize; + break; + default: + assert(0 && "invalid cryptotype passed to krb5int_arcfour_crypto_length"); + break; + } + + return 0; +} + +static krb5_error_code +alloc_derived_key(const struct krb5_enc_provider *enc, + krb5_keyblock *dst, + krb5_data *data, + const krb5_keyblock *src) +{ + data->length = enc->keybytes; + data->data = malloc(data->length); + if (data->data == NULL) + return ENOMEM; + + *dst = *src; + dst->length = data->length; + dst->contents = (void *)data->data; + + return 0; +} + +static krb5_error_code +krb5int_arcfour_encrypt_iov(const struct krb5_aead_provider *aead, + const struct krb5_enc_provider *enc, + const struct krb5_hash_provider *hash, + const krb5_keyblock *key, + krb5_keyusage usage, + const krb5_data *ivec, + krb5_crypto_iov *data, + size_t num_data) +{ + krb5_error_code ret; + krb5_crypto_iov *header, *trailer; + krb5_keyblock k1, k2, k3; + krb5_data d1, d2, d3; + krb5_data checksum, confounder, header_data; + krb5_keyusage ms_usage; + char salt_data[14]; + krb5_data salt; + size_t i; + + d1.length = d2.length = d3.length = 0; + d1.data = d2.data = d3.data = NULL; + + /* + * Caller must have provided space for the header, padding + * and trailer; per RFC 4757 we will arrange it as: + * + * Checksum | E(Confounder | Plaintext) + */ + + header = krb5int_c_locate_iov(data, num_data, KRB5_CRYPTO_TYPE_HEADER); + if (header == NULL || + header->data.length < hash->hashsize + CONFOUNDERLENGTH) + return KRB5_BAD_MSIZE; + + header_data = header->data; + + /* Trailer may be absent */ + trailer = krb5int_c_locate_iov(data, num_data, KRB5_CRYPTO_TYPE_TRAILER); + if (trailer != NULL) + trailer->data.length = 0; + + /* Ensure that there is no padding */ + for (i = 0; i < num_data; i++) { + if (data[i].flags == KRB5_CRYPTO_TYPE_PADDING) + data[i].data.length = 0; + } + + ret = alloc_derived_key(enc, &k1, &d1, key); + if (ret != 0) + goto cleanup; + + ret = alloc_derived_key(enc, &k2, &d2, key); + if (ret != 0) + goto cleanup; + + ret = alloc_derived_key(enc, &k3, &d3, key); + if (ret != 0) + goto cleanup; + + /* Begin the encryption, compute K1 */ + salt.data = salt_data; + salt.length = sizeof(salt_data); + + ms_usage = krb5int_arcfour_translate_usage(usage); + + if (key->enctype == ENCTYPE_ARCFOUR_HMAC_EXP) { + strncpy(salt.data, krb5int_arcfour_l40, salt.length); + store_32_le(ms_usage, salt.data + 10); + } else { + salt.length = 4; + store_32_le(ms_usage, salt.data); + } + ret = krb5_hmac(hash, key, 1, &salt, &d1); + if (ret != 0) + goto cleanup; + + memcpy(k2.contents, k1.contents, k2.length); + + if (key->enctype == ENCTYPE_ARCFOUR_HMAC_EXP) + memset(k1.contents + 7, 0xAB, 9); + + header->data.length = hash->hashsize + CONFOUNDERLENGTH; + + confounder.data = header->data.data + hash->hashsize; + confounder.length = CONFOUNDERLENGTH; + + ret = krb5_c_random_make_octets(0, &confounder); + if (ret != 0) + goto cleanup; + + checksum.data = header->data.data; + checksum.length = hash->hashsize; + + /* Adjust pointers so confounder is at start of header */ + header->data.length -= hash->hashsize; + header->data.data += hash->hashsize; + + ret = krb5int_hmac_iov(hash, &k2, data, num_data, &checksum); + if (ret != 0) + goto cleanup; + + ret = krb5_hmac(hash, &k1, 1, &checksum, &d3); + if (ret != 0) + goto cleanup; + + ret = enc->encrypt_iov(&k3, ivec, data, num_data); + if (ret != 0) + goto cleanup; + +cleanup: + header->data = header_data; /* restore header pointers */ + + if (d1.data != NULL) { + memset(d1.data, 0, d1.length); + free(d1.data); + } + if (d2.data != NULL) { + memset(d2.data, 0, d2.length); + free(d2.data); + } + if (d3.data != NULL) { + memset(d3.data, 0, d3.length); + free(d3.data); + } + + return ret; +} + +static krb5_error_code +krb5int_arcfour_decrypt_iov(const struct krb5_aead_provider *aead, + const struct krb5_enc_provider *enc, + const struct krb5_hash_provider *hash, + const krb5_keyblock *key, + krb5_keyusage usage, + const krb5_data *ivec, + krb5_crypto_iov *data, + size_t num_data) +{ + krb5_error_code ret; + krb5_crypto_iov *header, *trailer; + krb5_keyblock k1, k2, k3; + krb5_data d1, d2, d3; + krb5_data checksum, header_data; + krb5_keyusage ms_usage; + char salt_data[14]; + krb5_data salt; + + d1.length = d2.length = d3.length = 0; + d1.data = d2.data = d3.data = NULL; + + header = krb5int_c_locate_iov(data, num_data, KRB5_CRYPTO_TYPE_HEADER); + if (header == NULL || + header->data.length != hash->hashsize + CONFOUNDERLENGTH) + return KRB5_BAD_MSIZE; + + header_data = header->data; + + trailer = krb5int_c_locate_iov(data, num_data, KRB5_CRYPTO_TYPE_TRAILER); + if (trailer != NULL && trailer->data.length != 0) + return KRB5_BAD_MSIZE; + + ret = alloc_derived_key(enc, &k1, &d1, key); + if (ret != 0) + goto cleanup; + + ret = alloc_derived_key(enc, &k2, &d2, key); + if (ret != 0) + goto cleanup; + + ret = alloc_derived_key(enc, &k3, &d3, key); + if (ret != 0) + goto cleanup; + + /* Begin the decryption, compute K1 */ + salt.data = salt_data; + salt.length = sizeof(salt_data); + + ms_usage = krb5int_arcfour_translate_usage(usage); + + if (key->enctype == ENCTYPE_ARCFOUR_HMAC_EXP) { + strncpy(salt.data, krb5int_arcfour_l40, salt.length); + store_32_le(ms_usage, (unsigned char *)salt.data + 10); + } else { + salt.length = 4; + store_32_le(ms_usage, (unsigned char *)salt.data); + } + ret = krb5_hmac(hash, key, 1, &salt, &d1); + if (ret != 0) + goto cleanup; + + memcpy(k2.contents, k1.contents, k2.length); + + if (key->enctype == ENCTYPE_ARCFOUR_HMAC_EXP) + memset(k1.contents + 7, 0xAB, 9); + + checksum.data = header->data.data; + checksum.length = hash->hashsize; + + /* Adjust pointers so confounder is at start of header */ + header->data.length -= hash->hashsize; + header->data.data += hash->hashsize; + + ret = krb5_hmac(hash, &k1, 1, &checksum, &d3); + if (ret != 0) + goto cleanup; + + ret = enc->decrypt_iov(&k3, ivec, data, num_data); + if (ret != 0) + goto cleanup; + + ret = krb5int_hmac_iov(hash, &k2, data, num_data, &d1); + if (ret != 0) + goto cleanup; + + if (memcmp(checksum.data, d1.data, hash->hashsize) != 0) { + ret = KRB5KRB_AP_ERR_BAD_INTEGRITY; + goto cleanup; + } + +cleanup: + header->data = header_data; /* restore header pointers */ + + if (d1.data != NULL) { + memset(d1.data, 0, d1.length); + free(d1.data); + } + if (d2.data != NULL) { + memset(d2.data, 0, d2.length); + free(d2.data); + } + if (d3.data != NULL) { + memset(d3.data, 0, d3.length); + free(d3.data); + } + + return ret; +} + +const struct krb5_aead_provider krb5int_aead_arcfour = { + krb5int_arcfour_crypto_length, + krb5int_arcfour_encrypt_iov, + krb5int_arcfour_decrypt_iov +}; + diff --git a/src/lib/crypto/openssl/arcfour/arcfour_s2k.c b/src/lib/crypto/openssl/arcfour/arcfour_s2k.c new file mode 100644 index 000000000..41053ed17 --- /dev/null +++ b/src/lib/crypto/openssl/arcfour/arcfour_s2k.c @@ -0,0 +1,59 @@ +#include "k5-int.h" +#include "k5-utf8.h" +#include "rsa-md4.h" +#include "arcfour-int.h" + +#if TARGET_OS_MAC && !defined(DEPEND) +#include +#endif + +krb5_error_code +krb5int_arcfour_string_to_key(const struct krb5_enc_provider *enc, + const krb5_data *string, const krb5_data *salt, + const krb5_data *params, krb5_keyblock *key) +{ + krb5_error_code err = 0; + krb5_MD4_CTX md4_context; + unsigned char *copystr; + size_t copystrlen; + + if (params != NULL) + return KRB5_ERR_BAD_S2K_PARAMS; + + if (key->length != 16) + return (KRB5_BAD_MSIZE); + + /* We ignore salt per the Microsoft spec*/ + + /* compute the space needed for the new string. + Since the password must be stored in unicode, we need to increase + that number by 2x. + */ + + err = krb5int_utf8cs_to_ucs2les(string->data, string->length, ©str, ©strlen); + if (err) + return err; + + /* the actual MD4 hash of the data */ + krb5_MD4Init(&md4_context); + krb5_MD4Update(&md4_context, copystr, copystrlen); + krb5_MD4Final(&md4_context); + memcpy(key->contents, md4_context.digest, 16); + +#if 0 + /* test the string_to_key function */ + printf("Hash="); + { + int counter; + for(counter=0;counter<16;counter++) + printf("%02x", md4_context.digest[counter]); + printf("\n"); + } +#endif /* 0 */ + + /* Zero out the data behind us */ + memset(copystr, 0, copystrlen); + memset(&md4_context, 0, sizeof(md4_context)); + free(copystr); + return err; +} -- 2.26.2