示例#1
0
krb5_error_code KRB5_CALLCONV
krb5_c_crypto_length(krb5_context context, krb5_enctype enctype,
                     krb5_cryptotype type, unsigned int *size)
{
    const struct krb5_keytypes *ktp;

    ktp = find_enctype(enctype);
    if (ktp == NULL)
        return KRB5_BAD_ENCTYPE;

    switch (type) {
    case KRB5_CRYPTO_TYPE_EMPTY:
    case KRB5_CRYPTO_TYPE_SIGN_ONLY:
        *size = 0;
        break;
    case KRB5_CRYPTO_TYPE_DATA:
        *size = (unsigned int)~0; /* match Heimdal */
        break;
    case KRB5_CRYPTO_TYPE_HEADER:
    case KRB5_CRYPTO_TYPE_PADDING:
    case KRB5_CRYPTO_TYPE_TRAILER:
    case KRB5_CRYPTO_TYPE_CHECKSUM:
        *size = ktp->crypto_length(ktp, type);
        break;
    default:
        return EINVAL;
    }

    return 0;
}
示例#2
0
krb5_error_code KRB5_CALLCONV
krb5_k_decrypt(krb5_context context, krb5_key key,
               krb5_keyusage usage, const krb5_data *ivec,
               const krb5_enc_data *input, krb5_data *output)
{
    const struct krb5_keytypes *ktp;
    krb5_crypto_iov iov[4];
    krb5_error_code ret;
    unsigned int header_len, trailer_len, plain_len;
    char *scratch = NULL;

    ktp = find_enctype(key->keyblock.enctype);
    if (ktp == NULL)
        return KRB5_BAD_ENCTYPE;

    if (input->enctype != ENCTYPE_UNKNOWN && ktp->etype != input->enctype)
        return KRB5_BAD_ENCTYPE;

    /* Verify the input and output lengths. */
    header_len = ktp->crypto_length(ktp, KRB5_CRYPTO_TYPE_HEADER);
    trailer_len = ktp->crypto_length(ktp, KRB5_CRYPTO_TYPE_TRAILER);
    if (input->ciphertext.length < header_len + trailer_len)
        return KRB5_BAD_MSIZE;
    plain_len = input->ciphertext.length - header_len - trailer_len;
    if (output->length < plain_len)
        return KRB5_BAD_MSIZE;

    scratch = k5alloc(header_len + trailer_len, &ret);
    if (scratch == NULL)
        return ret;

    iov[0].flags = KRB5_CRYPTO_TYPE_HEADER;
    iov[0].data = make_data(scratch, header_len);
    memcpy(iov[0].data.data, input->ciphertext.data, header_len);

    iov[1].flags = KRB5_CRYPTO_TYPE_DATA;
    iov[1].data = make_data(output->data, plain_len);
    memcpy(iov[1].data.data, input->ciphertext.data + header_len, plain_len);

    /* Use empty padding since tokens don't indicate the padding length. */
    iov[2].flags = KRB5_CRYPTO_TYPE_PADDING;
    iov[2].data = empty_data();

    iov[3].flags = KRB5_CRYPTO_TYPE_TRAILER;
    iov[3].data = make_data(scratch + header_len, trailer_len);
    memcpy(iov[3].data.data, input->ciphertext.data + header_len + plain_len,
           trailer_len);

    ret = ktp->decrypt(ktp, key, usage, ivec, iov, 4);
    if (ret != 0)
        zap(output->data, plain_len);
    else
        output->length = plain_len;
    zapfree(scratch, header_len + trailer_len);
    return ret;
}
示例#3
0
krb5_error_code
srp_gen_keyblock(
    krb5_context krb5_ctx,
    char *enc_keytype,
    char *pass,
    char *salt,
    krb5_keyblock *key)
{
    krb5_error_code krb_err = 0;
    krb5_enctype enctype;
    krb5_data pass_data = {0};
    krb5_data salt_data = {0};

    memset(&enctype, 0, sizeof(enctype));

    pass_data.data = pass;
    pass_data.length = (int) strlen(pass);
    salt_data.data = salt;
    salt_data.length = (int) strlen(salt);

#if 0
    /* Prefer to use this, as it takes ENCTYPE_AES256_CTS_HMAC_SHA1_96 */
    enctype = find_enctype(enc_keytype);
    if (!enctype)
    {
        krb_err = EINVAL;
        goto error;
    }
#else
    krb_err = krb5_string_to_enctype(
                  enc_keytype,
                  &enctype);
    if (krb_err)
    {
        goto error;
    }
#endif

    krb_err = krb5_c_string_to_key(
                  krb5_ctx,
                  enctype,
                  &pass_data,
                  &salt_data,
                  key);
    if (krb_err)
    {
        goto error;
    }

error:

    return krb_err;
}
示例#4
0
krb5_error_code KRB5_CALLCONV
krb5_c_crypto_length_iov(krb5_context context, krb5_enctype enctype,
                         krb5_crypto_iov *data, size_t num_data)
{
    size_t i;
    const struct krb5_keytypes *ktp;
    unsigned int data_length = 0, pad_length;
    krb5_crypto_iov *padding = NULL;

    /*
     * XXX need to rejig internal interface so we can accurately
     * report variable header lengths.
     */

    ktp = find_enctype(enctype);
    if (ktp == NULL)
        return KRB5_BAD_ENCTYPE;

    for (i = 0; i < num_data; i++) {
        krb5_crypto_iov *iov = &data[i];

        switch (iov->flags) {
        case KRB5_CRYPTO_TYPE_DATA:
            data_length += iov->data.length;
            break;
        case KRB5_CRYPTO_TYPE_PADDING:
            if (padding != NULL)
                return EINVAL;

            padding = iov;
            break;
        case KRB5_CRYPTO_TYPE_HEADER:
        case KRB5_CRYPTO_TYPE_TRAILER:
        case KRB5_CRYPTO_TYPE_CHECKSUM:
            iov->data.length = ktp->crypto_length(ktp, iov->flags);
            break;
        case KRB5_CRYPTO_TYPE_EMPTY:
        case KRB5_CRYPTO_TYPE_SIGN_ONLY:
        default:
            break;
        }
    }

    pad_length = krb5int_c_padding_length(ktp, data_length);
    if (pad_length != 0 && padding == NULL)
        return EINVAL;

    if (padding != NULL)
        padding->data.length = pad_length;

    return 0;
}
示例#5
0
krb5_error_code KRB5_CALLCONV
krb5_c_padding_length(krb5_context context, krb5_enctype enctype,
                      size_t data_length, unsigned int *pad_length)
{
    const struct krb5_keytypes *ktp;

    ktp = find_enctype(enctype);
    if (ktp == NULL)
        return KRB5_BAD_ENCTYPE;

    *pad_length = krb5int_c_padding_length(ktp, data_length);
    return 0;
}
示例#6
0
文件: encrypt.c 项目: Baalmart/krb5
krb5_error_code KRB5_CALLCONV
krb5_k_encrypt(krb5_context context, krb5_key key,
               krb5_keyusage usage, const krb5_data *cipher_state,
               const krb5_data *input, krb5_enc_data *output)
{
    const struct krb5_keytypes *ktp;
    krb5_crypto_iov iov[4];
    krb5_error_code ret;
    unsigned int header_len, padding_len, trailer_len, total_len;

    ktp = find_enctype(key->keyblock.enctype);
    if (ktp == NULL)
        return KRB5_BAD_ENCTYPE;

    output->magic = KV5M_ENC_DATA;
    output->kvno = 0;
    output->enctype = key->keyblock.enctype;

    /* Get the lengths of the token parts and compute the total. */
    header_len = ktp->crypto_length(ktp, KRB5_CRYPTO_TYPE_HEADER);
    padding_len = krb5int_c_padding_length(ktp, input->length);
    trailer_len = ktp->crypto_length(ktp, KRB5_CRYPTO_TYPE_TRAILER);
    total_len = header_len + input->length + padding_len + trailer_len;
    if (output->ciphertext.length < total_len)
        return KRB5_BAD_MSIZE;

    /* Set up the iov structures for the token parts. */
    iov[0].flags = KRB5_CRYPTO_TYPE_HEADER;
    iov[0].data = make_data(output->ciphertext.data, header_len);

    iov[1].flags = KRB5_CRYPTO_TYPE_DATA;
    iov[1].data = make_data(output->ciphertext.data + header_len,
                            input->length);
    memcpy(iov[1].data.data, input->data, input->length);

    iov[2].flags = KRB5_CRYPTO_TYPE_PADDING;
    iov[2].data = make_data(iov[1].data.data + input->length, padding_len);

    iov[3].flags = KRB5_CRYPTO_TYPE_TRAILER;
    iov[3].data = make_data(iov[2].data.data + padding_len, trailer_len);

    ret = ktp->encrypt(ktp, key, usage, cipher_state, iov, 4);
    if (ret != 0)
        zap(iov[1].data.data, iov[1].data.length);
    else
        output->ciphertext.length = total_len;
    return ret;
}
示例#7
0
krb5_error_code KRB5_CALLCONV
krb5_c_string_to_key_with_params(krb5_context context, krb5_enctype enctype,
                                 const krb5_data *string,
                                 const krb5_data *salt,
                                 const krb5_data *params, krb5_keyblock *key)
{
    krb5_error_code ret;
    const struct krb5_keytypes *ktp;
    size_t keylength;

    ktp = find_enctype(enctype);
    if (ktp == NULL)
        return KRB5_BAD_ENCTYPE;
    keylength = ktp->enc->keylength;

    /*
     * xxx AFS string2key function is indicated by a special length  in
     * the salt in much of the code.  However only the DES enctypes can
     * deal with this.  Using s2kparams would be a much better solution.
     */
    if (salt && salt->length == SALT_TYPE_AFS_LENGTH) {
        switch (enctype) {
        case ENCTYPE_DES_CBC_CRC:
        case ENCTYPE_DES_CBC_MD4:
        case ENCTYPE_DES_CBC_MD5:
            break;
        default:
            return KRB5_CRYPTO_INTERNAL;
        }
    }

    key->contents = malloc(keylength);
    if (key->contents == NULL)
        return ENOMEM;

    key->magic = KV5M_KEYBLOCK;
    key->enctype = enctype;
    key->length = keylength;

    ret = (*ktp->str2key)(ktp, string, salt, params, key);
    if (ret) {
        zapfree(key->contents, keylength);
        key->length = 0;
        key->contents = NULL;
    }

    return ret;
}
示例#8
0
krb5_error_code KRB5_CALLCONV
krb5_k_decrypt_iov(krb5_context context, krb5_key key, krb5_keyusage usage,
                   const krb5_data *cipher_state, krb5_crypto_iov *data,
                   size_t num_data)
{
    const struct krb5_keytypes *ktp;

    ktp = find_enctype(key->keyblock.enctype);
    if (ktp == NULL)
        return KRB5_BAD_ENCTYPE;

    if (krb5int_c_locate_iov(data, num_data,
                             KRB5_CRYPTO_TYPE_STREAM) != NULL) {
        return krb5int_c_iov_decrypt_stream(ktp, key, usage, cipher_state,
                                            data, num_data);
    }

    return ktp->decrypt(ktp, key, usage, cipher_state, data, num_data);
}
示例#9
0
krb5_error_code KRB5_CALLCONV
krb5_c_string_to_key_with_params(krb5_context context, krb5_enctype enctype,
                                 const krb5_data *string,
                                 const krb5_data *salt,
                                 const krb5_data *params, krb5_keyblock *key)
{
    krb5_error_code ret;
    krb5_data empty = empty_data();
    const struct krb5_keytypes *ktp;
    size_t keylength;

    ktp = find_enctype(enctype);
    if (ktp == NULL)
        return KRB5_BAD_ENCTYPE;
    keylength = ktp->enc->keylength;

    /* For compatibility with past behavior, treat a null salt as empty. */
    if (salt == NULL)
        salt = &empty;

    /* Fail gracefully if someone is using the old AFS string-to-key hack. */
    if (salt->length == SALT_TYPE_AFS_LENGTH)
        return EINVAL;

    key->contents = malloc(keylength);
    if (key->contents == NULL)
        return ENOMEM;

    key->magic = KV5M_KEYBLOCK;
    key->enctype = enctype;
    key->length = keylength;

    ret = (*ktp->str2key)(ktp, string, salt, params, key);
    if (ret) {
        zapfree(key->contents, keylength);
        key->length = 0;
        key->contents = NULL;
    }

    return ret;
}
示例#10
0
krb5_error_code KRB5_CALLCONV
krb5_c_keyed_checksum_types(krb5_context context, krb5_enctype enctype,
                            unsigned int *count, krb5_cksumtype **cksumtypes)
{
    unsigned int i, c, nctypes;
    krb5_cksumtype *ctypes;
    const struct krb5_cksumtypes *ctp;
    const struct krb5_keytypes *ktp;

    *count = 0;
    *cksumtypes = NULL;

    ktp = find_enctype(enctype);
    if (ktp == NULL)
        return KRB5_BAD_ENCTYPE;

    nctypes = 0;
    for (i = 0; i < krb5int_cksumtypes_length; i++) {
        ctp = &krb5int_cksumtypes_list[i];
        if (is_keyed_for(ctp, ktp))
            nctypes++;
    }

    ctypes = malloc(nctypes * sizeof(krb5_cksumtype));
    if (ctypes == NULL)
        return ENOMEM;

    c = 0;
    for (i = 0; i < krb5int_cksumtypes_length; i++) {
        ctp = &krb5int_cksumtypes_list[i];
        if (is_keyed_for(ctp, ktp))
            ctypes[c++] = ctp->ctype;
    }

    *count = nctypes;
    *cksumtypes = ctypes;
    return 0;
}
示例#11
0
krb5_error_code
krb5int_c_combine_keys(krb5_context context, krb5_keyblock *key1,
                       krb5_keyblock *key2, krb5_keyblock *outkey)
{
    unsigned char *r1 = NULL, *r2 = NULL, *combined = NULL, *rnd = NULL;
    unsigned char *output = NULL;
    size_t keybytes, keylength;
    const struct krb5_enc_provider *enc;
    krb5_data input, randbits;
    krb5_keyblock tkeyblock;
    krb5_key tkey = NULL;
    krb5_error_code ret;
    const struct krb5_keytypes *ktp;
    krb5_boolean myalloc = FALSE;

    if (!enctype_ok(key1->enctype) || !enctype_ok(key2->enctype))
        return KRB5_CRYPTO_INTERNAL;

    if (key1->length != key2->length || key1->enctype != key2->enctype)
        return KRB5_CRYPTO_INTERNAL;

    /* Find our encryption algorithm. */
    ktp = find_enctype(key1->enctype);
    if (ktp == NULL)
        return KRB5_BAD_ENCTYPE;
    enc = ktp->enc;

    keybytes = enc->keybytes;
    keylength = enc->keylength;

    /* Allocate and set up buffers. */
    r1 = k5alloc(keybytes, &ret);
    if (ret)
        goto cleanup;
    r2 = k5alloc(keybytes, &ret);
    if (ret)
        goto cleanup;
    rnd = k5alloc(keybytes, &ret);
    if (ret)
        goto cleanup;
    combined = k5alloc(keybytes * 2, &ret);
    if (ret)
        goto cleanup;
    output = k5alloc(keylength, &ret);
    if (ret)
        goto cleanup;

    /*
     * Get R1 and R2 (by running the input keys through the DR algorithm.
     * Note this is most of derive-key, but not all.
     */

    input.length = key2->length;
    input.data = (char *) key2->contents;
    ret = dr(enc, key1, r1, &input);
    if (ret)
        goto cleanup;

    input.length = key1->length;
    input.data = (char *) key1->contents;
    ret = dr(enc, key2, r2, &input);
    if (ret)
        goto cleanup;

    /*
     * Concatenate the two keys together, and then run them through
     * n-fold to reduce them to a length appropriate for the random-to-key
     * operation.  Note here that krb5int_nfold() takes sizes in bits, hence
     * the multiply by 8.
     */

    memcpy(combined, r1, keybytes);
    memcpy(combined + keybytes, r2, keybytes);

    krb5int_nfold((keybytes * 2) * 8, combined, keybytes * 8, rnd);

    /*
     * Run the "random" bits through random-to-key to produce a encryption
     * key.
     */

    randbits.length = keybytes;
    randbits.data = (char *) rnd;
    tkeyblock.length = keylength;
    tkeyblock.contents = output;

    ret = (*ktp->rand2key)(&randbits, &tkeyblock);
    if (ret)
        goto cleanup;

    ret = krb5_k_create_key(NULL, &tkeyblock, &tkey);
    if (ret)
        goto cleanup;

    /*
     * Run through derive-key one more time to produce the final key.
     * Note that the input to derive-key is the ASCII string "combine".
     */

    input.length = 7;
    input.data = "combine";

    /*
     * Just FYI: _if_ we have space here in the key, then simply use it
     * without modification.  But if the key is blank (no allocated storage)
     * then allocate some memory for it.  This allows programs to use one of
     * the existing keys as the output key, _or_ pass in a blank keyblock
     * for us to allocate.  It's easier for us to allocate it since we already
     * know the crypto library internals
     */

    if (outkey->length == 0 || outkey->contents == NULL) {
        outkey->contents = k5alloc(keylength, &ret);
        if (ret)
            goto cleanup;
        outkey->length = keylength;
        outkey->enctype = key1->enctype;
        myalloc = TRUE;
    }

    ret = krb5int_derive_keyblock(enc, tkey, outkey, &input, DERIVE_RFC3961);
    if (ret) {
        if (myalloc) {
            free(outkey->contents);
            outkey->contents = NULL;
        }
        goto cleanup;
    }

cleanup:
    zapfree(r1, keybytes);
    zapfree(r2, keybytes);
    zapfree(rnd, keybytes);
    zapfree(combined, keybytes * 2);
    zapfree(output, keylength);
    krb5_k_free_key(NULL, tkey);
    return ret;
}