diff options
Diffstat (limited to 'src/lib/crypto/krb/arcfour/arcfour.c')
-rw-r--r-- | src/lib/crypto/krb/arcfour/arcfour.c | 601 |
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); } |