mirror of https://github.com/status-im/BearSSL.git
Added general-purpose API for AEAD algorithms, and GCM implementation.
This commit is contained in:
parent
4aac1cd5c6
commit
127fb4a31d
|
@ -127,6 +127,7 @@
|
|||
#include "bearssl_rand.h"
|
||||
#include "bearssl_prf.h"
|
||||
#include "bearssl_block.h"
|
||||
#include "bearssl_aead.h"
|
||||
#include "bearssl_rsa.h"
|
||||
#include "bearssl_ec.h"
|
||||
#include "bearssl_ssl.h"
|
||||
|
|
|
@ -0,0 +1,461 @@
|
|||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef BR_BEARSSL_AEAD_H__
|
||||
#define BR_BEARSSL_AEAD_H__
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include "bearssl_block.h"
|
||||
#include "bearssl_hash.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/** \file bearssl_aead.h
|
||||
*
|
||||
* # Authenticated Encryption with Additional Data
|
||||
*
|
||||
* This file documents the API for AEAD encryption.
|
||||
*
|
||||
*
|
||||
* ## Procedural API
|
||||
*
|
||||
* An AEAD algorithm processes messages and provides confidentiality
|
||||
* (encryption) and checked integrity (MAC). It uses the following
|
||||
* parameters:
|
||||
*
|
||||
* - A symmetric key. Exact size depends on the AEAD algorithm.
|
||||
*
|
||||
* - A nonce (IV). Size depends on the AEAD algorithm; for most
|
||||
* algorithms, it is crucial for security that any given nonce
|
||||
* value is never used twice for the same key and distinct
|
||||
* messages.
|
||||
*
|
||||
* - Data to encrypt and protect.
|
||||
*
|
||||
* - Additional authenticated data, which is covered by the MAC but
|
||||
* otherwise left untouched (i.e. not encrypted).
|
||||
*
|
||||
* The AEAD algorithm encrypts the data, and produces an authentication
|
||||
* tag. It is assumed that the encrypted data, the tag, the additional
|
||||
* authenticated data and the nonce are sent to the receiver; the
|
||||
* additional data and the nonce may be implicit (e.g. using elements of
|
||||
* the underlying transport protocol, such as record sequence numbers).
|
||||
* The receiver will recompute the tag value and compare it with the one
|
||||
* received; if they match, then the data is correct, and can be
|
||||
* decrypted and used; otherwise, at least one of the elements was
|
||||
* altered in transit, normally leading to wholesale rejection of the
|
||||
* complete message.
|
||||
*
|
||||
* For each AEAD algorithm, identified by a symbolic name (hereafter
|
||||
* denoted as "`xxx`"), the following functions are defined:
|
||||
*
|
||||
* - `br_xxx_init()`
|
||||
*
|
||||
* Initialise the AEAD algorithm, on a provided context structure.
|
||||
* Exact parameters depend on the algorithm, and may include
|
||||
* pointers to extra implementations and context structures. The
|
||||
* secret key is provided at this point, either directly or
|
||||
* indirectly.
|
||||
*
|
||||
* - `br_xxx_reset()`
|
||||
*
|
||||
* Start a new AEAD computation. The nonce value is provided as
|
||||
* parameter to this function.
|
||||
*
|
||||
* - `br_xxx_aad_inject()`
|
||||
*
|
||||
* Inject some additional authenticated data. Additional data may
|
||||
* be provided in several chunks of arbitrary length.
|
||||
*
|
||||
* - `br_xxx_flip()`
|
||||
*
|
||||
* This function MUST be called after injecting all additional
|
||||
* authenticated data, and before beginning to encrypt the plaintext
|
||||
* (or decrypt the ciphertext).
|
||||
*
|
||||
* - `br_xxx_run()`
|
||||
*
|
||||
* Process some plaintext (to encrypt) or ciphertext (to decrypt).
|
||||
* Encryption/decryption is done in place. Data may be provided in
|
||||
* several chunks of arbitrary length.
|
||||
*
|
||||
* - `br_xxx_get_tag()`
|
||||
*
|
||||
* Compute the authentication tag. All message data (encrypted or
|
||||
* decrypted) must have been injected at that point. Also, this
|
||||
* call may modify internal context elements, so it may be called
|
||||
* only once for a given AEAD computation.
|
||||
*
|
||||
* - `br_xxx_check_tag()`
|
||||
*
|
||||
* An alternative to `br_xxx_get_tag()`, meant to be used by the
|
||||
* receiver: the authentication tag is internally recomputed, and
|
||||
* compared with the one provided as parameter.
|
||||
*
|
||||
* This API makes the following assumptions on the AEAD algorithm:
|
||||
*
|
||||
* - Encryption does not expand the size of the ciphertext; there is
|
||||
* no padding. This is true of most modern AEAD modes such as GCM.
|
||||
*
|
||||
* - The additional authenticated data must be processed first,
|
||||
* before the encrypted/decrypted data.
|
||||
*
|
||||
* - 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.
|
||||
*
|
||||
* Each AEAD algorithm has its own requirements and limits on the sizes
|
||||
* of additional data and plaintext. This API does not provide any
|
||||
* way to report invalid usage; it is up to the caller to ensure that
|
||||
* the provided key, nonce, and data elements all fit the algorithm's
|
||||
* requirements.
|
||||
*
|
||||
*
|
||||
* ## Object-Oriented API
|
||||
*
|
||||
* Each context structure begins with a field (called `vtable`) that
|
||||
* points to an instance of a structure that references the relevant
|
||||
* functions through pointers. Each such structure contains the
|
||||
* following:
|
||||
*
|
||||
* - `reset`
|
||||
*
|
||||
* Pointer to the reset function, that allows starting a new
|
||||
* computation.
|
||||
*
|
||||
* - `aad_inject`
|
||||
*
|
||||
* Pointer to the additional authenticated data injection function.
|
||||
*
|
||||
* - `flip`
|
||||
*
|
||||
* Pointer to the function that transitions from additional data
|
||||
* to main message data processing.
|
||||
*
|
||||
* - `get_tag`
|
||||
*
|
||||
* Pointer to the function that computes and returns the tag.
|
||||
*
|
||||
* - `check_tag`
|
||||
*
|
||||
* Pointer to the function that computes and verifies the tag against
|
||||
* a received value.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/**
|
||||
* \brief Class type of an AEAD algorithm.
|
||||
*/
|
||||
typedef struct br_aead_class_ br_aead_class;
|
||||
struct br_aead_class_ {
|
||||
|
||||
/**
|
||||
* \brief Size (in bytes) of authentication tags created by
|
||||
* this AEAD algorithm.
|
||||
*/
|
||||
size_t tag_size;
|
||||
|
||||
/**
|
||||
* \brief Reset an AEAD context.
|
||||
*
|
||||
* This function resets an already initialised AEAD context for
|
||||
* a new computation run. Implementations and keys are
|
||||
* conserved. This function can be called at any time; it
|
||||
* cancels any ongoing AEAD computation that uses the provided
|
||||
* context structure.
|
||||
|
||||
* The provided IV is a _nonce_. Each AEAD algorithm has its
|
||||
* own requirements on IV size and contents; for most of them,
|
||||
* it is crucial to security that each nonce value is used
|
||||
* only once for a given secret key.
|
||||
*
|
||||
* \param cc AEAD context structure.
|
||||
* \param iv AEAD nonce to use.
|
||||
* \param len AEAD nonce length (in bytes).
|
||||
*/
|
||||
void (*reset)(const br_aead_class **cc, const void *iv, size_t len);
|
||||
|
||||
/**
|
||||
* \brief Inject additional authenticated data.
|
||||
*
|
||||
* The provided data is injected into a running AEAD
|
||||
* computation. Additional data must be injected _before_ the
|
||||
* call to `flip()`. Additional data can be injected in several
|
||||
* chunks of arbitrary length.
|
||||
*
|
||||
* \param cc AEAD context structure.
|
||||
* \param data pointer to additional authenticated data.
|
||||
* \param len length of additiona authenticated data (in bytes).
|
||||
*/
|
||||
void (*aad_inject)(const br_aead_class **cc,
|
||||
const void *data, size_t len);
|
||||
|
||||
/**
|
||||
* \brief Finish injection of additional authenticated data.
|
||||
*
|
||||
* This function MUST be called before beginning the actual
|
||||
* encryption or decryption (with `run()`), even if no
|
||||
* additional authenticated data was injected. No additional
|
||||
* authenticated data may be injected after this function call.
|
||||
*
|
||||
* \param cc AEAD context structure.
|
||||
*/
|
||||
void (*flip)(const br_aead_class **cc);
|
||||
|
||||
/**
|
||||
* \brief Encrypt or decrypt some data.
|
||||
*
|
||||
* Data encryption or decryption can be done after `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 cc AEAD 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 (*run)(const br_aead_class **cc, int encrypt,
|
||||
void *data, size_t len);
|
||||
|
||||
/**
|
||||
* \brief Compute authentication tag.
|
||||
*
|
||||
* Compute the AEAD authentication tag. The tag length depends
|
||||
* on the AEAD algorithm; it is written in the provided `tag`
|
||||
* buffer. This call terminates the AEAD run: no data may be
|
||||
* processed with that AEAD context afterwards, until `reset()`
|
||||
* is called to initiate a new AEAD 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
|
||||
* `check_tag()` function may be used to compute and check the
|
||||
* tag value.
|
||||
*
|
||||
* \param cc AEAD context structure.
|
||||
* \param tag destination buffer for the tag.
|
||||
*/
|
||||
void (*get_tag)(const br_aead_class **cc, void *tag);
|
||||
|
||||
/**
|
||||
* \brief Compute and check authentication tag.
|
||||
*
|
||||
* This function is an alternative to `get_tag()`, and is
|
||||
* normally used on the receiving end (i.e. when decrypting
|
||||
* messages). 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 cc AEAD context structure.
|
||||
* \param tag tag value to compare with (16 bytes).
|
||||
* \return 1 on success (exact match of tag value), 0 otherwise.
|
||||
*/
|
||||
uint32_t (*check_tag)(const br_aead_class **cc, const void *tag);
|
||||
};
|
||||
|
||||
/**
|
||||
* \brief Context structure for GCM.
|
||||
*
|
||||
* GCM is an AEAD mode that combines a block cipher in CTR mode with a
|
||||
* MAC based on GHASH, to provide authenticated encryption:
|
||||
*
|
||||
* - Any block cipher with 16-byte blocks can be used with GCM.
|
||||
*
|
||||
* - The nonce can have any length, from 0 up to 2^64-1 bits; however,
|
||||
* 96-bit nonces (12 bytes) are recommended (nonces with a length
|
||||
* distinct from 12 bytes are internally hashed, which risks reusing
|
||||
* nonce value with a small but not always negligible probability).
|
||||
*
|
||||
* - Additional authenticated data may have length up to 2^64-1 bits.
|
||||
*
|
||||
* - Message length may range up to 2^39-256 bits at most.
|
||||
*
|
||||
* - The authentication tag has length 16 bytes.
|
||||
*
|
||||
* The GCM 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
|
||||
* GCM 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_ctr_class **bctx;
|
||||
br_ghash gh;
|
||||
unsigned char h[16];
|
||||
unsigned char j0_1[12];
|
||||
unsigned char buf[16];
|
||||
unsigned char y[16];
|
||||
uint32_t j0_2, jc;
|
||||
uint64_t count_aad, count_ctr;
|
||||
#endif
|
||||
} br_gcm_context;
|
||||
|
||||
/**
|
||||
* \brief Initialize a GCM context.
|
||||
*
|
||||
* A block cipher implementation, with its initialised context structure,
|
||||
* is provided. The block cipher MUST use 16-byte blocks in CTR mode,
|
||||
* and its secret key MUST have been already set in the provided context.
|
||||
* A GHASH implementation must also be provided. The parameters are linked
|
||||
* in the GCM context.
|
||||
*
|
||||
* After this function has been called, the `br_gcm_reset()` function must
|
||||
* be called, to provide the IV for GCM computation.
|
||||
*
|
||||
* \param ctx GCM context structure.
|
||||
* \param bctx block cipher context (already initialised with secret key).
|
||||
* \param gh GHASH implementation.
|
||||
*/
|
||||
void br_gcm_init(br_gcm_context *ctx,
|
||||
const br_block_ctr_class **bctx, br_ghash gh);
|
||||
|
||||
/**
|
||||
* \brief Reset a GCM context.
|
||||
*
|
||||
* This function resets an already initialised GCM context for a new
|
||||
* computation run. Implementations and keys are conserved. This function
|
||||
* can be called at any time; it cancels any ongoing GCM computation that
|
||||
* uses the provided context structure.
|
||||
*
|
||||
* The provided IV is a _nonce_. It is critical to GCM security that IV
|
||||
* values are not repeated for the same encryption key. IV can have
|
||||
* arbitrary length (up to 2^64-1 bits), but the "normal" length is
|
||||
* 96 bits (12 bytes).
|
||||
*
|
||||
* \param ctx GCM context structure.
|
||||
* \param iv GCM nonce to use.
|
||||
* \param len GCM nonce length (in bytes).
|
||||
*/
|
||||
void br_gcm_reset(br_gcm_context *ctx, const void *iv, size_t len);
|
||||
|
||||
/**
|
||||
* \brief Inject additional authenticated data into GCM.
|
||||
*
|
||||
* The provided data is injected into a running GCM computation. Additional
|
||||
* data must be injected _before_ the call to `br_gcm_flip()`.
|
||||
* Additional data can be injected in several chunks of arbitrary length;
|
||||
* the maximum total size of additional authenticated data is 2^64-1
|
||||
* bits.
|
||||
*
|
||||
* \param ctx GCM context structure.
|
||||
* \param data pointer to additional authenticated data.
|
||||
* \param len length of additiona authenticated data (in bytes).
|
||||
*/
|
||||
void br_gcm_aad_inject(br_gcm_context *ctx, const void *data, size_t len);
|
||||
|
||||
/**
|
||||
* \brief Finish injection of additional authenticated data into GCM.
|
||||
*
|
||||
* This function MUST be called before beginning the actual encryption
|
||||
* or decryption (with `br_gcm_run()`), even if no additional authenticated
|
||||
* data was injected. No additional authenticated data may be injected
|
||||
* after this function call.
|
||||
*
|
||||
* \param ctx GCM context structure.
|
||||
*/
|
||||
void br_gcm_flip(br_gcm_context *ctx);
|
||||
|
||||
/**
|
||||
* \brief Encrypt or decrypt some data with GCM.
|
||||
*
|
||||
* Data encryption or decryption can be done after `br_gcm_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. The maximum
|
||||
* total length for data is 2^39-256 bits, i.e. about 65 gigabytes.
|
||||
*
|
||||
* \param ctx GCM 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_gcm_run(br_gcm_context *ctx, int encrypt, void *data, size_t len);
|
||||
|
||||
/**
|
||||
* \brief Compute GCM authentication tag.
|
||||
*
|
||||
* Compute the GCM authentication tag. The tag is a 16-byte value which
|
||||
* 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()` function can be used to
|
||||
* compute and check the tag value.
|
||||
*
|
||||
* \param ctx GCM context structure.
|
||||
* \param tag destination buffer for the tag (16 bytes).
|
||||
*/
|
||||
void br_gcm_get_tag(br_gcm_context *ctx, void *tag);
|
||||
|
||||
/**
|
||||
* \brief Compute and check GCM authentication tag.
|
||||
*
|
||||
* This function is an alternative to `br_gcm_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 GCM 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_gcm_check_tag(br_gcm_context *ctx, const void *tag);
|
||||
|
||||
/**
|
||||
* \brief Class instance for GCM.
|
||||
*/
|
||||
extern const br_aead_class br_gcm_vtable;
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
11
mk/Rules.mk
11
mk/Rules.mk
File diff suppressed because one or more lines are too long
|
@ -49,6 +49,7 @@ set -e
|
|||
|
||||
# Source files. Please keep in alphabetical order.
|
||||
coresrc=" \
|
||||
src/aead/gcm.c \
|
||||
src/codec/ccopy.c \
|
||||
src/codec/dec16be.c \
|
||||
src/codec/dec16le.c \
|
||||
|
@ -307,6 +308,7 @@ testx509src=" \
|
|||
# Public header files.
|
||||
headerspub=" \
|
||||
inc/bearssl.h \
|
||||
inc/bearssl_aead.h \
|
||||
inc/bearssl_block.h \
|
||||
inc/bearssl_ec.h \
|
||||
inc/bearssl_hash.h \
|
||||
|
@ -432,7 +434,9 @@ tools: \$(BRSSL)
|
|||
|
||||
tests: \$(TESTCRYPTO) \$(TESTSPEED) \$(TESTX509)
|
||||
|
||||
T0: \$(T0COMP) src\$Pssl\$Pssl_hs_common.t0 src\$Pssl\$Pssl_hs_client.t0 src\$Pssl\$Pssl_hs_server.t0 src\$Px509\$Pasn1.t0 src\$Px509\$Pskey_decoder.t0 src\$Px509\$Px509_decoder.t0 src\$Px509\$Px509_minimal.t0
|
||||
T0: kT0
|
||||
|
||||
kT0: \$(T0COMP) src\$Pssl\$Pssl_hs_common.t0 src\$Pssl\$Pssl_hs_client.t0 src\$Pssl\$Pssl_hs_server.t0 src\$Px509\$Pasn1.t0 src\$Px509\$Pskey_decoder.t0 src\$Px509\$Px509_decoder.t0 src\$Px509\$Px509_minimal.t0
|
||||
\$(RUNT0COMP) -o src\$Pcodec\$Ppemdec -r br_pem_decoder src\$Pcodec\$Ppemdec.t0
|
||||
\$(RUNT0COMP) -o src\$Pssl\$Pssl_hs_client -r br_ssl_hs_client src\$Pssl\$Pssl_hs_common.t0 src\$Pssl\$Pssl_hs_client.t0
|
||||
\$(RUNT0COMP) -o src\$Pssl\$Pssl_hs_server -r br_ssl_hs_server src\$Pssl\$Pssl_hs_common.t0 src\$Pssl\$Pssl_hs_server.t0
|
||||
|
|
|
@ -0,0 +1,296 @@
|
|||
/*
|
||||
* 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
|
||||
* ====================
|
||||
*
|
||||
* Since CTR and GHASH implementations can handle only full blocks, a
|
||||
* 16-byte buffer (buf[]) is maintained in the context:
|
||||
*
|
||||
* - When processing AAD, buf[] contains the 0-15 unprocessed bytes.
|
||||
*
|
||||
* - When doing CTR encryption / decryption, buf[] contains the AES output
|
||||
* for the last partial block, to be used with the next few bytes of
|
||||
* data, as well as the already encrypted bytes. For instance, if the
|
||||
* processed data length so far is 21 bytes, then buf[0..4] contains
|
||||
* the five last encrypted bytes, and buf[5..15] contains the next 11
|
||||
* AES output bytes to be XORed with the next 11 bytes of input.
|
||||
*
|
||||
* The recorded AES output bytes are used to complete the block when
|
||||
* the corresponding bytes are obtained. Note that buf[] always
|
||||
* contains the _encrypted_ bytes, whether we apply encryption or
|
||||
* decryption: these bytes are used as input to GHASH when the block
|
||||
* is complete.
|
||||
*
|
||||
* In both cases, the low bits of the data length counters (count_aad,
|
||||
* count_ctr) are used to work out the current situation.
|
||||
*/
|
||||
|
||||
/* see bearssl_aead.h */
|
||||
void
|
||||
br_gcm_init(br_gcm_context *ctx, const br_block_ctr_class **bctx, br_ghash gh)
|
||||
{
|
||||
unsigned char iv[12];
|
||||
|
||||
ctx->bctx = bctx;
|
||||
ctx->gh = gh;
|
||||
|
||||
/*
|
||||
* The GHASH key h[] is the raw encryption of the all-zero
|
||||
* block. Since we only have a CTR implementation, we use it
|
||||
* with an all-zero IV and a zero counter, to CTR-encrypt an
|
||||
* all-zero block.
|
||||
*/
|
||||
memset(ctx->h, 0, sizeof ctx->h);
|
||||
memset(iv, 0, sizeof iv);
|
||||
(*bctx)->run(bctx, iv, 0, ctx->h, sizeof ctx->h);
|
||||
}
|
||||
|
||||
/* see bearssl_aead.h */
|
||||
void
|
||||
br_gcm_reset(br_gcm_context *ctx, const void *iv, size_t len)
|
||||
{
|
||||
/*
|
||||
* If the provided nonce is 12 bytes, then this is the initial
|
||||
* IV for CTR mode; it will be used with a counter that starts
|
||||
* at 2 (value 1 is for encrypting the GHASH output into the tag).
|
||||
*
|
||||
* If the provided nonce has any other length, then it is hashed
|
||||
* (with GHASH) into a 16-byte value that will be the IV for CTR
|
||||
* (both 12-byte IV and 32-bit counter).
|
||||
*/
|
||||
if (len == 12) {
|
||||
memcpy(ctx->j0_1, iv, 12);
|
||||
ctx->j0_2 = 1;
|
||||
} else {
|
||||
unsigned char ty[16], tmp[16];
|
||||
|
||||
memset(ty, 0, sizeof ty);
|
||||
ctx->gh(ty, ctx->h, iv, len);
|
||||
memset(tmp, 0, 8);
|
||||
br_enc64be(tmp + 8, (uint64_t)len << 3);
|
||||
ctx->gh(ty, ctx->h, tmp, 16);
|
||||
memcpy(ctx->j0_1, ty, 12);
|
||||
ctx->j0_2 = br_dec32be(ty + 12);
|
||||
}
|
||||
ctx->jc = ctx->j0_2 + 1;
|
||||
memset(ctx->y, 0, sizeof ctx->y);
|
||||
ctx->count_aad = 0;
|
||||
ctx->count_ctr = 0;
|
||||
}
|
||||
|
||||
/* see bearssl_aead.h */
|
||||
void
|
||||
br_gcm_aad_inject(br_gcm_context *ctx, const void *data, size_t len)
|
||||
{
|
||||
size_t ptr, dlen;
|
||||
|
||||
ptr = (size_t)ctx->count_aad & (size_t)15;
|
||||
if (ptr != 0) {
|
||||
/*
|
||||
* If there is a partial block, then we first try to
|
||||
* complete it.
|
||||
*/
|
||||
size_t clen;
|
||||
|
||||
clen = 16 - ptr;
|
||||
if (len < clen) {
|
||||
memcpy(ctx->buf + ptr, data, len);
|
||||
ctx->count_aad += (uint64_t)len;
|
||||
return;
|
||||
}
|
||||
memcpy(ctx->buf + ptr, data, clen);
|
||||
ctx->gh(ctx->y, ctx->h, ctx->buf, 16);
|
||||
data = (const unsigned char *)data + clen;
|
||||
len -= clen;
|
||||
ctx->count_aad += (uint64_t)clen;
|
||||
}
|
||||
|
||||
/*
|
||||
* Now AAD is aligned on a 16-byte block (with regards to GHASH).
|
||||
* We process all complete blocks, and save the last partial
|
||||
* block.
|
||||
*/
|
||||
dlen = len & ~(size_t)15;
|
||||
ctx->gh(ctx->y, ctx->h, data, dlen);
|
||||
memcpy(ctx->buf, (const unsigned char *)data + dlen, len - dlen);
|
||||
ctx->count_aad += (uint64_t)len;
|
||||
}
|
||||
|
||||
/* see bearssl_aead.h */
|
||||
void
|
||||
br_gcm_flip(br_gcm_context *ctx)
|
||||
{
|
||||
/*
|
||||
* We complete the GHASH computation if there is a partial block.
|
||||
* The GHASH implementation automatically applies padding with
|
||||
* zeros.
|
||||
*/
|
||||
size_t ptr;
|
||||
|
||||
ptr = (size_t)ctx->count_aad & (size_t)15;
|
||||
if (ptr != 0) {
|
||||
ctx->gh(ctx->y, ctx->h, ctx->buf, ptr);
|
||||
}
|
||||
}
|
||||
|
||||
/* see bearssl_aead.h */
|
||||
void
|
||||
br_gcm_run(br_gcm_context *ctx, int encrypt, void *data, size_t len)
|
||||
{
|
||||
unsigned char *buf;
|
||||
size_t ptr, dlen;
|
||||
|
||||
buf = data;
|
||||
ptr = (size_t)ctx->count_ctr & (size_t)15;
|
||||
if (ptr != 0) {
|
||||
/*
|
||||
* If we have a partial block, then we try to complete it.
|
||||
*/
|
||||
size_t u, clen;
|
||||
|
||||
clen = 16 - ptr;
|
||||
if (len < clen) {
|
||||
clen = len;
|
||||
}
|
||||
for (u = 0; u < clen; u ++) {
|
||||
unsigned x, y;
|
||||
|
||||
x = buf[u];
|
||||
y = x ^ ctx->buf[ptr + u];
|
||||
ctx->buf[ptr + u] = encrypt ? y : x;
|
||||
buf[u] = y;
|
||||
}
|
||||
ctx->count_ctr += (uint64_t)clen;
|
||||
buf += clen;
|
||||
len -= clen;
|
||||
if (ptr + clen < 16) {
|
||||
return;
|
||||
}
|
||||
ctx->gh(ctx->y, ctx->h, ctx->buf, 16);
|
||||
}
|
||||
|
||||
/*
|
||||
* Process full blocks.
|
||||
*/
|
||||
dlen = len & ~(size_t)15;
|
||||
if (!encrypt) {
|
||||
ctx->gh(ctx->y, ctx->h, buf, dlen);
|
||||
}
|
||||
ctx->jc = (*ctx->bctx)->run(ctx->bctx, ctx->j0_1, ctx->jc, buf, dlen);
|
||||
if (encrypt) {
|
||||
ctx->gh(ctx->y, ctx->h, buf, dlen);
|
||||
}
|
||||
buf += dlen;
|
||||
len -= dlen;
|
||||
ctx->count_ctr += (uint64_t)dlen;
|
||||
|
||||
if (len > 0) {
|
||||
/*
|
||||
* There is a partial block.
|
||||
*/
|
||||
size_t u;
|
||||
|
||||
memset(ctx->buf, 0, sizeof ctx->buf);
|
||||
ctx->jc = (*ctx->bctx)->run(ctx->bctx, ctx->j0_1,
|
||||
ctx->jc, ctx->buf, 16);
|
||||
for (u = 0; u < len; u ++) {
|
||||
unsigned x, y;
|
||||
|
||||
x = buf[u];
|
||||
y = x ^ ctx->buf[u];
|
||||
ctx->buf[u] = encrypt ? y : x;
|
||||
buf[u] = y;
|
||||
}
|
||||
ctx->count_ctr += (uint64_t)len;
|
||||
}
|
||||
}
|
||||
|
||||
/* see bearssl_aead.h */
|
||||
void
|
||||
br_gcm_get_tag(br_gcm_context *ctx, void *tag)
|
||||
{
|
||||
size_t ptr;
|
||||
unsigned char tmp[16];
|
||||
|
||||
ptr = (size_t)ctx->count_ctr & (size_t)15;
|
||||
if (ptr > 0) {
|
||||
/*
|
||||
* There is a partial block: encrypted/decrypted data has
|
||||
* been produced, but the encrypted bytes must still be
|
||||
* processed by GHASH.
|
||||
*/
|
||||
ctx->gh(ctx->y, ctx->h, ctx->buf, ptr);
|
||||
}
|
||||
|
||||
/*
|
||||
* Final block for GHASH: the AAD and plaintext lengths (in bits).
|
||||
*/
|
||||
br_enc64be(tmp, ctx->count_aad << 3);
|
||||
br_enc64be(tmp + 8, ctx->count_ctr << 3);
|
||||
ctx->gh(ctx->y, ctx->h, tmp, 16);
|
||||
|
||||
/*
|
||||
* Tag is the GHASH output XORed with the encryption of the
|
||||
* nonce with the initial counter value.
|
||||
*/
|
||||
memcpy(tag, ctx->y, 16);
|
||||
(*ctx->bctx)->run(ctx->bctx, ctx->j0_1, ctx->j0_2, tag, 16);
|
||||
}
|
||||
|
||||
/* see bearssl_aead.h */
|
||||
uint32_t
|
||||
br_gcm_check_tag(br_gcm_context *ctx, const void *tag)
|
||||
{
|
||||
unsigned char tmp[16];
|
||||
size_t u;
|
||||
int x;
|
||||
|
||||
br_gcm_get_tag(ctx, tmp);
|
||||
x = 0;
|
||||
for (u = 0; u < sizeof tmp; u ++) {
|
||||
x |= tmp[u] ^ ((const unsigned char *)tag)[u];
|
||||
}
|
||||
return EQ0(x);
|
||||
}
|
||||
|
||||
/* see bearssl_aead.h */
|
||||
const br_aead_class br_gcm_vtable = {
|
||||
16,
|
||||
(void (*)(const br_aead_class **, const void *, size_t))
|
||||
&br_gcm_reset,
|
||||
(void (*)(const br_aead_class **, const void *, size_t))
|
||||
&br_gcm_aad_inject,
|
||||
(void (*)(const br_aead_class **))
|
||||
&br_gcm_flip,
|
||||
(void (*)(const br_aead_class **, int, void *, size_t))
|
||||
&br_gcm_run,
|
||||
(void (*)(const br_aead_class **, void *))
|
||||
&br_gcm_get_tag,
|
||||
(uint32_t (*)(const br_aead_class **, const void *))
|
||||
&br_gcm_check_tag
|
||||
};
|
|
@ -4892,6 +4892,258 @@ test_GHASH_pwr8(void)
|
|||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* From: http://csrc.nist.gov/groups/ST/toolkit/BCM/documents/proposedmodes/gcm/gcm-revised-spec.pdf
|
||||
*
|
||||
* Order: key, plaintext, AAD, IV, ciphertext, tag
|
||||
*/
|
||||
static const char *const KAT_GCM[] = {
|
||||
"00000000000000000000000000000000",
|
||||
"",
|
||||
"",
|
||||
"000000000000000000000000",
|
||||
"",
|
||||
"58e2fccefa7e3061367f1d57a4e7455a",
|
||||
|
||||
"00000000000000000000000000000000",
|
||||
"00000000000000000000000000000000",
|
||||
"",
|
||||
"000000000000000000000000",
|
||||
"0388dace60b6a392f328c2b971b2fe78",
|
||||
"ab6e47d42cec13bdf53a67b21257bddf",
|
||||
|
||||
"feffe9928665731c6d6a8f9467308308",
|
||||
"d9313225f88406e5a55909c5aff5269a86a7a9531534f7da2e4c303d8a318a721c3c0c95956809532fcf0e2449a6b525b16aedf5aa0de657ba637b391aafd255",
|
||||
"",
|
||||
"cafebabefacedbaddecaf888",
|
||||
"42831ec2217774244b7221b784d0d49ce3aa212f2c02a4e035c17e2329aca12e21d514b25466931c7d8f6a5aac84aa051ba30b396a0aac973d58e091473f5985",
|
||||
"4d5c2af327cd64a62cf35abd2ba6fab4",
|
||||
|
||||
"feffe9928665731c6d6a8f9467308308",
|
||||
"d9313225f88406e5a55909c5aff5269a86a7a9531534f7da2e4c303d8a318a721c3c0c95956809532fcf0e2449a6b525b16aedf5aa0de657ba637b39",
|
||||
"feedfacedeadbeeffeedfacedeadbeefabaddad2",
|
||||
"cafebabefacedbaddecaf888",
|
||||
"42831ec2217774244b7221b784d0d49ce3aa212f2c02a4e035c17e2329aca12e21d514b25466931c7d8f6a5aac84aa051ba30b396a0aac973d58e091",
|
||||
"5bc94fbc3221a5db94fae95ae7121a47",
|
||||
|
||||
"feffe9928665731c6d6a8f9467308308",
|
||||
"d9313225f88406e5a55909c5aff5269a86a7a9531534f7da2e4c303d8a318a721c3c0c95956809532fcf0e2449a6b525b16aedf5aa0de657ba637b39",
|
||||
"feedfacedeadbeeffeedfacedeadbeefabaddad2",
|
||||
"cafebabefacedbad",
|
||||
"61353b4c2806934a777ff51fa22a4755699b2a714fcdc6f83766e5f97b6c742373806900e49f24b22b097544d4896b424989b5e1ebac0f07c23f4598",
|
||||
"3612d2e79e3b0785561be14aaca2fccb",
|
||||
|
||||
"feffe9928665731c6d6a8f9467308308",
|
||||
"d9313225f88406e5a55909c5aff5269a86a7a9531534f7da2e4c303d8a318a721c3c0c95956809532fcf0e2449a6b525b16aedf5aa0de657ba637b39",
|
||||
"feedfacedeadbeeffeedfacedeadbeefabaddad2",
|
||||
"9313225df88406e555909c5aff5269aa6a7a9538534f7da1e4c303d2a318a728c3c0c95156809539fcf0e2429a6b525416aedbf5a0de6a57a637b39b",
|
||||
"8ce24998625615b603a033aca13fb894be9112a5c3a211a8ba262a3cca7e2ca701e4a9a4fba43c90ccdcb281d48c7c6fd62875d2aca417034c34aee5",
|
||||
"619cc5aefffe0bfa462af43c1699d050",
|
||||
|
||||
"000000000000000000000000000000000000000000000000",
|
||||
"",
|
||||
"",
|
||||
"000000000000000000000000",
|
||||
"",
|
||||
"cd33b28ac773f74ba00ed1f312572435",
|
||||
|
||||
"000000000000000000000000000000000000000000000000",
|
||||
"00000000000000000000000000000000",
|
||||
"",
|
||||
"000000000000000000000000",
|
||||
"98e7247c07f0fe411c267e4384b0f600",
|
||||
"2ff58d80033927ab8ef4d4587514f0fb",
|
||||
|
||||
"feffe9928665731c6d6a8f9467308308feffe9928665731c",
|
||||
"d9313225f88406e5a55909c5aff5269a86a7a9531534f7da2e4c303d8a318a721c3c0c95956809532fcf0e2449a6b525b16aedf5aa0de657ba637b391aafd255",
|
||||
"",
|
||||
"cafebabefacedbaddecaf888",
|
||||
"3980ca0b3c00e841eb06fac4872a2757859e1ceaa6efd984628593b40ca1e19c7d773d00c144c525ac619d18c84a3f4718e2448b2fe324d9ccda2710acade256",
|
||||
"9924a7c8587336bfb118024db8674a14",
|
||||
|
||||
"feffe9928665731c6d6a8f9467308308feffe9928665731c",
|
||||
"d9313225f88406e5a55909c5aff5269a86a7a9531534f7da2e4c303d8a318a721c3c0c95956809532fcf0e2449a6b525b16aedf5aa0de657ba637b39",
|
||||
"feedfacedeadbeeffeedfacedeadbeefabaddad2",
|
||||
"cafebabefacedbaddecaf888",
|
||||
"3980ca0b3c00e841eb06fac4872a2757859e1ceaa6efd984628593b40ca1e19c7d773d00c144c525ac619d18c84a3f4718e2448b2fe324d9ccda2710",
|
||||
"2519498e80f1478f37ba55bd6d27618c",
|
||||
|
||||
"feffe9928665731c6d6a8f9467308308feffe9928665731c",
|
||||
"d9313225f88406e5a55909c5aff5269a86a7a9531534f7da2e4c303d8a318a721c3c0c95956809532fcf0e2449a6b525b16aedf5aa0de657ba637b39",
|
||||
"feedfacedeadbeeffeedfacedeadbeefabaddad2",
|
||||
"cafebabefacedbad",
|
||||
"0f10f599ae14a154ed24b36e25324db8c566632ef2bbb34f8347280fc4507057fddc29df9a471f75c66541d4d4dad1c9e93a19a58e8b473fa0f062f7",
|
||||
"65dcc57fcf623a24094fcca40d3533f8",
|
||||
|
||||
"feffe9928665731c6d6a8f9467308308feffe9928665731c",
|
||||
"d9313225f88406e5a55909c5aff5269a86a7a9531534f7da2e4c303d8a318a721c3c0c95956809532fcf0e2449a6b525b16aedf5aa0de657ba637b39",
|
||||
"feedfacedeadbeeffeedfacedeadbeefabaddad2",
|
||||
"9313225df88406e555909c5aff5269aa6a7a9538534f7da1e4c303d2a318a728c3c0c95156809539fcf0e2429a6b525416aedbf5a0de6a57a637b39b",
|
||||
"d27e88681ce3243c4830165a8fdcf9ff1de9a1d8e6b447ef6ef7b79828666e4581e79012af34ddd9e2f037589b292db3e67c036745fa22e7e9b7373b",
|
||||
"dcf566ff291c25bbb8568fc3d376a6d9",
|
||||
|
||||
"0000000000000000000000000000000000000000000000000000000000000000",
|
||||
"",
|
||||
"",
|
||||
"000000000000000000000000",
|
||||
"",
|
||||
"530f8afbc74536b9a963b4f1c4cb738b",
|
||||
|
||||
"0000000000000000000000000000000000000000000000000000000000000000",
|
||||
"00000000000000000000000000000000",
|
||||
"",
|
||||
"000000000000000000000000",
|
||||
"cea7403d4d606b6e074ec5d3baf39d18",
|
||||
"d0d1c8a799996bf0265b98b5d48ab919",
|
||||
|
||||
"feffe9928665731c6d6a8f9467308308feffe9928665731c6d6a8f9467308308",
|
||||
"d9313225f88406e5a55909c5aff5269a86a7a9531534f7da2e4c303d8a318a721c3c0c95956809532fcf0e2449a6b525b16aedf5aa0de657ba637b391aafd255",
|
||||
"",
|
||||
"cafebabefacedbaddecaf888",
|
||||
"522dc1f099567d07f47f37a32a84427d643a8cdcbfe5c0c97598a2bd2555d1aa8cb08e48590dbb3da7b08b1056828838c5f61e6393ba7a0abcc9f662898015ad",
|
||||
"b094dac5d93471bdec1a502270e3cc6c",
|
||||
|
||||
"feffe9928665731c6d6a8f9467308308feffe9928665731c6d6a8f9467308308",
|
||||
"d9313225f88406e5a55909c5aff5269a86a7a9531534f7da2e4c303d8a318a721c3c0c95956809532fcf0e2449a6b525b16aedf5aa0de657ba637b39",
|
||||
"feedfacedeadbeeffeedfacedeadbeefabaddad2",
|
||||
"cafebabefacedbaddecaf888",
|
||||
"522dc1f099567d07f47f37a32a84427d643a8cdcbfe5c0c97598a2bd2555d1aa8cb08e48590dbb3da7b08b1056828838c5f61e6393ba7a0abcc9f662",
|
||||
"76fc6ece0f4e1768cddf8853bb2d551b",
|
||||
|
||||
"feffe9928665731c6d6a8f9467308308feffe9928665731c6d6a8f9467308308",
|
||||
"d9313225f88406e5a55909c5aff5269a86a7a9531534f7da2e4c303d8a318a721c3c0c95956809532fcf0e2449a6b525b16aedf5aa0de657ba637b39",
|
||||
"feedfacedeadbeeffeedfacedeadbeefabaddad2",
|
||||
"cafebabefacedbad",
|
||||
"c3762df1ca787d32ae47c13bf19844cbaf1ae14d0b976afac52ff7d79bba9de0feb582d33934a4f0954cc2363bc73f7862ac430e64abe499f47c9b1f",
|
||||
"3a337dbf46a792c45e454913fe2ea8f2",
|
||||
|
||||
"feffe9928665731c6d6a8f9467308308feffe9928665731c6d6a8f9467308308",
|
||||
"d9313225f88406e5a55909c5aff5269a86a7a9531534f7da2e4c303d8a318a721c3c0c95956809532fcf0e2449a6b525b16aedf5aa0de657ba637b39",
|
||||
"feedfacedeadbeeffeedfacedeadbeefabaddad2",
|
||||
"9313225df88406e555909c5aff5269aa6a7a9538534f7da1e4c303d2a318a728c3c0c95156809539fcf0e2429a6b525416aedbf5a0de6a57a637b39b",
|
||||
"5a8def2f0c9e53f1f75d7853659e2a20eeb2b22aafde6419a058ab4f6f746bf40fc0c3b780f244452da3ebf1c5d82cdea2418997200ef82e44ae7e3f",
|
||||
"a44a8266ee1c8eb0c8b5d4cf5ae9f19a",
|
||||
|
||||
NULL
|
||||
};
|
||||
|
||||
static void
|
||||
test_GCM(void)
|
||||
{
|
||||
size_t u;
|
||||
|
||||
printf("Test GCM: ");
|
||||
fflush(stdout);
|
||||
|
||||
for (u = 0; KAT_GCM[u]; u += 6) {
|
||||
unsigned char key[32];
|
||||
unsigned char plain[100];
|
||||
unsigned char aad[100];
|
||||
unsigned char iv[100];
|
||||
unsigned char cipher[100];
|
||||
unsigned char tag[100];
|
||||
size_t key_len, plain_len, aad_len, iv_len;
|
||||
br_aes_ct_ctr_keys bc;
|
||||
br_gcm_context gc;
|
||||
unsigned char tmp[100], out[16];
|
||||
size_t v;
|
||||
|
||||
key_len = hextobin(key, KAT_GCM[u]);
|
||||
plain_len = hextobin(plain, KAT_GCM[u + 1]);
|
||||
aad_len = hextobin(aad, KAT_GCM[u + 2]);
|
||||
iv_len = hextobin(iv, KAT_GCM[u + 3]);
|
||||
hextobin(cipher, KAT_GCM[u + 4]);
|
||||
hextobin(tag, KAT_GCM[u + 5]);
|
||||
|
||||
br_aes_ct_ctr_init(&bc, key, key_len);
|
||||
br_gcm_init(&gc, &bc.vtable, br_ghash_ctmul32);
|
||||
|
||||
memset(tmp, 0x54, sizeof tmp);
|
||||
|
||||
/*
|
||||
* Basic operation.
|
||||
*/
|
||||
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(&gc, out);
|
||||
check_equals("KAT GCM 1", tmp, cipher, plain_len);
|
||||
check_equals("KAT GCM 2", out, tag, 16);
|
||||
|
||||
br_gcm_reset(&gc, iv, iv_len);
|
||||
br_gcm_aad_inject(&gc, aad, aad_len);
|
||||
br_gcm_flip(&gc);
|
||||
br_gcm_run(&gc, 0, tmp, plain_len);
|
||||
check_equals("KAT GCM 3", tmp, plain, plain_len);
|
||||
if (!br_gcm_check_tag(&gc, 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_gcm_reset(&gc, iv, iv_len);
|
||||
for (v = 0; v < aad_len; v ++) {
|
||||
br_gcm_aad_inject(&gc, aad + v, 1);
|
||||
}
|
||||
br_gcm_flip(&gc);
|
||||
for (v = 0; v < plain_len; v ++) {
|
||||
br_gcm_run(&gc, 1, tmp + v, 1);
|
||||
}
|
||||
check_equals("KAT GCM 4", tmp, cipher, plain_len);
|
||||
if (!br_gcm_check_tag(&gc, tag)) {
|
||||
fprintf(stderr, "Tag not verified (2)\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
br_gcm_reset(&gc, iv, iv_len);
|
||||
for (v = 0; v < aad_len; v ++) {
|
||||
br_gcm_aad_inject(&gc, aad + v, 1);
|
||||
}
|
||||
br_gcm_flip(&gc);
|
||||
for (v = 0; v < plain_len; v ++) {
|
||||
br_gcm_run(&gc, 0, tmp + v, 1);
|
||||
}
|
||||
br_gcm_get_tag(&gc, out);
|
||||
check_equals("KAT GCM 5", tmp, plain, plain_len);
|
||||
check_equals("KAT GCM 6", out, tag, 16);
|
||||
|
||||
/*
|
||||
* Check that alterations are detected.
|
||||
*/
|
||||
for (v = 0; v < aad_len; v ++) {
|
||||
memcpy(tmp, cipher, plain_len);
|
||||
br_gcm_reset(&gc, iv, iv_len);
|
||||
aad[v] ^= 0x04;
|
||||
br_gcm_aad_inject(&gc, aad, aad_len);
|
||||
aad[v] ^= 0x04;
|
||||
br_gcm_flip(&gc);
|
||||
br_gcm_run(&gc, 0, tmp, plain_len);
|
||||
check_equals("KAT GCM 7", tmp, plain, plain_len);
|
||||
if (br_gcm_check_tag(&gc, tag)) {
|
||||
fprintf(stderr, "Tag should have changed\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
}
|
||||
|
||||
printf(".");
|
||||
fflush(stdout);
|
||||
}
|
||||
|
||||
printf(" done.\n");
|
||||
fflush(stdout);
|
||||
}
|
||||
|
||||
static void
|
||||
test_EC_inner(const char *sk, const char *sU,
|
||||
const br_ec_impl *impl, int curve)
|
||||
|
@ -5934,6 +6186,7 @@ static const struct {
|
|||
STU(GHASH_ctmul64),
|
||||
STU(GHASH_pclmul),
|
||||
STU(GHASH_pwr8),
|
||||
STU(GCM),
|
||||
STU(EC_prime_i15),
|
||||
STU(EC_prime_i31),
|
||||
STU(EC_p256_m15),
|
||||
|
|
Loading…
Reference in New Issue