/* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */ /* lib/crypto/krb/crypto_int.h - Master libk5crypto internal header */ /* * Copyright (C) 2011 by the Massachusetts Institute of Technology. * All rights reserved. * * Export of this software from the United States of America may * require a specific license from the United States Government. * It is the responsibility of any person or organization contemplating * export to obtain such a license before exporting. * * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and * distribute this software and its documentation for any purpose and * without fee is hereby granted, provided that the above copyright * notice appear in all copies and that both that copyright notice and * this permission notice appear in supporting documentation, and that * the name of M.I.T. not be used in advertising or publicity pertaining * to distribution of the software without specific, written prior * permission. Furthermore if you modify this software you must label * your software as modified software and not distribute it in such a * fashion that it might be confused with the original M.I.T. software. * M.I.T. makes no representations about the suitability of * this software for any purpose. It is provided "as is" without express * or implied warranty. */ /* This header is the entry point for libk5crypto sources, and also documents * requirements for crypto modules and PRNG modules. */ #ifndef CRYPTO_INT_H #define CRYPTO_INT_H #include /* Enc providers and hash providers specify well-known ciphers and hashes to be * implemented by the crypto module. */ struct krb5_enc_provider { /* keybytes is the input size to make_key; keylength is the output size */ size_t block_size, keybytes, keylength; krb5_error_code (*encrypt)(krb5_key key, const krb5_data *cipher_state, krb5_crypto_iov *data, size_t num_data); krb5_error_code (*decrypt)(krb5_key key, const krb5_data *cipher_state, krb5_crypto_iov *data, size_t num_data); /* May be NULL if the cipher is not used for a cbc-mac checksum. */ krb5_error_code (*cbc_mac)(krb5_key key, const krb5_crypto_iov *data, size_t num_data, const krb5_data *ivec, krb5_data *output); krb5_error_code (*init_state)(const krb5_keyblock *key, krb5_keyusage keyusage, krb5_data *out_state); void (*free_state)(krb5_data *state); /* May be NULL if there is no key-derived data cached. */ void (*key_cleanup)(krb5_key key); }; struct krb5_hash_provider { char hash_name[8]; size_t hashsize, blocksize; krb5_error_code (*hash)(const krb5_crypto_iov *data, size_t num_data, krb5_data *output); }; /*** RFC 3961 enctypes table ***/ #define MAX_ETYPE_ALIASES 2 struct krb5_keytypes; typedef unsigned int (*crypto_length_func)(const struct krb5_keytypes *ktp, krb5_cryptotype type); typedef krb5_error_code (*crypt_func)(const struct krb5_keytypes *ktp, krb5_key key, krb5_keyusage keyusage, const krb5_data *ivec, krb5_crypto_iov *data, size_t num_data); typedef krb5_error_code (*str2key_func)(const struct krb5_keytypes *ktp, const krb5_data *string, const krb5_data *salt, const krb5_data *parm, krb5_keyblock *key); typedef krb5_error_code (*rand2key_func)(const krb5_data *randombits, krb5_keyblock *key); typedef krb5_error_code (*prf_func)(const struct krb5_keytypes *ktp, krb5_key key, const krb5_data *in, krb5_data *out); struct krb5_keytypes { krb5_enctype etype; char *name; char *aliases[MAX_ETYPE_ALIASES]; char *out_string; const struct krb5_enc_provider *enc; const struct krb5_hash_provider *hash; size_t prf_length; crypto_length_func crypto_length; crypt_func encrypt; crypt_func decrypt; str2key_func str2key; rand2key_func rand2key; prf_func prf; krb5_cksumtype required_ctype; krb5_flags flags; unsigned int ssf; }; /* * "Weak" means the enctype is believed to be vulnerable to practical attacks, * and will be disabled unless allow_weak_crypto is set to true. "Deprecated" * means the enctype has been deprecated by the IETF, and affects display and * logging. */ #define ETYPE_WEAK (1 << 0) #define ETYPE_DEPRECATED (1 << 1) extern const struct krb5_keytypes krb5int_enctypes_list[]; extern const int krb5int_enctypes_length; /*** RFC 3961 checksum types table ***/ struct krb5_cksumtypes; /* * Compute a checksum over the header, data, padding, and sign-only fields of * the iov array data (of size num_data). The output buffer will already be * allocated with ctp->compute_size bytes available; the handler just needs to * fill in the contents. If ctp->enc is not NULL, the handler can assume that * key is a valid-length key of an enctype which uses that enc provider. */ typedef krb5_error_code (*checksum_func)(const struct krb5_cksumtypes *ctp, krb5_key key, krb5_keyusage usage, const krb5_crypto_iov *data, size_t num_data, krb5_data *output); /* * Verify a checksum over the header, data, padding, and sign-only fields of * the iov array data (of size num_data), and store the boolean result in * *valid. The handler can assume that hash has length ctp->output_size. If * ctp->enc is not NULL, the handler can assume that key a valid-length key of * an enctype which uses that enc provider. */ typedef krb5_error_code (*verify_func)(const struct krb5_cksumtypes *ctp, krb5_key key, krb5_keyusage usage, const krb5_crypto_iov *data, size_t num_data, const krb5_data *input, krb5_boolean *valid); struct krb5_cksumtypes { krb5_cksumtype ctype; char *name; char *aliases[2]; char *out_string; const struct krb5_enc_provider *enc; const struct krb5_hash_provider *hash; checksum_func checksum; verify_func verify; /* NULL means recompute checksum and compare */ unsigned int compute_size; /* Allocation size for checksum computation */ unsigned int output_size; /* Possibly truncated output size */ krb5_flags flags; }; #define CKSUM_UNKEYED 0x0001 #define CKSUM_NOT_COLL_PROOF 0x0002 extern const struct krb5_cksumtypes krb5int_cksumtypes_list[]; extern const size_t krb5int_cksumtypes_length; /*** Prototypes for enctype table functions ***/ /* Length */ unsigned int krb5int_raw_crypto_length(const struct krb5_keytypes *ktp, krb5_cryptotype type); unsigned int krb5int_arcfour_crypto_length(const struct krb5_keytypes *ktp, krb5_cryptotype type); unsigned int krb5int_dk_crypto_length(const struct krb5_keytypes *ktp, krb5_cryptotype type); unsigned int krb5int_aes_crypto_length(const struct krb5_keytypes *ktp, krb5_cryptotype type); unsigned int krb5int_camellia_crypto_length(const struct krb5_keytypes *ktp, krb5_cryptotype type); unsigned int krb5int_aes2_crypto_length(const struct krb5_keytypes *ktp, krb5_cryptotype type); /* Encrypt */ krb5_error_code krb5int_raw_encrypt(const struct krb5_keytypes *ktp, krb5_key key, krb5_keyusage usage, const krb5_data *ivec, krb5_crypto_iov *data, size_t num_data); krb5_error_code krb5int_arcfour_encrypt(const struct krb5_keytypes *ktp, krb5_key key, krb5_keyusage usage, const krb5_data *ivec, krb5_crypto_iov *data, size_t num_data); krb5_error_code krb5int_dk_encrypt(const struct krb5_keytypes *ktp, krb5_key key, krb5_keyusage usage, const krb5_data *ivec, krb5_crypto_iov *data, size_t num_data); krb5_error_code krb5int_dk_cmac_encrypt(const struct krb5_keytypes *ktp, krb5_key key, krb5_keyusage usage, const krb5_data *ivec, krb5_crypto_iov *data, size_t num_data); krb5_error_code krb5int_etm_encrypt(const struct krb5_keytypes *ktp, krb5_key key, krb5_keyusage usage, const krb5_data *ivec, krb5_crypto_iov *data, size_t num_data); /* Decrypt */ krb5_error_code krb5int_raw_decrypt(const struct krb5_keytypes *ktp, krb5_key key, krb5_keyusage usage, const krb5_data *ivec, krb5_crypto_iov *data, size_t num_data); krb5_error_code krb5int_arcfour_decrypt(const struct krb5_keytypes *ktp, krb5_key key, krb5_keyusage usage, const krb5_data *ivec, krb5_crypto_iov *data, size_t num_data); krb5_error_code krb5int_dk_decrypt(const struct krb5_keytypes *ktp, krb5_key key, krb5_keyusage usage, const krb5_data *ivec, krb5_crypto_iov *data, size_t num_data); krb5_error_code krb5int_dk_cmac_decrypt(const struct krb5_keytypes *ktp, krb5_key key, krb5_keyusage usage, const krb5_data *ivec, krb5_crypto_iov *data, size_t num_data); krb5_error_code krb5int_etm_decrypt(const struct krb5_keytypes *ktp, krb5_key key, krb5_keyusage usage, const krb5_data *ivec, krb5_crypto_iov *data, size_t num_data); /* String to key */ krb5_error_code krb5int_des_string_to_key(const struct krb5_keytypes *ktp, const krb5_data *string, const krb5_data *salt, const krb5_data *params, krb5_keyblock *key); krb5_error_code krb5int_arcfour_string_to_key(const struct krb5_keytypes *ktp, const krb5_data *string, const krb5_data *salt, const krb5_data *params, krb5_keyblock *key); krb5_error_code krb5int_dk_string_to_key(const struct krb5_keytypes *enc, const krb5_data *string, const krb5_data *salt, const krb5_data *params, krb5_keyblock *key); krb5_error_code krb5int_aes_string_to_key(const struct krb5_keytypes *enc, const krb5_data *string, const krb5_data *salt, const krb5_data *params, krb5_keyblock *key); krb5_error_code krb5int_camellia_string_to_key(const struct krb5_keytypes *enc, const krb5_data *string, const krb5_data *salt, const krb5_data *params, krb5_keyblock *key); krb5_error_code krb5int_aes2_string_to_key(const struct krb5_keytypes *enc, const krb5_data *string, const krb5_data *salt, const krb5_data *params, krb5_keyblock *key); /* Random to key */ krb5_error_code k5_rand2key_direct(const krb5_data *randombits, krb5_keyblock *keyblock); /* Pseudo-random function */ krb5_error_code krb5int_des_prf(const struct krb5_keytypes *ktp, krb5_key key, const krb5_data *in, krb5_data *out); krb5_error_code krb5int_arcfour_prf(const struct krb5_keytypes *ktp, krb5_key key, const krb5_data *in, krb5_data *out); krb5_error_code krb5int_dk_prf(const struct krb5_keytypes *ktp, krb5_key key, const krb5_data *in, krb5_data *out); krb5_error_code krb5int_dk_cmac_prf(const struct krb5_keytypes *ktp, krb5_key key, const krb5_data *in, krb5_data *out); krb5_error_code krb5int_aes2_prf(const struct krb5_keytypes *ktp, krb5_key key, const krb5_data *in, krb5_data *out); /*** Prototypes for cksumtype handler functions ***/ krb5_error_code krb5int_unkeyed_checksum(const struct krb5_cksumtypes *ctp, krb5_key key, krb5_keyusage usage, const krb5_crypto_iov *data, size_t num_data, krb5_data *output); krb5_error_code krb5int_hmacmd5_checksum(const struct krb5_cksumtypes *ctp, krb5_key key, krb5_keyusage usage, const krb5_crypto_iov *data, size_t num_data, krb5_data *output); krb5_error_code krb5int_dk_checksum(const struct krb5_cksumtypes *ctp, krb5_key key, krb5_keyusage usage, const krb5_crypto_iov *data, size_t num_data, krb5_data *output); krb5_error_code krb5int_dk_cmac_checksum(const struct krb5_cksumtypes *ctp, krb5_key key, krb5_keyusage usage, const krb5_crypto_iov *data, size_t num_data, krb5_data *output); krb5_error_code krb5int_etm_checksum(const struct krb5_cksumtypes *ctp, krb5_key key, krb5_keyusage usage, const krb5_crypto_iov *data, size_t num_data, krb5_data *output); /*** Key derivation functions ***/ enum deriv_alg { DERIVE_RFC3961, /* RFC 3961 section 5.1 */ DERIVE_SP800_108_CMAC, /* NIST SP 800-108 with CMAC as PRF */ DERIVE_SP800_108_HMAC /* NIST SP 800-108 with HMAC as PRF */ }; krb5_error_code krb5int_derive_keyblock(const struct krb5_enc_provider *enc, const struct krb5_hash_provider *hash, krb5_key inkey, krb5_keyblock *outkey, const krb5_data *in_constant, enum deriv_alg alg); krb5_error_code krb5int_derive_key(const struct krb5_enc_provider *enc, const struct krb5_hash_provider *hash, krb5_key inkey, krb5_key *outkey, const krb5_data *in_constant, enum deriv_alg alg); krb5_error_code krb5int_derive_random(const struct krb5_enc_provider *enc, const struct krb5_hash_provider *hash, krb5_key inkey, krb5_data *outrnd, const krb5_data *in_constant, enum deriv_alg alg); krb5_error_code k5_sp800_108_counter_hmac(const struct krb5_hash_provider *hash, krb5_key inkey, krb5_data *outrnd, const krb5_data *label, const krb5_data *context); /*** Miscellaneous prototypes ***/ /* nfold algorithm from RFC 3961 */ void krb5int_nfold(unsigned int inbits, const unsigned char *in, unsigned int outbits, unsigned char *out); /* Compute a CMAC checksum over data. */ krb5_error_code krb5int_cmac_checksum(const struct krb5_enc_provider *enc, krb5_key key, const krb5_crypto_iov *data, size_t num_data, krb5_data *output); /* Translate an RFC 3961 key usage to a Microsoft RC4 usage. */ krb5_keyusage krb5int_arcfour_translate_usage(krb5_keyusage usage); /* Ensure library initialization has occurred. */ int krb5int_crypto_init(void); /* Default state cleanup handler (used by module enc providers). */ void krb5int_default_free_state(krb5_data *state); /*** Input/output vector processing declarations **/ #define ENCRYPT_CONF_IOV(_iov) ((_iov)->flags == KRB5_CRYPTO_TYPE_HEADER) #define ENCRYPT_DATA_IOV(_iov) ((_iov)->flags == KRB5_CRYPTO_TYPE_DATA || \ (_iov)->flags == KRB5_CRYPTO_TYPE_PADDING) #define ENCRYPT_IOV(_iov) (ENCRYPT_CONF_IOV(_iov) || ENCRYPT_DATA_IOV(_iov)) #define SIGN_IOV(_iov) (ENCRYPT_IOV(_iov) || \ (_iov)->flags == KRB5_CRYPTO_TYPE_SIGN_ONLY ) struct iov_cursor { const krb5_crypto_iov *iov; /* iov array we are iterating over */ size_t iov_count; /* size of iov array */ size_t block_size; /* size of blocks we will be obtaining */ krb5_boolean signing; /* should we process SIGN_ONLY blocks */ size_t in_iov; /* read index into iov array */ size_t in_pos; /* read index into iov contents */ size_t out_iov; /* write index into iov array */ size_t out_pos; /* write index into iov contents */ }; krb5_crypto_iov *krb5int_c_locate_iov(krb5_crypto_iov *data, size_t num_data, krb5_cryptotype type); krb5_error_code krb5int_c_iov_decrypt_stream(const struct krb5_keytypes *ktp, krb5_key key, krb5_keyusage keyusage, const krb5_data *ivec, krb5_crypto_iov *data, size_t num_data); unsigned int krb5int_c_padding_length(const struct krb5_keytypes *ktp, size_t data_length); void k5_iov_cursor_init(struct iov_cursor *cursor, const krb5_crypto_iov *iov, size_t count, size_t block_size, krb5_boolean signing); krb5_boolean k5_iov_cursor_get(struct iov_cursor *cursor, unsigned char *block); void k5_iov_cursor_put(struct iov_cursor *cursor, unsigned char *block); /*** Crypto module declarations ***/ /* Modules must implement the k5_sha256() function prototyped in k5-int.h. */ /* Modules must implement the following enc_providers and hash_providers: */ extern const struct krb5_enc_provider krb5int_enc_arcfour; extern const struct krb5_enc_provider krb5int_enc_aes128; extern const struct krb5_enc_provider krb5int_enc_aes256; extern const struct krb5_enc_provider krb5int_enc_aes128_ctr; extern const struct krb5_enc_provider krb5int_enc_aes256_ctr; extern const struct krb5_enc_provider krb5int_enc_camellia128; extern const struct krb5_enc_provider krb5int_enc_camellia256; extern const struct krb5_hash_provider krb5int_hash_md4; extern const struct krb5_hash_provider krb5int_hash_md5; extern const struct krb5_hash_provider krb5int_hash_sha1; extern const struct krb5_hash_provider krb5int_hash_sha256; extern const struct krb5_hash_provider krb5int_hash_sha384; /* Modules must implement the following functions. */ /* Compute an HMAC using the provided hash function, key, and data, storing the * result into output (caller-allocated). */ krb5_error_code krb5int_hmac(const struct krb5_hash_provider *hash, krb5_key key, const krb5_crypto_iov *data, size_t num_data, krb5_data *output); /* As above, using a keyblock as the key input. */ krb5_error_code krb5int_hmac_keyblock(const struct krb5_hash_provider *hash, const krb5_keyblock *keyblock, const krb5_crypto_iov *data, size_t num_data, krb5_data *output); /* * Compute the PBKDF2 (see RFC 2898) of password and salt, with the specified * count, using HMAC with the specified hash as the pseudo-random function, * storing the result into out (caller-allocated). */ krb5_error_code krb5int_pbkdf2_hmac(const struct krb5_hash_provider *hash, const krb5_data *out, unsigned long count, const krb5_data *password, const krb5_data *salt); /* The following are used by test programs and are just handler functions from * the AES and Camellia enc providers. */ krb5_error_code krb5int_aes_encrypt(krb5_key key, const krb5_data *ivec, krb5_crypto_iov *data, size_t num_data); krb5_error_code krb5int_aes_decrypt(krb5_key key, const krb5_data *ivec, krb5_crypto_iov *data, size_t num_data); krb5_error_code krb5int_camellia_cbc_mac(krb5_key key, const krb5_crypto_iov *data, size_t num_data, const krb5_data *iv, krb5_data *output); /* These can be used to safely set up and tear down module global state. */ int krb5int_crypto_impl_init(void); void krb5int_crypto_impl_cleanup(void); /* * Modules must provide a crypto_mod.h header at the top level. To work with * the default PRNG module (prng_fortuna.c), crypto_mod.h must #define or * prototype the following symbols: * * aes_ctx - Stack-allocatable type for an AES-128 or AES-256 key schedule * krb5int_aes_enc_key(key, keybits, ctxptr) -- initialize a key schedule * krb5int_aes_enc_blk(in, out, ctxptr) -- encrypt a block * SHA256_CTX - Stack-allocatable type for a SHA-256 hash state * k5_sha256_init(ctxptr) - Initialize a hash state * k5_sha256_update(ctxptr, data, size) -- Hash some data * k5_sha256_final(ctxptr, out) -- Finalize a state, writing hash into out * * These functions must never fail on valid inputs, and contexts must remain * valid across forks. If the module cannot meet those constraints, then it * should provide its own PRNG module and the build system should ensure that * it is used. * * The function symbols named above are also in the library export list (so * they can be used by the t_fortuna.c test code), so even if the module * defines them away or doesn't work with Fortuna, the module must provide * stubs; see stubs.c in the openssl module for examples. */ #include /*** PRNG module declarations ***/ /* * PRNG modules must implement the following APIs from krb5.h: * krb5_c_random_add_entropy * krb5_c_random_make_octets * krb5_c_random_os_entropy * * PRNG modules should implement these functions. They are called from the * crypto library init and cleanup functions, and can be used to setup and tear * down static state without thread safety concerns. */ int k5_prng_init(void); void k5_prng_cleanup(void); /* Used by PRNG modules to gather OS entropy. Returns true on success. */ krb5_boolean k5_get_os_entropy(unsigned char *buf, size_t len, int strong); /*** Inline helper functions ***/ /* Find an enctype by number in the enctypes table. */ static inline const struct krb5_keytypes * find_enctype(krb5_enctype enctype) { int i; for (i = 0; i < krb5int_enctypes_length; i++) { if (krb5int_enctypes_list[i].etype == enctype) break; } if (i == krb5int_enctypes_length) return NULL; return &krb5int_enctypes_list[i]; } /* Find a checksum type by number in the cksumtypes table. */ static inline const struct krb5_cksumtypes * find_cksumtype(krb5_cksumtype ctype) { size_t i; for (i = 0; i < krb5int_cksumtypes_length; i++) { if (krb5int_cksumtypes_list[i].ctype == ctype) break; } if (i == krb5int_cksumtypes_length) return NULL; return &krb5int_cksumtypes_list[i]; } /* Verify that a key is appropriate for a checksum type. */ static inline krb5_error_code verify_key(const struct krb5_cksumtypes *ctp, krb5_key key) { const struct krb5_keytypes *ktp; ktp = key ? find_enctype(key->keyblock.enctype) : NULL; if (ctp->enc != NULL && (!ktp || ktp->enc != ctp->enc)) return KRB5_BAD_ENCTYPE; if (key && (!ktp || key->keyblock.length != ktp->enc->keylength)) return KRB5_BAD_KEYSIZE; return 0; } /* Encrypt one block of plaintext in place, for block ciphers. */ static inline krb5_error_code encrypt_block(const struct krb5_enc_provider *enc, krb5_key key, krb5_data *block) { krb5_crypto_iov iov; /* Verify that this is a block cipher and block is the right length. */ if (block->length != enc->block_size || enc->block_size == 1) return EINVAL; iov.flags = KRB5_CRYPTO_TYPE_DATA; iov.data = *block; if (enc->cbc_mac != NULL) /* One-block cbc-mac with no ivec. */ return enc->cbc_mac(key, &iov, 1, NULL, block); else /* Assume cbc-mode encrypt. */ return enc->encrypt(key, 0, &iov, 1); } /* Return the total length of the to-be-signed or to-be-encrypted buffers in an * iov chain. */ static inline size_t iov_total_length(const krb5_crypto_iov *data, size_t num_data, krb5_boolean signing) { size_t i, total = 0; for (i = 0; i < num_data; i++) { if (signing ? SIGN_IOV(&data[i]) : ENCRYPT_IOV(&data[i])) total += data[i].data.length; } return total; } /* * Return the number of contiguous blocks available within the current input * IOV of the cursor c, so that the caller can do in-place encryption. * Do not call if c might be exhausted. */ static inline size_t iov_cursor_contig_blocks(struct iov_cursor *c) { return (c->iov[c->in_iov].data.length - c->in_pos) / c->block_size; } /* Return the current input pointer within the cursor c. Do not call if c * might be exhausted. */ static inline unsigned char * iov_cursor_ptr(struct iov_cursor *c) { return (unsigned char *)&c->iov[c->in_iov].data.data[c->in_pos]; } /* * Advance the input and output pointers of c by nblocks blocks. nblocks must * not be greater than the return value of iov_cursor_contig_blocks, and the * input and output positions must be identical. */ static inline void iov_cursor_advance(struct iov_cursor *c, size_t nblocks) { c->in_pos += nblocks * c->block_size; c->out_pos += nblocks * c->block_size; } #endif /* CRYPTO_INT_H */