Home | History | Annotate | Line # | Download | only in krb5
      1 /*	$NetBSD: crypto-arcfour.c,v 1.6 2023/06/19 21:41:44 christos Exp $	*/
      2 
      3 /*
      4  * Copyright (c) 1997 - 2008 Kungliga Tekniska Hgskolan
      5  * (Royal Institute of Technology, Stockholm, Sweden).
      6  * All rights reserved.
      7  *
      8  * Redistribution and use in source and binary forms, with or without
      9  * modification, are permitted provided that the following conditions
     10  * are met:
     11  *
     12  * 1. Redistributions of source code must retain the above copyright
     13  *    notice, this list of conditions and the following disclaimer.
     14  *
     15  * 2. Redistributions in binary form must reproduce the above copyright
     16  *    notice, this list of conditions and the following disclaimer in the
     17  *    documentation and/or other materials provided with the distribution.
     18  *
     19  * 3. Neither the name of the Institute nor the names of its contributors
     20  *    may be used to endorse or promote products derived from this software
     21  *    without specific prior written permission.
     22  *
     23  * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
     24  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     25  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
     26  * ARE DISCLAIMED.  IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
     27  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
     28  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
     29  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     30  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
     31  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
     32  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
     33  * SUCH DAMAGE.
     34  */
     35 
     36 /*
     37  * ARCFOUR
     38  */
     39 
     40 #include "krb5_locl.h"
     41 
     42 static struct _krb5_key_type keytype_arcfour = {
     43     KRB5_ENCTYPE_ARCFOUR_HMAC_MD5,
     44     "arcfour",
     45     128,
     46     16,
     47     sizeof(struct _krb5_evp_schedule),
     48     NULL,
     49     _krb5_evp_schedule,
     50     _krb5_arcfour_salt,
     51     NULL,
     52     _krb5_evp_cleanup,
     53     EVP_rc4
     54 };
     55 
     56 /*
     57  * checksum according to section 5. of draft-brezak-win2k-krb-rc4-hmac-03.txt
     58  */
     59 
     60 krb5_error_code
     61 _krb5_HMAC_MD5_checksum(krb5_context context,
     62 			struct _krb5_key_data *key,
     63 			const void *data,
     64 			size_t len,
     65 			unsigned usage,
     66 			Checksum *result)
     67 {
     68     EVP_MD_CTX *m;
     69     struct _krb5_checksum_type *c = _krb5_find_checksum (CKSUMTYPE_RSA_MD5);
     70     const char signature[] = "signaturekey";
     71     Checksum ksign_c;
     72     struct _krb5_key_data ksign;
     73     krb5_keyblock kb;
     74     unsigned char t[4];
     75     unsigned char tmp[16];
     76     unsigned char ksign_c_data[16];
     77     krb5_error_code ret;
     78 
     79     m = EVP_MD_CTX_create();
     80     if (m == NULL)
     81 	return krb5_enomem(context);
     82     ksign_c.checksum.length = sizeof(ksign_c_data);
     83     ksign_c.checksum.data   = ksign_c_data;
     84     ret = _krb5_internal_hmac(context, c, signature, sizeof(signature),
     85 			      0, key, &ksign_c);
     86     if (ret) {
     87 	EVP_MD_CTX_destroy(m);
     88 	return ret;
     89     }
     90     ksign.key = &kb;
     91     kb.keyvalue = ksign_c.checksum;
     92     EVP_DigestInit_ex(m, EVP_md5(), NULL);
     93     t[0] = (usage >>  0) & 0xFF;
     94     t[1] = (usage >>  8) & 0xFF;
     95     t[2] = (usage >> 16) & 0xFF;
     96     t[3] = (usage >> 24) & 0xFF;
     97     EVP_DigestUpdate(m, t, 4);
     98     EVP_DigestUpdate(m, data, len);
     99     EVP_DigestFinal_ex (m, tmp, NULL);
    100     EVP_MD_CTX_destroy(m);
    101 
    102     ret = _krb5_internal_hmac(context, c, tmp, sizeof(tmp), 0, &ksign, result);
    103     if (ret)
    104 	return ret;
    105     return 0;
    106 }
    107 
    108 struct _krb5_checksum_type _krb5_checksum_hmac_md5 = {
    109     CKSUMTYPE_HMAC_MD5,
    110     "hmac-md5",
    111     64,
    112     16,
    113     F_KEYED | F_CPROOF,
    114     _krb5_HMAC_MD5_checksum,
    115     NULL
    116 };
    117 
    118 /*
    119  * section 6 of draft-brezak-win2k-krb-rc4-hmac-03
    120  *
    121  * warning: not for small children
    122  */
    123 
    124 static krb5_error_code
    125 ARCFOUR_subencrypt(krb5_context context,
    126 		   struct _krb5_key_data *key,
    127 		   void *data,
    128 		   size_t len,
    129 		   unsigned usage,
    130 		   void *ivec)
    131 {
    132     EVP_CIPHER_CTX *ctx;
    133     struct _krb5_checksum_type *c = _krb5_find_checksum (CKSUMTYPE_RSA_MD5);
    134     Checksum k1_c, k2_c, k3_c, cksum;
    135     struct _krb5_key_data ke;
    136     krb5_keyblock kb;
    137     unsigned char t[4];
    138     unsigned char *cdata = data;
    139     unsigned char k1_c_data[16], k2_c_data[16], k3_c_data[16];
    140     krb5_error_code ret;
    141 
    142     t[0] = (usage >>  0) & 0xFF;
    143     t[1] = (usage >>  8) & 0xFF;
    144     t[2] = (usage >> 16) & 0xFF;
    145     t[3] = (usage >> 24) & 0xFF;
    146 
    147     k1_c.checksum.length = sizeof(k1_c_data);
    148     k1_c.checksum.data   = k1_c_data;
    149 
    150     ret = _krb5_internal_hmac(context, c, t, sizeof(t), 0, key, &k1_c);
    151     if (ret)
    152 	krb5_abortx(context, "hmac failed");
    153 
    154     memcpy (k2_c_data, k1_c_data, sizeof(k1_c_data));
    155 
    156     k2_c.checksum.length = sizeof(k2_c_data);
    157     k2_c.checksum.data   = k2_c_data;
    158 
    159     ke.key = &kb;
    160     kb.keyvalue = k2_c.checksum;
    161 
    162     cksum.checksum.length = 16;
    163     cksum.checksum.data   = data;
    164 
    165     ret = _krb5_internal_hmac(context, c, cdata + 16, len - 16, 0, &ke, &cksum);
    166     if (ret)
    167 	krb5_abortx(context, "hmac failed");
    168 
    169     ke.key = &kb;
    170     kb.keyvalue = k1_c.checksum;
    171 
    172     k3_c.checksum.length = sizeof(k3_c_data);
    173     k3_c.checksum.data   = k3_c_data;
    174 
    175     ret = _krb5_internal_hmac(context, c, data, 16, 0, &ke, &k3_c);
    176     if (ret)
    177 	krb5_abortx(context, "hmac failed");
    178 
    179 #if OPENSSL_VERSION_NUMBER < 0x10100000UL
    180     EVP_CIPHER_CTX ctxst;
    181     ctx = &ctxst;
    182     EVP_CIPHER_CTX_init(ctx);
    183 #else
    184     ctx = EVP_CIPHER_CTX_new();
    185 #endif
    186 
    187     if (!EVP_CipherInit_ex(ctx, EVP_rc4(), NULL, k3_c.checksum.data, NULL, 1))
    188 	krb5_abortx(context, "rc4 cipher not supported");
    189     EVP_Cipher(ctx, cdata + 16, cdata + 16, len - 16);
    190 #if OPENSSL_VERSION_NUMBER < 0x10100000UL
    191     EVP_CIPHER_CTX_cleanup(ctx);
    192 #else
    193     EVP_CIPHER_CTX_free(ctx);
    194 #endif
    195 
    196     memset_s(k1_c_data, sizeof(k1_c_data), 0, sizeof(k1_c_data));
    197     memset_s(k2_c_data, sizeof(k2_c_data), 0, sizeof(k2_c_data));
    198     memset_s(k3_c_data, sizeof(k3_c_data), 0, sizeof(k3_c_data));
    199     return 0;
    200 }
    201 
    202 static krb5_error_code
    203 ARCFOUR_subdecrypt(krb5_context context,
    204 		   struct _krb5_key_data *key,
    205 		   void *data,
    206 		   size_t len,
    207 		   unsigned usage,
    208 		   void *ivec)
    209 {
    210     EVP_CIPHER_CTX *ctx;
    211     struct _krb5_checksum_type *c = _krb5_find_checksum (CKSUMTYPE_RSA_MD5);
    212     Checksum k1_c, k2_c, k3_c, cksum;
    213     struct _krb5_key_data ke;
    214     krb5_keyblock kb;
    215     unsigned char t[4];
    216     unsigned char *cdata = data;
    217     unsigned char k1_c_data[16], k2_c_data[16], k3_c_data[16];
    218     unsigned char cksum_data[16];
    219     krb5_error_code ret;
    220 
    221     t[0] = (usage >>  0) & 0xFF;
    222     t[1] = (usage >>  8) & 0xFF;
    223     t[2] = (usage >> 16) & 0xFF;
    224     t[3] = (usage >> 24) & 0xFF;
    225 
    226     k1_c.checksum.length = sizeof(k1_c_data);
    227     k1_c.checksum.data   = k1_c_data;
    228 
    229     ret = _krb5_internal_hmac(context, c, t, sizeof(t), 0, key, &k1_c);
    230     if (ret)
    231 	krb5_abortx(context, "hmac failed");
    232 
    233     memcpy (k2_c_data, k1_c_data, sizeof(k1_c_data));
    234 
    235     k2_c.checksum.length = sizeof(k2_c_data);
    236     k2_c.checksum.data   = k2_c_data;
    237 
    238     ke.key = &kb;
    239     kb.keyvalue = k1_c.checksum;
    240 
    241     k3_c.checksum.length = sizeof(k3_c_data);
    242     k3_c.checksum.data   = k3_c_data;
    243 
    244     ret = _krb5_internal_hmac(context, c, cdata, 16, 0, &ke, &k3_c);
    245     if (ret)
    246 	krb5_abortx(context, "hmac failed");
    247 
    248 #if OPENSSL_VERSION_NUMBER < 0x10100000UL
    249     EVP_CIPHER_CTX ctxst;
    250     ctx = &ctxst;
    251     EVP_CIPHER_CTX_init(ctx);
    252 #else
    253     ctx = EVP_CIPHER_CTX_new();
    254 #endif
    255     if (!EVP_CipherInit_ex(ctx, EVP_rc4(), NULL, k3_c.checksum.data, NULL, 0))
    256 	krb5_abortx(context, "rc4 cipher not supported");
    257     EVP_Cipher(ctx, cdata + 16, cdata + 16, len - 16);
    258 #if OPENSSL_VERSION_NUMBER < 0x10100000UL
    259     EVP_CIPHER_CTX_cleanup(ctx);
    260 #else
    261     EVP_CIPHER_CTX_free(ctx);
    262 #endif
    263 
    264     ke.key = &kb;
    265     kb.keyvalue = k2_c.checksum;
    266 
    267     cksum.checksum.length = 16;
    268     cksum.checksum.data   = cksum_data;
    269 
    270     ret = _krb5_internal_hmac(context, c, cdata + 16, len - 16, 0, &ke, &cksum);
    271     if (ret)
    272 	krb5_abortx(context, "hmac failed");
    273 
    274     memset_s(k1_c_data, sizeof(k1_c_data), 0, sizeof(k1_c_data));
    275     memset_s(k2_c_data, sizeof(k2_c_data), 0, sizeof(k2_c_data));
    276     memset_s(k3_c_data, sizeof(k3_c_data), 0, sizeof(k3_c_data));
    277 
    278     if (ct_memcmp (cksum.checksum.data, data, 16) != 0) {
    279 	krb5_clear_error_message (context);
    280 	return KRB5KRB_AP_ERR_BAD_INTEGRITY;
    281     } else {
    282 	return 0;
    283     }
    284 }
    285 
    286 /*
    287  * convert the usage numbers used in
    288  * draft-ietf-cat-kerb-key-derivation-00.txt to the ones in
    289  * draft-brezak-win2k-krb-rc4-hmac-04.txt
    290  */
    291 
    292 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
    293 _krb5_usage2arcfour(krb5_context context, unsigned *usage)
    294 {
    295     switch (*usage) {
    296     case KRB5_KU_AS_REP_ENC_PART : /* 3 */
    297 	*usage = 8;
    298 	return 0;
    299     case KRB5_KU_USAGE_SEAL :  /* 22 */
    300 	*usage = 13;
    301 	return 0;
    302     case KRB5_KU_USAGE_SIGN : /* 23 */
    303         *usage = 15;
    304         return 0;
    305     case KRB5_KU_USAGE_SEQ: /* 24 */
    306 	*usage = 0;
    307 	return 0;
    308     default :
    309 	return 0;
    310     }
    311 }
    312 
    313 static krb5_error_code
    314 ARCFOUR_encrypt(krb5_context context,
    315 		struct _krb5_key_data *key,
    316 		void *data,
    317 		size_t len,
    318 		krb5_boolean encryptp,
    319 		int usage,
    320 		void *ivec)
    321 {
    322     krb5_error_code ret;
    323     unsigned keyusage = usage;
    324 
    325     if((ret = _krb5_usage2arcfour (context, &keyusage)) != 0)
    326 	return ret;
    327 
    328     if (encryptp)
    329 	return ARCFOUR_subencrypt (context, key, data, len, keyusage, ivec);
    330     else
    331 	return ARCFOUR_subdecrypt (context, key, data, len, keyusage, ivec);
    332 }
    333 
    334 static krb5_error_code
    335 ARCFOUR_prf(krb5_context context,
    336 	    krb5_crypto crypto,
    337 	    const krb5_data *in,
    338 	    krb5_data *out)
    339 {
    340     struct _krb5_checksum_type *c = _krb5_find_checksum(CKSUMTYPE_SHA1);
    341     krb5_error_code ret;
    342     Checksum res;
    343 
    344     ret = krb5_data_alloc(out, c->checksumsize);
    345     if (ret)
    346 	return ret;
    347 
    348     res.checksum.data = out->data;
    349     res.checksum.length = out->length;
    350 
    351     ret = _krb5_internal_hmac(context, c, in->data, in->length, 0, &crypto->key, &res);
    352     if (ret)
    353 	krb5_data_free(out);
    354     return 0;
    355 }
    356 
    357 
    358 struct _krb5_encryption_type _krb5_enctype_arcfour_hmac_md5 = {
    359     ETYPE_ARCFOUR_HMAC_MD5,
    360     "arcfour-hmac-md5",
    361     "rc4-hmac",
    362     1,
    363     1,
    364     8,
    365     &keytype_arcfour,
    366     &_krb5_checksum_hmac_md5,
    367     &_krb5_checksum_hmac_md5,
    368     F_SPECIAL | F_WEAK,
    369     ARCFOUR_encrypt,
    370     0,
    371     ARCFOUR_prf
    372 };
    373