Example #1
0
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;
}
Example #2
0
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);
}