aboutsummaryrefslogtreecommitdiff
path: root/src/lib/crypto/krb/arcfour/arcfour.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/lib/crypto/krb/arcfour/arcfour.c')
-rw-r--r--src/lib/crypto/krb/arcfour/arcfour.c601
1 files changed, 301 insertions, 300 deletions
diff --git a/src/lib/crypto/krb/arcfour/arcfour.c b/src/lib/crypto/krb/arcfour/arcfour.c
index 1f49812..8939c30 100644
--- a/src/lib/crypto/krb/arcfour/arcfour.c
+++ b/src/lib/crypto/krb/arcfour/arcfour.c
@@ -1,9 +1,10 @@
+/* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */
/*
-ARCFOUR cipher (based on a cipher posted on the Usenet in Spring-95).
-This cipher is widely believed and has been tested to be equivalent
-with the RC4 cipher from RSA Data Security, Inc. (RC4 is a trademark
-of RSA Data Security)
+ ARCFOUR cipher (based on a cipher posted on the Usenet in Spring-95).
+ This cipher is widely believed and has been tested to be equivalent
+ with the RC4 cipher from RSA Data Security, Inc. (RC4 is a trademark
+ of RSA Data Security)
*/
#include "k5-int.h"
@@ -14,326 +15,326 @@ const char *const krb5int_arcfour_l40 = "fortybits";
void
krb5int_arcfour_encrypt_length(const struct krb5_enc_provider *enc,
- const struct krb5_hash_provider *hash,
- size_t inputlen, size_t *length)
+ const struct krb5_hash_provider *hash,
+ size_t inputlen, size_t *length)
{
- size_t blocksize, hashsize;
+ size_t blocksize, hashsize;
- blocksize = enc->block_size;
- hashsize = hash->hashsize;
+ blocksize = enc->block_size;
+ hashsize = hash->hashsize;
- /* checksum + (confounder + inputlen, in even blocksize) */
- *length = hashsize + krb5_roundup(8 + inputlen, blocksize);
+ /* checksum + (confounder + inputlen, in even blocksize) */
+ *length = hashsize + krb5_roundup(8 + inputlen, blocksize);
}
- krb5_keyusage
- krb5int_arcfour_translate_usage(krb5_keyusage usage)
+krb5_keyusage
+krb5int_arcfour_translate_usage(krb5_keyusage usage)
{
- switch (usage) {
- case 1: /* AS-REQ PA-ENC-TIMESTAMP padata timestamp, */
- return 1;
- case 2: /* ticket from kdc */
- return 2;
- case 3: /* as-rep encrypted part */
- return 8;
- case 4: /* tgs-req authz data */
- return 4;
- case 5: /* tgs-req authz data in subkey */
- return 5;
- case 6: /* tgs-req authenticator cksum */
- return 6;
-case 7: /* tgs-req authenticator */
- return 7;
+ switch (usage) {
+ case 1: /* AS-REQ PA-ENC-TIMESTAMP padata timestamp, */
+ return 1;
+ case 2: /* ticket from kdc */
+ return 2;
+ case 3: /* as-rep encrypted part */
+ return 8;
+ case 4: /* tgs-req authz data */
+ return 4;
+ case 5: /* tgs-req authz data in subkey */
+ return 5;
+ case 6: /* tgs-req authenticator cksum */
+ return 6;
+ case 7: /* tgs-req authenticator */
+ return 7;
case 8:
- return 8;
- case 9: /* tgs-rep encrypted with subkey */
- return 9;
- case 10: /* ap-rep authentication cksum */
- return 10; /* xxx Microsoft never uses this*/
- case 11: /* app-req authenticator */
- return 11;
- case 12: /* app-rep encrypted part */
- return 12;
- case 23: /* sign wrap token*/
- return 13;
- default:
- return usage;
-}
+ return 8;
+ case 9: /* tgs-rep encrypted with subkey */
+ return 9;
+ case 10: /* ap-rep authentication cksum */
+ return 10; /* xxx Microsoft never uses this*/
+ case 11: /* app-req authenticator */
+ return 11;
+ case 12: /* app-rep encrypted part */
+ return 12;
+ case 23: /* sign wrap token*/
+ return 13;
+ default:
+ return usage;
+ }
}
krb5_error_code
krb5int_arcfour_encrypt(const struct krb5_enc_provider *enc,
- const struct krb5_hash_provider *hash,
- krb5_key key, krb5_keyusage usage,
- const krb5_data *ivec, const krb5_data *input,
- krb5_data *output)
+ const struct krb5_hash_provider *hash,
+ krb5_key key, krb5_keyusage usage,
+ const krb5_data *ivec, const krb5_data *input,
+ krb5_data *output)
{
- krb5_keyblock k1, k2, k3;
- krb5_key k3key = NULL;
- krb5_data d1, d2, d3, salt, plaintext, checksum, ciphertext, confounder;
- krb5_keyusage ms_usage;
- size_t keylength, keybytes, blocksize, hashsize;
- krb5_error_code ret;
-
- blocksize = enc->block_size;
- keybytes = enc->keybytes;
- keylength = enc->keylength;
- hashsize = hash->hashsize;
-
- d1.length=keybytes;
- d1.data=malloc(d1.length);
- if (d1.data == NULL)
- return (ENOMEM);
- k1 = key->keyblock;
- k1.length=d1.length;
- k1.contents= (void *) d1.data;
-
- d2.length=keybytes;
- d2.data=malloc(d2.length);
- if (d2.data == NULL) {
- free(d1.data);
- return (ENOMEM);
- }
- k2 = key->keyblock;
- k2.length=d2.length;
- k2.contents=(void *) d2.data;
-
- d3.length=keybytes;
- d3.data=malloc(d3.length);
- if (d3.data == NULL) {
- free(d1.data);
- free(d2.data);
- return (ENOMEM);
- }
- k3 = key->keyblock;
- k3.length=d3.length;
- k3.contents= (void *) d3.data;
-
- salt.length=14;
- salt.data=malloc(salt.length);
- if (salt.data == NULL) {
- free(d1.data);
- free(d2.data);
- free(d3.data);
- return (ENOMEM);
- }
-
- /* is "input" already blocksize aligned? if it is, then we need this
- step, otherwise we do not */
- plaintext.length=krb5_roundup(input->length+CONFOUNDERLENGTH,blocksize);
- plaintext.data=malloc(plaintext.length);
- if (plaintext.data == NULL) {
+ krb5_keyblock k1, k2, k3;
+ krb5_key k3key = NULL;
+ krb5_data d1, d2, d3, salt, plaintext, checksum, ciphertext, confounder;
+ krb5_keyusage ms_usage;
+ size_t keylength, keybytes, blocksize, hashsize;
+ krb5_error_code ret;
+
+ blocksize = enc->block_size;
+ keybytes = enc->keybytes;
+ keylength = enc->keylength;
+ hashsize = hash->hashsize;
+
+ d1.length=keybytes;
+ d1.data=malloc(d1.length);
+ if (d1.data == NULL)
+ return (ENOMEM);
+ k1 = key->keyblock;
+ k1.length=d1.length;
+ k1.contents= (void *) d1.data;
+
+ d2.length=keybytes;
+ d2.data=malloc(d2.length);
+ if (d2.data == NULL) {
+ free(d1.data);
+ return (ENOMEM);
+ }
+ k2 = key->keyblock;
+ k2.length=d2.length;
+ k2.contents=(void *) d2.data;
+
+ d3.length=keybytes;
+ d3.data=malloc(d3.length);
+ if (d3.data == NULL) {
+ free(d1.data);
+ free(d2.data);
+ return (ENOMEM);
+ }
+ k3 = key->keyblock;
+ k3.length=d3.length;
+ k3.contents= (void *) d3.data;
+
+ salt.length=14;
+ salt.data=malloc(salt.length);
+ if (salt.data == NULL) {
+ free(d1.data);
+ free(d2.data);
+ free(d3.data);
+ return (ENOMEM);
+ }
+
+ /* is "input" already blocksize aligned? if it is, then we need this
+ step, otherwise we do not */
+ plaintext.length=krb5_roundup(input->length+CONFOUNDERLENGTH,blocksize);
+ plaintext.data=malloc(plaintext.length);
+ if (plaintext.data == NULL) {
+ free(d1.data);
+ free(d2.data);
+ free(d3.data);
+ free(salt.data);
+ return(ENOMEM);
+ }
+
+ /* setup convienient pointers into the allocated data */
+ checksum.length=hashsize;
+ checksum.data=output->data;
+ ciphertext.length=krb5_roundup(input->length+CONFOUNDERLENGTH,blocksize);
+ ciphertext.data=output->data+hashsize;
+ confounder.length=CONFOUNDERLENGTH;
+ confounder.data=plaintext.data;
+ output->length = plaintext.length+hashsize;
+
+ /* begin the encryption, computer K1 */
+ ms_usage=krb5int_arcfour_translate_usage(usage);
+ if (key->keyblock.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);
+ }
+ krb5int_hmac(hash, key, 1, &salt, &d1);
+
+ memcpy(k2.contents, k1.contents, k2.length);
+
+ if (key->keyblock.enctype==ENCTYPE_ARCFOUR_HMAC_EXP)
+ memset(k1.contents+7, 0xab, 9);
+
+ ret=krb5_c_random_make_octets(/* XXX */ 0, &confounder);
+ memcpy(plaintext.data+confounder.length, input->data, input->length);
+ if (ret)
+ goto cleanup;
+
+ ret = krb5int_hmac_keyblock(hash, &k2, 1, &plaintext, &checksum);
+ if (ret)
+ goto cleanup;
+
+ ret = krb5int_hmac_keyblock(hash, &k1, 1, &checksum, &d3);
+ if (ret)
+ goto cleanup;
+
+ ret = krb5_k_create_key(NULL, &k3, &k3key);
+ if (ret)
+ goto cleanup;
+
+ ret=(*(enc->encrypt))(k3key, ivec, &plaintext, &ciphertext);
+
+cleanup:
+ memset(d1.data, 0, d1.length);
+ memset(d2.data, 0, d2.length);
+ memset(d3.data, 0, d3.length);
+ memset(salt.data, 0, salt.length);
+ memset(plaintext.data, 0, plaintext.length);
+
free(d1.data);
free(d2.data);
free(d3.data);
free(salt.data);
- return(ENOMEM);
- }
-
- /* setup convienient pointers into the allocated data */
- checksum.length=hashsize;
- checksum.data=output->data;
- ciphertext.length=krb5_roundup(input->length+CONFOUNDERLENGTH,blocksize);
- ciphertext.data=output->data+hashsize;
- confounder.length=CONFOUNDERLENGTH;
- confounder.data=plaintext.data;
- output->length = plaintext.length+hashsize;
-
- /* begin the encryption, computer K1 */
- ms_usage=krb5int_arcfour_translate_usage(usage);
- if (key->keyblock.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);
- }
- krb5int_hmac(hash, key, 1, &salt, &d1);
-
- memcpy(k2.contents, k1.contents, k2.length);
-
- if (key->keyblock.enctype==ENCTYPE_ARCFOUR_HMAC_EXP)
- memset(k1.contents+7, 0xab, 9);
-
- ret=krb5_c_random_make_octets(/* XXX */ 0, &confounder);
- memcpy(plaintext.data+confounder.length, input->data, input->length);
- if (ret)
- goto cleanup;
-
- ret = krb5int_hmac_keyblock(hash, &k2, 1, &plaintext, &checksum);
- if (ret)
- goto cleanup;
-
- ret = krb5int_hmac_keyblock(hash, &k1, 1, &checksum, &d3);
- if (ret)
- goto cleanup;
-
- ret = krb5_k_create_key(NULL, &k3, &k3key);
- if (ret)
- goto cleanup;
-
- ret=(*(enc->encrypt))(k3key, ivec, &plaintext, &ciphertext);
-
- cleanup:
- memset(d1.data, 0, d1.length);
- memset(d2.data, 0, d2.length);
- memset(d3.data, 0, d3.length);
- memset(salt.data, 0, salt.length);
- memset(plaintext.data, 0, plaintext.length);
-
- free(d1.data);
- free(d2.data);
- free(d3.data);
- free(salt.data);
- free(plaintext.data);
- krb5_k_free_key(NULL, k3key);
- return (ret);
+ free(plaintext.data);
+ krb5_k_free_key(NULL, k3key);
+ return (ret);
}
/* This is the arcfour-hmac decryption routine */
krb5_error_code
krb5int_arcfour_decrypt(const struct krb5_enc_provider *enc,
- const struct krb5_hash_provider *hash,
- krb5_key key, krb5_keyusage usage,
- const krb5_data *ivec, const krb5_data *input,
- krb5_data *output)
+ const struct krb5_hash_provider *hash,
+ krb5_key key, krb5_keyusage usage,
+ const krb5_data *ivec, const krb5_data *input,
+ krb5_data *output)
{
- krb5_keyblock k1,k2,k3;
- krb5_key k3key;
- krb5_data d1,d2,d3,salt,ciphertext,plaintext,checksum;
- krb5_keyusage ms_usage;
- size_t keybytes, keylength, hashsize, blocksize;
- krb5_error_code ret;
-
- blocksize = enc->block_size;
- keybytes = enc->keybytes;
- keylength = enc->keylength;
- hashsize = hash->hashsize;
-
- d1.length=keybytes;
- d1.data=malloc(d1.length);
- if (d1.data == NULL)
- return (ENOMEM);
- k1 = key->keyblock;
- k1.length=d1.length;
- k1.contents= (void *) d1.data;
-
- d2.length=keybytes;
- d2.data=malloc(d2.length);
- if (d2.data == NULL) {
- free(d1.data);
- return (ENOMEM);
- }
- k2 = key->keyblock;
- k2.length=d2.length;
- k2.contents= (void *) d2.data;
-
- d3.length=keybytes;
- d3.data=malloc(d3.length);
- if (d3.data == NULL) {
- free(d1.data);
- free(d2.data);
- return (ENOMEM);
- }
- k3 = key->keyblock;
- k3.length=d3.length;
- k3.contents= (void *) d3.data;
-
- salt.length=14;
- salt.data=malloc(salt.length);
- if(salt.data==NULL) {
- free(d1.data);
- free(d2.data);
- free(d3.data);
- return (ENOMEM);
- }
-
- ciphertext.length=input->length-hashsize;
- ciphertext.data=input->data+hashsize;
- plaintext.length=ciphertext.length;
- plaintext.data=malloc(plaintext.length);
- if (plaintext.data == NULL) {
+ krb5_keyblock k1,k2,k3;
+ krb5_key k3key;
+ krb5_data d1,d2,d3,salt,ciphertext,plaintext,checksum;
+ krb5_keyusage ms_usage;
+ size_t keybytes, keylength, hashsize, blocksize;
+ krb5_error_code ret;
+
+ blocksize = enc->block_size;
+ keybytes = enc->keybytes;
+ keylength = enc->keylength;
+ hashsize = hash->hashsize;
+
+ d1.length=keybytes;
+ d1.data=malloc(d1.length);
+ if (d1.data == NULL)
+ return (ENOMEM);
+ k1 = key->keyblock;
+ k1.length=d1.length;
+ k1.contents= (void *) d1.data;
+
+ d2.length=keybytes;
+ d2.data=malloc(d2.length);
+ if (d2.data == NULL) {
+ free(d1.data);
+ return (ENOMEM);
+ }
+ k2 = key->keyblock;
+ k2.length=d2.length;
+ k2.contents= (void *) d2.data;
+
+ d3.length=keybytes;
+ d3.data=malloc(d3.length);
+ if (d3.data == NULL) {
+ free(d1.data);
+ free(d2.data);
+ return (ENOMEM);
+ }
+ k3 = key->keyblock;
+ k3.length=d3.length;
+ k3.contents= (void *) d3.data;
+
+ salt.length=14;
+ salt.data=malloc(salt.length);
+ if(salt.data==NULL) {
+ free(d1.data);
+ free(d2.data);
+ free(d3.data);
+ return (ENOMEM);
+ }
+
+ ciphertext.length=input->length-hashsize;
+ ciphertext.data=input->data+hashsize;
+ plaintext.length=ciphertext.length;
+ plaintext.data=malloc(plaintext.length);
+ if (plaintext.data == NULL) {
+ free(d1.data);
+ free(d2.data);
+ free(d3.data);
+ free(salt.data);
+ return (ENOMEM);
+ }
+
+ checksum.length=hashsize;
+ checksum.data=input->data;
+
+ ms_usage=krb5int_arcfour_translate_usage(usage);
+
+ /* We may have to try two ms_usage values; see below. */
+ do {
+ /* compute the salt */
+ if (key->keyblock.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 = krb5int_hmac(hash, key, 1, &salt, &d1);
+ if (ret)
+ goto cleanup;
+
+ memcpy(k2.contents, k1.contents, k2.length);
+
+ if (key->keyblock.enctype == ENCTYPE_ARCFOUR_HMAC_EXP)
+ memset(k1.contents + 7, 0xab, 9);
+
+ ret = krb5int_hmac_keyblock(hash, &k1, 1, &checksum, &d3);
+ if (ret)
+ goto cleanup;
+
+ ret = krb5_k_create_key(NULL, &k3, &k3key);
+ if (ret)
+ goto cleanup;
+ ret = (*(enc->decrypt))(k3key, ivec, &ciphertext, &plaintext);
+ krb5_k_free_key(NULL, k3key);
+ if (ret)
+ goto cleanup;
+
+ ret = krb5int_hmac_keyblock(hash, &k2, 1, &plaintext, &d1);
+ if (ret)
+ goto cleanup;
+
+ if (memcmp(checksum.data, d1.data, hashsize) != 0) {
+ if (ms_usage == 9) {
+ /*
+ * RFC 4757 specifies usage 8 for TGS-REP encrypted
+ * parts encrypted in a subkey, but the value used by MS
+ * is actually 9. We now use 9 to start with, but fall
+ * back to 8 on failure in case we are communicating
+ * with a KDC using the value from the RFC.
+ */
+ ms_usage = 8;
+ continue;
+ }
+ ret = KRB5KRB_AP_ERR_BAD_INTEGRITY;
+ goto cleanup;
+ }
+
+ break;
+ } while (1);
+
+ memcpy(output->data, plaintext.data+CONFOUNDERLENGTH,
+ (plaintext.length-CONFOUNDERLENGTH));
+ output->length=plaintext.length-CONFOUNDERLENGTH;
+
+cleanup:
+ memset(d1.data, 0, d1.length);
+ memset(d2.data, 0, d2.length);
+ memset(d3.data, 0, d2.length);
+ memset(salt.data, 0, salt.length);
+ memset(plaintext.data, 0, plaintext.length);
+
free(d1.data);
free(d2.data);
free(d3.data);
free(salt.data);
- return (ENOMEM);
- }
-
- checksum.length=hashsize;
- checksum.data=input->data;
-
- ms_usage=krb5int_arcfour_translate_usage(usage);
-
- /* We may have to try two ms_usage values; see below. */
- do {
- /* compute the salt */
- if (key->keyblock.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 = krb5int_hmac(hash, key, 1, &salt, &d1);
- if (ret)
- goto cleanup;
-
- memcpy(k2.contents, k1.contents, k2.length);
-
- if (key->keyblock.enctype == ENCTYPE_ARCFOUR_HMAC_EXP)
- memset(k1.contents + 7, 0xab, 9);
-
- ret = krb5int_hmac_keyblock(hash, &k1, 1, &checksum, &d3);
- if (ret)
- goto cleanup;
-
- ret = krb5_k_create_key(NULL, &k3, &k3key);
- if (ret)
- goto cleanup;
- ret = (*(enc->decrypt))(k3key, ivec, &ciphertext, &plaintext);
- krb5_k_free_key(NULL, k3key);
- if (ret)
- goto cleanup;
-
- ret = krb5int_hmac_keyblock(hash, &k2, 1, &plaintext, &d1);
- if (ret)
- goto cleanup;
-
- if (memcmp(checksum.data, d1.data, hashsize) != 0) {
- if (ms_usage == 9) {
- /*
- * RFC 4757 specifies usage 8 for TGS-REP encrypted
- * parts encrypted in a subkey, but the value used by MS
- * is actually 9. We now use 9 to start with, but fall
- * back to 8 on failure in case we are communicating
- * with a KDC using the value from the RFC.
- */
- ms_usage = 8;
- continue;
- }
- ret = KRB5KRB_AP_ERR_BAD_INTEGRITY;
- goto cleanup;
- }
-
- break;
- } while (1);
-
- memcpy(output->data, plaintext.data+CONFOUNDERLENGTH,
- (plaintext.length-CONFOUNDERLENGTH));
- output->length=plaintext.length-CONFOUNDERLENGTH;
-
- cleanup:
- memset(d1.data, 0, d1.length);
- memset(d2.data, 0, d2.length);
- memset(d3.data, 0, d2.length);
- memset(salt.data, 0, salt.length);
- memset(plaintext.data, 0, plaintext.length);
-
- free(d1.data);
- free(d2.data);
- free(d3.data);
- free(salt.data);
- free(plaintext.data);
- return (ret);
+ free(plaintext.data);
+ return (ret);
}