diff options
Diffstat (limited to 'src/lib/crypto/krb/checksum/confounder.c')
-rw-r--r-- | src/lib/crypto/krb/checksum/confounder.c | 159 |
1 files changed, 159 insertions, 0 deletions
diff --git a/src/lib/crypto/krb/checksum/confounder.c b/src/lib/crypto/krb/checksum/confounder.c new file mode 100644 index 0000000..73d69e3 --- /dev/null +++ b/src/lib/crypto/krb/checksum/confounder.c @@ -0,0 +1,159 @@ +/* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */ +/* + * lib/crypto/krb/checksum/confounder.c + * + * Copyright (C) 2009 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. + * + * Confounder checksum implementation, using tokens of the form: + * enc(xorkey, confounder | hash(confounder | data)) + * where xorkey is the key XOR'd with 0xf0 bytes. + */ + +#include "k5-int.h" +#include "cksumtypes.h" + +/* Derive a key by XOR with 0xF0 bytes. */ +static krb5_error_code +mk_xorkey(krb5_key origkey, krb5_key *xorkey) +{ + krb5_error_code retval = 0; + unsigned char *xorbytes; + krb5_keyblock xorkeyblock; + size_t i = 0; + + xorbytes = malloc(origkey->keyblock.length); + if (xorbytes == NULL) + return ENOMEM; + memcpy(xorbytes, origkey->keyblock.contents, origkey->keyblock.length); + for (i = 0; i < sizeof(xorbytes); i++) + xorbytes[i] ^= 0xf0; + + /* Do a shallow copy here. */ + xorkeyblock = origkey->keyblock; + xorkeyblock.contents = xorbytes; + + retval = krb5_k_create_key(0, &xorkeyblock, xorkey); + zapfree(xorbytes, sizeof(xorbytes)); + return retval; +} + +krb5_error_code +krb5int_confounder_checksum(const struct krb5_cksumtypes *ctp, + krb5_key key, krb5_keyusage usage, + const krb5_crypto_iov *data, size_t num_data, + krb5_data *output) +{ + krb5_error_code ret; + krb5_data conf, hashval; + krb5_key xorkey = NULL; + krb5_crypto_iov *hash_iov, iov; + size_t blocksize = ctp->enc->block_size, hashsize = ctp->hash->hashsize; + + conf = make_data(output->data, blocksize); + hashval = make_data(output->data + blocksize, hashsize); + + /* Create the confounder. */ + ret = krb5_c_random_make_octets(NULL, &conf); + if (ret != 0) + return ret; + + ret = mk_xorkey(key, &xorkey); + if (ret) + return ret; + + /* Hash the confounder, then the input data. */ + hash_iov = k5alloc((num_data + 1) * sizeof(krb5_crypto_iov), &ret); + if (hash_iov == NULL) + goto cleanup; + hash_iov[0].flags = KRB5_CRYPTO_TYPE_DATA; + hash_iov[0].data = conf; + memcpy(hash_iov + 1, data, num_data * sizeof(krb5_crypto_iov)); + ret = ctp->hash->hash(hash_iov, num_data + 1, &hashval); + if (ret != 0) + goto cleanup; + + /* Encrypt the confounder and hash value. */ + iov.flags = KRB5_CRYPTO_TYPE_DATA; + iov.data = *output; + ret = ctp->enc->encrypt(xorkey, NULL, &iov, 1); + +cleanup: + free(hash_iov); + krb5_k_free_key(NULL, xorkey); + return ret; +} + +krb5_error_code krb5int_confounder_verify(const struct krb5_cksumtypes *ctp, + krb5_key key, krb5_keyusage usage, + const krb5_crypto_iov *data, + size_t num_data, + const krb5_data *input, + krb5_boolean *valid) +{ + krb5_error_code ret; + unsigned char *plaintext = NULL; + krb5_key xorkey = NULL; + krb5_data computed = empty_data(); + krb5_crypto_iov *hash_iov, iov; + size_t blocksize = ctp->enc->block_size, hashsize = ctp->hash->hashsize; + + plaintext = k5alloc(input->length, &ret); + if (plaintext == NULL) + return ret; + + ret = mk_xorkey(key, &xorkey); + if (ret != 0) + goto cleanup; + + /* Decrypt the input checksum. */ + iov.flags = KRB5_CRYPTO_TYPE_DATA; + iov.data = make_data(plaintext, input->length); + memcpy(plaintext, input->data, input->length); + ret = ctp->enc->decrypt(xorkey, NULL, &iov, 1); + if (ret != 0) + goto cleanup; + + /* Hash the confounder, then the input data. */ + hash_iov = k5alloc((num_data + 1) * sizeof(krb5_crypto_iov), &ret); + if (hash_iov == NULL) + goto cleanup; + hash_iov[0].flags = KRB5_CRYPTO_TYPE_DATA; + hash_iov[0].data = make_data(plaintext, blocksize); + memcpy(hash_iov + 1, data, num_data * sizeof(krb5_crypto_iov)); + ret = alloc_data(&computed, hashsize); + if (ret != 0) + goto cleanup; + ret = ctp->hash->hash(hash_iov, num_data + 1, &computed); + if (ret != 0) + goto cleanup; + + /* Compare the decrypted hash to the computed one. */ + *valid = (memcmp(plaintext + blocksize, computed.data, hashsize) == 0); + +cleanup: + zapfree(plaintext, input->length); + zapfree(computed.data, hashsize); + free(hash_iov); + krb5_k_free_key(NULL, xorkey); + return ret; +} |