static krb5_error_code hmac1(const struct krb5_hash_provider *h, krb5_keyblock *key, krb5_data *in, krb5_data *out) { char tmp[40]; size_t blocksize, hashsize; krb5_error_code err; printk(" test key", key); blocksize = h->blocksize; hashsize = h->hashsize; if (hashsize > sizeof(tmp)) abort(); if (key->length > blocksize) { krb5_data d, d2; d.data = (char *) key->contents; d.length = key->length; d2.data = tmp; d2.length = hashsize; err = h->hash (1, &d, &d2); if (err) { com_err(whoami, err, "hashing key before calling hmac"); exit(1); } key->length = d2.length; key->contents = (krb5_octet *) d2.data; printk(" pre-hashed key", key); } printd(" hmac input", in); err = krb5_hmac(h, key, 1, in, out); if (err == 0) printd(" hmac output", out); return err; }
static krb5_error_code arcfour_mic_key(krb5_context context, krb5_keyblock *key, void *cksum_data, size_t cksum_size, void *key6_data, size_t key6_size) { krb5_error_code ret; Checksum cksum_k5; krb5_keyblock key5; char k5_data[16]; Checksum cksum_k6; char T[4]; memset(T, 0, 4); cksum_k5.checksum.data = k5_data; cksum_k5.checksum.length = sizeof(k5_data); if (key->keytype == KRB5_ENCTYPE_ARCFOUR_HMAC_MD5_56) { char L40[14] = "fortybits"; memcpy(L40 + 10, T, sizeof(T)); ret = krb5_hmac(context, CKSUMTYPE_RSA_MD5, L40, 14, 0, key, &cksum_k5); memset(&k5_data[7], 0xAB, 9); } else { ret = krb5_hmac(context, CKSUMTYPE_RSA_MD5, T, 4, 0, key, &cksum_k5); } if (ret) return ret; key5.keytype = KRB5_ENCTYPE_ARCFOUR_HMAC_MD5; key5.keyvalue = cksum_k5.checksum; cksum_k6.checksum.data = key6_data; cksum_k6.checksum.length = key6_size; return krb5_hmac(context, CKSUMTYPE_RSA_MD5, cksum_data, cksum_size, 0, &key5, &cksum_k6); }
static krb5_error_code k5_md5_hmac_hash (const krb5_keyblock *key, krb5_keyusage usage, const krb5_data *iv, const krb5_data *input, krb5_data *output) { krb5_keyusage ms_usage; krb5_MD5_CTX ctx; unsigned char t[4]; krb5_data ds; krb5_MD5Init(&ctx); ms_usage = krb5int_arcfour_translate_usage (usage); store_32_le(ms_usage, t); krb5_MD5Update(&ctx, t, sizeof(t)); krb5_MD5Update(&ctx, (unsigned char *)input->data, input->length); krb5_MD5Final(&ctx); ds.magic = KV5M_DATA; ds.length = 16; ds.data = (char *)ctx.digest; return krb5_hmac ( &krb5int_hash_md5, key, 1, &ds, output); }
krb5_error_code krb5_dk_make_checksum(const struct krb5_hash_provider *hash, const krb5_keyblock *key, krb5_keyusage usage, const krb5_data *input, krb5_data *output) { int i; const struct krb5_enc_provider *enc; size_t blocksize, keybytes, keylength; krb5_error_code ret; unsigned char constantdata[K5CLENGTH]; krb5_data datain; unsigned char *kcdata; krb5_keyblock kc; for (i=0; i<krb5_enctypes_length; i++) { if (krb5_enctypes_list[i].etype == key->enctype) break; } if (i == krb5_enctypes_length) return(KRB5_BAD_ENCTYPE); enc = krb5_enctypes_list[i].enc; /* allocate and set to-be-derived keys */ blocksize = enc->block_size; keybytes = enc->keybytes; keylength = enc->keylength; /* key->length will be tested in enc->encrypt output->length will be tested in krb5_hmac */ if ((kcdata = (unsigned char *) malloc(keylength)) == NULL) return(ENOMEM); kc.contents = kcdata; kc.length = keylength; /* derive the key */ datain.data = (char *) constantdata; datain.length = K5CLENGTH; store_32_be(usage, constantdata); datain.data[4] = (char) 0x99; if ((ret = krb5_derive_key(enc, key, &kc, &datain)) != 0) goto cleanup; /* hash the data */ datain = *input; if ((ret = krb5_hmac(hash, &kc, 1, &datain, output)) != 0) memset(output->data, 0, output->length); /* ret is set correctly by the prior call */ cleanup: memset(kcdata, 0, keylength); free(kcdata); return(ret); }
static krb5_error_code krb5_dk_decrypt_maybe_trunc_hmac( krb5_context context, 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, enclen, plainlen; unsigned char *plaindata = NULL, *cksum = NULL, *cn; krb5_data d1, d2; krb5_keyblock *derived_encr_key = NULL; krb5_keyblock *derived_hmac_key = NULL; KRB5_LOG0(KRB5_INFO, "krb5_dk_decrypt() start\n"); /* * Derive the encryption and hmac keys. * This routine is optimized to fetch the DK * from the original key's DK list. */ ret = init_derived_keydata(context, enc, (krb5_keyblock *)key, usage, &derived_encr_key, &derived_hmac_key); if (ret) return (ret); hashsize = hash->hashsize; blocksize = enc->block_size; if (hmacsize == 0) hmacsize = hashsize; else if (hmacsize > hashsize) return (KRB5KRB_AP_ERR_BAD_INTEGRITY); enclen = input->length - hmacsize; if ((plaindata = (unsigned char *) MALLOC(enclen)) == NULL) { ret = ENOMEM; goto cleanup; } /* decrypt the ciphertext */ d1.length = enclen; d1.data = input->data; d2.length = enclen; d2.data = (char *) plaindata; if ((ret = ((*(enc->decrypt))(context, derived_encr_key, ivec, &d1, &d2))) != 0) goto cleanup; if (ivec != NULL && ivec->length == blocksize) { cn = (unsigned char *) d1.data + d1.length - blocksize; } else { cn = NULL; } /* verify the hash */ if ((cksum = (unsigned char *) MALLOC(hashsize)) == NULL) { ret = ENOMEM; goto cleanup; } d1.length = hashsize; d1.data = (char *) cksum; #ifdef _KERNEL if ((ret = krb5_hmac(context, derived_hmac_key, &d2, &d1)) != 0) goto cleanup; #else if ((ret = krb5_hmac(context, hash, derived_hmac_key, 1, &d2, &d1)) != 0) goto cleanup; #endif /* _KERNEL */ if (memcmp(cksum, input->data+enclen, hmacsize) != 0) { ret = KRB5KRB_AP_ERR_BAD_INTEGRITY; goto cleanup; } /* because this encoding isn't self-describing wrt length, the best we can do here is to compute the length minus the confounder. */ plainlen = enclen - blocksize; if (output->length < plainlen) { ret = KRB5_BAD_MSIZE; goto cleanup; } output->length = plainlen; (void) memcpy(output->data, d2.data+blocksize, output->length); /* * AES crypto updates the ivec differently, it is handled * in the AES crypto routines directly. */ if (cn != NULL && key->enctype != ENCTYPE_AES128_CTS_HMAC_SHA1_96 && key->enctype != ENCTYPE_AES256_CTS_HMAC_SHA1_96) { (void) memcpy(ivec->data, cn, blocksize); } ret = 0; cleanup: if (plaindata) { (void) memset(plaindata, 0, enclen); FREE(plaindata, enclen); } if (cksum) { (void) memset(cksum, 0, hashsize); FREE(cksum, hashsize); } KRB5_LOG(KRB5_INFO, "krb5_dk_decrypt() end, ret=%d\n", ret); return(ret); }
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; }