Added generic EAX and CCM implementations.

This commit is contained in:
Thomas Pornin 2017-10-23 23:27:28 +02:00
parent 8e94ad2fcb
commit dddc412922
14 changed files with 4530 additions and 13 deletions

View File

@ -127,7 +127,7 @@ extern "C" {
*
* - Nonce, plaintext and additional authenticated data all consist
* in an integral number of bytes. There is no provision to use
* elements whose lengh in bits is not a multiple of 8.
* elements whose length in bits is not a multiple of 8.
*
* Each AEAD algorithm has its own requirements and limits on the sizes
* of additional data and plaintext. This API does not provide any
@ -169,6 +169,9 @@ extern "C" {
* Note that there is no OOP method for context initialisation: the
* various AEAD algorithms have different requirements that would not
* map well to a single initialisation API.
*
* The OOP API is not provided for CCM, due to its specific requirements
* (length of plaintext must be known in advance).
*/
/**
@ -213,7 +216,7 @@ struct br_aead_class_ {
*
* \param cc AEAD context structure.
* \param data pointer to additional authenticated data.
* \param len length of additiona authenticated data (in bytes).
* \param len length of additional authenticated data (in bytes).
*/
void (*aad_inject)(const br_aead_class **cc,
const void *data, size_t len);
@ -266,6 +269,8 @@ struct br_aead_class_ {
* `check_tag()` function may be used to compute and check the
* tag value.
*
* Tag length depends on the AEAD algorithm.
*
* \param cc AEAD context structure.
* \param tag destination buffer for the tag.
*/
@ -282,11 +287,44 @@ struct br_aead_class_ {
* data or the tag was altered in transit, normally leading to
* wholesale rejection of the complete message.
*
* Tag length depends on the AEAD algorithm.
*
* \param cc AEAD context structure.
* \param tag tag value to compare with (16 bytes).
* \param tag tag value to compare with.
* \return 1 on success (exact match of tag value), 0 otherwise.
*/
uint32_t (*check_tag)(const br_aead_class **cc, const void *tag);
/**
* \brief Compute authentication tag (with truncation).
*
* This function is similar to `get_tag()`, except that the tag
* length is provided. Some AEAD algorithms allow several tag
* lengths, usually by truncating the normal tag. Shorter tags
* mechanically increase success probability of forgeries.
* The range of allowed tag lengths depends on the algorithm.
*
* \param cc AEAD context structure.
* \param tag destination buffer for the tag.
* \param len tag length (in bytes).
*/
void (*get_tag_trunc)(const br_aead_class **cc, void *tag, size_t len);
/**
* \brief Compute and check authentication tag (with truncation).
*
* This function is similar to `check_tag()` except that it
* works over an explicit tag length. See `get_tag()` for a
* discussion of explicit tag lengths; the range of allowed tag
* lengths depends on the algorithm.
*
* \param cc AEAD context structure.
* \param tag tag value to compare with.
* \param len tag length (in bytes).
* \return 1 on success (exact match of tag value), 0 otherwise.
*/
uint32_t (*check_tag_trunc)(const br_aead_class **cc,
const void *tag, size_t len);
};
/**
@ -379,7 +417,7 @@ void br_gcm_reset(br_gcm_context *ctx, const void *iv, size_t len);
*
* \param ctx GCM context structure.
* \param data pointer to additional authenticated data.
* \param len length of additiona authenticated data (in bytes).
* \param len length of additional authenticated data (in bytes).
*/
void br_gcm_aad_inject(br_gcm_context *ctx, const void *data, size_t len);
@ -449,11 +487,478 @@ void br_gcm_get_tag(br_gcm_context *ctx, void *tag);
*/
uint32_t br_gcm_check_tag(br_gcm_context *ctx, const void *tag);
/**
* \brief Compute GCM authentication tag (with truncation).
*
* This function is similar to `br_gcm_get_tag()`, except that it allows
* the tag to be truncated to a smaller length. The intended tag length
* is provided as `len` (in bytes); it MUST be no more than 16, but
* it may be smaller. Note that decreasing tag length mechanically makes
* forgeries easier; NIST SP 800-38D specifies that the tag length shall
* lie between 12 and 16 bytes (inclusive), but may be truncated down to
* 4 or 8 bytes, for specific applications that can tolerate it. It must
* also be noted that successful forgeries leak information on the
* authentication key, making subsequent forgeries easier. Therefore,
* tag truncation, and in particular truncation to sizes lower than 12
* bytes, shall be envisioned only with great care.
*
* The tag is written in the provided `tag` buffer. This call terminates
* the GCM run: no data may be processed with that GCM context
* afterwards, until `br_gcm_reset()` is called to initiate a new GCM
* run.
*
* The tag value must normally be sent along with the encrypted data.
* When decrypting, the tag value must be recomputed and compared with
* the received tag: if the two tag values differ, then either the tag
* or the encrypted data was altered in transit. As an alternative to
* this function, the `br_gcm_check_tag_trunc()` function can be used to
* compute and check the tag value.
*
* \param ctx GCM context structure.
* \param tag destination buffer for the tag.
* \param len tag length (16 bytes or less).
*/
void br_gcm_get_tag_trunc(br_gcm_context *ctx, void *tag, size_t len);
/**
* \brief Compute and check GCM authentication tag (with truncation).
*
* This function is an alternative to `br_gcm_get_tag_trunc()`, normally used
* on the receiving end (i.e. when decrypting value). The tag value is
* recomputed and compared with the provided tag value. If they match, 1
* is returned; on mismatch, 0 is returned. A returned value of 0 means
* that the data or the tag was altered in transit, normally leading to
* wholesale rejection of the complete message.
*
* Tag length MUST be 16 bytes or less. The normal GCM tag length is 16
* bytes. See `br_check_tag_trunc()` for some discussion on the potential
* perils of truncating authentication tags.
*
* \param ctx GCM context structure.
* \param tag tag value to compare with.
* \param len tag length (in bytes).
* \return 1 on success (exact match of tag value), 0 otherwise.
*/
uint32_t br_gcm_check_tag_trunc(br_gcm_context *ctx,
const void *tag, size_t len);
/**
* \brief Class instance for GCM.
*/
extern const br_aead_class br_gcm_vtable;
/**
* \brief Context structure for EAX.
*
* EAX is an AEAD mode that combines a block cipher in CTR mode with
* CBC-MAC using the same block cipher and the same key, to provide
* authenticated encryption:
*
* - Any block cipher with 16-byte blocks can be used with EAX
* (technically, other block sizes are defined as well, but this
* is not implemented by these functions; shorter blocks also
* imply numerous security issues).
*
* - The nonce can have any length, as long as nonce values are
* not reused (thus, if nonces are randomly selected, the nonce
* size should be such that reuse probability is negligible).
*
* - Additional authenticated data length is unlimited.
*
* - Message length is unlimited.
*
* - The authentication tag has length 16 bytes.
*
* The EAX initialisation function receives as parameter an
* _initialised_ block cipher implementation context, with the secret
* key already set. A pointer to that context will be kept within the
* EAX context structure. It is up to the caller to allocate and
* initialise that block cipher context.
*/
typedef struct {
/** \brief Pointer to vtable for this context. */
const br_aead_class *vtable;
#ifndef BR_DOXYGEN_IGNORE
const br_block_ctrcbc_class **bctx;
unsigned char L2[16];
unsigned char L4[16];
unsigned char nonce[16];
unsigned char head[16];
unsigned char ctr[16];
unsigned char cbcmac[16];
unsigned char buf[16];
size_t ptr;
#endif
} br_eax_context;
/**
* \brief Initialize an EAX context.
*
* A block cipher implementation, with its initialised context
* structure, is provided. The block cipher MUST use 16-byte blocks in
* CTR + CBC-MAC mode, and its secret key MUST have been already set in
* the provided context. The parameters are linked in the EAX context.
*
* After this function has been called, the `br_eax_reset()` function must
* be called, to provide the nonce for EAX computation.
*
* \param ctx EAX context structure.
* \param bctx block cipher context (already initialised with secret key).
*/
void br_eax_init(br_eax_context *ctx, const br_block_ctrcbc_class **bctx);
/**
* \brief Reset an EAX context.
*
* This function resets an already initialised EAX context for a new
* computation run. Implementations and keys are conserved. This function
* can be called at any time; it cancels any ongoing EAX computation that
* uses the provided context structure.
*
* It is critical to EAX security that nonce values are not repeated for
* the same encryption key. Nonces can have arbitrary length. If nonces
* are randomly generated, then a nonce length of at least 128 bits (16
* bytes) is recommended, to make nonce reuse probability sufficiently
* low.
*
* \param ctx EAX context structure.
* \param nonce EAX nonce to use.
* \param len EAX nonce length (in bytes).
*/
void br_eax_reset(br_eax_context *ctx, const void *nonce, size_t len);
/**
* \brief Inject additional authenticated data into EAX.
*
* The provided data is injected into a running EAX computation. Additional
* data must be injected _before_ the call to `br_eax_flip()`.
* Additional data can be injected in several chunks of arbitrary length;
* the total amount of additional authenticated data is unlimited.
*
* \param ctx EAX context structure.
* \param data pointer to additional authenticated data.
* \param len length of additional authenticated data (in bytes).
*/
void br_eax_aad_inject(br_eax_context *ctx, const void *data, size_t len);
/**
* \brief Finish injection of additional authenticated data into EAX.
*
* This function MUST be called before beginning the actual encryption
* or decryption (with `br_eax_run()`), even if no additional authenticated
* data was injected. No additional authenticated data may be injected
* after this function call.
*
* \param ctx EAX context structure.
*/
void br_eax_flip(br_eax_context *ctx);
/**
* \brief Encrypt or decrypt some data with EAX.
*
* Data encryption or decryption can be done after `br_eax_flip()`
* has been called on the context. If `encrypt` is non-zero, then the
* provided data shall be plaintext, and it is encrypted in place.
* Otherwise, the data shall be ciphertext, and it is decrypted in place.
*
* Data may be provided in several chunks of arbitrary length.
*
* \param ctx EAX context structure.
* \param encrypt non-zero for encryption, zero for decryption.
* \param data data to encrypt or decrypt.
* \param len data length (in bytes).
*/
void br_eax_run(br_eax_context *ctx, int encrypt, void *data, size_t len);
/**
* \brief Compute EAX authentication tag.
*
* Compute the EAX authentication tag. The tag is a 16-byte value which
* is written in the provided `tag` buffer. This call terminates the
* EAX run: no data may be processed with that EAX context afterwards,
* until `br_eax_reset()` is called to initiate a new EAX run.
*
* The tag value must normally be sent along with the encrypted data.
* When decrypting, the tag value must be recomputed and compared with
* the received tag: if the two tag values differ, then either the tag
* or the encrypted data was altered in transit. As an alternative to
* this function, the `br_eax_check_tag()` function can be used to
* compute and check the tag value.
*
* \param ctx EAX context structure.
* \param tag destination buffer for the tag (16 bytes).
*/
void br_eax_get_tag(br_eax_context *ctx, void *tag);
/**
* \brief Compute and check EAX authentication tag.
*
* This function is an alternative to `br_eax_get_tag()`, normally used
* on the receiving end (i.e. when decrypting value). The tag value is
* recomputed and compared with the provided tag value. If they match, 1
* is returned; on mismatch, 0 is returned. A returned value of 0 means
* that the data or the tag was altered in transit, normally leading to
* wholesale rejection of the complete message.
*
* \param ctx EAX context structure.
* \param tag tag value to compare with (16 bytes).
* \return 1 on success (exact match of tag value), 0 otherwise.
*/
uint32_t br_eax_check_tag(br_eax_context *ctx, const void *tag);
/**
* \brief Compute EAX authentication tag (with truncation).
*
* This function is similar to `br_eax_get_tag()`, except that it allows
* the tag to be truncated to a smaller length. The intended tag length
* is provided as `len` (in bytes); it MUST be no more than 16, but
* it may be smaller. Note that decreasing tag length mechanically makes
* forgeries easier; NIST SP 800-38D specifies that the tag length shall
* lie between 12 and 16 bytes (inclusive), but may be truncated down to
* 4 or 8 bytes, for specific applications that can tolerate it. It must
* also be noted that successful forgeries leak information on the
* authentication key, making subsequent forgeries easier. Therefore,
* tag truncation, and in particular truncation to sizes lower than 12
* bytes, shall be envisioned only with great care.
*
* The tag is written in the provided `tag` buffer. This call terminates
* the EAX run: no data may be processed with that EAX context
* afterwards, until `br_eax_reset()` is called to initiate a new EAX
* run.
*
* The tag value must normally be sent along with the encrypted data.
* When decrypting, the tag value must be recomputed and compared with
* the received tag: if the two tag values differ, then either the tag
* or the encrypted data was altered in transit. As an alternative to
* this function, the `br_eax_check_tag_trunc()` function can be used to
* compute and check the tag value.
*
* \param ctx EAX context structure.
* \param tag destination buffer for the tag.
* \param len tag length (16 bytes or less).
*/
void br_eax_get_tag_trunc(br_eax_context *ctx, void *tag, size_t len);
/**
* \brief Compute and check EAX authentication tag (with truncation).
*
* This function is an alternative to `br_eax_get_tag_trunc()`, normally used
* on the receiving end (i.e. when decrypting value). The tag value is
* recomputed and compared with the provided tag value. If they match, 1
* is returned; on mismatch, 0 is returned. A returned value of 0 means
* that the data or the tag was altered in transit, normally leading to
* wholesale rejection of the complete message.
*
* Tag length MUST be 16 bytes or less. The normal EAX tag length is 16
* bytes. See `br_check_tag_trunc()` for some discussion on the potential
* perils of truncating authentication tags.
*
* \param ctx EAX context structure.
* \param tag tag value to compare with.
* \param len tag length (in bytes).
* \return 1 on success (exact match of tag value), 0 otherwise.
*/
uint32_t br_eax_check_tag_trunc(br_eax_context *ctx,
const void *tag, size_t len);
/**
* \brief Class instance for EAX.
*/
extern const br_aead_class br_eax_vtable;
/**
* \brief Context structure for CCM.
*
* CCM is an AEAD mode that combines a block cipher in CTR mode with
* CBC-MAC using the same block cipher and the same key, to provide
* authenticated encryption:
*
* - Any block cipher with 16-byte blocks can be used with CCM
* (technically, other block sizes are defined as well, but this
* is not implemented by these functions; shorter blocks also
* imply numerous security issues).
*
* - The authentication tag length, and plaintext length, MUST be
* known when starting processing data. Plaintext and ciphertext
* can still be provided by chunks, but the total size must match
* the value provided upon initialisation.
*
* - The nonce length is constrained betwen 7 and 13 bytes (inclusive).
* Furthermore, the plaintext length, when encoded, must fit over
* 15-nonceLen bytes; thus, if the nonce has length 13 bytes, then
* the plaintext length cannot exceed 65535 bytes.
*
* - Additional authenticated data length is practically unlimited
* (formal limit is at 2^64 bytes).
*
* - The authentication tag has length 4 to 16 bytes (even values only).
*
* The CCM initialisation function receives as parameter an
* _initialised_ block cipher implementation context, with the secret
* key already set. A pointer to that context will be kept within the
* CCM context structure. It is up to the caller to allocate and
* initialise that block cipher context.
*/
typedef struct {
#ifndef BR_DOXYGEN_IGNORE
const br_block_ctrcbc_class **bctx;
unsigned char ctr[16];
unsigned char cbcmac[16];
unsigned char tagmask[16];
unsigned char buf[16];
size_t ptr;
size_t tag_len;
#endif
} br_ccm_context;
/**
* \brief Initialize a CCM context.
*
* A block cipher implementation, with its initialised context
* structure, is provided. The block cipher MUST use 16-byte blocks in
* CTR + CBC-MAC mode, and its secret key MUST have been already set in
* the provided context. The parameters are linked in the CCM context.
*
* After this function has been called, the `br_ccm_reset()` function must
* be called, to provide the nonce for CCM computation.
*
* \param ctx CCM context structure.
* \param bctx block cipher context (already initialised with secret key).
*/
void br_ccm_init(br_ccm_context *ctx, const br_block_ctrcbc_class **bctx);
/**
* \brief Reset a CCM context.
*
* This function resets an already initialised CCM context for a new
* computation run. Implementations and keys are conserved. This function
* can be called at any time; it cancels any ongoing CCM computation that
* uses the provided context structure.
*
* The `aad_len` parameter contains the total length, in bytes, of the
* additional authenticated data. It may be zero. That length MUST be
* exact.
*
* The `data_len` parameter contains the total length, in bytes, of the
* data that will be injected (plaintext or ciphertext). That length MUST
* be exact. Moreover, that length MUST be less than 2^(8*(15-nonce_len)).
*
* The nonce length (`nonce_len`), in bytes, must be in the 7..13 range
* (inclusive).
*
* The tag length (`tag_len`), in bytes, must be in the 4..16 range, and
* be an even integer. Short tags mechanically allow for higher forgery
* probabilities; hence, tag sizes smaller than 12 bytes shall be used only
* with care.
*
* It is critical to CCM security that nonce values are not repeated for
* the same encryption key. Random generation of nonces is not generally
* recommended, due to the relatively small maximum nonce value.
*
* Returned value is 1 on success, 0 on error. An error is reported if
* the tag or nonce length is out of range, or if the
* plaintext/ciphertext length cannot be encoded with the specified
* nonce length.
*
* \param ctx CCM context structure.
* \param nonce CCM nonce to use.
* \param nonce_len CCM nonce length (in bytes, 7 to 13).
* \param aad_len additional authenticated data length (in bytes).
* \param data_len plaintext/ciphertext length (in bytes).
* \param tag_len tag length (in bytes).
* \return 1 on success, 0 on error.
*/
int br_ccm_reset(br_ccm_context *ctx, const void *nonce, size_t nonce_len,
uint64_t aad_len, uint64_t data_len, size_t tag_len);
/**
* \brief Inject additional authenticated data into CCM.
*
* The provided data is injected into a running CCM computation. Additional
* data must be injected _before_ the call to `br_ccm_flip()`.
* Additional data can be injected in several chunks of arbitrary length,
* but the total amount MUST exactly match the value which was provided
* to `br_ccm_reset()`.
*
* \param ctx CCM context structure.
* \param data pointer to additional authenticated data.
* \param len length of additional authenticated data (in bytes).
*/
void br_ccm_aad_inject(br_ccm_context *ctx, const void *data, size_t len);
/**
* \brief Finish injection of additional authenticated data into CCM.
*
* This function MUST be called before beginning the actual encryption
* or decryption (with `br_ccm_run()`), even if no additional authenticated
* data was injected. No additional authenticated data may be injected
* after this function call.
*
* \param ctx CCM context structure.
*/
void br_ccm_flip(br_ccm_context *ctx);
/**
* \brief Encrypt or decrypt some data with CCM.
*
* Data encryption or decryption can be done after `br_ccm_flip()`
* has been called on the context. If `encrypt` is non-zero, then the
* provided data shall be plaintext, and it is encrypted in place.
* Otherwise, the data shall be ciphertext, and it is decrypted in place.
*
* Data may be provided in several chunks of arbitrary length, provided
* that the total length exactly matches the length provided to the
* `br_ccm_reset()` call.
*
* \param ctx CCM context structure.
* \param encrypt non-zero for encryption, zero for decryption.
* \param data data to encrypt or decrypt.
* \param len data length (in bytes).
*/
void br_ccm_run(br_ccm_context *ctx, int encrypt, void *data, size_t len);
/**
* \brief Compute CCM authentication tag.
*
* Compute the CCM authentication tag. This call terminates the CCM
* run: all data must have been injected with `br_ccm_run()` (in zero,
* one or more successive calls). After this function has been called,
* no more data can br processed; a `br_ccm_reset()` call is required
* to start a new message.
*
* The tag length was provided upon context initialisation (last call
* to `br_ccm_reset()`); it is returned by this function.
*
* The tag value must normally be sent along with the encrypted data.
* When decrypting, the tag value must be recomputed and compared with
* the received tag: if the two tag values differ, then either the tag
* or the encrypted data was altered in transit. As an alternative to
* this function, the `br_ccm_check_tag()` function can be used to
* compute and check the tag value.
*
* \param ctx CCM context structure.
* \param tag destination buffer for the tag (up to 16 bytes).
* \return the tag length (in bytes).
*/
size_t br_ccm_get_tag(br_ccm_context *ctx, void *tag);
/**
* \brief Compute and check CCM authentication tag.
*
* This function is an alternative to `br_ccm_get_tag()`, normally used
* on the receiving end (i.e. when decrypting value). The tag value is
* recomputed and compared with the provided tag value. If they match, 1
* is returned; on mismatch, 0 is returned. A returned value of 0 means
* that the data or the tag was altered in transit, normally leading to
* wholesale rejection of the complete message.
*
* \param ctx CCM context structure.
* \param tag tag value to compare with (up to 16 bytes).
* \return 1 on success (exact match of tag value), 0 otherwise.
*/
uint32_t br_ccm_check_tag(br_ccm_context *ctx, const void *tag);
#ifdef __cplusplus
}
#endif

View File

@ -136,6 +136,73 @@ extern "C" {
* chunked processing, provided that each chunk length (except possibly
* the last one) is a multiple of the block size.
*
* - `br_xxx_ctrcbc_keys`
*
* Context structure that contains the subkeys resulting from the
* key expansion. These subkeys are appropriate for doing combined
* CTR encryption/decryption and CBC-MAC, as used in the CCM and EAX
* authenticated encryption modes. The structure first field is
* called `vtable` and points to the appropriate OOP structure.
*
* - `br_xxx_ctrcbc_init(br_xxx_ctr_keys *ctx, const void *key, size_t len)`
*
* Perform key expansion: subkeys for combined CTR
* encryption/decryption and CBC-MAC are computed and written in the
* provided context structure. The key length MUST be adequate for
* the implemented block cipher. This function also sets the
* `vtable` field.
*
* - `br_xxx_ctrcbc_encrypt(const br_xxx_ctrcbc_keys *ctx, void *ctr, void *cbcmac, void *data, size_t len)`
*
* Perform CTR encryption of some data, and CBC-MAC. Processing is
* done "in place" (the output data replaces the input data). This
* function applies CTR encryption on the data, using a full
* block-size counter (i.e. for 128-bit blocks, the counter is
* incremented as a 128-bit value). The 'ctr' array contains the
* initial value for the counter (used in the first block) and it is
* updated with the new value after data processing. The 'cbcmac'
* value shall point to a block-sized value which is used as IV for
* CBC-MAC, computed over the encrypted data (output of CTR
* encryption); the resulting CBC-MAC is written over 'cbcmac' on
* output.
*
* The data length MUST be a multiple of the block size.
*
* - `br_xxx_ctrcbc_decrypt(const br_xxx_ctrcbc_keys *ctx, void *ctr, void *cbcmac, void *data, size_t len)`
*
* Perform CTR decryption of some data, and CBC-MAC. Processing is
* done "in place" (the output data replaces the input data). This
* function applies CTR decryption on the data, using a full
* block-size counter (i.e. for 128-bit blocks, the counter is
* incremented as a 128-bit value). The 'ctr' array contains the
* initial value for the counter (used in the first block) and it is
* updated with the new value after data processing. The 'cbcmac'
* value shall point to a block-sized value which is used as IV for
* CBC-MAC, computed over the encrypted data (input of CTR
* encryption); the resulting CBC-MAC is written over 'cbcmac' on
* output.
*
* The data length MUST be a multiple of the block size.
*
* - `br_xxx_ctrcbc_ctr(const br_xxx_ctrcbc_keys *ctx, void *ctr, void *data, size_t len)`
*
* Perform CTR encryption or decryption of the provided data. The
* data is processed "in place" (the output data replaces the input
* data). A full block-sized counter is applied (i.e. for 128-bit
* blocks, the counter is incremented as a 128-bit value). The 'ctr'
* array contains the initial value for the counter (used in the
* first block), and it is updated with the new value after data
* processing.
*
* The data length MUST be a multiple of the block size.
*
* - `br_xxx_ctrcbc_mac(const br_xxx_ctrcbc_keys *ctx, void *cbcmac, const void *data, size_t len)`
*
* Compute CBC-MAC over the provided data. The IV for CBC-MAC is
* provided as 'cbcmac'; the output is written over the same array.
* The data itself is untouched. The data length MUST be a multiple
* of the block size.
*
*
* It shall be noted that the key expansion functions return `void`. If
* the provided key length is not allowed, then there will be no error
@ -176,6 +243,41 @@ extern "C" {
*
* Pointer to the encryption/decryption function.
*
* For combined CTR/CBC-MAC encryption, the `vtable` has a slightly
* different structure:
*
* - `context_size`
*
* The size (in bytes) of the context structure for subkeys.
*
* - `block_size`
*
* The cipher block size (in bytes).
*
* - `log_block_size`
*
* The base-2 logarithm of cipher block size (e.g. 4 for blocks
* of 16 bytes).
*
* - `init`
*
* Pointer to the key expansion function.
*
* - `encrypt`
*
* Pointer to the CTR encryption + CBC-MAC function.
*
* - `decrypt`
*
* Pointer to the CTR decryption + CBC-MAC function.
*
* - `ctr`
*
* Pointer to the CTR encryption/decryption function.
*
* - `mac`
*
* Pointer to the CBC-MAC function.
*
* For block cipher "`xxx`", static, constant instances of these
* structures are defined, under the names:
@ -183,6 +285,7 @@ extern "C" {
* - `br_xxx_cbcenc_vtable`
* - `br_xxx_cbcdec_vtable`
* - `br_xxx_ctr_vtable`
* - `br_xxx_ctrcbc_vtable`
*
*
* ## Implemented Block Ciphers
@ -460,6 +563,132 @@ struct br_block_ctr_class_ {
const void *iv, uint32_t cc, void *data, size_t len);
};
/**
* \brief Class type for combined CTR and CBC-MAC implementations.
*
* A `br_block_ctrcbc_class` instance points to the functions implementing
* a specific block cipher, when used in CTR mode for encrypting or
* decrypting data, along with CBC-MAC.
*/
typedef struct br_block_ctrcbc_class_ br_block_ctrcbc_class;
struct br_block_ctrcbc_class_ {
/**
* \brief Size (in bytes) of the context structure appropriate
* for containing subkeys.
*/
size_t context_size;
/**
* \brief Size of individual blocks (in bytes).
*/
unsigned block_size;
/**
* \brief Base-2 logarithm of the size of individual blocks,
* expressed in bytes.
*/
unsigned log_block_size;
/**
* \brief Initialisation function.
*
* This function sets the `vtable` field in the context structure.
* The key length MUST be one of the key lengths supported by
* the implementation.
*
* \param ctx context structure to initialise.
* \param key secret key.
* \param key_len key length (in bytes).
*/
void (*init)(const br_block_ctrcbc_class **ctx,
const void *key, size_t key_len);
/**
* \brief Run the CTR encryption + CBC-MAC.
*
* The `ctr` parameter points to the counter; its length shall
* be equal to the block size. It is updated by this function
* as encryption proceeds.
*
* The `cbcmac` parameter points to the IV for CBC-MAC. The MAC
* is computed over the encrypted data (output of CTR
* encryption). Its length shall be equal to the block size. The
* computed CBC-MAC value is written over the `cbcmac` array.
*
* The data to encrypt is updated "in place". Its length (`len`
* bytes) MUST be a multiple of the block size.
*
* \param ctx context structure (already initialised).
* \param ctr counter for CTR encryption (initial and final).
* \param cbcmac IV and output buffer for CBC-MAC.
* \param data data to encrypt.
* \param len data length (in bytes).
*/
void (*encrypt)(const br_block_ctrcbc_class *const *ctx,
void *ctr, void *cbcmac, void *data, size_t len);
/**
* \brief Run the CTR decryption + CBC-MAC.
*
* The `ctr` parameter points to the counter; its length shall
* be equal to the block size. It is updated by this function
* as decryption proceeds.
*
* The `cbcmac` parameter points to the IV for CBC-MAC. The MAC
* is computed over the encrypted data (i.e. before CTR
* decryption). Its length shall be equal to the block size. The
* computed CBC-MAC value is written over the `cbcmac` array.
*
* The data to decrypt is updated "in place". Its length (`len`
* bytes) MUST be a multiple of the block size.
*
* \param ctx context structure (already initialised).
* \param ctr counter for CTR encryption (initial and final).
* \param cbcmac IV and output buffer for CBC-MAC.
* \param data data to decrypt.
* \param len data length (in bytes).
*/
void (*decrypt)(const br_block_ctrcbc_class *const *ctx,
void *ctr, void *cbcmac, void *data, size_t len);
/**
* \brief Run the CTR encryption/decryption only.
*
* The `ctr` parameter points to the counter; its length shall
* be equal to the block size. It is updated by this function
* as decryption proceeds.
*
* The data to decrypt is updated "in place". Its length (`len`
* bytes) MUST be a multiple of the block size.
*
* \param ctx context structure (already initialised).
* \param ctr counter for CTR encryption (initial and final).
* \param data data to decrypt.
* \param len data length (in bytes).
*/
void (*ctr)(const br_block_ctrcbc_class *const *ctx,
void *ctr, void *data, size_t len);
/**
* \brief Run the CBC-MAC only.
*
* The `cbcmac` parameter points to the IV for CBC-MAC. The MAC
* is computed over the encrypted data (i.e. before CTR
* decryption). Its length shall be equal to the block size. The
* computed CBC-MAC value is written over the `cbcmac` array.
*
* The data is unmodified. Its length (`len` bytes) MUST be a
* multiple of the block size.
*
* \param ctx context structure (already initialised).
* \param cbcmac IV and output buffer for CBC-MAC.
* \param data data to decrypt.
* \param len data length (in bytes).
*/
void (*mac)(const br_block_ctrcbc_class *const *ctx,
void *cbcmac, const void *data, size_t len);
};
/*
* Traditional, table-based AES implementation. It is fast, but uses
* internal tables (in particular a 1 kB table for encryption, another
@ -517,6 +746,22 @@ typedef struct {
#endif
} br_aes_big_ctr_keys;
/**
* \brief Context for AES subkeys (`aes_big` implementation, CTR encryption
* and decryption + CBC-MAC).
*
* First field is a pointer to the vtable; it is set by the initialisation
* function. Other fields are not supposed to be accessed by user code.
*/
typedef struct {
/** \brief Pointer to vtable for this context. */
const br_block_ctrcbc_class *vtable;
#ifndef BR_DOXYGEN_IGNORE
uint32_t skey[60];
unsigned num_rounds;
#endif
} br_aes_big_ctrcbc_keys;
/**
* \brief Class instance for AES CBC encryption (`aes_big` implementation).
*/
@ -533,6 +778,12 @@ extern const br_block_cbcdec_class br_aes_big_cbcdec_vtable;
*/
extern const br_block_ctr_class br_aes_big_ctr_vtable;
/**
* \brief Class instance for AES CTR encryption/decryption + CBC-MAC
* (`aes_big` implementation).
*/
extern const br_block_ctrcbc_class br_aes_big_ctrcbc_vtable;
/**
* \brief Context initialisation (key schedule) for AES CBC encryption
* (`aes_big` implementation).
@ -566,6 +817,17 @@ void br_aes_big_cbcdec_init(br_aes_big_cbcdec_keys *ctx,
void br_aes_big_ctr_init(br_aes_big_ctr_keys *ctx,
const void *key, size_t len);
/**
* \brief Context initialisation (key schedule) for AES CTR + CBC-MAC
* (`aes_big` implementation).
*
* \param ctx context to initialise.
* \param key secret key.
* \param len secret key length (in bytes).
*/
void br_aes_big_ctrcbc_init(br_aes_big_ctrcbc_keys *ctx,
const void *key, size_t len);
/**
* \brief CBC encryption with AES (`aes_big` implementation).
*
@ -594,13 +856,59 @@ void br_aes_big_cbcdec_run(const br_aes_big_cbcdec_keys *ctx, void *iv,
* \param ctx context (already initialised).
* \param iv IV (constant, 12 bytes).
* \param cc initial block counter value.
* \param data data to decrypt (updated).
* \param data data to encrypt or decrypt (updated).
* \param len data length (in bytes).
* \return new block counter value.
*/
uint32_t br_aes_big_ctr_run(const br_aes_big_ctr_keys *ctx,
const void *iv, uint32_t cc, void *data, size_t len);
/**
* \brief CTR encryption + CBC-MAC with AES (`aes_big` implementation).
*
* \param ctx context (already initialised).
* \param ctr counter for CTR (16 bytes, updated).
* \param cbcmac IV for CBC-MAC (updated).
* \param data data to encrypt (updated).
* \param len data length (in bytes, MUST be a multiple of 16).
*/
void br_aes_big_ctrcbc_encrypt(const br_aes_big_ctrcbc_keys *ctx,
void *ctr, void *cbcmac, void *data, size_t len);
/**
* \brief CTR decryption + CBC-MAC with AES (`aes_big` implementation).
*
* \param ctx context (already initialised).
* \param ctr counter for CTR (16 bytes, updated).
* \param cbcmac IV for CBC-MAC (updated).
* \param data data to decrypt (updated).
* \param len data length (in bytes, MUST be a multiple of 16).
*/
void br_aes_big_ctrcbc_decrypt(const br_aes_big_ctrcbc_keys *ctx,
void *ctr, void *cbcmac, void *data, size_t len);
/**
* \brief CTR encryption/decryption with AES (`aes_big` implementation).
*
* \param ctx context (already initialised).
* \param ctr counter for CTR (16 bytes, updated).
* \param data data to MAC (updated).
* \param len data length (in bytes, MUST be a multiple of 16).
*/
void br_aes_big_ctrcbc_ctr(const br_aes_big_ctrcbc_keys *ctx,
void *ctr, void *data, size_t len);
/**
* \brief CBC-MAC with AES (`aes_big` implementation).
*
* \param ctx context (already initialised).
* \param cbcmac IV for CBC-MAC (updated).
* \param data data to MAC (unmodified).
* \param len data length (in bytes, MUST be a multiple of 16).
*/
void br_aes_big_ctrcbc_mac(const br_aes_big_ctrcbc_keys *ctx,
void *cbcmac, const void *data, size_t len);
/*
* AES implementation optimized for size. It is slower than the
* traditional table-based AES implementation, but requires much less
@ -658,6 +966,22 @@ typedef struct {
#endif
} br_aes_small_ctr_keys;
/**
* \brief Context for AES subkeys (`aes_small` implementation, CTR encryption
* and decryption + CBC-MAC).
*
* First field is a pointer to the vtable; it is set by the initialisation
* function. Other fields are not supposed to be accessed by user code.
*/
typedef struct {
/** \brief Pointer to vtable for this context. */
const br_block_ctrcbc_class *vtable;
#ifndef BR_DOXYGEN_IGNORE
uint32_t skey[60];
unsigned num_rounds;
#endif
} br_aes_small_ctrcbc_keys;
/**
* \brief Class instance for AES CBC encryption (`aes_small` implementation).
*/
@ -674,6 +998,12 @@ extern const br_block_cbcdec_class br_aes_small_cbcdec_vtable;
*/
extern const br_block_ctr_class br_aes_small_ctr_vtable;
/**
* \brief Class instance for AES CTR encryption/decryption + CBC-MAC
* (`aes_small` implementation).
*/
extern const br_block_ctrcbc_class br_aes_small_ctrcbc_vtable;
/**
* \brief Context initialisation (key schedule) for AES CBC encryption
* (`aes_small` implementation).
@ -707,6 +1037,17 @@ void br_aes_small_cbcdec_init(br_aes_small_cbcdec_keys *ctx,
void br_aes_small_ctr_init(br_aes_small_ctr_keys *ctx,
const void *key, size_t len);
/**
* \brief Context initialisation (key schedule) for AES CTR + CBC-MAC
* (`aes_small` implementation).
*
* \param ctx context to initialise.
* \param key secret key.
* \param len secret key length (in bytes).
*/
void br_aes_small_ctrcbc_init(br_aes_small_ctrcbc_keys *ctx,
const void *key, size_t len);
/**
* \brief CBC encryption with AES (`aes_small` implementation).
*
@ -742,6 +1083,52 @@ void br_aes_small_cbcdec_run(const br_aes_small_cbcdec_keys *ctx, void *iv,
uint32_t br_aes_small_ctr_run(const br_aes_small_ctr_keys *ctx,
const void *iv, uint32_t cc, void *data, size_t len);
/**
* \brief CTR encryption + CBC-MAC with AES (`aes_small` implementation).
*
* \param ctx context (already initialised).
* \param ctr counter for CTR (16 bytes, updated).
* \param cbcmac IV for CBC-MAC (updated).
* \param data data to encrypt (updated).
* \param len data length (in bytes, MUST be a multiple of 16).
*/
void br_aes_small_ctrcbc_encrypt(const br_aes_small_ctrcbc_keys *ctx,
void *ctr, void *cbcmac, void *data, size_t len);
/**
* \brief CTR decryption + CBC-MAC with AES (`aes_small` implementation).
*
* \param ctx context (already initialised).
* \param ctr counter for CTR (16 bytes, updated).
* \param cbcmac IV for CBC-MAC (updated).
* \param data data to decrypt (updated).
* \param len data length (in bytes, MUST be a multiple of 16).
*/
void br_aes_small_ctrcbc_decrypt(const br_aes_small_ctrcbc_keys *ctx,
void *ctr, void *cbcmac, void *data, size_t len);
/**
* \brief CTR encryption/decryption with AES (`aes_small` implementation).
*
* \param ctx context (already initialised).
* \param ctr counter for CTR (16 bytes, updated).
* \param data data to MAC (updated).
* \param len data length (in bytes, MUST be a multiple of 16).
*/
void br_aes_small_ctrcbc_ctr(const br_aes_small_ctrcbc_keys *ctx,
void *ctr, void *data, size_t len);
/**
* \brief CBC-MAC with AES (`aes_small` implementation).
*
* \param ctx context (already initialised).
* \param cbcmac IV for CBC-MAC (updated).
* \param data data to MAC (unmodified).
* \param len data length (in bytes, MUST be a multiple of 16).
*/
void br_aes_small_ctrcbc_mac(const br_aes_small_ctrcbc_keys *ctx,
void *cbcmac, const void *data, size_t len);
/*
* Constant-time AES implementation. Its size is similar to that of
* 'aes_big', and its performance is similar to that of 'aes_small' (faster
@ -798,6 +1185,22 @@ typedef struct {
#endif
} br_aes_ct_ctr_keys;
/**
* \brief Context for AES subkeys (`aes_ct` implementation, CTR encryption
* and decryption + CBC-MAC).
*
* First field is a pointer to the vtable; it is set by the initialisation
* function. Other fields are not supposed to be accessed by user code.
*/
typedef struct {
/** \brief Pointer to vtable for this context. */
const br_block_ctrcbc_class *vtable;
#ifndef BR_DOXYGEN_IGNORE
uint32_t skey[60];
unsigned num_rounds;
#endif
} br_aes_ct_ctrcbc_keys;
/**
* \brief Class instance for AES CBC encryption (`aes_ct` implementation).
*/
@ -814,6 +1217,12 @@ extern const br_block_cbcdec_class br_aes_ct_cbcdec_vtable;
*/
extern const br_block_ctr_class br_aes_ct_ctr_vtable;
/**
* \brief Class instance for AES CTR encryption/decryption + CBC-MAC
* (`aes_ct` implementation).
*/
extern const br_block_ctrcbc_class br_aes_ct_ctrcbc_vtable;
/**
* \brief Context initialisation (key schedule) for AES CBC encryption
* (`aes_ct` implementation).
@ -847,6 +1256,17 @@ void br_aes_ct_cbcdec_init(br_aes_ct_cbcdec_keys *ctx,
void br_aes_ct_ctr_init(br_aes_ct_ctr_keys *ctx,
const void *key, size_t len);
/**
* \brief Context initialisation (key schedule) for AES CTR + CBC-MAC
* (`aes_ct` implementation).
*
* \param ctx context to initialise.
* \param key secret key.
* \param len secret key length (in bytes).
*/
void br_aes_ct_ctrcbc_init(br_aes_ct_ctrcbc_keys *ctx,
const void *key, size_t len);
/**
* \brief CBC encryption with AES (`aes_ct` implementation).
*
@ -882,6 +1302,52 @@ void br_aes_ct_cbcdec_run(const br_aes_ct_cbcdec_keys *ctx, void *iv,
uint32_t br_aes_ct_ctr_run(const br_aes_ct_ctr_keys *ctx,
const void *iv, uint32_t cc, void *data, size_t len);
/**
* \brief CTR encryption + CBC-MAC with AES (`aes_ct` implementation).
*
* \param ctx context (already initialised).
* \param ctr counter for CTR (16 bytes, updated).
* \param cbcmac IV for CBC-MAC (updated).
* \param data data to encrypt (updated).
* \param len data length (in bytes, MUST be a multiple of 16).
*/
void br_aes_ct_ctrcbc_encrypt(const br_aes_ct_ctrcbc_keys *ctx,
void *ctr, void *cbcmac, void *data, size_t len);
/**
* \brief CTR decryption + CBC-MAC with AES (`aes_ct` implementation).
*
* \param ctx context (already initialised).
* \param ctr counter for CTR (16 bytes, updated).
* \param cbcmac IV for CBC-MAC (updated).
* \param data data to decrypt (updated).
* \param len data length (in bytes, MUST be a multiple of 16).
*/
void br_aes_ct_ctrcbc_decrypt(const br_aes_ct_ctrcbc_keys *ctx,
void *ctr, void *cbcmac, void *data, size_t len);
/**
* \brief CTR encryption/decryption with AES (`aes_ct` implementation).
*
* \param ctx context (already initialised).
* \param ctr counter for CTR (16 bytes, updated).
* \param data data to MAC (updated).
* \param len data length (in bytes, MUST be a multiple of 16).
*/
void br_aes_ct_ctrcbc_ctr(const br_aes_ct_ctrcbc_keys *ctx,
void *ctr, void *data, size_t len);
/**
* \brief CBC-MAC with AES (`aes_ct` implementation).
*
* \param ctx context (already initialised).
* \param cbcmac IV for CBC-MAC (updated).
* \param data data to MAC (unmodified).
* \param len data length (in bytes, MUST be a multiple of 16).
*/
void br_aes_ct_ctrcbc_mac(const br_aes_ct_ctrcbc_keys *ctx,
void *cbcmac, const void *data, size_t len);
/*
* 64-bit constant-time AES implementation. It is similar to 'aes_ct'
* but uses 64-bit registers, making it about twice faster than 'aes_ct'
@ -940,6 +1406,22 @@ typedef struct {
#endif
} br_aes_ct64_ctr_keys;
/**
* \brief Context for AES subkeys (`aes_ct64` implementation, CTR encryption
* and decryption + CBC-MAC).
*
* First field is a pointer to the vtable; it is set by the initialisation
* function. Other fields are not supposed to be accessed by user code.
*/
typedef struct {
/** \brief Pointer to vtable for this context. */
const br_block_ctrcbc_class *vtable;
#ifndef BR_DOXYGEN_IGNORE
uint64_t skey[30];
unsigned num_rounds;
#endif
} br_aes_ct64_ctrcbc_keys;
/**
* \brief Class instance for AES CBC encryption (`aes_ct64` implementation).
*/
@ -956,6 +1438,12 @@ extern const br_block_cbcdec_class br_aes_ct64_cbcdec_vtable;
*/
extern const br_block_ctr_class br_aes_ct64_ctr_vtable;
/**
* \brief Class instance for AES CTR encryption/decryption + CBC-MAC
* (`aes_ct64` implementation).
*/
extern const br_block_ctrcbc_class br_aes_ct64_ctrcbc_vtable;
/**
* \brief Context initialisation (key schedule) for AES CBC encryption
* (`aes_ct64` implementation).
@ -989,6 +1477,17 @@ void br_aes_ct64_cbcdec_init(br_aes_ct64_cbcdec_keys *ctx,
void br_aes_ct64_ctr_init(br_aes_ct64_ctr_keys *ctx,
const void *key, size_t len);
/**
* \brief Context initialisation (key schedule) for AES CTR + CBC-MAC
* (`aes_ct64` implementation).
*
* \param ctx context to initialise.
* \param key secret key.
* \param len secret key length (in bytes).
*/
void br_aes_ct64_ctrcbc_init(br_aes_ct64_ctrcbc_keys *ctx,
const void *key, size_t len);
/**
* \brief CBC encryption with AES (`aes_ct64` implementation).
*
@ -1024,6 +1523,52 @@ void br_aes_ct64_cbcdec_run(const br_aes_ct64_cbcdec_keys *ctx, void *iv,
uint32_t br_aes_ct64_ctr_run(const br_aes_ct64_ctr_keys *ctx,
const void *iv, uint32_t cc, void *data, size_t len);
/**
* \brief CTR encryption + CBC-MAC with AES (`aes_ct64` implementation).
*
* \param ctx context (already initialised).
* \param ctr counter for CTR (16 bytes, updated).
* \param cbcmac IV for CBC-MAC (updated).
* \param data data to encrypt (updated).
* \param len data length (in bytes, MUST be a multiple of 16).
*/
void br_aes_ct64_ctrcbc_encrypt(const br_aes_ct64_ctrcbc_keys *ctx,
void *ctr, void *cbcmac, void *data, size_t len);
/**
* \brief CTR decryption + CBC-MAC with AES (`aes_ct64` implementation).
*
* \param ctx context (already initialised).
* \param ctr counter for CTR (16 bytes, updated).
* \param cbcmac IV for CBC-MAC (updated).
* \param data data to decrypt (updated).
* \param len data length (in bytes, MUST be a multiple of 16).
*/
void br_aes_ct64_ctrcbc_decrypt(const br_aes_ct64_ctrcbc_keys *ctx,
void *ctr, void *cbcmac, void *data, size_t len);
/**
* \brief CTR encryption/decryption with AES (`aes_ct64` implementation).
*
* \param ctx context (already initialised).
* \param ctr counter for CTR (16 bytes, updated).
* \param data data to MAC (updated).
* \param len data length (in bytes, MUST be a multiple of 16).
*/
void br_aes_ct64_ctrcbc_ctr(const br_aes_ct64_ctrcbc_keys *ctx,
void *ctr, void *data, size_t len);
/**
* \brief CBC-MAC with AES (`aes_ct64` implementation).
*
* \param ctx context (already initialised).
* \param cbcmac IV for CBC-MAC (updated).
* \param data data to MAC (unmodified).
* \param len data length (in bytes, MUST be a multiple of 16).
*/
void br_aes_ct64_ctrcbc_mac(const br_aes_ct64_ctrcbc_keys *ctx,
void *cbcmac, const void *data, size_t len);
/*
* AES implementation using AES-NI opcodes (x86 platform).
*/
@ -1083,6 +1628,24 @@ typedef struct {
#endif
} br_aes_x86ni_ctr_keys;
/**
* \brief Context for AES subkeys (`aes_x86ni` implementation, CTR encryption
* and decryption + CBC-MAC).
*
* First field is a pointer to the vtable; it is set by the initialisation
* function. Other fields are not supposed to be accessed by user code.
*/
typedef struct {
/** \brief Pointer to vtable for this context. */
const br_block_ctrcbc_class *vtable;
#ifndef BR_DOXYGEN_IGNORE
union {
unsigned char skni[16 * 15];
} skey;
unsigned num_rounds;
#endif
} br_aes_x86ni_ctrcbc_keys;
/**
* \brief Class instance for AES CBC encryption (`aes_x86ni` implementation).
*
@ -1111,6 +1674,16 @@ extern const br_block_cbcdec_class br_aes_x86ni_cbcdec_vtable;
*/
extern const br_block_ctr_class br_aes_x86ni_ctr_vtable;
/**
* \brief Class instance for AES CTR encryption/decryption + CBC-MAC
* (`aes_x86ni` implementation).
*
* Since this implementation might be omitted from the library, or the
* AES opcode unavailable on the current CPU, a pointer to this class
* instance should be obtained through `br_aes_x86ni_ctrcbc_get_vtable()`.
*/
extern const br_block_ctrcbc_class br_aes_x86ni_ctrcbc_vtable;
/**
* \brief Context initialisation (key schedule) for AES CBC encryption
* (`aes_x86ni` implementation).
@ -1144,6 +1717,17 @@ void br_aes_x86ni_cbcdec_init(br_aes_x86ni_cbcdec_keys *ctx,
void br_aes_x86ni_ctr_init(br_aes_x86ni_ctr_keys *ctx,
const void *key, size_t len);
/**
* \brief Context initialisation (key schedule) for AES CTR + CBC-MAC
* (`aes_x86ni` implementation).
*
* \param ctx context to initialise.
* \param key secret key.
* \param len secret key length (in bytes).
*/
void br_aes_x86ni_ctrcbc_init(br_aes_x86ni_ctrcbc_keys *ctx,
const void *key, size_t len);
/**
* \brief CBC encryption with AES (`aes_x86ni` implementation).
*
@ -1179,6 +1763,52 @@ void br_aes_x86ni_cbcdec_run(const br_aes_x86ni_cbcdec_keys *ctx, void *iv,
uint32_t br_aes_x86ni_ctr_run(const br_aes_x86ni_ctr_keys *ctx,
const void *iv, uint32_t cc, void *data, size_t len);
/**
* \brief CTR encryption + CBC-MAC with AES (`aes_x86ni` implementation).
*
* \param ctx context (already initialised).
* \param ctr counter for CTR (16 bytes, updated).
* \param cbcmac IV for CBC-MAC (updated).
* \param data data to encrypt (updated).
* \param len data length (in bytes, MUST be a multiple of 16).
*/
void br_aes_x86ni_ctrcbc_encrypt(const br_aes_x86ni_ctrcbc_keys *ctx,
void *ctr, void *cbcmac, void *data, size_t len);
/**
* \brief CTR decryption + CBC-MAC with AES (`aes_x86ni` implementation).
*
* \param ctx context (already initialised).
* \param ctr counter for CTR (16 bytes, updated).
* \param cbcmac IV for CBC-MAC (updated).
* \param data data to decrypt (updated).
* \param len data length (in bytes, MUST be a multiple of 16).
*/
void br_aes_x86ni_ctrcbc_decrypt(const br_aes_x86ni_ctrcbc_keys *ctx,
void *ctr, void *cbcmac, void *data, size_t len);
/**
* \brief CTR encryption/decryption with AES (`aes_x86ni` implementation).
*
* \param ctx context (already initialised).
* \param ctr counter for CTR (16 bytes, updated).
* \param data data to MAC (updated).
* \param len data length (in bytes, MUST be a multiple of 16).
*/
void br_aes_x86ni_ctrcbc_ctr(const br_aes_x86ni_ctrcbc_keys *ctx,
void *ctr, void *data, size_t len);
/**
* \brief CBC-MAC with AES (`aes_x86ni` implementation).
*
* \param ctx context (already initialised).
* \param cbcmac IV for CBC-MAC (updated).
* \param data data to MAC (unmodified).
* \param len data length (in bytes, MUST be a multiple of 16).
*/
void br_aes_x86ni_ctrcbc_mac(const br_aes_x86ni_ctrcbc_keys *ctx,
void *cbcmac, const void *data, size_t len);
/**
* \brief Obtain the `aes_x86ni` AES-CBC (encryption) implementation, if
* available.
@ -1188,7 +1818,7 @@ uint32_t br_aes_x86ni_ctr_run(const br_aes_x86ni_ctr_keys *ctx,
* opcodes are available on the currently running CPU. If either of
* these conditions is not met, then this function returns `NULL`.
*
* \return the `aes_x868ni` AES-CBC (encryption) implementation, or `NULL`.
* \return the `aes_x86ni` AES-CBC (encryption) implementation, or `NULL`.
*/
const br_block_cbcenc_class *br_aes_x86ni_cbcenc_get_vtable(void);
@ -1201,7 +1831,7 @@ const br_block_cbcenc_class *br_aes_x86ni_cbcenc_get_vtable(void);
* opcodes are available on the currently running CPU. If either of
* these conditions is not met, then this function returns `NULL`.
*
* \return the `aes_x868ni` AES-CBC (decryption) implementation, or `NULL`.
* \return the `aes_x86ni` AES-CBC (decryption) implementation, or `NULL`.
*/
const br_block_cbcdec_class *br_aes_x86ni_cbcdec_get_vtable(void);
@ -1213,10 +1843,23 @@ const br_block_cbcdec_class *br_aes_x86ni_cbcdec_get_vtable(void);
* opcodes are available on the currently running CPU. If either of
* these conditions is not met, then this function returns `NULL`.
*
* \return the `aes_x868ni` AES-CTR implementation, or `NULL`.
* \return the `aes_x86ni` AES-CTR implementation, or `NULL`.
*/
const br_block_ctr_class *br_aes_x86ni_ctr_get_vtable(void);
/**
* \brief Obtain the `aes_x86ni` AES-CTR + CBC-MAC implementation, if
* available.
*
* This function returns a pointer to `br_aes_x86ni_ctrcbc_vtable`, if
* that implementation was compiled in the library _and_ the x86 AES
* opcodes are available on the currently running CPU. If either of
* these conditions is not met, then this function returns `NULL`.
*
* \return the `aes_x86ni` AES-CTR implementation, or `NULL`.
*/
const br_block_ctrcbc_class *br_aes_x86ni_ctrcbc_get_vtable(void);
/*
* AES implementation using POWER8 opcodes.
*/
@ -1452,6 +2095,22 @@ typedef union {
br_aes_pwr8_ctr_keys c_pwr8;
} br_aes_gen_ctr_keys;
/**
* \brief Aggregate structure large enough to be used as context for
* subkeys (CTR encryption/decryption + CBC-MAC) for all AES implementations.
*/
typedef union {
const br_block_ctrcbc_class *vtable;
br_aes_big_ctrcbc_keys c_big;
br_aes_small_ctrcbc_keys c_small;
br_aes_ct_ctrcbc_keys c_ct;
br_aes_ct64_ctrcbc_keys c_ct64;
/* FIXME
br_aes_x86ni_ctrcbc_keys c_x86ni;
br_aes_pwr8_ctrcbc_keys c_pwr8;
*/
} br_aes_gen_ctrcbc_keys;
/*
* Traditional, table-based implementation for DES/3DES. Since tables are
* used, cache-timing attacks are conceptually possible.

File diff suppressed because one or more lines are too long

View File

@ -50,6 +50,8 @@ set -e
# Source files. Please keep in alphabetical order.
coresrc=" \
src/settings.c \
src/aead/ccm.c \
src/aead/eax.c \
src/aead/gcm.c \
src/codec/ccopy.c \
src/codec/dec16be.c \
@ -231,6 +233,7 @@ coresrc=" \
src/symcipher/aes_big_cbcdec.c \
src/symcipher/aes_big_cbcenc.c \
src/symcipher/aes_big_ctr.c \
src/symcipher/aes_big_ctrcbc.c \
src/symcipher/aes_big_dec.c \
src/symcipher/aes_big_enc.c \
src/symcipher/aes_common.c \
@ -239,11 +242,13 @@ coresrc=" \
src/symcipher/aes_ct64_cbcdec.c \
src/symcipher/aes_ct64_cbcenc.c \
src/symcipher/aes_ct64_ctr.c \
src/symcipher/aes_ct64_ctrcbc.c \
src/symcipher/aes_ct64_dec.c \
src/symcipher/aes_ct64_enc.c \
src/symcipher/aes_ct_cbcdec.c \
src/symcipher/aes_ct_cbcenc.c \
src/symcipher/aes_ct_ctr.c \
src/symcipher/aes_ct_ctrcbc.c \
src/symcipher/aes_ct_dec.c \
src/symcipher/aes_ct_enc.c \
src/symcipher/aes_pwr8.c \
@ -253,12 +258,14 @@ coresrc=" \
src/symcipher/aes_small_cbcdec.c \
src/symcipher/aes_small_cbcenc.c \
src/symcipher/aes_small_ctr.c \
src/symcipher/aes_small_ctrcbc.c \
src/symcipher/aes_small_dec.c \
src/symcipher/aes_small_enc.c \
src/symcipher/aes_x86ni.c \
src/symcipher/aes_x86ni_cbcdec.c \
src/symcipher/aes_x86ni_cbcenc.c \
src/symcipher/aes_x86ni_ctr.c \
src/symcipher/aes_x86ni_ctrcbc.c \
src/symcipher/chacha20_ct.c \
src/symcipher/chacha20_sse2.c \
src/symcipher/des_ct.c \

346
src/aead/ccm.c Normal file
View File

@ -0,0 +1,346 @@
/*
* Copyright (c) 2017 Thomas Pornin <pornin@bolet.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.
*/
#include "inner.h"
/*
* Implementation Notes
* ====================
*
* The combined CTR + CBC-MAC functions can only handle full blocks,
* so some buffering is necessary.
*
* - 'ptr' contains a value from 0 to 15, which is the number of bytes
* accumulated in buf[] that still needs to be processed with the
* current CBC-MAC computation.
*
* - When processing the message itself, CTR encryption/decryption is
* also done at the same time. The first 'ptr' bytes of buf[] then
* contains the plaintext bytes, while the last '16 - ptr' bytes of
* buf[] are the remnants of the stream block, to be used against
* the next input bytes, when available. When 'ptr' is 0, the
* contents of buf[] are to be ignored.
*
* - The current counter and running CBC-MAC values are kept in 'ctr'
* and 'cbcmac', respectively.
*/
/* see bearssl_block.h */
void
br_ccm_init(br_ccm_context *ctx, const br_block_ctrcbc_class **bctx)
{
ctx->bctx = bctx;
}
/* see bearssl_block.h */
int
br_ccm_reset(br_ccm_context *ctx, const void *nonce, size_t nonce_len,
uint64_t aad_len, uint64_t data_len, size_t tag_len)
{
unsigned char tmp[16];
unsigned u, q;
if (nonce_len < 7 || nonce_len > 13) {
return 0;
}
if (tag_len < 4 || tag_len > 16 || (tag_len & 1) != 0) {
return 0;
}
q = 15 - (unsigned)nonce_len;
ctx->tag_len = tag_len;
/*
* Block B0, to start CBC-MAC.
*/
tmp[0] = (aad_len > 0 ? 0x40 : 0x00)
| (((unsigned)tag_len - 2) << 2)
| (q - 1);
memcpy(tmp + 1, nonce, nonce_len);
for (u = 0; u < q; u ++) {
tmp[15 - u] = (unsigned char)data_len;
data_len >>= 8;
}
if (data_len != 0) {
/*
* If the data length was not entirely consumed in the
* loop above, then it exceeds the maximum limit of
* q bytes (when encoded).
*/
return 0;
}
/*
* Start CBC-MAC.
*/
memset(ctx->cbcmac, 0, sizeof ctx->cbcmac);
(*ctx->bctx)->mac(ctx->bctx, ctx->cbcmac, tmp, sizeof tmp);
/*
* Assemble AAD length header.
*/
if ((aad_len >> 32) != 0) {
ctx->buf[0] = 0xFF;
ctx->buf[1] = 0xFF;
br_enc64be(ctx->buf + 2, aad_len);
ctx->ptr = 10;
} else if (aad_len >= 0xFF00) {
ctx->buf[0] = 0xFF;
ctx->buf[1] = 0xFE;
br_enc32be(ctx->buf + 2, (uint32_t)aad_len);
ctx->ptr = 6;
} else if (aad_len > 0) {
br_enc16be(ctx->buf, (unsigned)aad_len);
ctx->ptr = 2;
} else {
ctx->ptr = 0;
}
/*
* Make initial counter value and compute tag mask.
*/
ctx->ctr[0] = q - 1;
memcpy(ctx->ctr + 1, nonce, nonce_len);
memset(ctx->ctr + 1 + nonce_len, 0, q);
memset(ctx->tagmask, 0, sizeof ctx->tagmask);
(*ctx->bctx)->ctr(ctx->bctx, ctx->ctr,
ctx->tagmask, sizeof ctx->tagmask);
return 1;
}
/* see bearssl_block.h */
void
br_ccm_aad_inject(br_ccm_context *ctx, const void *data, size_t len)
{
const unsigned char *dbuf;
size_t ptr;
dbuf = data;
/*
* Complete partial block, if needed.
*/
ptr = ctx->ptr;
if (ptr != 0) {
size_t clen;
clen = (sizeof ctx->buf) - ptr;
if (clen > len) {
memcpy(ctx->buf + ptr, dbuf, len);
ctx->ptr = ptr + len;
return;
}
memcpy(ctx->buf + ptr, dbuf, clen);
dbuf += clen;
len -= clen;
(*ctx->bctx)->mac(ctx->bctx, ctx->cbcmac,
ctx->buf, sizeof ctx->buf);
}
/*
* Process complete blocks.
*/
ptr = len & 15;
len -= ptr;
(*ctx->bctx)->mac(ctx->bctx, ctx->cbcmac, dbuf, len);
dbuf += len;
/*
* Copy last partial block in the context buffer.
*/
memcpy(ctx->buf, dbuf, ptr);
ctx->ptr = ptr;
}
/* see bearssl_block.h */
void
br_ccm_flip(br_ccm_context *ctx)
{
size_t ptr;
/*
* Complete AAD partial block with zeros, if necessary.
*/
ptr = ctx->ptr;
if (ptr != 0) {
memset(ctx->buf + ptr, 0, (sizeof ctx->buf) - ptr);
(*ctx->bctx)->mac(ctx->bctx, ctx->cbcmac,
ctx->buf, sizeof ctx->buf);
ctx->ptr = 0;
}
/*
* Counter was already set by br_ccm_reset().
*/
}
/* see bearssl_block.h */
void
br_ccm_run(br_ccm_context *ctx, int encrypt, void *data, size_t len)
{
unsigned char *dbuf;
size_t ptr;
dbuf = data;
/*
* Complete a partial block, if any: ctx->buf[] contains
* ctx->ptr plaintext bytes (already reported), and the other
* bytes are CTR stream output.
*/
ptr = ctx->ptr;
if (ptr != 0) {
size_t clen;
size_t u;
clen = (sizeof ctx->buf) - ptr;
if (clen > len) {
clen = len;
}
if (encrypt) {
for (u = 0; u < clen; u ++) {
unsigned w, x;
w = ctx->buf[ptr + u];
x = dbuf[u];
ctx->buf[ptr + u] = x;
dbuf[u] = w ^ x;
}
} else {
for (u = 0; u < clen; u ++) {
unsigned w;
w = ctx->buf[ptr + u] ^ dbuf[u];
dbuf[u] = w;
ctx->buf[ptr + u] = w;
}
}
dbuf += clen;
len -= clen;
ptr += clen;
if (ptr < sizeof ctx->buf) {
ctx->ptr = ptr;
return;
}
(*ctx->bctx)->mac(ctx->bctx,
ctx->cbcmac, ctx->buf, sizeof ctx->buf);
}
/*
* Process all complete blocks. Note that the ctrcbc API is for
* encrypt-then-MAC (CBC-MAC is computed over the encrypted
* blocks) while CCM uses MAC-and-encrypt (CBC-MAC is computed
* over the plaintext blocks). Therefore, we need to use the
* _decryption_ function for encryption, and the encryption
* function for decryption (this works because CTR encryption
* and decryption are identical, so the choice really is about
* computing the CBC-MAC before or after XORing with the CTR
* stream).
*/
ptr = len & 15;
len -= ptr;
if (encrypt) {
(*ctx->bctx)->decrypt(ctx->bctx, ctx->ctr, ctx->cbcmac,
dbuf, len);
} else {
(*ctx->bctx)->encrypt(ctx->bctx, ctx->ctr, ctx->cbcmac,
dbuf, len);
}
dbuf += len;
/*
* If there is some remaining data, then we need to compute an
* extra block of CTR stream.
*/
if (ptr != 0) {
size_t u;
memset(ctx->buf, 0, sizeof ctx->buf);
(*ctx->bctx)->ctr(ctx->bctx, ctx->ctr,
ctx->buf, sizeof ctx->buf);
if (encrypt) {
for (u = 0; u < ptr; u ++) {
unsigned w, x;
w = ctx->buf[u];
x = dbuf[u];
ctx->buf[u] = x;
dbuf[u] = w ^ x;
}
} else {
for (u = 0; u < ptr; u ++) {
unsigned w;
w = ctx->buf[u] ^ dbuf[u];
dbuf[u] = w;
ctx->buf[u] = w;
}
}
}
ctx->ptr = ptr;
}
/* see bearssl_block.h */
size_t
br_ccm_get_tag(br_ccm_context *ctx, void *tag)
{
size_t ptr;
size_t u;
/*
* If there is some buffered data, then we need to pad it with
* zeros and finish up CBC-MAC.
*/
ptr = ctx->ptr;
if (ptr != 0) {
memset(ctx->buf + ptr, 0, (sizeof ctx->buf) - ptr);
(*ctx->bctx)->mac(ctx->bctx, ctx->cbcmac,
ctx->buf, sizeof ctx->buf);
}
/*
* XOR the tag mask into the CBC-MAC output.
*/
for (u = 0; u < ctx->tag_len; u ++) {
ctx->cbcmac[u] ^= ctx->tagmask[u];
}
memcpy(tag, ctx->cbcmac, ctx->tag_len);
return ctx->tag_len;
}
/* see bearssl_block.h */
uint32_t
br_ccm_check_tag(br_ccm_context *ctx, const void *tag)
{
unsigned char tmp[16];
size_t u, tag_len;
uint32_t z;
tag_len = br_ccm_get_tag(ctx, tmp);
z = 0;
for (u = 0; u < tag_len; u ++) {
z |= tmp[u] ^ ((const unsigned char *)tag)[u];
}
return EQ0(z);
}

413
src/aead/eax.c Normal file
View File

@ -0,0 +1,413 @@
/*
* Copyright (c) 2017 Thomas Pornin <pornin@bolet.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.
*/
#include "inner.h"
/*
* Implementation Notes
* ====================
*
* The combined CTR + CBC-MAC functions can only handle full blocks,
* so some buffering is necessary. Moreover, EAX has a special padding
* rule for CBC-MAC, which implies that we cannot compute the MAC over
* the last received full block until we know whether we are at the
* end of the data or not.
*
* - 'ptr' contains a value from 1 to 16, which is the number of bytes
* accumulated in buf[] that still needs to be processed with the
* current OMAC computation. Beware that this can go to 16: a
* complete block cannot be processed until it is known whether it
* is the last block or not. However, it can never be 0, because
* OMAC^t works on an input that is at least one-block long.
*
* - When processing the message itself, CTR encryption/decryption is
* also done at the same time. The first 'ptr' bytes of buf[] then
* contains the encrypted bytes, while the last '16 - ptr' bytes of
* buf[] are the remnants of the stream block, to be used against
* the next input bytes, when available.
*
* - The current counter and running CBC-MAC values are kept in 'ctr'
* and 'cbcmac', respectively.
*
* - The derived keys for padding are kept in L2 and L4 (double and
* quadruple of Enc_K(0^n), in GF(2^128), respectively).
*/
/*
* Start an OMAC computation; the first block is the big-endian
* representation of the provided value ('val' must fit on one byte).
* We make it a delayed block because it may also be the last one,
*/
static void
omac_start(br_eax_context *ctx, unsigned val)
{
memset(ctx->cbcmac, 0, sizeof ctx->cbcmac);
memset(ctx->buf, 0, sizeof ctx->buf);
ctx->buf[15] = val;
ctx->ptr = 16;
}
/*
* Double a value in finite field GF(2^128), defined with modulus
* X^128+X^7+X^2+X+1.
*/
static void
double_gf128(unsigned char *dst, const unsigned char *src)
{
unsigned cc;
int i;
cc = 0x87 & -((unsigned)src[0] >> 7);
for (i = 15; i >= 0; i --) {
unsigned z;
z = (src[i] << 1) ^ cc;
cc = z >> 8;
dst[i] = (unsigned char)z;
}
}
/*
* Apply padding to the last block, currently in ctx->buf (with
* ctx->ptr bytes), and finalize OMAC computation.
*/
static void
do_pad(br_eax_context *ctx)
{
unsigned char *pad;
size_t ptr, u;
ptr = ctx->ptr;
if (ptr == 16) {
pad = ctx->L2;
} else {
ctx->buf[ptr ++] = 0x80;
memset(ctx->buf + ptr, 0x00, 16 - ptr);
pad = ctx->L4;
}
for (u = 0; u < sizeof ctx->buf; u ++) {
ctx->buf[u] ^= pad[u];
}
(*ctx->bctx)->mac(ctx->bctx, ctx->cbcmac, ctx->buf, sizeof ctx->buf);
}
/*
* Apply CBC-MAC on the provided data, with buffering management. This
* function assumes that on input, ctx->buf contains a full block of
* unprocessed data.
*/
static void
do_cbcmac_chunk(br_eax_context *ctx, const void *data, size_t len)
{
size_t ptr;
if (len == 0) {
return;
}
ptr = len & (size_t)15;
if (ptr == 0) {
len -= 16;
ptr = 16;
} else {
len -= ptr;
}
(*ctx->bctx)->mac(ctx->bctx, ctx->cbcmac, ctx->buf, sizeof ctx->buf);
(*ctx->bctx)->mac(ctx->bctx, ctx->cbcmac, data, len);
memcpy(ctx->buf, (const unsigned char *)data + len, ptr);
ctx->ptr = ptr;
}
/* see bearssl_aead.h */
void
br_eax_init(br_eax_context *ctx, const br_block_ctrcbc_class **bctx)
{
unsigned char tmp[16], iv[16];
ctx->vtable = &br_eax_vtable;
ctx->bctx = bctx;
/*
* Encrypt a whole-zero block to compute L2 and L4.
*/
memset(tmp, 0, sizeof tmp);
memset(iv, 0, sizeof iv);
(*bctx)->ctr(bctx, iv, tmp, sizeof tmp);
double_gf128(ctx->L2, tmp);
double_gf128(ctx->L4, ctx->L2);
}
/* see bearssl_aead.h */
void
br_eax_reset(br_eax_context *ctx, const void *nonce, size_t len)
{
/*
* Process nonce with OMAC^0.
*/
omac_start(ctx, 0);
do_cbcmac_chunk(ctx, nonce, len);
do_pad(ctx);
memcpy(ctx->nonce, ctx->cbcmac, sizeof ctx->cbcmac);
/*
* Start OMAC^1 for the AAD ("header" in the EAX specification).
*/
omac_start(ctx, 1);
}
/* see bearssl_aead.h */
void
br_eax_aad_inject(br_eax_context *ctx, const void *data, size_t len)
{
size_t ptr;
ptr = ctx->ptr;
/*
* If there is a partial block, first complete it.
*/
if (ptr < 16) {
size_t clen;
clen = 16 - ptr;
if (len <= clen) {
memcpy(ctx->buf + ptr, data, len);
ctx->ptr = ptr + len;
return;
}
memcpy(ctx->buf + ptr, data, clen);
data = (const unsigned char *)data + clen;
len -= clen;
}
/*
* We now have a full block in buf[], and this is not the last
* block.
*/
do_cbcmac_chunk(ctx, data, len);
}
/* see bearssl_aead.h */
void
br_eax_flip(br_eax_context *ctx)
{
/*
* Complete the OMAC computation on the AAD.
*/
do_pad(ctx);
memcpy(ctx->head, ctx->cbcmac, sizeof ctx->cbcmac);
/*
* Start OMAC^2 for the encrypted data.
*/
omac_start(ctx, 2);
/*
* Initial counter value for CTR is the processed nonce.
*/
memcpy(ctx->ctr, ctx->nonce, sizeof ctx->nonce);
}
/* see bearssl_aead.h */
void
br_eax_run(br_eax_context *ctx, int encrypt, void *data, size_t len)
{
unsigned char *dbuf;
size_t ptr;
/*
* Ensure that there is actual data to process.
*/
if (len == 0) {
return;
}
dbuf = data;
ptr = ctx->ptr;
if (ptr != 16) {
/*
* We have a partially consumed block.
*/
size_t u, clen;
clen = 16 - ptr;
if (len <= clen) {
clen = len;
}
if (encrypt) {
for (u = 0; u < clen; u ++) {
ctx->buf[ptr + u] ^= dbuf[u];
}
memcpy(dbuf, ctx->buf + ptr, clen);
} else {
for (u = 0; u < clen; u ++) {
unsigned dx, sx;
sx = ctx->buf[ptr + u];
dx = dbuf[u];
ctx->buf[ptr + u] = dx;
dbuf[u] = sx ^ dx;
}
}
if (len <= clen) {
ctx->ptr = ptr + clen;
return;
}
dbuf += clen;
len -= clen;
}
/*
* We now have a complete encrypted block in buf[] that must still
* be processed with OMAC, and this is not the final buf.
*/
(*ctx->bctx)->mac(ctx->bctx, ctx->cbcmac, ctx->buf, sizeof ctx->buf);
/*
* Do CTR encryption or decryption and CBC-MAC for all full blocks
* except the last.
*/
ptr = len & (size_t)15;
if (ptr == 0) {
len -= 16;
ptr = 16;
} else {
len -= ptr;
}
if (encrypt) {
(*ctx->bctx)->encrypt(ctx->bctx, ctx->ctr, ctx->cbcmac,
dbuf, len);
} else {
(*ctx->bctx)->decrypt(ctx->bctx, ctx->ctr, ctx->cbcmac,
dbuf, len);
}
dbuf += len;
/*
* Compute next block of CTR stream, and use it to finish
* encrypting or decrypting the data.
*/
memset(ctx->buf, 0, sizeof ctx->buf);
(*ctx->bctx)->ctr(ctx->bctx, ctx->ctr, ctx->buf, sizeof ctx->buf);
if (encrypt) {
size_t u;
for (u = 0; u < ptr; u ++) {
ctx->buf[u] ^= dbuf[u];
}
memcpy(dbuf, ctx->buf, ptr);
} else {
size_t u;
for (u = 0; u < ptr; u ++) {
unsigned dx, sx;
sx = ctx->buf[u];
dx = dbuf[u];
ctx->buf[u] = dx;
dbuf[u] = sx ^ dx;
}
}
ctx->ptr = ptr;
}
/*
* Complete tag computation. The final tag is written in ctx->cbcmac.
*/
static void
do_final(br_eax_context *ctx)
{
size_t u;
do_pad(ctx);
/*
* Authentication tag is the XOR of the three OMAC outputs for
* the nonce, AAD and encrypted data.
*/
for (u = 0; u < 16; u ++) {
ctx->cbcmac[u] ^= ctx->nonce[u] ^ ctx->head[u];
}
}
/* see bearssl_aead.h */
void
br_eax_get_tag(br_eax_context *ctx, void *tag)
{
do_final(ctx);
memcpy(tag, ctx->cbcmac, sizeof ctx->cbcmac);
}
/* see bearssl_aead.h */
void
br_eax_get_tag_trunc(br_eax_context *ctx, void *tag, size_t len)
{
do_final(ctx);
memcpy(tag, ctx->cbcmac, len);
}
/* see bearssl_aead.h */
uint32_t
br_eax_check_tag_trunc(br_eax_context *ctx, const void *tag, size_t len)
{
unsigned char tmp[16];
size_t u;
int x;
br_eax_get_tag(ctx, tmp);
x = 0;
for (u = 0; u < len; u ++) {
x |= tmp[u] ^ ((const unsigned char *)tag)[u];
}
return EQ0(x);
}
/* see bearssl_aead.h */
uint32_t
br_eax_check_tag(br_eax_context *ctx, const void *tag)
{
return br_eax_check_tag_trunc(ctx, tag, 16);
}
/* see bearssl_aead.h */
const br_aead_class br_eax_vtable = {
16,
(void (*)(const br_aead_class **, const void *, size_t))
&br_eax_reset,
(void (*)(const br_aead_class **, const void *, size_t))
&br_eax_aad_inject,
(void (*)(const br_aead_class **))
&br_eax_flip,
(void (*)(const br_aead_class **, int, void *, size_t))
&br_eax_run,
(void (*)(const br_aead_class **, void *))
&br_eax_get_tag,
(uint32_t (*)(const br_aead_class **, const void *))
&br_eax_check_tag,
(void (*)(const br_aead_class **, void *, size_t))
&br_eax_get_tag_trunc,
(uint32_t (*)(const br_aead_class **, const void *, size_t))
&br_eax_check_tag_trunc
};

View File

@ -56,6 +56,7 @@ br_gcm_init(br_gcm_context *ctx, const br_block_ctr_class **bctx, br_ghash gh)
{
unsigned char iv[12];
ctx->vtable = &br_gcm_vtable;
ctx->bctx = bctx;
ctx->gh = gh;
@ -262,9 +263,19 @@ br_gcm_get_tag(br_gcm_context *ctx, void *tag)
(*ctx->bctx)->run(ctx->bctx, ctx->j0_1, ctx->j0_2, tag, 16);
}
/* see bearssl_aead.h */
void
br_gcm_get_tag_trunc(br_gcm_context *ctx, void *tag, size_t len)
{
unsigned char tmp[16];
br_gcm_get_tag(ctx, tmp);
memcpy(tag, tmp, len);
}
/* see bearssl_aead.h */
uint32_t
br_gcm_check_tag(br_gcm_context *ctx, const void *tag)
br_gcm_check_tag_trunc(br_gcm_context *ctx, const void *tag, size_t len)
{
unsigned char tmp[16];
size_t u;
@ -272,12 +283,19 @@ br_gcm_check_tag(br_gcm_context *ctx, const void *tag)
br_gcm_get_tag(ctx, tmp);
x = 0;
for (u = 0; u < sizeof tmp; u ++) {
for (u = 0; u < len; u ++) {
x |= tmp[u] ^ ((const unsigned char *)tag)[u];
}
return EQ0(x);
}
/* see bearssl_aead.h */
uint32_t
br_gcm_check_tag(br_gcm_context *ctx, const void *tag)
{
return br_gcm_check_tag_trunc(ctx, tag, 16);
}
/* see bearssl_aead.h */
const br_aead_class br_gcm_vtable = {
16,
@ -292,5 +310,9 @@ const br_aead_class br_gcm_vtable = {
(void (*)(const br_aead_class **, void *))
&br_gcm_get_tag,
(uint32_t (*)(const br_aead_class **, const void *))
&br_gcm_check_tag
&br_gcm_check_tag,
(void (*)(const br_aead_class **, void *, size_t))
&br_gcm_get_tag_trunc,
(uint32_t (*)(const br_aead_class **, const void *, size_t))
&br_gcm_check_tag_trunc
};

View File

@ -0,0 +1,142 @@
/*
* Copyright (c) 2017 Thomas Pornin <pornin@bolet.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.
*/
#include "inner.h"
/* see bearssl_block.h */
void
br_aes_big_ctrcbc_init(br_aes_big_ctrcbc_keys *ctx,
const void *key, size_t len)
{
ctx->vtable = &br_aes_big_ctrcbc_vtable;
ctx->num_rounds = br_aes_keysched(ctx->skey, key, len);
}
static void
xorbuf(void *dst, const void *src, size_t len)
{
unsigned char *d;
const unsigned char *s;
d = dst;
s = src;
while (len -- > 0) {
*d ++ ^= *s ++;
}
}
/* see bearssl_block.h */
void
br_aes_big_ctrcbc_ctr(const br_aes_big_ctrcbc_keys *ctx,
void *ctr, void *data, size_t len)
{
unsigned char *buf, *bctr;
uint32_t cc0, cc1, cc2, cc3;
buf = data;
bctr = ctr;
cc3 = br_dec32be(bctr + 0);
cc2 = br_dec32be(bctr + 4);
cc1 = br_dec32be(bctr + 8);
cc0 = br_dec32be(bctr + 12);
while (len > 0) {
unsigned char tmp[16];
uint32_t carry;
br_enc32be(tmp + 0, cc3);
br_enc32be(tmp + 4, cc2);
br_enc32be(tmp + 8, cc1);
br_enc32be(tmp + 12, cc0);
br_aes_big_encrypt(ctx->num_rounds, ctx->skey, tmp);
xorbuf(buf, tmp, 16);
buf += 16;
len -= 16;
cc0 ++;
carry = (~(cc0 | -cc0)) >> 31;
cc1 += carry;
carry &= (~(cc1 | -cc1)) >> 31;
cc2 += carry;
carry &= (~(cc2 | -cc2)) >> 31;
cc3 += carry;
}
br_enc32be(bctr + 0, cc3);
br_enc32be(bctr + 4, cc2);
br_enc32be(bctr + 8, cc1);
br_enc32be(bctr + 12, cc0);
}
/* see bearssl_block.h */
void
br_aes_big_ctrcbc_mac(const br_aes_big_ctrcbc_keys *ctx,
void *cbcmac, const void *data, size_t len)
{
const unsigned char *buf;
buf = data;
while (len > 0) {
xorbuf(cbcmac, buf, 16);
br_aes_big_encrypt(ctx->num_rounds, ctx->skey, cbcmac);
buf += 16;
len -= 16;
}
}
/* see bearssl_block.h */
void
br_aes_big_ctrcbc_encrypt(const br_aes_big_ctrcbc_keys *ctx,
void *ctr, void *cbcmac, void *data, size_t len)
{
br_aes_big_ctrcbc_ctr(ctx, ctr, data, len);
br_aes_big_ctrcbc_mac(ctx, cbcmac, data, len);
}
/* see bearssl_block.h */
void
br_aes_big_ctrcbc_decrypt(const br_aes_big_ctrcbc_keys *ctx,
void *ctr, void *cbcmac, void *data, size_t len)
{
br_aes_big_ctrcbc_mac(ctx, cbcmac, data, len);
br_aes_big_ctrcbc_ctr(ctx, ctr, data, len);
}
/* see bearssl_block.h */
const br_block_ctrcbc_class br_aes_big_ctrcbc_vtable = {
sizeof(br_aes_big_ctrcbc_keys),
16,
4,
(void (*)(const br_block_ctrcbc_class **, const void *, size_t))
&br_aes_big_ctrcbc_init,
(void (*)(const br_block_ctrcbc_class *const *,
void *, void *, void *, size_t))
&br_aes_big_ctrcbc_encrypt,
(void (*)(const br_block_ctrcbc_class *const *,
void *, void *, void *, size_t))
&br_aes_big_ctrcbc_decrypt,
(void (*)(const br_block_ctrcbc_class *const *,
void *, void *, size_t))
&br_aes_big_ctrcbc_ctr,
(void (*)(const br_block_ctrcbc_class *const *,
void *, const void *, size_t))
&br_aes_big_ctrcbc_mac
};

View File

@ -0,0 +1,433 @@
/*
* Copyright (c) 2017 Thomas Pornin <pornin@bolet.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.
*/
#include "inner.h"
/* see bearssl_block.h */
void
br_aes_ct64_ctrcbc_init(br_aes_ct64_ctrcbc_keys *ctx,
const void *key, size_t len)
{
ctx->vtable = &br_aes_ct64_ctrcbc_vtable;
ctx->num_rounds = br_aes_ct64_keysched(ctx->skey, key, len);
}
static void
xorbuf(void *dst, const void *src, size_t len)
{
unsigned char *d;
const unsigned char *s;
d = dst;
s = src;
while (len -- > 0) {
*d ++ ^= *s ++;
}
}
/* see bearssl_block.h */
void
br_aes_ct64_ctrcbc_ctr(const br_aes_ct64_ctrcbc_keys *ctx,
void *ctr, void *data, size_t len)
{
unsigned char *buf;
unsigned char *ivbuf;
uint32_t iv0, iv1, iv2, iv3;
uint64_t sk_exp[120];
br_aes_ct64_skey_expand(sk_exp, ctx->num_rounds, ctx->skey);
/*
* We keep the counter as four 32-bit values, with big-endian
* convention, because that's what is expected for purposes of
* incrementing the counter value.
*/
ivbuf = ctr;
iv0 = br_dec32be(ivbuf + 0);
iv1 = br_dec32be(ivbuf + 4);
iv2 = br_dec32be(ivbuf + 8);
iv3 = br_dec32be(ivbuf + 12);
buf = data;
while (len > 0) {
uint64_t q[8];
uint32_t w[16];
unsigned char tmp[64];
int i, j;
/*
* The bitslice implementation expects values in
* little-endian convention, so we have to byteswap them.
*/
j = (len >= 64) ? 16 : (int)(len >> 2);
for (i = 0; i < j; i += 4) {
uint32_t carry;
w[i + 0] = br_swap32(iv0);
w[i + 1] = br_swap32(iv1);
w[i + 2] = br_swap32(iv2);
w[i + 3] = br_swap32(iv3);
iv3 ++;
carry = ~(iv3 | -iv3) >> 31;
iv2 += carry;
carry &= -(~(iv2 | -iv2) >> 31);
iv1 += carry;
carry &= -(~(iv1 | -iv1) >> 31);
iv0 += carry;
}
memset(w + i, 0, (16 - i) * sizeof(uint32_t));
for (i = 0; i < 4; i ++) {
br_aes_ct64_interleave_in(
&q[i], &q[i + 4], w + (i << 2));
}
br_aes_ct64_ortho(q);
br_aes_ct64_bitslice_encrypt(ctx->num_rounds, sk_exp, q);
br_aes_ct64_ortho(q);
for (i = 0; i < 4; i ++) {
br_aes_ct64_interleave_out(
w + (i << 2), q[i], q[i + 4]);
}
br_range_enc32le(tmp, w, 16);
if (len <= 64) {
xorbuf(buf, tmp, len);
break;
}
xorbuf(buf, tmp, 64);
buf += 64;
len -= 64;
}
br_enc32be(ivbuf + 0, iv0);
br_enc32be(ivbuf + 4, iv1);
br_enc32be(ivbuf + 8, iv2);
br_enc32be(ivbuf + 12, iv3);
}
/* see bearssl_block.h */
void
br_aes_ct64_ctrcbc_mac(const br_aes_ct64_ctrcbc_keys *ctx,
void *cbcmac, const void *data, size_t len)
{
const unsigned char *buf;
uint32_t cm0, cm1, cm2, cm3;
uint64_t q[8];
uint64_t sk_exp[120];
br_aes_ct64_skey_expand(sk_exp, ctx->num_rounds, ctx->skey);
cm0 = br_dec32le((unsigned char *)cbcmac + 0);
cm1 = br_dec32le((unsigned char *)cbcmac + 4);
cm2 = br_dec32le((unsigned char *)cbcmac + 8);
cm3 = br_dec32le((unsigned char *)cbcmac + 12);
buf = data;
memset(q, 0, sizeof q);
while (len > 0) {
uint32_t w[4];
w[0] = cm0 ^ br_dec32le(buf + 0);
w[1] = cm1 ^ br_dec32le(buf + 4);
w[2] = cm2 ^ br_dec32le(buf + 8);
w[3] = cm3 ^ br_dec32le(buf + 12);
br_aes_ct64_interleave_in(&q[0], &q[4], w);
br_aes_ct64_ortho(q);
br_aes_ct64_bitslice_encrypt(ctx->num_rounds, sk_exp, q);
br_aes_ct64_ortho(q);
br_aes_ct64_interleave_out(w, q[0], q[4]);
cm0 = w[0];
cm1 = w[1];
cm2 = w[2];
cm3 = w[3];
buf += 16;
len -= 16;
}
br_enc32le((unsigned char *)cbcmac + 0, cm0);
br_enc32le((unsigned char *)cbcmac + 4, cm1);
br_enc32le((unsigned char *)cbcmac + 8, cm2);
br_enc32le((unsigned char *)cbcmac + 12, cm3);
}
/* see bearssl_block.h */
void
br_aes_ct64_ctrcbc_encrypt(const br_aes_ct64_ctrcbc_keys *ctx,
void *ctr, void *cbcmac, void *data, size_t len)
{
/*
* When encrypting, the CBC-MAC processing must be lagging by
* one block, since it operates on the encrypted values, so
* it must wait for that encryption to complete.
*/
unsigned char *buf;
unsigned char *ivbuf;
uint32_t iv0, iv1, iv2, iv3;
uint32_t cm0, cm1, cm2, cm3;
uint64_t sk_exp[120];
uint64_t q[8];
int first_iter;
br_aes_ct64_skey_expand(sk_exp, ctx->num_rounds, ctx->skey);
/*
* We keep the counter as four 32-bit values, with big-endian
* convention, because that's what is expected for purposes of
* incrementing the counter value.
*/
ivbuf = ctr;
iv0 = br_dec32be(ivbuf + 0);
iv1 = br_dec32be(ivbuf + 4);
iv2 = br_dec32be(ivbuf + 8);
iv3 = br_dec32be(ivbuf + 12);
/*
* The current CBC-MAC value is kept in little-endian convention.
*/
cm0 = br_dec32le((unsigned char *)cbcmac + 0);
cm1 = br_dec32le((unsigned char *)cbcmac + 4);
cm2 = br_dec32le((unsigned char *)cbcmac + 8);
cm3 = br_dec32le((unsigned char *)cbcmac + 12);
buf = data;
first_iter = 1;
memset(q, 0, sizeof q);
while (len > 0) {
uint32_t w[8], carry;
/*
* The bitslice implementation expects values in
* little-endian convention, so we have to byteswap them.
*/
w[0] = br_swap32(iv0);
w[1] = br_swap32(iv1);
w[2] = br_swap32(iv2);
w[3] = br_swap32(iv3);
iv3 ++;
carry = ~(iv3 | -iv3) >> 31;
iv2 += carry;
carry &= -(~(iv2 | -iv2) >> 31);
iv1 += carry;
carry &= -(~(iv1 | -iv1) >> 31);
iv0 += carry;
/*
* The block for CBC-MAC.
*/
w[4] = cm0;
w[5] = cm1;
w[6] = cm2;
w[7] = cm3;
br_aes_ct64_interleave_in(&q[0], &q[4], w);
br_aes_ct64_interleave_in(&q[1], &q[5], w + 4);
br_aes_ct64_ortho(q);
br_aes_ct64_bitslice_encrypt(ctx->num_rounds, sk_exp, q);
br_aes_ct64_ortho(q);
br_aes_ct64_interleave_out(w, q[0], q[4]);
br_aes_ct64_interleave_out(w + 4, q[1], q[5]);
/*
* We do the XOR with the plaintext in 32-bit registers,
* so that the value are available for CBC-MAC processing
* as well.
*/
w[0] ^= br_dec32le(buf + 0);
w[1] ^= br_dec32le(buf + 4);
w[2] ^= br_dec32le(buf + 8);
w[3] ^= br_dec32le(buf + 12);
br_enc32le(buf + 0, w[0]);
br_enc32le(buf + 4, w[1]);
br_enc32le(buf + 8, w[2]);
br_enc32le(buf + 12, w[3]);
buf += 16;
len -= 16;
/*
* We set the cm* values to the block to encrypt in the
* next iteration.
*/
if (first_iter) {
first_iter = 0;
cm0 ^= w[0];
cm1 ^= w[1];
cm2 ^= w[2];
cm3 ^= w[3];
} else {
cm0 = w[0] ^ w[4];
cm1 = w[1] ^ w[5];
cm2 = w[2] ^ w[6];
cm3 = w[3] ^ w[7];
}
/*
* If this was the last iteration, then compute the
* extra block encryption to complete CBC-MAC.
*/
if (len == 0) {
w[0] = cm0;
w[1] = cm1;
w[2] = cm2;
w[3] = cm3;
br_aes_ct64_interleave_in(&q[0], &q[4], w);
br_aes_ct64_ortho(q);
br_aes_ct64_bitslice_encrypt(
ctx->num_rounds, sk_exp, q);
br_aes_ct64_ortho(q);
br_aes_ct64_interleave_out(w, q[0], q[4]);
cm0 = w[0];
cm1 = w[1];
cm2 = w[2];
cm3 = w[3];
break;
}
}
br_enc32be(ivbuf + 0, iv0);
br_enc32be(ivbuf + 4, iv1);
br_enc32be(ivbuf + 8, iv2);
br_enc32be(ivbuf + 12, iv3);
br_enc32le((unsigned char *)cbcmac + 0, cm0);
br_enc32le((unsigned char *)cbcmac + 4, cm1);
br_enc32le((unsigned char *)cbcmac + 8, cm2);
br_enc32le((unsigned char *)cbcmac + 12, cm3);
}
/* see bearssl_block.h */
void
br_aes_ct64_ctrcbc_decrypt(const br_aes_ct64_ctrcbc_keys *ctx,
void *ctr, void *cbcmac, void *data, size_t len)
{
unsigned char *buf;
unsigned char *ivbuf;
uint32_t iv0, iv1, iv2, iv3;
uint32_t cm0, cm1, cm2, cm3;
uint64_t sk_exp[120];
uint64_t q[8];
br_aes_ct64_skey_expand(sk_exp, ctx->num_rounds, ctx->skey);
/*
* We keep the counter as four 32-bit values, with big-endian
* convention, because that's what is expected for purposes of
* incrementing the counter value.
*/
ivbuf = ctr;
iv0 = br_dec32be(ivbuf + 0);
iv1 = br_dec32be(ivbuf + 4);
iv2 = br_dec32be(ivbuf + 8);
iv3 = br_dec32be(ivbuf + 12);
/*
* The current CBC-MAC value is kept in little-endian convention.
*/
cm0 = br_dec32le((unsigned char *)cbcmac + 0);
cm1 = br_dec32le((unsigned char *)cbcmac + 4);
cm2 = br_dec32le((unsigned char *)cbcmac + 8);
cm3 = br_dec32le((unsigned char *)cbcmac + 12);
buf = data;
memset(q, 0, sizeof q);
while (len > 0) {
uint32_t w[8], carry;
unsigned char tmp[16];
/*
* The bitslice implementation expects values in
* little-endian convention, so we have to byteswap them.
*/
w[0] = br_swap32(iv0);
w[1] = br_swap32(iv1);
w[2] = br_swap32(iv2);
w[3] = br_swap32(iv3);
iv3 ++;
carry = ~(iv3 | -iv3) >> 31;
iv2 += carry;
carry &= -(~(iv2 | -iv2) >> 31);
iv1 += carry;
carry &= -(~(iv1 | -iv1) >> 31);
iv0 += carry;
/*
* The block for CBC-MAC.
*/
w[4] = cm0 ^ br_dec32le(buf + 0);
w[5] = cm1 ^ br_dec32le(buf + 4);
w[6] = cm2 ^ br_dec32le(buf + 8);
w[7] = cm3 ^ br_dec32le(buf + 12);
br_aes_ct64_interleave_in(&q[0], &q[4], w);
br_aes_ct64_interleave_in(&q[1], &q[5], w + 4);
br_aes_ct64_ortho(q);
br_aes_ct64_bitslice_encrypt(ctx->num_rounds, sk_exp, q);
br_aes_ct64_ortho(q);
br_aes_ct64_interleave_out(w, q[0], q[4]);
br_aes_ct64_interleave_out(w + 4, q[1], q[5]);
br_enc32le(tmp + 0, w[0]);
br_enc32le(tmp + 4, w[1]);
br_enc32le(tmp + 8, w[2]);
br_enc32le(tmp + 12, w[3]);
xorbuf(buf, tmp, 16);
cm0 = w[4];
cm1 = w[5];
cm2 = w[6];
cm3 = w[7];
buf += 16;
len -= 16;
}
br_enc32be(ivbuf + 0, iv0);
br_enc32be(ivbuf + 4, iv1);
br_enc32be(ivbuf + 8, iv2);
br_enc32be(ivbuf + 12, iv3);
br_enc32le((unsigned char *)cbcmac + 0, cm0);
br_enc32le((unsigned char *)cbcmac + 4, cm1);
br_enc32le((unsigned char *)cbcmac + 8, cm2);
br_enc32le((unsigned char *)cbcmac + 12, cm3);
}
/* see bearssl_block.h */
const br_block_ctrcbc_class br_aes_ct64_ctrcbc_vtable = {
sizeof(br_aes_ct64_ctrcbc_keys),
16,
4,
(void (*)(const br_block_ctrcbc_class **, const void *, size_t))
&br_aes_ct64_ctrcbc_init,
(void (*)(const br_block_ctrcbc_class *const *,
void *, void *, void *, size_t))
&br_aes_ct64_ctrcbc_encrypt,
(void (*)(const br_block_ctrcbc_class *const *,
void *, void *, void *, size_t))
&br_aes_ct64_ctrcbc_decrypt,
(void (*)(const br_block_ctrcbc_class *const *,
void *, void *, size_t))
&br_aes_ct64_ctrcbc_ctr,
(void (*)(const br_block_ctrcbc_class *const *,
void *, const void *, size_t))
&br_aes_ct64_ctrcbc_mac
};

View File

@ -0,0 +1,422 @@
/*
* Copyright (c) 2017 Thomas Pornin <pornin@bolet.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.
*/
#include "inner.h"
/* see bearssl_block.h */
void
br_aes_ct_ctrcbc_init(br_aes_ct_ctrcbc_keys *ctx,
const void *key, size_t len)
{
ctx->vtable = &br_aes_ct_ctrcbc_vtable;
ctx->num_rounds = br_aes_ct_keysched(ctx->skey, key, len);
}
static void
xorbuf(void *dst, const void *src, size_t len)
{
unsigned char *d;
const unsigned char *s;
d = dst;
s = src;
while (len -- > 0) {
*d ++ ^= *s ++;
}
}
/* see bearssl_block.h */
void
br_aes_ct_ctrcbc_ctr(const br_aes_ct_ctrcbc_keys *ctx,
void *ctr, void *data, size_t len)
{
unsigned char *buf;
unsigned char *ivbuf;
uint32_t iv0, iv1, iv2, iv3;
uint32_t sk_exp[120];
br_aes_ct_skey_expand(sk_exp, ctx->num_rounds, ctx->skey);
/*
* We keep the counter as four 32-bit values, with big-endian
* convention, because that's what is expected for purposes of
* incrementing the counter value.
*/
ivbuf = ctr;
iv0 = br_dec32be(ivbuf + 0);
iv1 = br_dec32be(ivbuf + 4);
iv2 = br_dec32be(ivbuf + 8);
iv3 = br_dec32be(ivbuf + 12);
buf = data;
while (len > 0) {
uint32_t q[8], carry;
unsigned char tmp[32];
/*
* The bitslice implementation expects values in
* little-endian convention, so we have to byteswap them.
*/
q[0] = br_swap32(iv0);
q[2] = br_swap32(iv1);
q[4] = br_swap32(iv2);
q[6] = br_swap32(iv3);
iv3 ++;
carry = ~(iv3 | -iv3) >> 31;
iv2 += carry;
carry &= -(~(iv2 | -iv2) >> 31);
iv1 += carry;
carry &= -(~(iv1 | -iv1) >> 31);
iv0 += carry;
q[1] = br_swap32(iv0);
q[3] = br_swap32(iv1);
q[5] = br_swap32(iv2);
q[7] = br_swap32(iv3);
if (len > 16) {
iv3 ++;
carry = ~(iv3 | -iv3) >> 31;
iv2 += carry;
carry &= -(~(iv2 | -iv2) >> 31);
iv1 += carry;
carry &= -(~(iv1 | -iv1) >> 31);
iv0 += carry;
}
br_aes_ct_ortho(q);
br_aes_ct_bitslice_encrypt(ctx->num_rounds, sk_exp, q);
br_aes_ct_ortho(q);
br_enc32le(tmp, q[0]);
br_enc32le(tmp + 4, q[2]);
br_enc32le(tmp + 8, q[4]);
br_enc32le(tmp + 12, q[6]);
br_enc32le(tmp + 16, q[1]);
br_enc32le(tmp + 20, q[3]);
br_enc32le(tmp + 24, q[5]);
br_enc32le(tmp + 28, q[7]);
if (len <= 32) {
xorbuf(buf, tmp, len);
break;
}
xorbuf(buf, tmp, 32);
buf += 32;
len -= 32;
}
br_enc32be(ivbuf + 0, iv0);
br_enc32be(ivbuf + 4, iv1);
br_enc32be(ivbuf + 8, iv2);
br_enc32be(ivbuf + 12, iv3);
}
/* see bearssl_block.h */
void
br_aes_ct_ctrcbc_mac(const br_aes_ct_ctrcbc_keys *ctx,
void *cbcmac, const void *data, size_t len)
{
const unsigned char *buf;
uint32_t cm0, cm1, cm2, cm3;
uint32_t q[8];
uint32_t sk_exp[120];
br_aes_ct_skey_expand(sk_exp, ctx->num_rounds, ctx->skey);
buf = data;
cm0 = br_dec32le((unsigned char *)cbcmac + 0);
cm1 = br_dec32le((unsigned char *)cbcmac + 4);
cm2 = br_dec32le((unsigned char *)cbcmac + 8);
cm3 = br_dec32le((unsigned char *)cbcmac + 12);
q[1] = 0;
q[3] = 0;
q[5] = 0;
q[7] = 0;
while (len > 0) {
q[0] = cm0 ^ br_dec32le(buf + 0);
q[2] = cm1 ^ br_dec32le(buf + 4);
q[4] = cm2 ^ br_dec32le(buf + 8);
q[6] = cm3 ^ br_dec32le(buf + 12);
br_aes_ct_ortho(q);
br_aes_ct_bitslice_encrypt(ctx->num_rounds, sk_exp, q);
br_aes_ct_ortho(q);
cm0 = q[0];
cm1 = q[2];
cm2 = q[4];
cm3 = q[6];
buf += 16;
len -= 16;
}
br_enc32le((unsigned char *)cbcmac + 0, cm0);
br_enc32le((unsigned char *)cbcmac + 4, cm1);
br_enc32le((unsigned char *)cbcmac + 8, cm2);
br_enc32le((unsigned char *)cbcmac + 12, cm3);
}
/* see bearssl_block.h */
void
br_aes_ct_ctrcbc_encrypt(const br_aes_ct_ctrcbc_keys *ctx,
void *ctr, void *cbcmac, void *data, size_t len)
{
/*
* When encrypting, the CBC-MAC processing must be lagging by
* one block, since it operates on the encrypted values, so
* it must wait for that encryption to complete.
*/
unsigned char *buf;
unsigned char *ivbuf;
uint32_t iv0, iv1, iv2, iv3;
uint32_t cm0, cm1, cm2, cm3;
uint32_t sk_exp[120];
int first_iter;
br_aes_ct_skey_expand(sk_exp, ctx->num_rounds, ctx->skey);
/*
* We keep the counter as four 32-bit values, with big-endian
* convention, because that's what is expected for purposes of
* incrementing the counter value.
*/
ivbuf = ctr;
iv0 = br_dec32be(ivbuf + 0);
iv1 = br_dec32be(ivbuf + 4);
iv2 = br_dec32be(ivbuf + 8);
iv3 = br_dec32be(ivbuf + 12);
/*
* The current CBC-MAC value is kept in little-endian convention.
*/
cm0 = br_dec32le((unsigned char *)cbcmac + 0);
cm1 = br_dec32le((unsigned char *)cbcmac + 4);
cm2 = br_dec32le((unsigned char *)cbcmac + 8);
cm3 = br_dec32le((unsigned char *)cbcmac + 12);
buf = data;
first_iter = 1;
while (len > 0) {
uint32_t q[8], carry;
/*
* The bitslice implementation expects values in
* little-endian convention, so we have to byteswap them.
*/
q[0] = br_swap32(iv0);
q[2] = br_swap32(iv1);
q[4] = br_swap32(iv2);
q[6] = br_swap32(iv3);
iv3 ++;
carry = ~(iv3 | -iv3) >> 31;
iv2 += carry;
carry &= -(~(iv2 | -iv2) >> 31);
iv1 += carry;
carry &= -(~(iv1 | -iv1) >> 31);
iv0 += carry;
/*
* The odd values are used for CBC-MAC.
*/
q[1] = cm0;
q[3] = cm1;
q[5] = cm2;
q[7] = cm3;
br_aes_ct_ortho(q);
br_aes_ct_bitslice_encrypt(ctx->num_rounds, sk_exp, q);
br_aes_ct_ortho(q);
/*
* We do the XOR with the plaintext in 32-bit registers,
* so that the value are available for CBC-MAC processing
* as well.
*/
q[0] ^= br_dec32le(buf + 0);
q[2] ^= br_dec32le(buf + 4);
q[4] ^= br_dec32le(buf + 8);
q[6] ^= br_dec32le(buf + 12);
br_enc32le(buf + 0, q[0]);
br_enc32le(buf + 4, q[2]);
br_enc32le(buf + 8, q[4]);
br_enc32le(buf + 12, q[6]);
buf += 16;
len -= 16;
/*
* We set the cm* values to the block to encrypt in the
* next iteration.
*/
if (first_iter) {
first_iter = 0;
cm0 ^= q[0];
cm1 ^= q[2];
cm2 ^= q[4];
cm3 ^= q[6];
} else {
cm0 = q[0] ^ q[1];
cm1 = q[2] ^ q[3];
cm2 = q[4] ^ q[5];
cm3 = q[6] ^ q[7];
}
/*
* If this was the last iteration, then compute the
* extra block encryption to complete CBC-MAC.
*/
if (len == 0) {
q[0] = cm0;
q[2] = cm1;
q[4] = cm2;
q[6] = cm3;
br_aes_ct_ortho(q);
br_aes_ct_bitslice_encrypt(ctx->num_rounds, sk_exp, q);
br_aes_ct_ortho(q);
cm0 = q[0];
cm1 = q[2];
cm2 = q[4];
cm3 = q[6];
break;
}
}
br_enc32be(ivbuf + 0, iv0);
br_enc32be(ivbuf + 4, iv1);
br_enc32be(ivbuf + 8, iv2);
br_enc32be(ivbuf + 12, iv3);
br_enc32le((unsigned char *)cbcmac + 0, cm0);
br_enc32le((unsigned char *)cbcmac + 4, cm1);
br_enc32le((unsigned char *)cbcmac + 8, cm2);
br_enc32le((unsigned char *)cbcmac + 12, cm3);
}
/* see bearssl_block.h */
void
br_aes_ct_ctrcbc_decrypt(const br_aes_ct_ctrcbc_keys *ctx,
void *ctr, void *cbcmac, void *data, size_t len)
{
unsigned char *buf;
unsigned char *ivbuf;
uint32_t iv0, iv1, iv2, iv3;
uint32_t cm0, cm1, cm2, cm3;
uint32_t sk_exp[120];
br_aes_ct_skey_expand(sk_exp, ctx->num_rounds, ctx->skey);
/*
* We keep the counter as four 32-bit values, with big-endian
* convention, because that's what is expected for purposes of
* incrementing the counter value.
*/
ivbuf = ctr;
iv0 = br_dec32be(ivbuf + 0);
iv1 = br_dec32be(ivbuf + 4);
iv2 = br_dec32be(ivbuf + 8);
iv3 = br_dec32be(ivbuf + 12);
/*
* The current CBC-MAC value is kept in little-endian convention.
*/
cm0 = br_dec32le((unsigned char *)cbcmac + 0);
cm1 = br_dec32le((unsigned char *)cbcmac + 4);
cm2 = br_dec32le((unsigned char *)cbcmac + 8);
cm3 = br_dec32le((unsigned char *)cbcmac + 12);
buf = data;
while (len > 0) {
uint32_t q[8], carry;
unsigned char tmp[16];
/*
* The bitslice implementation expects values in
* little-endian convention, so we have to byteswap them.
*/
q[0] = br_swap32(iv0);
q[2] = br_swap32(iv1);
q[4] = br_swap32(iv2);
q[6] = br_swap32(iv3);
iv3 ++;
carry = ~(iv3 | -iv3) >> 31;
iv2 += carry;
carry &= -(~(iv2 | -iv2) >> 31);
iv1 += carry;
carry &= -(~(iv1 | -iv1) >> 31);
iv0 += carry;
/*
* The odd values are used for CBC-MAC.
*/
q[1] = cm0 ^ br_dec32le(buf + 0);
q[3] = cm1 ^ br_dec32le(buf + 4);
q[5] = cm2 ^ br_dec32le(buf + 8);
q[7] = cm3 ^ br_dec32le(buf + 12);
br_aes_ct_ortho(q);
br_aes_ct_bitslice_encrypt(ctx->num_rounds, sk_exp, q);
br_aes_ct_ortho(q);
br_enc32le(tmp + 0, q[0]);
br_enc32le(tmp + 4, q[2]);
br_enc32le(tmp + 8, q[4]);
br_enc32le(tmp + 12, q[6]);
xorbuf(buf, tmp, 16);
cm0 = q[1];
cm1 = q[3];
cm2 = q[5];
cm3 = q[7];
buf += 16;
len -= 16;
}
br_enc32be(ivbuf + 0, iv0);
br_enc32be(ivbuf + 4, iv1);
br_enc32be(ivbuf + 8, iv2);
br_enc32be(ivbuf + 12, iv3);
br_enc32le((unsigned char *)cbcmac + 0, cm0);
br_enc32le((unsigned char *)cbcmac + 4, cm1);
br_enc32le((unsigned char *)cbcmac + 8, cm2);
br_enc32le((unsigned char *)cbcmac + 12, cm3);
}
/* see bearssl_block.h */
const br_block_ctrcbc_class br_aes_ct_ctrcbc_vtable = {
sizeof(br_aes_ct_ctrcbc_keys),
16,
4,
(void (*)(const br_block_ctrcbc_class **, const void *, size_t))
&br_aes_ct_ctrcbc_init,
(void (*)(const br_block_ctrcbc_class *const *,
void *, void *, void *, size_t))
&br_aes_ct_ctrcbc_encrypt,
(void (*)(const br_block_ctrcbc_class *const *,
void *, void *, void *, size_t))
&br_aes_ct_ctrcbc_decrypt,
(void (*)(const br_block_ctrcbc_class *const *,
void *, void *, size_t))
&br_aes_ct_ctrcbc_ctr,
(void (*)(const br_block_ctrcbc_class *const *,
void *, const void *, size_t))
&br_aes_ct_ctrcbc_mac
};

View File

@ -0,0 +1,142 @@
/*
* Copyright (c) 2017 Thomas Pornin <pornin@bolet.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.
*/
#include "inner.h"
/* see bearssl_block.h */
void
br_aes_small_ctrcbc_init(br_aes_small_ctrcbc_keys *ctx,
const void *key, size_t len)
{
ctx->vtable = &br_aes_small_ctrcbc_vtable;
ctx->num_rounds = br_aes_keysched(ctx->skey, key, len);
}
static void
xorbuf(void *dst, const void *src, size_t len)
{
unsigned char *d;
const unsigned char *s;
d = dst;
s = src;
while (len -- > 0) {
*d ++ ^= *s ++;
}
}
/* see bearssl_block.h */
void
br_aes_small_ctrcbc_ctr(const br_aes_small_ctrcbc_keys *ctx,
void *ctr, void *data, size_t len)
{
unsigned char *buf, *bctr;
uint32_t cc0, cc1, cc2, cc3;
buf = data;
bctr = ctr;
cc3 = br_dec32be(bctr + 0);
cc2 = br_dec32be(bctr + 4);
cc1 = br_dec32be(bctr + 8);
cc0 = br_dec32be(bctr + 12);
while (len > 0) {
unsigned char tmp[16];
uint32_t carry;
br_enc32be(tmp + 0, cc3);
br_enc32be(tmp + 4, cc2);
br_enc32be(tmp + 8, cc1);
br_enc32be(tmp + 12, cc0);
br_aes_small_encrypt(ctx->num_rounds, ctx->skey, tmp);
xorbuf(buf, tmp, 16);
buf += 16;
len -= 16;
cc0 ++;
carry = (~(cc0 | -cc0)) >> 31;
cc1 += carry;
carry &= (~(cc1 | -cc1)) >> 31;
cc2 += carry;
carry &= (~(cc2 | -cc2)) >> 31;
cc3 += carry;
}
br_enc32be(bctr + 0, cc3);
br_enc32be(bctr + 4, cc2);
br_enc32be(bctr + 8, cc1);
br_enc32be(bctr + 12, cc0);
}
/* see bearssl_block.h */
void
br_aes_small_ctrcbc_mac(const br_aes_small_ctrcbc_keys *ctx,
void *cbcmac, const void *data, size_t len)
{
const unsigned char *buf;
buf = data;
while (len > 0) {
xorbuf(cbcmac, buf, 16);
br_aes_small_encrypt(ctx->num_rounds, ctx->skey, cbcmac);
buf += 16;
len -= 16;
}
}
/* see bearssl_block.h */
void
br_aes_small_ctrcbc_encrypt(const br_aes_small_ctrcbc_keys *ctx,
void *ctr, void *cbcmac, void *data, size_t len)
{
br_aes_small_ctrcbc_ctr(ctx, ctr, data, len);
br_aes_small_ctrcbc_mac(ctx, cbcmac, data, len);
}
/* see bearssl_block.h */
void
br_aes_small_ctrcbc_decrypt(const br_aes_small_ctrcbc_keys *ctx,
void *ctr, void *cbcmac, void *data, size_t len)
{
br_aes_small_ctrcbc_mac(ctx, cbcmac, data, len);
br_aes_small_ctrcbc_ctr(ctx, ctr, data, len);
}
/* see bearssl_block.h */
const br_block_ctrcbc_class br_aes_small_ctrcbc_vtable = {
sizeof(br_aes_small_ctrcbc_keys),
16,
4,
(void (*)(const br_block_ctrcbc_class **, const void *, size_t))
&br_aes_small_ctrcbc_init,
(void (*)(const br_block_ctrcbc_class *const *,
void *, void *, void *, size_t))
&br_aes_small_ctrcbc_encrypt,
(void (*)(const br_block_ctrcbc_class *const *,
void *, void *, void *, size_t))
&br_aes_small_ctrcbc_decrypt,
(void (*)(const br_block_ctrcbc_class *const *,
void *, void *, size_t))
&br_aes_small_ctrcbc_ctr,
(void (*)(const br_block_ctrcbc_class *const *,
void *, const void *, size_t))
&br_aes_small_ctrcbc_mac
};

View File

@ -0,0 +1,596 @@
/*
* Copyright (c) 2017 Thomas Pornin <pornin@bolet.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.
*/
#define BR_ENABLE_INTRINSICS 1
#include "inner.h"
#if BR_AES_X86NI
/* see bearssl_block.h */
const br_block_ctrcbc_class *
br_aes_x86ni_ctrcbc_get_vtable(void)
{
return br_aes_x86ni_supported() ? &br_aes_x86ni_ctrcbc_vtable : NULL;
}
/* see bearssl_block.h */
void
br_aes_x86ni_ctrcbc_init(br_aes_x86ni_ctrcbc_keys *ctx,
const void *key, size_t len)
{
ctx->vtable = &br_aes_x86ni_ctrcbc_vtable;
ctx->num_rounds = br_aes_x86ni_keysched_enc(ctx->skey.skni, key, len);
}
BR_TARGETS_X86_UP
/* see bearssl_block.h */
BR_TARGET("sse2,sse4.1,aes")
void
br_aes_x86ni_ctrcbc_ctr(const br_aes_x86ni_ctrcbc_keys *ctx,
void *ctr, void *data, size_t len)
{
unsigned char *buf;
unsigned num_rounds;
__m128i sk[15];
__m128i ivx0, ivx1, ivx2, ivx3;
__m128i erev, zero, one, four, notthree;
unsigned u;
buf = data;
num_rounds = ctx->num_rounds;
for (u = 0; u <= num_rounds; u ++) {
sk[u] = _mm_loadu_si128((void *)(ctx->skey.skni + (u << 4)));
}
/*
* Some SSE2 constants.
*/
erev = _mm_set_epi8(0, 1, 2, 3, 4, 5, 6, 7,
8, 9, 10, 11, 12, 13, 14, 15);
zero = _mm_setzero_si128();
one = _mm_set_epi64x(0, 1);
four = _mm_set_epi64x(0, 4);
notthree = _mm_sub_epi64(zero, four);
/*
* Decode the counter in big-endian and pre-increment the other
* three counters.
*/
ivx0 = _mm_shuffle_epi8(_mm_loadu_si128((void *)ctr), erev);
ivx1 = _mm_add_epi64(ivx0, one);
ivx1 = _mm_sub_epi64(ivx1,
_mm_slli_si128(_mm_cmpeq_epi64(ivx1, zero), 8));
ivx2 = _mm_add_epi64(ivx1, one);
ivx2 = _mm_sub_epi64(ivx2,
_mm_slli_si128(_mm_cmpeq_epi64(ivx2, zero), 8));
ivx3 = _mm_add_epi64(ivx2, one);
ivx3 = _mm_sub_epi64(ivx3,
_mm_slli_si128(_mm_cmpeq_epi64(ivx3, zero), 8));
while (len > 0) {
__m128i x0, x1, x2, x3;
/*
* Load counter values; we need to byteswap them because
* the specification says that they use big-endian.
*/
x0 = _mm_shuffle_epi8(ivx0, erev);
x1 = _mm_shuffle_epi8(ivx1, erev);
x2 = _mm_shuffle_epi8(ivx2, erev);
x3 = _mm_shuffle_epi8(ivx3, erev);
x0 = _mm_xor_si128(x0, sk[0]);
x1 = _mm_xor_si128(x1, sk[0]);
x2 = _mm_xor_si128(x2, sk[0]);
x3 = _mm_xor_si128(x3, sk[0]);
x0 = _mm_aesenc_si128(x0, sk[1]);
x1 = _mm_aesenc_si128(x1, sk[1]);
x2 = _mm_aesenc_si128(x2, sk[1]);
x3 = _mm_aesenc_si128(x3, sk[1]);
x0 = _mm_aesenc_si128(x0, sk[2]);
x1 = _mm_aesenc_si128(x1, sk[2]);
x2 = _mm_aesenc_si128(x2, sk[2]);
x3 = _mm_aesenc_si128(x3, sk[2]);
x0 = _mm_aesenc_si128(x0, sk[3]);
x1 = _mm_aesenc_si128(x1, sk[3]);
x2 = _mm_aesenc_si128(x2, sk[3]);
x3 = _mm_aesenc_si128(x3, sk[3]);
x0 = _mm_aesenc_si128(x0, sk[4]);
x1 = _mm_aesenc_si128(x1, sk[4]);
x2 = _mm_aesenc_si128(x2, sk[4]);
x3 = _mm_aesenc_si128(x3, sk[4]);
x0 = _mm_aesenc_si128(x0, sk[5]);
x1 = _mm_aesenc_si128(x1, sk[5]);
x2 = _mm_aesenc_si128(x2, sk[5]);
x3 = _mm_aesenc_si128(x3, sk[5]);
x0 = _mm_aesenc_si128(x0, sk[6]);
x1 = _mm_aesenc_si128(x1, sk[6]);
x2 = _mm_aesenc_si128(x2, sk[6]);
x3 = _mm_aesenc_si128(x3, sk[6]);
x0 = _mm_aesenc_si128(x0, sk[7]);
x1 = _mm_aesenc_si128(x1, sk[7]);
x2 = _mm_aesenc_si128(x2, sk[7]);
x3 = _mm_aesenc_si128(x3, sk[7]);
x0 = _mm_aesenc_si128(x0, sk[8]);
x1 = _mm_aesenc_si128(x1, sk[8]);
x2 = _mm_aesenc_si128(x2, sk[8]);
x3 = _mm_aesenc_si128(x3, sk[8]);
x0 = _mm_aesenc_si128(x0, sk[9]);
x1 = _mm_aesenc_si128(x1, sk[9]);
x2 = _mm_aesenc_si128(x2, sk[9]);
x3 = _mm_aesenc_si128(x3, sk[9]);
if (num_rounds == 10) {
x0 = _mm_aesenclast_si128(x0, sk[10]);
x1 = _mm_aesenclast_si128(x1, sk[10]);
x2 = _mm_aesenclast_si128(x2, sk[10]);
x3 = _mm_aesenclast_si128(x3, sk[10]);
} else if (num_rounds == 12) {
x0 = _mm_aesenc_si128(x0, sk[10]);
x1 = _mm_aesenc_si128(x1, sk[10]);
x2 = _mm_aesenc_si128(x2, sk[10]);
x3 = _mm_aesenc_si128(x3, sk[10]);
x0 = _mm_aesenc_si128(x0, sk[11]);
x1 = _mm_aesenc_si128(x1, sk[11]);
x2 = _mm_aesenc_si128(x2, sk[11]);
x3 = _mm_aesenc_si128(x3, sk[11]);
x0 = _mm_aesenclast_si128(x0, sk[12]);
x1 = _mm_aesenclast_si128(x1, sk[12]);
x2 = _mm_aesenclast_si128(x2, sk[12]);
x3 = _mm_aesenclast_si128(x3, sk[12]);
} else {
x0 = _mm_aesenc_si128(x0, sk[10]);
x1 = _mm_aesenc_si128(x1, sk[10]);
x2 = _mm_aesenc_si128(x2, sk[10]);
x3 = _mm_aesenc_si128(x3, sk[10]);
x0 = _mm_aesenc_si128(x0, sk[11]);
x1 = _mm_aesenc_si128(x1, sk[11]);
x2 = _mm_aesenc_si128(x2, sk[11]);
x3 = _mm_aesenc_si128(x3, sk[11]);
x0 = _mm_aesenc_si128(x0, sk[12]);
x1 = _mm_aesenc_si128(x1, sk[12]);
x2 = _mm_aesenc_si128(x2, sk[12]);
x3 = _mm_aesenc_si128(x3, sk[12]);
x0 = _mm_aesenc_si128(x0, sk[13]);
x1 = _mm_aesenc_si128(x1, sk[13]);
x2 = _mm_aesenc_si128(x2, sk[13]);
x3 = _mm_aesenc_si128(x3, sk[13]);
x0 = _mm_aesenclast_si128(x0, sk[14]);
x1 = _mm_aesenclast_si128(x1, sk[14]);
x2 = _mm_aesenclast_si128(x2, sk[14]);
x3 = _mm_aesenclast_si128(x3, sk[14]);
}
if (len >= 64) {
x0 = _mm_xor_si128(x0,
_mm_loadu_si128((void *)(buf + 0)));
x1 = _mm_xor_si128(x1,
_mm_loadu_si128((void *)(buf + 16)));
x2 = _mm_xor_si128(x2,
_mm_loadu_si128((void *)(buf + 32)));
x3 = _mm_xor_si128(x3,
_mm_loadu_si128((void *)(buf + 48)));
_mm_storeu_si128((void *)(buf + 0), x0);
_mm_storeu_si128((void *)(buf + 16), x1);
_mm_storeu_si128((void *)(buf + 32), x2);
_mm_storeu_si128((void *)(buf + 48), x3);
buf += 64;
len -= 64;
} else {
unsigned char tmp[64];
_mm_storeu_si128((void *)(tmp + 0), x0);
_mm_storeu_si128((void *)(tmp + 16), x1);
_mm_storeu_si128((void *)(tmp + 32), x2);
_mm_storeu_si128((void *)(tmp + 48), x3);
for (u = 0; u < len; u ++) {
buf[u] ^= tmp[u];
}
switch (len) {
case 16:
ivx0 = ivx1;
break;
case 32:
ivx0 = ivx2;
break;
case 48:
ivx0 = ivx3;
break;
}
break;
}
/*
* Add 4 to each counter value. For carry propagation
* into the upper 64-bit words, we would need to compare
* the results with 4, but SSE2+ has only _signed_
* comparisons. Instead, we mask out the low two bits,
* and check whether the remaining bits are zero.
*/
ivx0 = _mm_add_epi64(ivx0, four);
ivx1 = _mm_add_epi64(ivx1, four);
ivx2 = _mm_add_epi64(ivx2, four);
ivx3 = _mm_add_epi64(ivx3, four);
ivx0 = _mm_sub_epi64(ivx0,
_mm_slli_si128(_mm_cmpeq_epi64(
_mm_and_si128(ivx0, notthree), zero), 8));
ivx1 = _mm_sub_epi64(ivx1,
_mm_slli_si128(_mm_cmpeq_epi64(
_mm_and_si128(ivx1, notthree), zero), 8));
ivx2 = _mm_sub_epi64(ivx2,
_mm_slli_si128(_mm_cmpeq_epi64(
_mm_and_si128(ivx2, notthree), zero), 8));
ivx3 = _mm_sub_epi64(ivx3,
_mm_slli_si128(_mm_cmpeq_epi64(
_mm_and_si128(ivx3, notthree), zero), 8));
}
/*
* Write back new counter value. The loop took care to put the
* right counter value in ivx0.
*/
_mm_storeu_si128((void *)ctr, _mm_shuffle_epi8(ivx0, erev));
}
/* see bearssl_block.h */
BR_TARGET("sse2,sse4.1,aes")
void
br_aes_x86ni_ctrcbc_mac(const br_aes_x86ni_ctrcbc_keys *ctx,
void *cbcmac, const void *data, size_t len)
{
const unsigned char *buf;
unsigned num_rounds;
__m128i sk[15], ivx;
unsigned u;
buf = data;
ivx = _mm_loadu_si128(cbcmac);
num_rounds = ctx->num_rounds;
for (u = 0; u <= num_rounds; u ++) {
sk[u] = _mm_loadu_si128((void *)(ctx->skey.skni + (u << 4)));
}
while (len > 0) {
__m128i x;
x = _mm_xor_si128(_mm_loadu_si128((void *)buf), ivx);
x = _mm_xor_si128(x, sk[0]);
x = _mm_aesenc_si128(x, sk[1]);
x = _mm_aesenc_si128(x, sk[2]);
x = _mm_aesenc_si128(x, sk[3]);
x = _mm_aesenc_si128(x, sk[4]);
x = _mm_aesenc_si128(x, sk[5]);
x = _mm_aesenc_si128(x, sk[6]);
x = _mm_aesenc_si128(x, sk[7]);
x = _mm_aesenc_si128(x, sk[8]);
x = _mm_aesenc_si128(x, sk[9]);
if (num_rounds == 10) {
x = _mm_aesenclast_si128(x, sk[10]);
} else if (num_rounds == 12) {
x = _mm_aesenc_si128(x, sk[10]);
x = _mm_aesenc_si128(x, sk[11]);
x = _mm_aesenclast_si128(x, sk[12]);
} else {
x = _mm_aesenc_si128(x, sk[10]);
x = _mm_aesenc_si128(x, sk[11]);
x = _mm_aesenc_si128(x, sk[12]);
x = _mm_aesenc_si128(x, sk[13]);
x = _mm_aesenclast_si128(x, sk[14]);
}
ivx = x;
buf += 16;
len -= 16;
}
_mm_storeu_si128(cbcmac, ivx);
}
/* see bearssl_block.h */
BR_TARGET("sse2,sse4.1,aes")
void
br_aes_x86ni_ctrcbc_encrypt(const br_aes_x86ni_ctrcbc_keys *ctx,
void *ctr, void *cbcmac, void *data, size_t len)
{
unsigned char *buf;
unsigned num_rounds;
__m128i sk[15];
__m128i ivx, cmx;
__m128i erev, zero, one;
unsigned u;
int first_iter;
num_rounds = ctx->num_rounds;
for (u = 0; u <= num_rounds; u ++) {
sk[u] = _mm_loadu_si128((void *)(ctx->skey.skni + (u << 4)));
}
/*
* Some SSE2 constants.
*/
erev = _mm_set_epi8(0, 1, 2, 3, 4, 5, 6, 7,
8, 9, 10, 11, 12, 13, 14, 15);
zero = _mm_setzero_si128();
one = _mm_set_epi64x(0, 1);
/*
* Decode the counter in big-endian.
*/
ivx = _mm_shuffle_epi8(_mm_loadu_si128(ctr), erev);
cmx = _mm_loadu_si128(cbcmac);
buf = data;
first_iter = 1;
while (len > 0) {
__m128i dx, x0, x1;
/*
* Load initial values:
* dx encrypted block of data
* x0 counter (for CTR encryption)
* x1 input for CBC-MAC
*/
dx = _mm_loadu_si128((void *)buf);
x0 = _mm_shuffle_epi8(ivx, erev);
x1 = cmx;
x0 = _mm_xor_si128(x0, sk[0]);
x1 = _mm_xor_si128(x1, sk[0]);
x0 = _mm_aesenc_si128(x0, sk[1]);
x1 = _mm_aesenc_si128(x1, sk[1]);
x0 = _mm_aesenc_si128(x0, sk[2]);
x1 = _mm_aesenc_si128(x1, sk[2]);
x0 = _mm_aesenc_si128(x0, sk[3]);
x1 = _mm_aesenc_si128(x1, sk[3]);
x0 = _mm_aesenc_si128(x0, sk[4]);
x1 = _mm_aesenc_si128(x1, sk[4]);
x0 = _mm_aesenc_si128(x0, sk[5]);
x1 = _mm_aesenc_si128(x1, sk[5]);
x0 = _mm_aesenc_si128(x0, sk[6]);
x1 = _mm_aesenc_si128(x1, sk[6]);
x0 = _mm_aesenc_si128(x0, sk[7]);
x1 = _mm_aesenc_si128(x1, sk[7]);
x0 = _mm_aesenc_si128(x0, sk[8]);
x1 = _mm_aesenc_si128(x1, sk[8]);
x0 = _mm_aesenc_si128(x0, sk[9]);
x1 = _mm_aesenc_si128(x1, sk[9]);
if (num_rounds == 10) {
x0 = _mm_aesenclast_si128(x0, sk[10]);
x1 = _mm_aesenclast_si128(x1, sk[10]);
} else if (num_rounds == 12) {
x0 = _mm_aesenc_si128(x0, sk[10]);
x1 = _mm_aesenc_si128(x1, sk[10]);
x0 = _mm_aesenc_si128(x0, sk[11]);
x1 = _mm_aesenc_si128(x1, sk[11]);
x0 = _mm_aesenclast_si128(x0, sk[12]);
x1 = _mm_aesenclast_si128(x1, sk[12]);
} else {
x0 = _mm_aesenc_si128(x0, sk[10]);
x1 = _mm_aesenc_si128(x1, sk[10]);
x0 = _mm_aesenc_si128(x0, sk[11]);
x1 = _mm_aesenc_si128(x1, sk[11]);
x0 = _mm_aesenc_si128(x0, sk[12]);
x1 = _mm_aesenc_si128(x1, sk[12]);
x0 = _mm_aesenc_si128(x0, sk[13]);
x1 = _mm_aesenc_si128(x1, sk[13]);
x0 = _mm_aesenclast_si128(x0, sk[14]);
x1 = _mm_aesenclast_si128(x1, sk[14]);
}
x0 = _mm_xor_si128(x0, dx);
if (first_iter) {
cmx = _mm_xor_si128(cmx, x0);
first_iter = 0;
} else {
cmx = _mm_xor_si128(x1, x0);
}
_mm_storeu_si128((void *)buf, x0);
buf += 16;
len -= 16;
/*
* Increment the counter value.
*/
ivx = _mm_add_epi64(ivx, one);
ivx = _mm_sub_epi64(ivx,
_mm_slli_si128(_mm_cmpeq_epi64(ivx, zero), 8));
/*
* If this was the last iteration, then compute the
* extra block encryption to complete CBC-MAC.
*/
if (len == 0) {
cmx = _mm_xor_si128(cmx, sk[0]);
cmx = _mm_aesenc_si128(cmx, sk[1]);
cmx = _mm_aesenc_si128(cmx, sk[2]);
cmx = _mm_aesenc_si128(cmx, sk[3]);
cmx = _mm_aesenc_si128(cmx, sk[4]);
cmx = _mm_aesenc_si128(cmx, sk[5]);
cmx = _mm_aesenc_si128(cmx, sk[6]);
cmx = _mm_aesenc_si128(cmx, sk[7]);
cmx = _mm_aesenc_si128(cmx, sk[8]);
cmx = _mm_aesenc_si128(cmx, sk[9]);
if (num_rounds == 10) {
cmx = _mm_aesenclast_si128(cmx, sk[10]);
} else if (num_rounds == 12) {
cmx = _mm_aesenc_si128(cmx, sk[10]);
cmx = _mm_aesenc_si128(cmx, sk[11]);
cmx = _mm_aesenclast_si128(cmx, sk[12]);
} else {
cmx = _mm_aesenc_si128(cmx, sk[10]);
cmx = _mm_aesenc_si128(cmx, sk[11]);
cmx = _mm_aesenc_si128(cmx, sk[12]);
cmx = _mm_aesenc_si128(cmx, sk[13]);
cmx = _mm_aesenclast_si128(cmx, sk[14]);
}
break;
}
}
/*
* Write back new counter value and CBC-MAC value.
*/
_mm_storeu_si128(ctr, _mm_shuffle_epi8(ivx, erev));
_mm_storeu_si128(cbcmac, cmx);
}
/* see bearssl_block.h */
BR_TARGET("sse2,sse4.1,aes")
void
br_aes_x86ni_ctrcbc_decrypt(const br_aes_x86ni_ctrcbc_keys *ctx,
void *ctr, void *cbcmac, void *data, size_t len)
{
unsigned char *buf;
unsigned num_rounds;
__m128i sk[15];
__m128i ivx, cmx;
__m128i erev, zero, one;
unsigned u;
num_rounds = ctx->num_rounds;
for (u = 0; u <= num_rounds; u ++) {
sk[u] = _mm_loadu_si128((void *)(ctx->skey.skni + (u << 4)));
}
/*
* Some SSE2 constants.
*/
erev = _mm_set_epi8(0, 1, 2, 3, 4, 5, 6, 7,
8, 9, 10, 11, 12, 13, 14, 15);
zero = _mm_setzero_si128();
one = _mm_set_epi64x(0, 1);
/*
* Decode the counter in big-endian.
*/
ivx = _mm_shuffle_epi8(_mm_loadu_si128(ctr), erev);
cmx = _mm_loadu_si128(cbcmac);
buf = data;
while (len > 0) {
__m128i dx, x0, x1;
/*
* Load initial values:
* dx encrypted block of data
* x0 counter (for CTR encryption)
* x1 input for CBC-MAC
*/
dx = _mm_loadu_si128((void *)buf);
x0 = _mm_shuffle_epi8(ivx, erev);
x1 = _mm_xor_si128(cmx, dx);
x0 = _mm_xor_si128(x0, sk[0]);
x1 = _mm_xor_si128(x1, sk[0]);
x0 = _mm_aesenc_si128(x0, sk[1]);
x1 = _mm_aesenc_si128(x1, sk[1]);
x0 = _mm_aesenc_si128(x0, sk[2]);
x1 = _mm_aesenc_si128(x1, sk[2]);
x0 = _mm_aesenc_si128(x0, sk[3]);
x1 = _mm_aesenc_si128(x1, sk[3]);
x0 = _mm_aesenc_si128(x0, sk[4]);
x1 = _mm_aesenc_si128(x1, sk[4]);
x0 = _mm_aesenc_si128(x0, sk[5]);
x1 = _mm_aesenc_si128(x1, sk[5]);
x0 = _mm_aesenc_si128(x0, sk[6]);
x1 = _mm_aesenc_si128(x1, sk[6]);
x0 = _mm_aesenc_si128(x0, sk[7]);
x1 = _mm_aesenc_si128(x1, sk[7]);
x0 = _mm_aesenc_si128(x0, sk[8]);
x1 = _mm_aesenc_si128(x1, sk[8]);
x0 = _mm_aesenc_si128(x0, sk[9]);
x1 = _mm_aesenc_si128(x1, sk[9]);
if (num_rounds == 10) {
x0 = _mm_aesenclast_si128(x0, sk[10]);
x1 = _mm_aesenclast_si128(x1, sk[10]);
} else if (num_rounds == 12) {
x0 = _mm_aesenc_si128(x0, sk[10]);
x1 = _mm_aesenc_si128(x1, sk[10]);
x0 = _mm_aesenc_si128(x0, sk[11]);
x1 = _mm_aesenc_si128(x1, sk[11]);
x0 = _mm_aesenclast_si128(x0, sk[12]);
x1 = _mm_aesenclast_si128(x1, sk[12]);
} else {
x0 = _mm_aesenc_si128(x0, sk[10]);
x1 = _mm_aesenc_si128(x1, sk[10]);
x0 = _mm_aesenc_si128(x0, sk[11]);
x1 = _mm_aesenc_si128(x1, sk[11]);
x0 = _mm_aesenc_si128(x0, sk[12]);
x1 = _mm_aesenc_si128(x1, sk[12]);
x0 = _mm_aesenc_si128(x0, sk[13]);
x1 = _mm_aesenc_si128(x1, sk[13]);
x0 = _mm_aesenclast_si128(x0, sk[14]);
x1 = _mm_aesenclast_si128(x1, sk[14]);
}
x0 = _mm_xor_si128(x0, dx);
cmx = x1;
_mm_storeu_si128((void *)buf, x0);
buf += 16;
len -= 16;
/*
* Increment the counter value.
*/
ivx = _mm_add_epi64(ivx, one);
ivx = _mm_sub_epi64(ivx,
_mm_slli_si128(_mm_cmpeq_epi64(ivx, zero), 8));
}
/*
* Write back new counter value and CBC-MAC value.
*/
_mm_storeu_si128(ctr, _mm_shuffle_epi8(ivx, erev));
_mm_storeu_si128(cbcmac, cmx);
}
BR_TARGETS_X86_DOWN
/* see bearssl_block.h */
const br_block_ctrcbc_class br_aes_x86ni_ctrcbc_vtable = {
sizeof(br_aes_x86ni_ctrcbc_keys),
16,
4,
(void (*)(const br_block_ctrcbc_class **, const void *, size_t))
&br_aes_x86ni_ctrcbc_init,
(void (*)(const br_block_ctrcbc_class *const *,
void *, void *, void *, size_t))
&br_aes_x86ni_ctrcbc_encrypt,
(void (*)(const br_block_ctrcbc_class *const *,
void *, void *, void *, size_t))
&br_aes_x86ni_ctrcbc_decrypt,
(void (*)(const br_block_ctrcbc_class *const *,
void *, void *, size_t))
&br_aes_x86ni_ctrcbc_ctr,
(void (*)(const br_block_ctrcbc_class *const *,
void *, const void *, size_t))
&br_aes_x86ni_ctrcbc_mac
};
#else
/* see bearssl_block.h */
const br_block_ctrcbc_class *
br_aes_x86ni_ctrcbc_get_vtable(void)
{
return NULL;
}
#endif

View File

@ -3411,6 +3411,224 @@ test_AES_pwr8(void)
}
}
/*
* Custom CTR + CBC-MAC AES implementation. Can also do CTR-only, and
* CBC-MAC-only. The 'aes_big' implementation (CTR) is used. This is
* meant for comparisons.
*
* If 'ctr' is NULL then no encryption/decryption is done; otherwise,
* CTR encryption/decryption is performed (full-block counter) and the
* 'ctr' array is updated with the new counter value.
*
* If 'cbcmac' is NULL then no CBC-MAC is done; otherwise, CBC-MAC is
* applied on the encrypted data, with 'cbcmac' as IV and destination
* buffer for the output. If 'ctr' is not NULL and 'encrypt' is non-zero,
* then CBC-MAC is computed over the result of CTR processing; otherwise,
* CBC-MAC is computed over the input data itself.
*/
static void
do_aes_ctrcbc(const void *key, size_t key_len, int encrypt,
void *ctr, void *cbcmac, unsigned char *data, size_t len)
{
br_aes_big_ctr_keys bc;
int i;
br_aes_big_ctr_init(&bc, key, key_len);
for (i = 0; i < 2; i ++) {
/*
* CBC-MAC is computed on the encrypted data, so in
* first pass if decrypting, second pass if encrypting.
*/
if (cbcmac != NULL
&& ((encrypt && i == 1) || (!encrypt && i == 0)))
{
unsigned char zz[16];
size_t u;
memcpy(zz, cbcmac, sizeof zz);
for (u = 0; u < len; u += 16) {
unsigned char tmp[16];
size_t v;
for (v = 0; v < 16; v ++) {
tmp[v] = zz[v] ^ data[u + v];
}
memset(zz, 0, sizeof zz);
br_aes_big_ctr_run(&bc,
tmp, br_dec32be(tmp + 12), zz, 16);
}
memcpy(cbcmac, zz, sizeof zz);
}
/*
* CTR encryption/decryption is done only in the first pass.
* We process data block per block, because the CTR-only
* class uses a 32-bit counter, while the CTR+CBC-MAC
* class uses a 128-bit counter.
*/
if (ctr != NULL && i == 0) {
unsigned char zz[16];
size_t u;
memcpy(zz, ctr, sizeof zz);
for (u = 0; u < len; u += 16) {
int i;
br_aes_big_ctr_run(&bc,
zz, br_dec32be(zz + 12), data + u, 16);
for (i = 15; i >= 0; i --) {
zz[i] = (zz[i] + 1) & 0xFF;
if (zz[i] != 0) {
break;
}
}
}
memcpy(ctr, zz, sizeof zz);
}
}
}
static void
test_AES_CTRCBC_inner(const char *name, const br_block_ctrcbc_class *vt)
{
br_hmac_drbg_context rng;
size_t key_len;
printf("Test AES CTR/CBC-MAC %s: ", name);
fflush(stdout);
br_hmac_drbg_init(&rng, &br_sha256_vtable, name, strlen(name));
for (key_len = 16; key_len <= 32; key_len += 8) {
br_aes_gen_ctrcbc_keys bc;
unsigned char key[32];
size_t data_len;
br_hmac_drbg_generate(&rng, key, key_len);
vt->init(&bc.vtable, key, key_len);
for (data_len = 0; data_len <= 512; data_len += 16) {
unsigned char plain[512];
unsigned char data1[sizeof plain];
unsigned char data2[sizeof plain];
unsigned char ctr[16], cbcmac[16];
unsigned char ctr1[16], cbcmac1[16];
unsigned char ctr2[16], cbcmac2[16];
int i;
br_hmac_drbg_generate(&rng, plain, data_len);
for (i = 0; i <= 16; i ++) {
if (i == 0) {
br_hmac_drbg_generate(&rng, ctr, 16);
} else {
memset(ctr, 0, i - 1);
memset(ctr + i - 1, 0xFF, 17 - i);
}
br_hmac_drbg_generate(&rng, cbcmac, 16);
memcpy(data1, plain, data_len);
memcpy(ctr1, ctr, 16);
vt->ctr(&bc.vtable, ctr1, data1, data_len);
memcpy(data2, plain, data_len);
memcpy(ctr2, ctr, 16);
do_aes_ctrcbc(key, key_len, 1,
ctr2, NULL, data2, data_len);
check_equals("CTR-only data",
data1, data2, data_len);
check_equals("CTR-only counter",
ctr1, ctr2, 16);
memcpy(data1, plain, data_len);
memcpy(cbcmac1, cbcmac, 16);
vt->mac(&bc.vtable, cbcmac1, data1, data_len);
memcpy(data2, plain, data_len);
memcpy(cbcmac2, cbcmac, 16);
do_aes_ctrcbc(key, key_len, 1,
NULL, cbcmac2, data2, data_len);
check_equals("CBC-MAC-only",
cbcmac1, cbcmac2, 16);
memcpy(data1, plain, data_len);
memcpy(ctr1, ctr, 16);
memcpy(cbcmac1, cbcmac, 16);
vt->encrypt(&bc.vtable,
ctr1, cbcmac1, data1, data_len);
memcpy(data2, plain, data_len);
memcpy(ctr2, ctr, 16);
memcpy(cbcmac2, cbcmac, 16);
do_aes_ctrcbc(key, key_len, 1,
ctr2, cbcmac2, data2, data_len);
check_equals("encrypt: combined data",
data1, data2, data_len);
check_equals("encrypt: combined counter",
ctr1, ctr2, 16);
check_equals("encrypt: combined CBC-MAC",
cbcmac1, cbcmac2, 16);
memcpy(ctr1, ctr, 16);
memcpy(cbcmac1, cbcmac, 16);
vt->decrypt(&bc.vtable,
ctr1, cbcmac1, data1, data_len);
memcpy(ctr2, ctr, 16);
memcpy(cbcmac2, cbcmac, 16);
do_aes_ctrcbc(key, key_len, 0,
ctr2, cbcmac2, data2, data_len);
check_equals("decrypt: combined data",
data1, data2, data_len);
check_equals("decrypt: combined counter",
ctr1, ctr2, 16);
check_equals("decrypt: combined CBC-MAC",
cbcmac1, cbcmac2, 16);
}
printf(".");
fflush(stdout);
}
printf(" ");
fflush(stdout);
}
printf("done.\n");
fflush(stdout);
}
static void
test_AES_CTRCBC_big(void)
{
test_AES_CTRCBC_inner("big", &br_aes_big_ctrcbc_vtable);
}
static void
test_AES_CTRCBC_small(void)
{
test_AES_CTRCBC_inner("small", &br_aes_small_ctrcbc_vtable);
}
static void
test_AES_CTRCBC_ct(void)
{
test_AES_CTRCBC_inner("ct", &br_aes_ct_ctrcbc_vtable);
}
static void
test_AES_CTRCBC_ct64(void)
{
test_AES_CTRCBC_inner("ct64", &br_aes_ct64_ctrcbc_vtable);
}
static void
test_AES_CTRCBC_x86ni(void)
{
const br_block_ctrcbc_class *vt;
vt = br_aes_x86ni_ctrcbc_get_vtable();
if (vt != NULL) {
test_AES_CTRCBC_inner("x86ni", vt);
} else {
printf("Test AES CTR/CBC-MAC x86ni: UNAVAILABLE\n");
}
}
/*
* DES known-answer tests. Order: plaintext, key, ciphertext.
* (mostly from NIST SP 800-20).
@ -5077,7 +5295,7 @@ test_GCM(void)
br_aes_ct_ctr_keys bc;
br_gcm_context gc;
unsigned char tmp[100], out[16];
size_t v;
size_t v, tag_len;
key_len = hextobin(key, KAT_GCM[u]);
plain_len = hextobin(plain, KAT_GCM[u + 1]);
@ -5167,6 +5385,36 @@ test_GCM(void)
}
}
/*
* Tag truncation.
*/
for (tag_len = 1; tag_len <= 16; tag_len ++) {
memset(out, 0x54, sizeof out);
memcpy(tmp, plain, plain_len);
br_gcm_reset(&gc, iv, iv_len);
br_gcm_aad_inject(&gc, aad, aad_len);
br_gcm_flip(&gc);
br_gcm_run(&gc, 1, tmp, plain_len);
br_gcm_get_tag_trunc(&gc, out, tag_len);
check_equals("KAT GCM 8", out, tag, tag_len);
for (v = tag_len; v < sizeof out; v ++) {
if (out[v] != 0x54) {
fprintf(stderr, "overflow on tag\n");
exit(EXIT_FAILURE);
}
}
memcpy(tmp, plain, plain_len);
br_gcm_reset(&gc, iv, iv_len);
br_gcm_aad_inject(&gc, aad, aad_len);
br_gcm_flip(&gc);
br_gcm_run(&gc, 1, tmp, plain_len);
if (!br_gcm_check_tag_trunc(&gc, out, tag_len)) {
fprintf(stderr, "Tag not verified (3)\n");
exit(EXIT_FAILURE);
}
}
printf(".");
fflush(stdout);
}
@ -5175,6 +5423,468 @@ test_GCM(void)
fflush(stdout);
}
/*
* From "The EAX Mode of Operation (A Two-Pass Authenticated Encryption
* Scheme Optimized for Simplicity and Efficiency)" (Bellare, Rogaway,
* Wagner), presented at FSE 2004. Full article is available at:
* http://web.cs.ucdavis.edu/~rogaway/papers/eax.html
*
* EAX specification concatenates the authentication tag at the end of
* the ciphertext; in our API and the vectors below, the tag is separate.
*
* Order is: plaintext, key, nonce, header, ciphertext, tag.
*/
static const char *const KAT_EAX[] = {
"",
"233952dee4d5ed5f9b9c6d6ff80ff478",
"62ec67f9c3a4a407fcb2a8c49031a8b3",
"6bfb914fd07eae6b",
"",
"e037830e8389f27b025a2d6527e79d01",
"f7fb",
"91945d3f4dcbee0bf45ef52255f095a4",
"becaf043b0a23d843194ba972c66debd",
"fa3bfd4806eb53fa",
"19dd",
"5c4c9331049d0bdab0277408f67967e5",
"1a47cb4933",
"01f74ad64077f2e704c0f60ada3dd523",
"70c3db4f0d26368400a10ed05d2bff5e",
"234a3463c1264ac6",
"d851d5bae0",
"3a59f238a23e39199dc9266626c40f80",
"481c9e39b1",
"d07cf6cbb7f313bdde66b727afd3c5e8",
"8408dfff3c1a2b1292dc199e46b7d617",
"33cce2eabff5a79d",
"632a9d131a",
"d4c168a4225d8e1ff755939974a7bede",
"40d0c07da5e4",
"35b6d0580005bbc12b0587124557d2c2",
"fdb6b06676eedc5c61d74276e1f8e816",
"aeb96eaebe2970e9",
"071dfe16c675",
"cb0677e536f73afe6a14b74ee49844dd",
"4de3b35c3fc039245bd1fb7d",
"bd8e6e11475e60b268784c38c62feb22",
"6eac5c93072d8e8513f750935e46da1b",
"d4482d1ca78dce0f",
"835bb4f15d743e350e728414",
"abb8644fd6ccb86947c5e10590210a4f",
"8b0a79306c9ce7ed99dae4f87f8dd61636",
"7c77d6e813bed5ac98baa417477a2e7d",
"1a8c98dcd73d38393b2bf1569deefc19",
"65d2017990d62528",
"02083e3979da014812f59f11d52630da30",
"137327d10649b0aa6e1c181db617d7f2",
"1bda122bce8a8dbaf1877d962b8592dd2d56",
"5fff20cafab119ca2fc73549e20f5b0d",
"dde59b97d722156d4d9aff2bc7559826",
"54b9f04e6a09189a",
"2ec47b2c4954a489afc7ba4897edcdae8cc3",
"3b60450599bd02c96382902aef7f832a",
"6cf36720872b8513f6eab1a8a44438d5ef11",
"a4a4782bcffd3ec5e7ef6d8c34a56123",
"b781fcf2f75fa5a8de97a9ca48e522ec",
"899a175897561d7e",
"0de18fd0fdd91e7af19f1d8ee8733938b1e8",
"e7f6d2231618102fdb7fe55ff1991700",
"ca40d7446e545ffaed3bd12a740a659ffbbb3ceab7",
"8395fcf1e95bebd697bd010bc766aac3",
"22e7add93cfc6393c57ec0b3c17d6b44",
"126735fcc320d25a",
"cb8920f87a6c75cff39627b56e3ed197c552d295a7",
"cfc46afc253b4652b1af3795b124ab6e",
NULL
};
static void
test_EAX_inner(const char *name, const br_block_ctrcbc_class *vt)
{
size_t u;
printf("Test EAX %s: ", name);
fflush(stdout);
for (u = 0; KAT_EAX[u]; u += 6) {
unsigned char plain[100];
unsigned char key[32];
unsigned char nonce[100];
unsigned char aad[100];
unsigned char cipher[100];
unsigned char tag[100];
size_t plain_len, key_len, nonce_len, aad_len;
br_aes_gen_ctrcbc_keys bc;
br_eax_context ec;
unsigned char tmp[100], out[16];
size_t v, tag_len;
plain_len = hextobin(plain, KAT_EAX[u]);
key_len = hextobin(key, KAT_EAX[u + 1]);
nonce_len = hextobin(nonce, KAT_EAX[u + 2]);
aad_len = hextobin(aad, KAT_EAX[u + 3]);
hextobin(cipher, KAT_EAX[u + 4]);
hextobin(tag, KAT_EAX[u + 5]);
vt->init(&bc.vtable, key, key_len);
br_eax_init(&ec, &bc.vtable);
memset(tmp, 0x54, sizeof tmp);
/*
* Basic operation.
*/
memcpy(tmp, plain, plain_len);
br_eax_reset(&ec, nonce, nonce_len);
br_eax_aad_inject(&ec, aad, aad_len);
br_eax_flip(&ec);
br_eax_run(&ec, 1, tmp, plain_len);
br_eax_get_tag(&ec, out);
check_equals("KAT EAX 1", tmp, cipher, plain_len);
check_equals("KAT EAX 2", out, tag, 16);
br_eax_reset(&ec, nonce, nonce_len);
br_eax_aad_inject(&ec, aad, aad_len);
br_eax_flip(&ec);
br_eax_run(&ec, 0, tmp, plain_len);
check_equals("KAT EAX 3", tmp, plain, plain_len);
if (!br_eax_check_tag(&ec, tag)) {
fprintf(stderr, "Tag not verified (1)\n");
exit(EXIT_FAILURE);
}
for (v = plain_len; v < sizeof tmp; v ++) {
if (tmp[v] != 0x54) {
fprintf(stderr, "overflow on data\n");
exit(EXIT_FAILURE);
}
}
/*
* Byte-by-byte injection.
*/
br_eax_reset(&ec, nonce, nonce_len);
for (v = 0; v < aad_len; v ++) {
br_eax_aad_inject(&ec, aad + v, 1);
}
br_eax_flip(&ec);
for (v = 0; v < plain_len; v ++) {
br_eax_run(&ec, 1, tmp + v, 1);
}
check_equals("KAT EAX 4", tmp, cipher, plain_len);
if (!br_eax_check_tag(&ec, tag)) {
fprintf(stderr, "Tag not verified (2)\n");
exit(EXIT_FAILURE);
}
br_eax_reset(&ec, nonce, nonce_len);
for (v = 0; v < aad_len; v ++) {
br_eax_aad_inject(&ec, aad + v, 1);
}
br_eax_flip(&ec);
for (v = 0; v < plain_len; v ++) {
br_eax_run(&ec, 0, tmp + v, 1);
}
br_eax_get_tag(&ec, out);
check_equals("KAT EAX 5", tmp, plain, plain_len);
check_equals("KAT EAX 6", out, tag, 16);
/*
* Check that alterations are detected.
*/
for (v = 0; v < aad_len; v ++) {
memcpy(tmp, cipher, plain_len);
br_eax_reset(&ec, nonce, nonce_len);
aad[v] ^= 0x04;
br_eax_aad_inject(&ec, aad, aad_len);
aad[v] ^= 0x04;
br_eax_flip(&ec);
br_eax_run(&ec, 0, tmp, plain_len);
check_equals("KAT EAX 7", tmp, plain, plain_len);
if (br_eax_check_tag(&ec, tag)) {
fprintf(stderr, "Tag should have changed\n");
exit(EXIT_FAILURE);
}
}
/*
* Tag truncation.
*/
for (tag_len = 1; tag_len <= 16; tag_len ++) {
memset(out, 0x54, sizeof out);
memcpy(tmp, plain, plain_len);
br_eax_reset(&ec, nonce, nonce_len);
br_eax_aad_inject(&ec, aad, aad_len);
br_eax_flip(&ec);
br_eax_run(&ec, 1, tmp, plain_len);
br_eax_get_tag_trunc(&ec, out, tag_len);
check_equals("KAT EAX 8", out, tag, tag_len);
for (v = tag_len; v < sizeof out; v ++) {
if (out[v] != 0x54) {
fprintf(stderr, "overflow on tag\n");
exit(EXIT_FAILURE);
}
}
memcpy(tmp, plain, plain_len);
br_eax_reset(&ec, nonce, nonce_len);
br_eax_aad_inject(&ec, aad, aad_len);
br_eax_flip(&ec);
br_eax_run(&ec, 1, tmp, plain_len);
if (!br_eax_check_tag_trunc(&ec, out, tag_len)) {
fprintf(stderr, "Tag not verified (3)\n");
exit(EXIT_FAILURE);
}
}
printf(".");
fflush(stdout);
}
printf(" done.\n");
fflush(stdout);
}
static void
test_EAX(void)
{
const br_block_ctrcbc_class *x_ctrcbc;
test_EAX_inner("aes_big", &br_aes_big_ctrcbc_vtable);
test_EAX_inner("aes_small", &br_aes_small_ctrcbc_vtable);
test_EAX_inner("aes_ct", &br_aes_ct_ctrcbc_vtable);
test_EAX_inner("aes_ct64", &br_aes_ct64_ctrcbc_vtable);
x_ctrcbc = br_aes_x86ni_ctrcbc_get_vtable();
if (x_ctrcbc != NULL) {
test_EAX_inner("aes_x86ni", x_ctrcbc);
} else {
printf("Test EAX aes_x86ni: UNAVAILABLE\n");
}
}
/*
* From NIST SP 800-38C, appendix C.
*
* CCM specification concatenates the authentication tag at the end of
* the ciphertext; in our API and the vectors below, the tag is separate.
*
* Order is: key, nonce, aad, plaintext, ciphertext, tag.
*/
static const char *const KAT_CCM[] = {
"404142434445464748494a4b4c4d4e4f",
"10111213141516",
"0001020304050607",
"20212223",
"7162015b",
"4dac255d",
"404142434445464748494a4b4c4d4e4f",
"1011121314151617",
"000102030405060708090a0b0c0d0e0f",
"202122232425262728292a2b2c2d2e2f",
"d2a1f0e051ea5f62081a7792073d593d",
"1fc64fbfaccd",
"404142434445464748494a4b4c4d4e4f",
"101112131415161718191a1b",
"000102030405060708090a0b0c0d0e0f10111213",
"202122232425262728292a2b2c2d2e2f3031323334353637",
"e3b201a9f5b71a7a9b1ceaeccd97e70b6176aad9a4428aa5",
"484392fbc1b09951",
"404142434445464748494a4b4c4d4e4f",
"101112131415161718191a1b1c",
NULL,
"202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f",
"69915dad1e84c6376a68c2967e4dab615ae0fd1faec44cc484828529463ccf72",
"b4ac6bec93e8598e7f0dadbcea5b",
NULL
};
static void
test_CCM_inner(const char *name, const br_block_ctrcbc_class *vt)
{
size_t u;
printf("Test CCM %s: ", name);
fflush(stdout);
for (u = 0; KAT_CCM[u]; u += 6) {
unsigned char plain[100];
unsigned char key[32];
unsigned char nonce[100];
unsigned char aad_buf[100], *aad;
unsigned char cipher[100];
unsigned char tag[100];
size_t plain_len, key_len, nonce_len, aad_len, tag_len;
br_aes_gen_ctrcbc_keys bc;
br_ccm_context ec;
unsigned char tmp[100], out[16];
size_t v;
key_len = hextobin(key, KAT_CCM[u]);
nonce_len = hextobin(nonce, KAT_CCM[u + 1]);
if (KAT_CCM[u + 2] == NULL) {
aad_len = 65536;
aad = malloc(aad_len);
if (aad == NULL) {
fprintf(stderr, "OOM error\n");
exit(EXIT_FAILURE);
}
for (v = 0; v < 65536; v ++) {
aad[v] = (unsigned char)v;
}
} else {
aad = aad_buf;
aad_len = hextobin(aad, KAT_CCM[u + 2]);
}
plain_len = hextobin(plain, KAT_CCM[u + 3]);
hextobin(cipher, KAT_CCM[u + 4]);
tag_len = hextobin(tag, KAT_CCM[u + 5]);
vt->init(&bc.vtable, key, key_len);
br_ccm_init(&ec, &bc.vtable);
memset(tmp, 0x54, sizeof tmp);
/*
* Basic operation.
*/
memcpy(tmp, plain, plain_len);
if (!br_ccm_reset(&ec, nonce, nonce_len,
aad_len, plain_len, tag_len))
{
fprintf(stderr, "CCM reset failed\n");
exit(EXIT_FAILURE);
}
br_ccm_aad_inject(&ec, aad, aad_len);
br_ccm_flip(&ec);
br_ccm_run(&ec, 1, tmp, plain_len);
if (br_ccm_get_tag(&ec, out) != tag_len) {
fprintf(stderr, "CCM returned wrong tag length\n");
exit(EXIT_FAILURE);
}
check_equals("KAT CCM 1", tmp, cipher, plain_len);
check_equals("KAT CCM 2", out, tag, tag_len);
br_ccm_reset(&ec, nonce, nonce_len,
aad_len, plain_len, tag_len);
br_ccm_aad_inject(&ec, aad, aad_len);
br_ccm_flip(&ec);
br_ccm_run(&ec, 0, tmp, plain_len);
check_equals("KAT CCM 3", tmp, plain, plain_len);
if (!br_ccm_check_tag(&ec, tag)) {
fprintf(stderr, "Tag not verified (1)\n");
exit(EXIT_FAILURE);
}
for (v = plain_len; v < sizeof tmp; v ++) {
if (tmp[v] != 0x54) {
fprintf(stderr, "overflow on data\n");
exit(EXIT_FAILURE);
}
}
/*
* Byte-by-byte injection.
*/
br_ccm_reset(&ec, nonce, nonce_len,
aad_len, plain_len, tag_len);
for (v = 0; v < aad_len; v ++) {
br_ccm_aad_inject(&ec, aad + v, 1);
}
br_ccm_flip(&ec);
for (v = 0; v < plain_len; v ++) {
br_ccm_run(&ec, 1, tmp + v, 1);
}
check_equals("KAT CCM 4", tmp, cipher, plain_len);
if (!br_ccm_check_tag(&ec, tag)) {
fprintf(stderr, "Tag not verified (2)\n");
exit(EXIT_FAILURE);
}
br_ccm_reset(&ec, nonce, nonce_len,
aad_len, plain_len, tag_len);
for (v = 0; v < aad_len; v ++) {
br_ccm_aad_inject(&ec, aad + v, 1);
}
br_ccm_flip(&ec);
for (v = 0; v < plain_len; v ++) {
br_ccm_run(&ec, 0, tmp + v, 1);
}
br_ccm_get_tag(&ec, out);
check_equals("KAT CCM 5", tmp, plain, plain_len);
check_equals("KAT CCM 6", out, tag, tag_len);
/*
* Check that alterations are detected.
*/
for (v = 0; v < aad_len; v ++) {
memcpy(tmp, cipher, plain_len);
br_ccm_reset(&ec, nonce, nonce_len,
aad_len, plain_len, tag_len);
aad[v] ^= 0x04;
br_ccm_aad_inject(&ec, aad, aad_len);
aad[v] ^= 0x04;
br_ccm_flip(&ec);
br_ccm_run(&ec, 0, tmp, plain_len);
check_equals("KAT CCM 7", tmp, plain, plain_len);
if (br_ccm_check_tag(&ec, tag)) {
fprintf(stderr, "Tag should have changed\n");
exit(EXIT_FAILURE);
}
/*
* When the AAD is really big, we don't want to do
* the complete quadratic operation.
*/
if (v >= 32) {
break;
}
}
if (aad != aad_buf) {
free(aad);
}
printf(".");
fflush(stdout);
}
printf(" done.\n");
fflush(stdout);
}
static void
test_CCM(void)
{
const br_block_ctrcbc_class *x_ctrcbc;
test_CCM_inner("aes_big", &br_aes_big_ctrcbc_vtable);
test_CCM_inner("aes_small", &br_aes_small_ctrcbc_vtable);
test_CCM_inner("aes_ct", &br_aes_ct_ctrcbc_vtable);
test_CCM_inner("aes_ct64", &br_aes_ct64_ctrcbc_vtable);
x_ctrcbc = br_aes_x86ni_ctrcbc_get_vtable();
if (x_ctrcbc != NULL) {
test_CCM_inner("aes_x86ni", x_ctrcbc);
} else {
printf("Test CCM aes_x86ni: UNAVAILABLE\n");
}
}
static void
test_EC_inner(const char *sk, const char *sU,
const br_ec_impl *impl, int curve)
@ -6201,6 +6911,11 @@ static const struct {
STU(AES_ct64),
STU(AES_pwr8),
STU(AES_x86ni),
STU(AES_CTRCBC_big),
STU(AES_CTRCBC_small),
STU(AES_CTRCBC_ct),
STU(AES_CTRCBC_ct64),
STU(AES_CTRCBC_x86ni),
STU(DES_tab),
STU(DES_ct),
STU(ChaCha20_ct),
@ -6218,6 +6933,8 @@ static const struct {
STU(GHASH_ctmul64),
STU(GHASH_pclmul),
STU(GHASH_pwr8),
STU(CCM),
STU(EAX),
STU(GCM),
STU(EC_prime_i15),
STU(EC_prime_i31),

View File

@ -443,6 +443,82 @@ test_speed_poly1305_i15(void)
test_speed_poly1305_inner("Poly1305 (i15)", &br_poly1305_i15_run);
}
static void
test_speed_eax_inner(char *name,
const br_block_ctrcbc_class *vt, size_t key_len)
{
unsigned char buf[8192], key[32], nonce[16], aad[16], tag[16];
int i;
long num;
br_aes_gen_ctrcbc_keys ac;
br_eax_context ec;
memset(key, 'K', key_len);
memset(nonce, 'N', sizeof nonce);
memset(aad, 'A', sizeof aad);
memset(buf, 'T', sizeof buf);
for (i = 0; i < 10; i ++) {
vt->init(&ac.vtable, key, key_len);
br_eax_init(&ec, &ac.vtable);
br_eax_reset(&ec, nonce, sizeof nonce);
br_eax_aad_inject(&ec, aad, sizeof aad);
br_eax_flip(&ec);
br_eax_run(&ec, 1, buf, sizeof buf);
br_eax_get_tag(&ec, tag);
}
num = 10;
for (;;) {
clock_t begin, end;
double tt;
long k;
begin = clock();
for (k = num; k > 0; k --) {
vt->init(&ac.vtable, key, key_len);
br_eax_init(&ec, &ac.vtable);
br_eax_reset(&ec, nonce, sizeof nonce);
br_eax_aad_inject(&ec, aad, sizeof aad);
br_eax_flip(&ec);
br_eax_run(&ec, 1, buf, sizeof buf);
br_eax_get_tag(&ec, tag);
}
end = clock();
tt = (double)(end - begin) / CLOCKS_PER_SEC;
if (tt >= 2.0) {
printf("%-30s %8.2f MB/s\n", name,
((double)sizeof buf) * (double)num
/ (tt * 1000000.0));
fflush(stdout);
return;
}
num <<= 1;
}
}
#define SPEED_EAX(Algo, algo, keysize, impl) \
static void \
test_speed_eax_ ## algo ## keysize ## _ ## impl(void) \
{ \
test_speed_eax_inner("EAX " #Algo "-" #keysize "(" #impl ")", \
&br_ ## algo ## _ ## impl ## _ctrcbc_vtable, (keysize) >> 3); \
}
SPEED_EAX(AES, aes, 128, big)
SPEED_EAX(AES, aes, 128, small)
SPEED_EAX(AES, aes, 128, ct)
SPEED_EAX(AES, aes, 128, ct64)
SPEED_EAX(AES, aes, 128, x86ni)
SPEED_EAX(AES, aes, 192, big)
SPEED_EAX(AES, aes, 192, small)
SPEED_EAX(AES, aes, 192, ct)
SPEED_EAX(AES, aes, 192, ct64)
SPEED_EAX(AES, aes, 192, x86ni)
SPEED_EAX(AES, aes, 256, big)
SPEED_EAX(AES, aes, 256, small)
SPEED_EAX(AES, aes, 256, ct)
SPEED_EAX(AES, aes, 256, ct64)
SPEED_EAX(AES, aes, 256, x86ni)
static const unsigned char RSA_N[] = {
0xE9, 0xF2, 0x4A, 0x2F, 0x96, 0xDF, 0x0A, 0x23,
0x01, 0x85, 0xF1, 0x2C, 0xB2, 0xA8, 0xEF, 0x23,
@ -1300,6 +1376,22 @@ static const struct {
STU(poly1305_ctmulq),
STU(poly1305_i15),
STU(eax_aes128_big),
STU(eax_aes192_big),
STU(eax_aes256_big),
STU(eax_aes128_small),
STU(eax_aes192_small),
STU(eax_aes256_small),
STU(eax_aes128_ct),
STU(eax_aes192_ct),
STU(eax_aes256_ct),
STU(eax_aes128_ct64),
STU(eax_aes192_ct64),
STU(eax_aes256_ct64),
STU(eax_aes128_x86ni),
STU(eax_aes192_x86ni),
STU(eax_aes256_x86ni),
STU(rsa_i15),
STU(rsa_i31),
STU(rsa_i32),