/* * Ideally, this would use the PKCS#11 interface * for doing DES_CBC_MAC_* operations, but for now we * can fake it by using the des-cbc crypto operation. * and truncating the output. */ krb5_error_code k5_ef_mac(krb5_context context, krb5_keyblock *key, krb5_data *ivec, krb5_const krb5_data *input, krb5_data *output) { krb5_error_code retval = 0; char *outbuf = NULL; char *inbuf = NULL; int inlen; int outlen; /* * This is ugly but necessary until proper PKCS#11 * interface is ready. */ inlen = K5ROUNDUP(input->length, 8); outlen = inlen; if (inlen != input->length) { inbuf = (char *)malloc(inlen); if (inbuf == NULL) retval = ENOMEM; } else inbuf = input->data; outbuf = (char *)malloc(outlen); if (outbuf == NULL) retval = ENOMEM; (void) memset(outbuf, 0, outlen); if (outbuf != NULL && inbuf != NULL) { if (inlen != input->length) { (void) memset(inbuf, 0, inlen); (void) memcpy(inbuf, input->data, input->length); } retval = mit_des_cbc_encrypt(context, (const mit_des_cblock *)inbuf, (mit_des_cblock *)outbuf, inlen, key, (unsigned char *)ivec->data, 1); if (retval == 0) { (void) memcpy(output->data, &outbuf[outlen-8], 8); output->length = 8; } } if (inlen != input->length && inbuf != NULL) free(inbuf); if (outbuf != NULL) free(outbuf); return (retval); }
static krb5_error_code k5_des_docrypt(const krb5_keyblock *key, const krb5_data *ivec, const krb5_data *input, krb5_data *output, int enc) { mit_des_key_schedule schedule; /* key->enctype was checked by the caller */ if (key->length != 8) return(KRB5_BAD_KEYSIZE); if ((input->length%8) != 0) return(KRB5_BAD_MSIZE); if (ivec && (ivec->length != 8)) return(KRB5_BAD_MSIZE); if (input->length != output->length) return(KRB5_BAD_MSIZE); switch (mit_des_key_sched(key->contents, schedule)) { case -1: return(KRB5DES_BAD_KEYPAR); case -2: return(KRB5DES_WEAK_KEY); } /* this has a return value, but the code always returns zero */ mit_des_cbc_encrypt((krb5_pointer) input->data, (krb5_pointer) output->data, input->length, schedule, (ivec ? (const unsigned char *) ivec->data : (const unsigned char *) mit_des_zeroblock), enc); memset(schedule, 0, sizeof(schedule)); return(0); }
static krb5_error_code k5_md4des_hash(const krb5_keyblock *key, krb5_keyusage usage, const krb5_data *ivec, const krb5_data *input, krb5_data *output) { krb5_error_code ret; krb5_data data; krb5_MD4_CTX ctx; unsigned char conf[CONFLENGTH]; unsigned char xorkey[8]; unsigned int i; mit_des_key_schedule schedule; if (key->length != 8) return(KRB5_BAD_KEYSIZE); if (ivec) return(KRB5_CRYPTO_INTERNAL); if (output->length != (CONFLENGTH+RSA_MD4_CKSUM_LENGTH)) return(KRB5_CRYPTO_INTERNAL); /* create the confouder */ data.length = CONFLENGTH; data.data = (char *) conf; if ((ret = krb5_c_random_make_octets(/* XXX */ 0, &data))) return(ret); /* create and schedule the encryption key */ memcpy(xorkey, key->contents, sizeof(xorkey)); for (i=0; i<sizeof(xorkey); i++) xorkey[i] ^= 0xf0; switch (ret = mit_des_key_sched(xorkey, schedule)) { case -1: return(KRB5DES_BAD_KEYPAR); case -2: return(KRB5DES_WEAK_KEY); } /* hash the confounder, then the input data */ krb5_MD4Init(&ctx); krb5_MD4Update(&ctx, conf, CONFLENGTH); krb5_MD4Update(&ctx, (unsigned char *) input->data, (unsigned int) input->length); krb5_MD4Final(&ctx); /* construct the buffer to be encrypted */ memcpy(output->data, conf, CONFLENGTH); memcpy(output->data+CONFLENGTH, ctx.digest, RSA_MD4_CKSUM_LENGTH); /* encrypt it, in place. this has a return value, but it's always zero. */ mit_des_cbc_encrypt((krb5_pointer) output->data, (krb5_pointer) output->data, output->length, schedule, (const unsigned char *) mit_des_zeroblock, 1); return(0); }
static krb5_error_code k5_md4des_verify(const krb5_keyblock *key, krb5_keyusage usage, const krb5_data *ivec, const krb5_data *input, const krb5_data *hash, krb5_boolean *valid) { krb5_MD4_CTX ctx; unsigned char plaintext[CONFLENGTH+RSA_MD4_CKSUM_LENGTH]; unsigned char xorkey[8]; unsigned int i; mit_des_key_schedule schedule; int compathash = 0; if (key->length != 8) return(KRB5_BAD_KEYSIZE); if (ivec) return(KRB5_CRYPTO_INTERNAL); if (hash->length != (CONFLENGTH+RSA_MD4_CKSUM_LENGTH)) { #ifdef KRB5_MD4DES_BETA5_COMPAT if (hash->length != RSA_MD4_CKSUM_LENGTH) return(KRB5_CRYPTO_INTERNAL); else compathash = 1; #else return(KRB5_CRYPTO_INTERNAL); #endif return(KRB5_CRYPTO_INTERNAL); } /* create and schedule the encryption key */ memcpy(xorkey, key->contents, sizeof(xorkey)); if (!compathash) { for (i=0; i<sizeof(xorkey); i++) xorkey[i] ^= 0xf0; } switch (mit_des_key_sched(xorkey, schedule)) { case -1: return(KRB5DES_BAD_KEYPAR); case -2: return(KRB5DES_WEAK_KEY); } /* decrypt it. this has a return value, but it's always zero. */ if (!compathash) { mit_des_cbc_encrypt((krb5_pointer) hash->data, (krb5_pointer) plaintext, hash->length, schedule, (const unsigned char *) mit_des_zeroblock, 0); } else { mit_des_cbc_encrypt((krb5_pointer) hash->data, (krb5_pointer) plaintext, hash->length, schedule, xorkey, 0); } /* hash the confounder, then the input data */ krb5_MD4Init(&ctx); if (!compathash) { krb5_MD4Update(&ctx, plaintext, CONFLENGTH); } krb5_MD4Update(&ctx, (unsigned char *) input->data, (unsigned int) input->length); krb5_MD4Final(&ctx); /* compare the decrypted hash to the computed one */ if (!compathash) { *valid = (memcmp(plaintext+CONFLENGTH, ctx.digest, RSA_MD4_CKSUM_LENGTH) == 0); } else { *valid = (memcmp(plaintext, ctx.digest, RSA_MD4_CKSUM_LENGTH) == 0); } memset(plaintext, 0, sizeof(plaintext)); return(0); }
/*ARGSUSED*/ static krb5_error_code k5_md5des_hash(krb5_context context, krb5_const krb5_keyblock *key, krb5_keyusage usage, const krb5_data *ivec, const krb5_data *input, krb5_data *output) { krb5_error_code ret = 0; krb5_data data; unsigned char conf[CONFLENGTH]; krb5_keyblock xorkey; int i; CK_MECHANISM mechanism; CK_RV rv; CK_ULONG hashlen = MD5_CKSUM_LENGTH; if (key->length != 8) return(KRB5_BAD_KEYSIZE); if (ivec) return(KRB5_CRYPTO_INTERNAL); if (output->length != (CONFLENGTH+MD5_CKSUM_LENGTH)) return(KRB5_CRYPTO_INTERNAL); /* create the confouder */ data.length = CONFLENGTH; data.data = (char *) conf; if ((ret = krb5_c_random_make_octets(context, &data))) return(ret); xorkey.magic = key->magic; xorkey.enctype = key->enctype; xorkey.length = key->length; xorkey.contents = (krb5_octet *)malloc(key->length); if (xorkey.contents == NULL) return(KRB5_CRYPTO_INTERNAL); (void) memcpy(xorkey.contents, key->contents, xorkey.length); for (i=0; i<xorkey.length; i++) xorkey.contents[i] ^= 0xf0; if (!mit_des_check_key_parity(xorkey.contents)) { ret = KRB5DES_BAD_KEYPAR; goto cleanup; } if (mit_des_is_weak_key(xorkey.contents)) { ret = KRB5DES_WEAK_KEY; goto cleanup; } /* hash the confounder, then the input data */ mechanism.mechanism = CKM_MD5; mechanism.pParameter = NULL_PTR; mechanism.ulParameterLen = 0; if ((rv = C_DigestInit(krb_ctx_hSession(context), &mechanism)) != CKR_OK) { KRB5_LOG(KRB5_ERR, "C_DigestInit failed in k5_md5des_hash: " "rv = 0x%x.", rv); ret = PKCS_ERR; goto cleanup; } if ((rv = C_DigestUpdate(krb_ctx_hSession(context), (CK_BYTE_PTR)conf, (CK_ULONG)sizeof(conf))) != CKR_OK) { KRB5_LOG(KRB5_ERR, "C_DigestUpdate failed in k5_md5des_hash: " "rv = 0x%x", rv); ret = PKCS_ERR; goto cleanup; } if ((rv = C_DigestUpdate(krb_ctx_hSession(context), (CK_BYTE_PTR)input->data, (CK_ULONG)input->length)) != CKR_OK) { KRB5_LOG(KRB5_ERR, "C_DigestUpdate failed in k5_md5des_hash: " "rv = 0x%x", rv); return(PKCS_ERR); } if ((rv = C_DigestFinal(krb_ctx_hSession(context), (CK_BYTE_PTR)(output->data + CONFLENGTH), (CK_ULONG_PTR)&hashlen)) != CKR_OK) { KRB5_LOG(KRB5_ERR, "C_DigestFinal failed in k5_md5des_hash: " "rv = 0x%x", rv); ret = PKCS_ERR; goto cleanup; } /* construct the buffer to be encrypted */ (void) memcpy(output->data, conf, CONFLENGTH); /* encrypt it, in place. this has a return value, but it's always zero. */ ret = mit_des_cbc_encrypt(context, (krb5_pointer) output->data, (krb5_pointer) output->data, output->length, &xorkey, (unsigned char*) mit_des_zeroblock, 1); cleanup: free(xorkey.contents); return(ret); }
/*ARGSUSED*/ static krb5_error_code k5_md5des_verify(krb5_context context, krb5_const krb5_keyblock *key, krb5_keyusage usage, krb5_const krb5_data *ivec, krb5_const krb5_data *input, krb5_const krb5_data *hash, krb5_boolean *valid) { krb5_error_code ret = 0; unsigned char plaintext[CONFLENGTH+MD5_CKSUM_LENGTH]; unsigned char digest[MD5_CKSUM_LENGTH]; krb5_keyblock xorkey; int i; int compathash = 0; CK_MECHANISM mechanism; CK_RV rv; CK_ULONG hashlen = MD5_CKSUM_LENGTH; if (key->length != 8) return(KRB5_BAD_KEYSIZE); if (ivec) return(KRB5_CRYPTO_INTERNAL); if (hash->length != (CONFLENGTH + MD5_CKSUM_LENGTH)) { #ifdef KRB5_MD5DES_BETA5_COMPAT if (hash->length != MD5_CKSUM_LENGTH) return(KRB5_CRYPTO_INTERNAL); else compathash = 1; #else return(KRB5_CRYPTO_INTERNAL); #endif } /* create and the encryption key */ xorkey.magic = key->magic; xorkey.enctype = key->enctype; xorkey.length = key->length; xorkey.contents = (krb5_octet *)malloc(key->length); if (xorkey.contents == NULL) return(KRB5_CRYPTO_INTERNAL); (void) memcpy(xorkey.contents, key->contents, xorkey.length); if (!compathash) { for (i=0; i<xorkey.length; i++) xorkey.contents[i] ^= 0xf0; } if (!mit_des_check_key_parity(xorkey.contents)) { ret = KRB5DES_BAD_KEYPAR; goto cleanup; } if (mit_des_is_weak_key(xorkey.contents)) { ret = KRB5DES_WEAK_KEY; goto cleanup; } /* decrypt it. this has a return value, but it's always zero. */ if (!compathash) { ret = mit_des_cbc_encrypt(context, (krb5_pointer) hash->data, (krb5_pointer) plaintext, hash->length, &xorkey, (unsigned char*) mit_des_zeroblock, 0); } else { ret = mit_des_cbc_encrypt(context, (krb5_pointer) hash->data, (krb5_pointer) plaintext, hash->length, &xorkey, xorkey.contents, 0); } if (ret) goto cleanup; /* hash the confounder, then the input data */ mechanism.mechanism = CKM_MD5; mechanism.pParameter = NULL_PTR; mechanism.ulParameterLen = 0; if ((rv = C_DigestInit(krb_ctx_hSession(context), &mechanism)) != CKR_OK) { KRB5_LOG(KRB5_ERR, "C_DigestInit failed in k5_md5des_verify: " "rv = 0x%x.", rv); ret = PKCS_ERR; goto cleanup; } if (!compathash) { if ((rv = C_DigestUpdate(krb_ctx_hSession(context), (CK_BYTE_PTR)plaintext, (CK_ULONG)CONFLENGTH)) != CKR_OK) { KRB5_LOG(KRB5_ERR, "C_DigestUpdate failed in k5_md5des_verify: " "rv = 0x%x", rv); ret = PKCS_ERR; goto cleanup; } } if ((rv = C_DigestUpdate(krb_ctx_hSession(context), (CK_BYTE_PTR)input->data, (CK_ULONG)input->length)) != CKR_OK) { KRB5_LOG(KRB5_ERR, "C_DigestUpdate failed in k5_md5des_verify: " "rv = 0x%x", rv); ret = PKCS_ERR; goto cleanup; } if ((rv = C_DigestFinal(krb_ctx_hSession(context), (CK_BYTE_PTR)digest, (CK_ULONG_PTR)&hashlen)) != CKR_OK) { KRB5_LOG(KRB5_ERR, "C_DigestFinal failed in k5_md5des_verify: " "rv = 0x%x", rv); ret = PKCS_ERR; goto cleanup; } /* compare the decrypted hash to the computed one */ if (!compathash) { *valid = (memcmp(plaintext+CONFLENGTH, digest, sizeof(digest)) == 0); } else { *valid = (memcmp(plaintext, digest, sizeof(digest)) == 0); } (void) memset(plaintext, 0, sizeof(plaintext)); cleanup: free(xorkey.contents); return(ret); }
/*ARGSUSED*/ static krb5_error_code k5_md5des_hash(krb5_context context, krb5_const krb5_keyblock *key, krb5_keyusage usage, krb5_const krb5_data *ivec, krb5_const krb5_data *input, krb5_data *output) { krb5_error_code ret = 0; krb5_data data; unsigned char conf[CONFLENGTH]; unsigned char xorkey[MIT_DES_KEYSIZE]; int i; krb5_data *hash_input; char *outptr; krb5_keyblock newkey; if (key->length != MIT_DES_KEYSIZE) return(KRB5_BAD_KEYSIZE); if (ivec) return(KRB5_CRYPTO_INTERNAL); if (output->length != (CONFLENGTH + MD5_CKSUM_LENGTH)) return(KRB5_CRYPTO_INTERNAL); /* create the confounder */ data.length = CONFLENGTH; data.data = (char *) conf; if ((ret = krb5_c_random_make_octets(context, &data))) return(ret); /* hash the confounder, then the input data */ hash_input = (krb5_data *)MALLOC(sizeof(krb5_data) * 2); if (hash_input == NULL) return(KRB5_RC_MALLOC); hash_input[0].data = (char *)conf; hash_input[0].length = CONFLENGTH; hash_input[1].data = input->data; hash_input[1].length = input->length; /* Save the pointer to the beginning of the output buffer */ outptr = (char *)output->data; /* * Move the output ptr ahead so we can write the hash * digest directly into the buffer. */ output->data = output->data + CONFLENGTH; /* Use generic hash function that calls to kEF */ if (k5_ef_hash(context, 2, hash_input, output)) { FREE(hash_input, sizeof(krb5_data) * 2); return(KRB5_KEF_ERROR); } /* restore the original ptr to the output data */ output->data = outptr; /* * Put the confounder in the beginning of the buffer to be * encrypted. */ bcopy(conf, output->data, CONFLENGTH); bcopy(key->contents, xorkey, sizeof(xorkey)); for (i=0; i<sizeof(xorkey); i++) xorkey[i] ^= 0xf0; /* * Solaris Kerberos: * Encryption Framework checks for parity and weak keys. */ bzero(&newkey, sizeof(krb5_keyblock)); newkey.enctype = key->enctype; newkey.contents = xorkey; newkey.length = sizeof(xorkey); newkey.dk_list = NULL; newkey.kef_key.ck_data = NULL; ret = init_key_kef(context->kef_cipher_mt, &newkey); if (ret) { FREE(hash_input, sizeof(krb5_data) * 2); return (ret); } /* encrypt it, in place. this has a return value, but it's always zero. */ ret = mit_des_cbc_encrypt(context, (krb5_pointer) output->data, (krb5_pointer) output->data, output->length, &newkey, (unsigned char*) mit_des_zeroblock, 1); FREE(hash_input, sizeof(krb5_data) * 2); (void)crypto_destroy_ctx_template(newkey.key_tmpl); return(ret); }
/*ARGSUSED*/ static krb5_error_code k5_md5des_verify(krb5_context context, krb5_const krb5_keyblock *key, krb5_keyusage usage, krb5_const krb5_data *ivec, krb5_const krb5_data *input, krb5_const krb5_data *hash, krb5_boolean *valid) { krb5_error_code ret = 0; unsigned char plaintext[CONFLENGTH + MD5_CKSUM_LENGTH]; unsigned char xorkey[8]; int i; int compathash = 0; krb5_octet outtmp[MD5_CKSUM_LENGTH]; size_t hisize; krb5_data *hash_input; krb5_data hash_output; krb5_keyblock newkey; if (key->length != MIT_DES_KEYSIZE) return(KRB5_BAD_KEYSIZE); if (ivec) return(KRB5_CRYPTO_INTERNAL); if (hash->length != (CONFLENGTH + MD5_CKSUM_LENGTH)) { #ifdef KRB5_MD5DES_BETA5_COMPAT if (hash->length != MD5_CKSUM_LENGTH) return(KRB5_CRYPTO_INTERNAL); else compathash = 1; #else return(KRB5_CRYPTO_INTERNAL); #endif } /* create and schedule the encryption key */ (void) bcopy(key->contents, xorkey, sizeof(xorkey)); if (!compathash) { for (i=0; i<sizeof(xorkey); i++) xorkey[i] ^= 0xf0; } /* * Solaris Kerberos: * Encryption Framework checks for parity and weak keys */ bzero(&newkey, sizeof(krb5_keyblock)); newkey.enctype = key->enctype; newkey.contents = xorkey; newkey.length = sizeof(xorkey); newkey.dk_list = NULL; newkey.kef_key.ck_data = NULL; ret = init_key_kef(context->kef_cipher_mt, &newkey); /* decrypt it. this has a return value, but it's always zero. */ if (!compathash) { ret = mit_des_cbc_encrypt(context, (krb5_pointer) hash->data, (krb5_pointer) plaintext, hash->length, &newkey, (unsigned char*) mit_des_zeroblock, 0); } else { ret = mit_des_cbc_encrypt(context, (krb5_pointer) hash->data, (krb5_pointer) plaintext, hash->length, &newkey, xorkey, 0); } if (ret) goto cleanup; /* hash the confounder, then the input data */ i = 1; if (!compathash) i++; hisize = sizeof(krb5_data) * i; hash_input = (krb5_data *)MALLOC(hisize); if (hash_input == NULL) return(KRB5_RC_MALLOC); i=0; if (!compathash) { hash_input[i].data = (char *)plaintext; hash_input[i].length = CONFLENGTH; i++; } hash_input[i].data = input->data; hash_input[i].length = input->length; hash_output.data = (char *)outtmp; hash_output.length = sizeof(outtmp); if (k5_ef_hash(context, 1, hash_input, &hash_output)) { ret = KRB5_KEF_ERROR; goto cleanup; } /* compare the decrypted hash to the computed one */ if (!compathash) { *valid = !bcmp((const void *)(plaintext+CONFLENGTH), (void *)outtmp, MD5_CKSUM_LENGTH); } else { *valid = !bcmp((const void *)plaintext, (void *)outtmp, MD5_CKSUM_LENGTH); } bzero((void *)plaintext, sizeof(plaintext)); cleanup: if (hash_input != NULL && hisize > 0) FREE(hash_input, hisize); (void)crypto_destroy_ctx_template(newkey.key_tmpl); return(ret); }