/* $NetBSD: crypto-arcfour.c,v 1.4.8.1 2023/08/11 13:40:00 martin Exp $ */ /* * Copyright (c) 1997 - 2008 Kungliga Tekniska Högskolan * (Royal Institute of Technology, Stockholm, Sweden). * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * 3. Neither the name of the Institute nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ /* * ARCFOUR */ #include "krb5_locl.h" static struct _krb5_key_type keytype_arcfour = { KRB5_ENCTYPE_ARCFOUR_HMAC_MD5, "arcfour", 128, 16, sizeof(struct _krb5_evp_schedule), NULL, _krb5_evp_schedule, _krb5_arcfour_salt, NULL, _krb5_evp_cleanup, EVP_rc4 }; /* * checksum according to section 5. of draft-brezak-win2k-krb-rc4-hmac-03.txt */ krb5_error_code _krb5_HMAC_MD5_checksum(krb5_context context, struct _krb5_key_data *key, const void *data, size_t len, unsigned usage, Checksum *result) { EVP_MD_CTX *m; struct _krb5_checksum_type *c = _krb5_find_checksum (CKSUMTYPE_RSA_MD5); const char signature[] = "signaturekey"; Checksum ksign_c; struct _krb5_key_data ksign; krb5_keyblock kb; unsigned char t[4]; unsigned char tmp[16]; unsigned char ksign_c_data[16]; krb5_error_code ret; m = EVP_MD_CTX_create(); if (m == NULL) return krb5_enomem(context); ksign_c.checksum.length = sizeof(ksign_c_data); ksign_c.checksum.data = ksign_c_data; ret = _krb5_internal_hmac(context, c, signature, sizeof(signature), 0, key, &ksign_c); if (ret) { EVP_MD_CTX_destroy(m); return ret; } ksign.key = &kb; kb.keyvalue = ksign_c.checksum; EVP_DigestInit_ex(m, EVP_md5(), NULL); t[0] = (usage >> 0) & 0xFF; t[1] = (usage >> 8) & 0xFF; t[2] = (usage >> 16) & 0xFF; t[3] = (usage >> 24) & 0xFF; EVP_DigestUpdate(m, t, 4); EVP_DigestUpdate(m, data, len); EVP_DigestFinal_ex (m, tmp, NULL); EVP_MD_CTX_destroy(m); ret = _krb5_internal_hmac(context, c, tmp, sizeof(tmp), 0, &ksign, result); if (ret) return ret; return 0; } struct _krb5_checksum_type _krb5_checksum_hmac_md5 = { CKSUMTYPE_HMAC_MD5, "hmac-md5", 64, 16, F_KEYED | F_CPROOF, _krb5_HMAC_MD5_checksum, NULL }; /* * section 6 of draft-brezak-win2k-krb-rc4-hmac-03 * * warning: not for small children */ static krb5_error_code ARCFOUR_subencrypt(krb5_context context, struct _krb5_key_data *key, void *data, size_t len, unsigned usage, void *ivec) { EVP_CIPHER_CTX *ctx; struct _krb5_checksum_type *c = _krb5_find_checksum (CKSUMTYPE_RSA_MD5); Checksum k1_c, k2_c, k3_c, cksum; struct _krb5_key_data ke; krb5_keyblock kb; unsigned char t[4]; unsigned char *cdata = data; unsigned char k1_c_data[16], k2_c_data[16], k3_c_data[16]; krb5_error_code ret; t[0] = (usage >> 0) & 0xFF; t[1] = (usage >> 8) & 0xFF; t[2] = (usage >> 16) & 0xFF; t[3] = (usage >> 24) & 0xFF; k1_c.checksum.length = sizeof(k1_c_data); k1_c.checksum.data = k1_c_data; ret = _krb5_internal_hmac(context, c, t, sizeof(t), 0, key, &k1_c); if (ret) krb5_abortx(context, "hmac failed"); memcpy (k2_c_data, k1_c_data, sizeof(k1_c_data)); k2_c.checksum.length = sizeof(k2_c_data); k2_c.checksum.data = k2_c_data; ke.key = &kb; kb.keyvalue = k2_c.checksum; cksum.checksum.length = 16; cksum.checksum.data = data; ret = _krb5_internal_hmac(context, c, cdata + 16, len - 16, 0, &ke, &cksum); if (ret) krb5_abortx(context, "hmac failed"); ke.key = &kb; kb.keyvalue = k1_c.checksum; k3_c.checksum.length = sizeof(k3_c_data); k3_c.checksum.data = k3_c_data; ret = _krb5_internal_hmac(context, c, data, 16, 0, &ke, &k3_c); if (ret) krb5_abortx(context, "hmac failed"); #if OPENSSL_VERSION_NUMBER < 0x10100000UL EVP_CIPHER_CTX ctxst; ctx = &ctxst; EVP_CIPHER_CTX_init(ctx); #else ctx = EVP_CIPHER_CTX_new(); #endif if (!EVP_CipherInit_ex(ctx, EVP_rc4(), NULL, k3_c.checksum.data, NULL, 1)) krb5_abortx(context, "rc4 cipher not supported"); EVP_Cipher(ctx, cdata + 16, cdata + 16, len - 16); #if OPENSSL_VERSION_NUMBER < 0x10100000UL EVP_CIPHER_CTX_cleanup(ctx); #else EVP_CIPHER_CTX_free(ctx); #endif memset_s(k1_c_data, sizeof(k1_c_data), 0, sizeof(k1_c_data)); memset_s(k2_c_data, sizeof(k2_c_data), 0, sizeof(k2_c_data)); memset_s(k3_c_data, sizeof(k3_c_data), 0, sizeof(k3_c_data)); return 0; } static krb5_error_code ARCFOUR_subdecrypt(krb5_context context, struct _krb5_key_data *key, void *data, size_t len, unsigned usage, void *ivec) { EVP_CIPHER_CTX *ctx; struct _krb5_checksum_type *c = _krb5_find_checksum (CKSUMTYPE_RSA_MD5); Checksum k1_c, k2_c, k3_c, cksum; struct _krb5_key_data ke; krb5_keyblock kb; unsigned char t[4]; unsigned char *cdata = data; unsigned char k1_c_data[16], k2_c_data[16], k3_c_data[16]; unsigned char cksum_data[16]; krb5_error_code ret; t[0] = (usage >> 0) & 0xFF; t[1] = (usage >> 8) & 0xFF; t[2] = (usage >> 16) & 0xFF; t[3] = (usage >> 24) & 0xFF; k1_c.checksum.length = sizeof(k1_c_data); k1_c.checksum.data = k1_c_data; ret = _krb5_internal_hmac(context, c, t, sizeof(t), 0, key, &k1_c); if (ret) krb5_abortx(context, "hmac failed"); memcpy (k2_c_data, k1_c_data, sizeof(k1_c_data)); k2_c.checksum.length = sizeof(k2_c_data); k2_c.checksum.data = k2_c_data; ke.key = &kb; kb.keyvalue = k1_c.checksum; k3_c.checksum.length = sizeof(k3_c_data); k3_c.checksum.data = k3_c_data; ret = _krb5_internal_hmac(context, c, cdata, 16, 0, &ke, &k3_c); if (ret) krb5_abortx(context, "hmac failed"); #if OPENSSL_VERSION_NUMBER < 0x10100000UL EVP_CIPHER_CTX ctxst; ctx = &ctxst; EVP_CIPHER_CTX_init(ctx); #else ctx = EVP_CIPHER_CTX_new(); #endif if (!EVP_CipherInit_ex(ctx, EVP_rc4(), NULL, k3_c.checksum.data, NULL, 0)) krb5_abortx(context, "rc4 cipher not supported"); EVP_Cipher(ctx, cdata + 16, cdata + 16, len - 16); #if OPENSSL_VERSION_NUMBER < 0x10100000UL EVP_CIPHER_CTX_cleanup(ctx); #else EVP_CIPHER_CTX_free(ctx); #endif ke.key = &kb; kb.keyvalue = k2_c.checksum; cksum.checksum.length = 16; cksum.checksum.data = cksum_data; ret = _krb5_internal_hmac(context, c, cdata + 16, len - 16, 0, &ke, &cksum); if (ret) krb5_abortx(context, "hmac failed"); memset_s(k1_c_data, sizeof(k1_c_data), 0, sizeof(k1_c_data)); memset_s(k2_c_data, sizeof(k2_c_data), 0, sizeof(k2_c_data)); memset_s(k3_c_data, sizeof(k3_c_data), 0, sizeof(k3_c_data)); if (ct_memcmp (cksum.checksum.data, data, 16) != 0) { krb5_clear_error_message (context); return KRB5KRB_AP_ERR_BAD_INTEGRITY; } else { return 0; } } /* * convert the usage numbers used in * draft-ietf-cat-kerb-key-derivation-00.txt to the ones in * draft-brezak-win2k-krb-rc4-hmac-04.txt */ KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL _krb5_usage2arcfour(krb5_context context, unsigned *usage) { switch (*usage) { case KRB5_KU_AS_REP_ENC_PART : /* 3 */ *usage = 8; return 0; case KRB5_KU_USAGE_SEAL : /* 22 */ *usage = 13; return 0; case KRB5_KU_USAGE_SIGN : /* 23 */ *usage = 15; return 0; case KRB5_KU_USAGE_SEQ: /* 24 */ *usage = 0; return 0; default : return 0; } } static krb5_error_code ARCFOUR_encrypt(krb5_context context, struct _krb5_key_data *key, void *data, size_t len, krb5_boolean encryptp, int usage, void *ivec) { krb5_error_code ret; unsigned keyusage = usage; if((ret = _krb5_usage2arcfour (context, &keyusage)) != 0) return ret; if (encryptp) return ARCFOUR_subencrypt (context, key, data, len, keyusage, ivec); else return ARCFOUR_subdecrypt (context, key, data, len, keyusage, ivec); } static krb5_error_code ARCFOUR_prf(krb5_context context, krb5_crypto crypto, const krb5_data *in, krb5_data *out) { struct _krb5_checksum_type *c = _krb5_find_checksum(CKSUMTYPE_SHA1); krb5_error_code ret; Checksum res; ret = krb5_data_alloc(out, c->checksumsize); if (ret) return ret; res.checksum.data = out->data; res.checksum.length = out->length; ret = _krb5_internal_hmac(context, c, in->data, in->length, 0, &crypto->key, &res); if (ret) krb5_data_free(out); return 0; } struct _krb5_encryption_type _krb5_enctype_arcfour_hmac_md5 = { ETYPE_ARCFOUR_HMAC_MD5, "arcfour-hmac-md5", "rc4-hmac", 1, 1, 8, &keytype_arcfour, &_krb5_checksum_hmac_md5, &_krb5_checksum_hmac_md5, F_SPECIAL | F_WEAK, ARCFOUR_encrypt, 0, ARCFOUR_prf };