void zcrypt_key_free(zcrypt_key_t *key) { if (key == NULL) return; refcount_destroy(&key->zk_refcnt); if (key->zk_key.ck_length != 0) { /* * This will need updating for key * types other than CRYPTO_KEY_RAW. */ bzero(key->zk_key.ck_data, key->zk_key.ck_length / 8); kmem_free(key->zk_key.ck_data, key->zk_key.ck_length / 8); } crypto_destroy_ctx_template(key->zk_ctx_tmpl); if (key->zk_mackey.ck_length != 0) { /* * This will need updating for key * types other than CRYPTO_KEY_RAW. */ bzero(key->zk_mackey.ck_data, key->zk_mackey.ck_length / 8); kmem_free(key->zk_mackey.ck_data, key->zk_mackey.ck_length / 8); } crypto_destroy_ctx_template(key->zk_mac_ctx_tmpl); bzero(key, sizeof (zcrypt_key_t)); kmem_free(key, sizeof (zcrypt_key_t)); key = NULL; }
static int pbkdf2(uint8_t *passphrase, size_t passphraselen, uint8_t *salt, size_t saltlen, uint64_t iterations, uint8_t *output, size_t outputlen) { int ret; uint64_t iter; uint32_t blockptr, i; uint16_t hmac_key_len; uint8_t *hmac_key; uint8_t block[SHA1_DIGEST_LEN * 2]; uint8_t *hmacresult = block + SHA1_DIGEST_LEN; crypto_mechanism_t mech; crypto_key_t key; crypto_data_t in_data, out_data; crypto_ctx_template_t tmpl = NULL; /* initialize output */ memset(output, 0, outputlen); /* initialize icp for use */ thread_init(); icp_init(); /* HMAC key size is max(sizeof(uint32_t) + salt len, sha 256 len) */ if (saltlen > SHA1_DIGEST_LEN) { hmac_key_len = saltlen + sizeof (uint32_t); } else { hmac_key_len = SHA1_DIGEST_LEN; } hmac_key = calloc(hmac_key_len, 1); if (!hmac_key) { ret = ENOMEM; goto error; } /* initialize sha 256 hmac mechanism */ mech.cm_type = crypto_mech2id(SUN_CKM_SHA1_HMAC); mech.cm_param = NULL; mech.cm_param_len = 0; /* initialize passphrase as a crypto key */ key.ck_format = CRYPTO_KEY_RAW; key.ck_length = CRYPTO_BYTES2BITS(passphraselen); key.ck_data = passphrase; /* * initialize crypto data for the input data. length will change * after the first iteration, so we will initialize it in the loop. */ in_data.cd_format = CRYPTO_DATA_RAW; in_data.cd_offset = 0; in_data.cd_raw.iov_base = (char *)hmac_key; /* initialize crypto data for the output data */ out_data.cd_format = CRYPTO_DATA_RAW; out_data.cd_offset = 0; out_data.cd_length = SHA1_DIGEST_LEN; out_data.cd_raw.iov_base = (char *)hmacresult; out_data.cd_raw.iov_len = out_data.cd_length; /* initialize the context template */ ret = crypto_create_ctx_template(&mech, &key, &tmpl, KM_SLEEP); if (ret != CRYPTO_SUCCESS) { ret = EIO; goto error; } /* main loop */ for (blockptr = 0; blockptr < outputlen; blockptr += SHA1_DIGEST_LEN) { /* * for the first iteration, the HMAC key is the user-provided * salt concatenated with the block index (1-indexed) */ i = htobe32(1 + (blockptr / SHA1_DIGEST_LEN)); memmove(hmac_key, salt, saltlen); memmove(hmac_key + saltlen, (uint8_t *)(&i), sizeof (uint32_t)); /* block initializes to zeroes (no XOR) */ memset(block, 0, SHA1_DIGEST_LEN); for (iter = 0; iter < iterations; iter++) { if (iter > 0) { in_data.cd_length = SHA1_DIGEST_LEN; in_data.cd_raw.iov_len = in_data.cd_length; } else { in_data.cd_length = saltlen + sizeof (uint32_t); in_data.cd_raw.iov_len = in_data.cd_length; } ret = crypto_mac(&mech, &in_data, &key, tmpl, &out_data, NULL); if (ret != CRYPTO_SUCCESS) { ret = EIO; goto error; } /* HMAC key now becomes the output of this iteration */ memmove(hmac_key, hmacresult, SHA1_DIGEST_LEN); /* XOR this iteration's result with the current block */ for (i = 0; i < SHA1_DIGEST_LEN; i++) { block[i] ^= hmacresult[i]; } } /* * compute length of this block, make sure we don't write * beyond the end of the output, truncating if necessary */ if (blockptr + SHA1_DIGEST_LEN > outputlen) { memmove(output + blockptr, block, outputlen - blockptr); } else { memmove(output + blockptr, block, SHA1_DIGEST_LEN); } } crypto_destroy_ctx_template(tmpl); free(hmac_key); icp_fini(); thread_fini(); return (0); error: crypto_destroy_ctx_template(tmpl); if (hmac_key != NULL) free(hmac_key); icp_fini(); thread_fini(); 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); }