summaryrefslogtreecommitdiff
path: root/third_party/heimdal/lib/krb5/crypto-arcfour.c
diff options
context:
space:
mode:
Diffstat (limited to 'third_party/heimdal/lib/krb5/crypto-arcfour.c')
-rw-r--r--third_party/heimdal/lib/krb5/crypto-arcfour.c368
1 files changed, 368 insertions, 0 deletions
diff --git a/third_party/heimdal/lib/krb5/crypto-arcfour.c b/third_party/heimdal/lib/krb5/crypto-arcfour.c
new file mode 100644
index 00000000000..28fc52e4cbf
--- /dev/null
+++ b/third_party/heimdal/lib/krb5/crypto-arcfour.c
@@ -0,0 +1,368 @@
+/*
+ * 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,
+ krb5_crypto crypto,
+ struct _krb5_key_data *key,
+ unsigned usage,
+ const struct krb5_crypto_iov *iov,
+ int niov,
+ 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;
+ int i;
+
+ if (crypto != NULL) {
+ if (crypto->mdctx == NULL)
+ crypto->mdctx = EVP_MD_CTX_create();
+ if (crypto->mdctx == NULL)
+ return krb5_enomem(context);
+ m = crypto->mdctx;
+ } else
+ m = EVP_MD_CTX_create();
+
+ ksign_c.checksum.length = sizeof(ksign_c_data);
+ ksign_c.checksum.data = ksign_c_data;
+ ret = _krb5_internal_hmac(context, crypto, c, signature, sizeof(signature),
+ 0, key, &ksign_c);
+ if (ret)
+ goto out;
+
+ 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);
+ for (i = 0; i < niov; i++) {
+ if (_krb5_crypto_iov_should_sign(&iov[i]))
+ EVP_DigestUpdate(m, iov[i].data.data, iov[i].data.length);
+ }
+ EVP_DigestFinal_ex (m, tmp, NULL);
+
+ ret = _krb5_internal_hmac(context, crypto, c, tmp, sizeof(tmp), 0, &ksign, result);
+out:
+ if (crypto == NULL)
+ EVP_MD_CTX_destroy(m);
+
+ return ret;
+}
+
+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;
+
+ if (len < 16) {
+ return KRB5KRB_AP_ERR_INAPP_CKSUM;
+ }
+
+ 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, NULL, 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, NULL, 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, NULL, c, data, 16, 0, &ke, &k3_c);
+ if (ret)
+ krb5_abortx(context, "hmac failed");
+
+ EVP_CIPHER_CTX_init(&ctx);
+
+ EVP_CipherInit_ex(&ctx, EVP_rc4(), NULL, k3_c.checksum.data, NULL, 1);
+ EVP_Cipher(&ctx, cdata + 16, cdata + 16, len - 16);
+ EVP_CIPHER_CTX_cleanup(&ctx);
+
+ 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;
+
+ if (len < 16) {
+ return KRB5KRB_AP_ERR_INAPP_CKSUM;
+ }
+
+ 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, NULL, 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, NULL, c, cdata, 16, 0, &ke, &k3_c);
+ if (ret)
+ krb5_abortx(context, "hmac failed");
+
+ EVP_CIPHER_CTX_init(&ctx);
+ EVP_CipherInit_ex(&ctx, EVP_rc4(), NULL, k3_c.checksum.data, NULL, 0);
+ EVP_Cipher(&ctx, cdata + 16, cdata + 16, len - 16);
+ EVP_CIPHER_CTX_cleanup(&ctx);
+
+ ke.key = &kb;
+ kb.keyvalue = k2_c.checksum;
+
+ cksum.checksum.length = 16;
+ cksum.checksum.data = cksum_data;
+
+ ret = _krb5_internal_hmac(context, NULL, 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, crypto, 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 | F_OLD,
+ ARCFOUR_encrypt,
+ NULL,
+ 0,
+ ARCFOUR_prf
+};