mbed port of tinydtls
Diff: crypto.h
- Revision:
- 0:04990d454f45
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/crypto.h Thu Oct 10 21:38:07 2013 +0000 @@ -0,0 +1,298 @@ +/* dtls -- a very basic DTLS implementation + * + * Copyright (C) 2011--2012 Olaf Bergmann <bergmann@tzi.org> + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#ifndef _CRYPTO_H_ +#define _CRYPTO_H_ + +#include "config.h" + +#include <stdlib.h> /* for rand() and srand() */ + +#include "aes/rijndael.h" + +#include "prng.h" +#include "global.h" +#include "numeric.h" +#include "hmac.h" +#include "ccm.h" + +/* TLS_PSK_WITH_AES_128_CCM_8 */ +#define DTLS_MAC_KEY_LENGTH 0 +#define DTLS_KEY_LENGTH 16 /* AES-128 */ +#define DTLS_BLK_LENGTH 16 /* AES-128 */ +#define DTLS_MAC_LENGTH DTLS_HMAC_DIGEST_SIZE +#define DTLS_IV_LENGTH 4 /* length of nonce_explicit */ + +/** + * Maximum size of the generated keyblock. Note that MAX_KEYBLOCK_LENGTH must + * be large enough to hold the pre_master_secret, i.e. twice the length of the + * pre-shared key + 1. + */ +#define MAX_KEYBLOCK_LENGTH \ + (2 * DTLS_MAC_KEY_LENGTH + 2 * DTLS_KEY_LENGTH + 2 * DTLS_IV_LENGTH) + +/** Length of DTLS master_secret */ +#define DTLS_MASTER_SECRET_LENGTH 48 + +#ifndef DTLS_CIPHER_CONTEXT_MAX +#define DTLS_CIPHER_CONTEXT_MAX 4 +#endif + +typedef enum { AES128=0 +} dtls_crypto_alg; + +/** Crypto context for TLS_PSK_WITH_AES_128_CCM_8 cipher suite. */ +typedef struct { + rijndael_ctx ctx; /**< AES-128 encryption context */ + unsigned char N[DTLS_CCM_BLOCKSIZE]; /**< nonce */ +} aes128_ccm_t; + +typedef struct dtls_cipher_context_t { + /** numeric identifier of this cipher suite in host byte order. */ + dtls_cipher_t code; + aes128_ccm_t data; /**< The crypto context */ +} dtls_cipher_context_t; + +typedef enum { DTLS_CLIENT=0, DTLS_SERVER } dtls_peer_type; + +typedef struct { + uint8 client_random[32]; /**< client random gmt and bytes */ + + dtls_peer_type role; /**< denotes if the remote peer is DTLS_CLIENT or DTLS_SERVER */ + unsigned char compression; /**< compression method */ + + dtls_cipher_t cipher; /**< cipher type */ + + /** the session's master secret */ + uint8 master_secret[DTLS_MASTER_SECRET_LENGTH]; + + /** + * The key block generated from PRF applied to client and server + * random bytes. The actual size is given by the selected cipher and + * can be calculated using dtls_kb_size(). Use \c dtls_kb_ macros to + * access the components of the key block. + */ + uint8 key_block[MAX_KEYBLOCK_LENGTH]; + + dtls_cipher_context_t *read_cipher; /**< decryption context */ + dtls_cipher_context_t *write_cipher; /**< encryption context */ +} dtls_security_parameters_t; + +/* The following macros provide access to the components of the + * key_block in the security parameters. */ + +#define dtls_kb_client_mac_secret(Param) ((Param)->key_block) +#define dtls_kb_server_mac_secret(Param) \ + (dtls_kb_client_mac_secret(Param) + DTLS_MAC_KEY_LENGTH) +#define dtls_kb_remote_mac_secret(Param) \ + ((Param)->role == DTLS_CLIENT \ + ? dtls_kb_client_mac_secret(Param) \ + : dtls_kb_server_mac_secret(Param)) +#define dtls_kb_local_mac_secret(Param) \ + ((Param)->role == DTLS_SERVER \ + ? dtls_kb_client_mac_secret(Param) \ + : dtls_kb_server_mac_secret(Param)) +#define dtls_kb_mac_secret_size(Param) DTLS_MAC_KEY_LENGTH +#define dtls_kb_client_write_key(Param) \ + (dtls_kb_server_mac_secret(Param) + DTLS_MAC_KEY_LENGTH) +#define dtls_kb_server_write_key(Param) \ + (dtls_kb_client_write_key(Param) + DTLS_KEY_LENGTH) +#define dtls_kb_remote_write_key(Param) \ + ((Param)->role == DTLS_CLIENT \ + ? dtls_kb_client_write_key(Param) \ + : dtls_kb_server_write_key(Param)) +#define dtls_kb_local_write_key(Param) \ + ((Param)->role == DTLS_SERVER \ + ? dtls_kb_client_write_key(Param) \ + : dtls_kb_server_write_key(Param)) +#define dtls_kb_key_size(Param) DTLS_KEY_LENGTH +#define dtls_kb_client_iv(Param) \ + (dtls_kb_server_write_key(Param) + DTLS_KEY_LENGTH) +#define dtls_kb_server_iv(Param) \ + (dtls_kb_client_iv(Param) + DTLS_IV_LENGTH) +#define dtls_kb_remote_iv(Param) \ + ((Param)->role == DTLS_CLIENT \ + ? dtls_kb_client_iv(Param) \ + : dtls_kb_server_iv(Param)) +#define dtls_kb_local_iv(Param) \ + ((Param)->role == DTLS_SERVER \ + ? dtls_kb_client_iv(Param) \ + : dtls_kb_server_iv(Param)) +#define dtls_kb_iv_size(Param) DTLS_IV_LENGTH + +#define dtls_kb_size(Param) \ + (2 * (dtls_kb_mac_secret_size(Param) + \ + dtls_kb_key_size(Param) + dtls_kb_iv_size(Param))) + +/* just for consistency */ +#define dtls_kb_digest_size(Param) DTLS_MAC_LENGTH + +/** + * Expands the secret and key to a block of DTLS_HMAC_MAX + * size according to the algorithm specified in section 5 of + * RFC 4346. + * + * \param h Identifier of the hash function to use. + * \param key The secret. + * \param keylen Length of \p key. + * \param seed The seed. + * \param seedlen Length of \p seed. + * \param buf Output buffer where the result is XORed into + * The buffe must be capable to hold at least + * \p buflen bytes. + * \return The actual number of bytes written to \p buf or 0 + * on error. + */ +size_t dtls_p_hash(dtls_hashfunc_t h, + const unsigned char *key, size_t keylen, + const unsigned char *label, size_t labellen, + const unsigned char *random1, size_t random1len, + const unsigned char *random2, size_t random2len, + unsigned char *buf, size_t buflen); + +/** + * This function implements the TLS PRF for DTLS_VERSION. For version + * 1.0, the PRF is P_MD5 ^ P_SHA1 while version 1.2 uses + * P_SHA256. Currently, the actual PRF is selected at compile time. + */ +size_t dtls_prf(const unsigned char *key, size_t keylen, + const unsigned char *label, size_t labellen, + const unsigned char *random1, size_t random1len, + const unsigned char *random2, size_t random2len, + unsigned char *buf, size_t buflen); + +/** + * Calculates MAC for record + cleartext packet and places the result + * in \p buf. The given \p hmac_ctx must be initialized with the HMAC + * function to use and the proper secret. As the DTLS mac calculation + * requires data from the record header, \p record must point to a + * buffer of at least \c sizeof(dtls_record_header_t) bytes. Usually, + * the remaining packet will be encrypted, therefore, the cleartext + * is passed separately in \p packet. + * + * \param hmac_ctx The HMAC context to use for MAC calculation. + * \param record The record header. + * \param packet Cleartext payload to apply the MAC to. + * \param length Size of \p packet. + * \param buf A result buffer that is large enough to hold + * the generated digest. + */ +void dtls_mac(dtls_hmac_context_t *hmac_ctx, + const unsigned char *record, + const unsigned char *packet, size_t length, + unsigned char *buf); + +/** + * Encrypts the specified \p src of given \p length, writing the + * result to \p buf. The cipher implementation may add more data to + * the result buffer such as an initialization vector or padding + * (e.g. for block cipers in CBC mode). The caller therefore must + * ensure that \p buf provides sufficient storage to hold the result. + * Usually this means ( 2 + \p length / blocksize ) * blocksize. The + * function returns a value less than zero on error or otherwise the + * number of bytes written. + * + * \param ctx The cipher context to use. + * \param src The data to encrypt. + * \param length The actual size of of \p src. + * \param buf The result buffer. \p src and \p buf must not + * overlap. + * \param aad additional data for AEAD ciphers + * \param aad_length actual size of @p aad + * \return The number of encrypted bytes on success, less than zero + * otherwise. + */ +int dtls_encrypt(dtls_cipher_context_t *ctx, + const unsigned char *src, size_t length, + unsigned char *buf, + const unsigned char *aad, size_t aad_length); + +/** + * Decrypts the given buffer \p src of given \p length, writing the + * result to \p buf. The function returns \c -1 in case of an error, + * or the number of bytes written. Note that for block ciphers, \p + * length must be a multiple of the cipher's block size. A return + * value between \c 0 and the actual length indicates that only \c n-1 + * block have been processed. Unlike dtls_encrypt(), the source + * and destination of dtls_decrypt() may overlap. + * + * \param ctx The cipher context to use. + * \param src The buffer to decrypt. + * \param length The length of the input buffer. + * \param buf The result buffer. + * \param aad additional authentication data for AEAD ciphers + * \param aad_length actual size of @p aad + * \return Less than zero on error, the number of decrypted bytes + * otherwise. + */ +int dtls_decrypt(dtls_cipher_context_t *ctx, + const unsigned char *src, size_t length, + unsigned char *buf, + const unsigned char *a_data, size_t a_data_length); + +/* helper functions */ + +/** + * Generates pre_master_sercet from given PSK and fills the result + * according to the "plain PSK" case in section 2 of RFC 4279. + * Diffie-Hellman and RSA key exchange are currently not supported. + * + * @param key The shared key. + * @param keylen Length of @p key in bytes. + * @param result The derived pre master secret. + * @return The actual length of @p result. + */ +size_t dtls_pre_master_secret(unsigned char *key, size_t keylen, + unsigned char *result); + +/** + * Creates a new dtls_cipher_context_t object for given @c cipher. + * The storage allocated for this object must be released using + * dtls_cipher_free(). + * + * @param code Code of the requested cipher (host byte order) + * @param key The encryption and decryption key. + * @param keylen Actual length of @p key. + * @return A new dtls_cipher_context_t object or @c NULL in case + * something went wrong (e.g. insufficient memory or wrong + * key length) + */ +dtls_cipher_context_t *dtls_cipher_new(dtls_cipher_t code, + unsigned char *key, size_t keylen); + +/** + * Releases the storage allocated by dtls_cipher_new() for @p cipher_context + */ +void dtls_cipher_free(dtls_cipher_context_t *cipher_context); + + +/** + * Initializes the given cipher context @p ctx with the initialization + * vector @p iv of length @p length. */ +void dtls_cipher_set_iv(dtls_cipher_context_t *ctx, + unsigned char *iv, size_t length); + +#endif /* _CRYPTO_H_ */ +