siv: add internal implementation based on Nettle
This adds an internal implementation of the AES-SIV-CMAC-256 cipher based on GNU Nettle and the following patch (which was later reworked and included in Nettle): https://gitlab.com/gnutls/gnutls/uploads/1ab02c51e317264f9dba07ddfbc01d9a/0001-Added-support-for-AES_SIV_CMAC_256-and-AES_SIV_CMAC_.patch This implementation will be dropped when the cipher is widely supported by gnutls or Nettle.
This commit is contained in:
parent
881d07fa0a
commit
2d798bc4cf
3 changed files with 460 additions and 2 deletions
6
configure
vendored
6
configure
vendored
|
@ -923,12 +923,14 @@ LIBS="$LIBS $HASH_LINK"
|
|||
if true && \
|
||||
echo "$HASH_LINK" | grep 'nettle' > /dev/null; then
|
||||
|
||||
EXTRA_OBJECTS="$EXTRA_OBJECTS siv_nettle.o"
|
||||
add_def HAVE_SIV
|
||||
|
||||
if test_code 'SIV in nettle' \
|
||||
'nettle/siv-cmac.h' "" "$LIBS" \
|
||||
'siv_cmac_aes128_set_key(NULL, NULL);'
|
||||
then
|
||||
EXTRA_OBJECTS="$EXTRA_OBJECTS siv_nettle.o"
|
||||
add_def HAVE_SIV
|
||||
add_def HAVE_NETTLE_SIV_CMAC
|
||||
fi
|
||||
fi
|
||||
|
||||
|
|
|
@ -28,7 +28,11 @@
|
|||
|
||||
#include "sysincl.h"
|
||||
|
||||
#ifdef HAVE_NETTLE_SIV_CMAC
|
||||
#include <nettle/siv-cmac.h>
|
||||
#else
|
||||
#include "siv_nettle_int.c"
|
||||
#endif
|
||||
|
||||
#include "memory.h"
|
||||
#include "siv.h"
|
||||
|
|
452
siv_nettle_int.c
Normal file
452
siv_nettle_int.c
Normal file
|
@ -0,0 +1,452 @@
|
|||
/* This is a single-file implementation of AES-SIV-CMAC-256 based on
|
||||
a patch for GNU Nettle by Nikos Mavrogiannopoulos */
|
||||
|
||||
/*
|
||||
AES-CMAC-128 (rfc 4493)
|
||||
Copyright (C) Stefan Metzmacher 2012
|
||||
Copyright (C) Jeremy Allison 2012
|
||||
Copyright (C) Michael Adam 2012
|
||||
Copyright (C) 2017, Red Hat Inc.
|
||||
|
||||
This file is part of GNU Nettle.
|
||||
|
||||
GNU Nettle is free software: you can redistribute it and/or
|
||||
modify it under the terms of either:
|
||||
|
||||
* the GNU Lesser General Public License as published by the Free
|
||||
Software Foundation; either version 3 of the License, or (at your
|
||||
option) any later version.
|
||||
|
||||
or
|
||||
|
||||
* the GNU General Public License as published by the Free
|
||||
Software Foundation; either version 2 of the License, or (at your
|
||||
option) any later version.
|
||||
|
||||
or both in parallel, as here.
|
||||
|
||||
GNU Nettle is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
General Public License for more details.
|
||||
|
||||
You should have received copies of the GNU General Public License and
|
||||
the GNU Lesser General Public License along with this program. If
|
||||
not, see http://www.gnu.org/licenses/.
|
||||
*/
|
||||
/* siv-aes128.c, siv-cmac.c, siv.h
|
||||
|
||||
AES-SIV, RFC5297
|
||||
SIV-CMAC, RFC5297
|
||||
|
||||
Copyright (C) 2017 Nikos Mavrogiannopoulos
|
||||
|
||||
This file is part of GNU Nettle.
|
||||
|
||||
GNU Nettle is free software: you can redistribute it and/or
|
||||
modify it under the terms of either:
|
||||
|
||||
* the GNU Lesser General Public License as published by the Free
|
||||
Software Foundation; either version 3 of the License, or (at your
|
||||
option) any later version.
|
||||
|
||||
or
|
||||
|
||||
* the GNU General Public License as published by the Free
|
||||
Software Foundation; either version 2 of the License, or (at your
|
||||
option) any later version.
|
||||
|
||||
or both in parallel, as here.
|
||||
|
||||
GNU Nettle is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
General Public License for more details.
|
||||
|
||||
You should have received copies of the GNU General Public License and
|
||||
the GNU Lesser General Public License along with this program. If
|
||||
not, see http://www.gnu.org/licenses/.
|
||||
*/
|
||||
/* cmac.h, siv-cmac.h, cmac-aes128.c
|
||||
|
||||
CMAC mode, as specified in RFC4493
|
||||
SIV-CMAC mode, as specified in RFC5297
|
||||
CMAC using AES128 as the underlying cipher.
|
||||
|
||||
Copyright (C) 2017 Red Hat, Inc.
|
||||
|
||||
Contributed by Nikos Mavrogiannopoulos
|
||||
|
||||
This file is part of GNU Nettle.
|
||||
|
||||
GNU Nettle is free software: you can redistribute it and/or
|
||||
modify it under the terms of either:
|
||||
|
||||
* the GNU Lesser General Public License as published by the Free
|
||||
Software Foundation; either version 3 of the License, or (at your
|
||||
option) any later version.
|
||||
|
||||
or
|
||||
|
||||
* the GNU General Public License as published by the Free
|
||||
Software Foundation; either version 2 of the License, or (at your
|
||||
option) any later version.
|
||||
|
||||
or both in parallel, as here.
|
||||
|
||||
GNU Nettle is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
General Public License for more details.
|
||||
|
||||
You should have received copies of the GNU General Public License and
|
||||
the GNU Lesser General Public License along with this program. If
|
||||
not, see http://www.gnu.org/licenses/.
|
||||
*/
|
||||
|
||||
# include "config.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "nettle/aes.h"
|
||||
#include "nettle/ctr.h"
|
||||
#include "nettle/macros.h"
|
||||
#include "nettle/memxor.h"
|
||||
#include "nettle/memops.h"
|
||||
|
||||
#include "nettle/nettle-types.h"
|
||||
|
||||
/* For SIV, the block size of the block cipher shall be 128 bits. */
|
||||
#define SIV_BLOCK_SIZE 16
|
||||
#define SIV_DIGEST_SIZE 16
|
||||
#define SIV_MIN_NONCE_SIZE 1
|
||||
|
||||
/*
|
||||
* SIV mode requires the aad and plaintext when building the IV, which
|
||||
* prevents streaming processing and it incompatible with the AEAD API.
|
||||
*/
|
||||
|
||||
/* AES_SIV_CMAC_256 */
|
||||
struct siv_cmac_aes128_ctx {
|
||||
struct aes128_ctx cipher;
|
||||
uint8_t s2vk[AES128_KEY_SIZE];
|
||||
};
|
||||
|
||||
struct cmac128_ctx
|
||||
{
|
||||
/* Key */
|
||||
union nettle_block16 K1;
|
||||
union nettle_block16 K2;
|
||||
|
||||
/* MAC state */
|
||||
union nettle_block16 X;
|
||||
|
||||
/* Block buffer */
|
||||
union nettle_block16 block;
|
||||
size_t index;
|
||||
};
|
||||
|
||||
/* shift one and XOR with 0x87. */
|
||||
static void
|
||||
_cmac128_block_mulx(union nettle_block16 *dst,
|
||||
const union nettle_block16 *src)
|
||||
{
|
||||
uint64_t b1 = READ_UINT64(src->b);
|
||||
uint64_t b2 = READ_UINT64(src->b+8);
|
||||
|
||||
b1 = (b1 << 1) | (b2 >> 63);
|
||||
b2 <<= 1;
|
||||
|
||||
if (src->b[0] & 0x80)
|
||||
b2 ^= 0x87;
|
||||
|
||||
WRITE_UINT64(dst->b, b1);
|
||||
WRITE_UINT64(dst->b+8, b2);
|
||||
}
|
||||
|
||||
static void
|
||||
cmac128_set_key(struct cmac128_ctx *ctx, const void *cipher,
|
||||
nettle_cipher_func *encrypt)
|
||||
{
|
||||
static const uint8_t const_zero[] = {
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
|
||||
};
|
||||
union nettle_block16 *L = &ctx->block;
|
||||
memset(ctx, 0, sizeof(*ctx));
|
||||
|
||||
/* step 1 - generate subkeys k1 and k2 */
|
||||
encrypt(cipher, 16, L->b, const_zero);
|
||||
|
||||
_cmac128_block_mulx(&ctx->K1, L);
|
||||
_cmac128_block_mulx(&ctx->K2, &ctx->K1);
|
||||
}
|
||||
|
||||
#define MIN(x,y) ((x)<(y)?(x):(y))
|
||||
|
||||
static void
|
||||
cmac128_update(struct cmac128_ctx *ctx, const void *cipher,
|
||||
nettle_cipher_func *encrypt,
|
||||
size_t msg_len, const uint8_t *msg)
|
||||
{
|
||||
union nettle_block16 Y;
|
||||
/*
|
||||
* check if we expand the block
|
||||
*/
|
||||
if (ctx->index < 16)
|
||||
{
|
||||
size_t len = MIN(16 - ctx->index, msg_len);
|
||||
memcpy(&ctx->block.b[ctx->index], msg, len);
|
||||
msg += len;
|
||||
msg_len -= len;
|
||||
ctx->index += len;
|
||||
}
|
||||
|
||||
if (msg_len == 0) {
|
||||
/* if it is still the last block, we are done */
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* now checksum everything but the last block
|
||||
*/
|
||||
memxor3(Y.b, ctx->X.b, ctx->block.b, 16);
|
||||
encrypt(cipher, 16, ctx->X.b, Y.b);
|
||||
|
||||
while (msg_len > 16)
|
||||
{
|
||||
memxor3(Y.b, ctx->X.b, msg, 16);
|
||||
encrypt(cipher, 16, ctx->X.b, Y.b);
|
||||
msg += 16;
|
||||
msg_len -= 16;
|
||||
}
|
||||
|
||||
/*
|
||||
* copy the last block, it will be processed in
|
||||
* cmac128_digest().
|
||||
*/
|
||||
memcpy(ctx->block.b, msg, msg_len);
|
||||
ctx->index = msg_len;
|
||||
}
|
||||
|
||||
static void
|
||||
cmac128_digest(struct cmac128_ctx *ctx, const void *cipher,
|
||||
nettle_cipher_func *encrypt,
|
||||
unsigned length,
|
||||
uint8_t *dst)
|
||||
{
|
||||
union nettle_block16 Y;
|
||||
|
||||
memset(ctx->block.b+ctx->index, 0, sizeof(ctx->block.b)-ctx->index);
|
||||
|
||||
/* re-use ctx->block for memxor output */
|
||||
if (ctx->index < 16)
|
||||
{
|
||||
ctx->block.b[ctx->index] = 0x80;
|
||||
memxor(ctx->block.b, ctx->K2.b, 16);
|
||||
}
|
||||
else
|
||||
{
|
||||
memxor(ctx->block.b, ctx->K1.b, 16);
|
||||
}
|
||||
|
||||
memxor3(Y.b, ctx->block.b, ctx->X.b, 16);
|
||||
|
||||
assert(length <= 16);
|
||||
if (length == 16)
|
||||
{
|
||||
encrypt(cipher, 16, dst, Y.b);
|
||||
}
|
||||
else
|
||||
{
|
||||
encrypt(cipher, 16, ctx->block.b, Y.b);
|
||||
memcpy(dst, ctx->block.b, length);
|
||||
}
|
||||
|
||||
/* reset state for re-use */
|
||||
memset(&ctx->X, 0, sizeof(ctx->X));
|
||||
ctx->index = 0;
|
||||
}
|
||||
|
||||
|
||||
#define CMAC128_CTX(type) \
|
||||
{ struct cmac128_ctx ctx; type cipher; }
|
||||
|
||||
/* NOTE: Avoid using NULL, as we don't include anything defining it. */
|
||||
#define CMAC128_SET_KEY(self, set_key, encrypt, cmac_key) \
|
||||
do { \
|
||||
(set_key)(&(self)->cipher, (cmac_key)); \
|
||||
if (0) (encrypt)(&(self)->cipher, ~(size_t) 0, \
|
||||
(uint8_t *) 0, (const uint8_t *) 0); \
|
||||
cmac128_set_key(&(self)->ctx, &(self)->cipher, \
|
||||
(nettle_cipher_func *) (encrypt)); \
|
||||
} while (0)
|
||||
|
||||
#define CMAC128_UPDATE(self, encrypt, length, src) \
|
||||
cmac128_update(&(self)->ctx, &(self)->cipher, \
|
||||
(nettle_cipher_func *)encrypt, (length), (src))
|
||||
|
||||
#define CMAC128_DIGEST(self, encrypt, length, digest) \
|
||||
(0 ? (encrypt)(&(self)->cipher, ~(size_t) 0, \
|
||||
(uint8_t *) 0, (const uint8_t *) 0) \
|
||||
: cmac128_digest(&(self)->ctx, &(self)->cipher, \
|
||||
(nettle_cipher_func *) (encrypt), \
|
||||
(length), (digest)))
|
||||
|
||||
struct cmac_aes128_ctx CMAC128_CTX(struct aes128_ctx);
|
||||
|
||||
static void
|
||||
cmac_aes128_set_key(struct cmac_aes128_ctx *ctx, const uint8_t *key)
|
||||
{
|
||||
CMAC128_SET_KEY(ctx, aes128_set_encrypt_key, aes128_encrypt, key);
|
||||
}
|
||||
|
||||
static void
|
||||
cmac_aes128_update (struct cmac_aes128_ctx *ctx,
|
||||
size_t length, const uint8_t *data)
|
||||
{
|
||||
CMAC128_UPDATE (ctx, aes128_encrypt, length, data);
|
||||
}
|
||||
|
||||
static void
|
||||
cmac_aes128_digest(struct cmac_aes128_ctx *ctx,
|
||||
size_t length, uint8_t *digest)
|
||||
{
|
||||
CMAC128_DIGEST(ctx, aes128_encrypt, length, digest);
|
||||
}
|
||||
|
||||
static const uint8_t const_one[] = {
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01
|
||||
};
|
||||
|
||||
static const uint8_t const_zero[] = {
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
|
||||
};
|
||||
|
||||
static
|
||||
void _siv_s2v(nettle_set_key_func *cmac_set_key,
|
||||
nettle_hash_update_func *cmac_update,
|
||||
nettle_hash_digest_func *cmac_digest,
|
||||
size_t cmac_ctx_size,
|
||||
const uint8_t *s2vk, size_t alength, const uint8_t *adata,
|
||||
size_t nlength, const uint8_t *nonce,
|
||||
size_t plength, const uint8_t *pdata,
|
||||
uint8_t *v)
|
||||
{
|
||||
uint8_t ctx[sizeof(struct cmac128_ctx)+sizeof(struct aes_ctx)];
|
||||
union nettle_block16 D, S, T;
|
||||
|
||||
assert(cmac_ctx_size <= sizeof (ctx));
|
||||
|
||||
cmac_set_key(ctx, s2vk);
|
||||
|
||||
if (nlength == 0 && alength == 0) {
|
||||
cmac_update(ctx, 16, const_one);
|
||||
cmac_digest(ctx, 16, v);
|
||||
return;
|
||||
}
|
||||
|
||||
cmac_update(ctx, 16, const_zero);
|
||||
cmac_digest(ctx, 16, D.b);
|
||||
|
||||
if (1) {
|
||||
_cmac128_block_mulx(&D, &D);
|
||||
cmac_update(ctx, alength, adata);
|
||||
cmac_digest(ctx, 16, S.b);
|
||||
|
||||
memxor(D.b, S.b, 16);
|
||||
}
|
||||
|
||||
if (nlength > 0) {
|
||||
_cmac128_block_mulx(&D, &D);
|
||||
cmac_update(ctx, nlength, nonce);
|
||||
cmac_digest(ctx, 16, S.b);
|
||||
|
||||
memxor(D.b, S.b, 16);
|
||||
}
|
||||
|
||||
/* Sn */
|
||||
if (plength >= 16) {
|
||||
cmac_update(ctx, plength-16, pdata);
|
||||
|
||||
pdata += plength-16;
|
||||
|
||||
memxor3(T.b, pdata, D.b, 16);
|
||||
} else {
|
||||
union nettle_block16 pad;
|
||||
|
||||
_cmac128_block_mulx(&T, &D);
|
||||
memcpy(pad.b, pdata, plength);
|
||||
pad.b[plength] = 0x80;
|
||||
if (plength+1 < 16)
|
||||
memset(&pad.b[plength+1], 0, 16-plength-1);
|
||||
|
||||
memxor(T.b, pad.b, 16);
|
||||
}
|
||||
|
||||
cmac_update(ctx, 16, T.b);
|
||||
cmac_digest(ctx, 16, v);
|
||||
}
|
||||
|
||||
static void
|
||||
siv_cmac_aes128_set_key(struct siv_cmac_aes128_ctx *ctx, const uint8_t *key)
|
||||
{
|
||||
memcpy(ctx->s2vk, key, 16);
|
||||
aes128_set_encrypt_key(&ctx->cipher, key+16);
|
||||
}
|
||||
|
||||
static void
|
||||
siv_cmac_aes128_encrypt_message(struct siv_cmac_aes128_ctx *ctx,
|
||||
size_t nlength, const uint8_t *nonce,
|
||||
size_t alength, const uint8_t *adata,
|
||||
size_t clength, uint8_t *dst, const uint8_t *src)
|
||||
{
|
||||
union nettle_block16 siv;
|
||||
size_t slength;
|
||||
|
||||
assert (clength >= SIV_DIGEST_SIZE);
|
||||
slength = clength - SIV_DIGEST_SIZE;
|
||||
|
||||
/* create CTR nonce */
|
||||
_siv_s2v((nettle_set_key_func*)cmac_aes128_set_key,
|
||||
(nettle_hash_update_func*)cmac_aes128_update,
|
||||
(nettle_hash_digest_func*)cmac_aes128_digest,
|
||||
sizeof(struct cmac_aes128_ctx), ctx->s2vk, alength, adata,
|
||||
nlength, nonce, slength, src, siv.b);
|
||||
memcpy(dst, siv.b, SIV_DIGEST_SIZE);
|
||||
siv.b[8] &= ~0x80;
|
||||
siv.b[12] &= ~0x80;
|
||||
|
||||
ctr_crypt(&ctx->cipher, (nettle_cipher_func *)aes128_encrypt, AES_BLOCK_SIZE,
|
||||
siv.b, slength, dst+SIV_DIGEST_SIZE, src);
|
||||
}
|
||||
|
||||
static int
|
||||
siv_cmac_aes128_decrypt_message(struct siv_cmac_aes128_ctx *ctx,
|
||||
size_t nlength, const uint8_t *nonce,
|
||||
size_t alength, const uint8_t *adata,
|
||||
size_t mlength, uint8_t *dst, const uint8_t *src)
|
||||
{
|
||||
union nettle_block16 siv;
|
||||
union nettle_block16 ctr;
|
||||
|
||||
memcpy(ctr.b, src, SIV_DIGEST_SIZE);
|
||||
ctr.b[8] &= ~0x80;
|
||||
ctr.b[12] &= ~0x80;
|
||||
|
||||
ctr_crypt(&ctx->cipher, (nettle_cipher_func *)aes128_encrypt, AES_BLOCK_SIZE,
|
||||
ctr.b, mlength, dst, src+SIV_DIGEST_SIZE);
|
||||
|
||||
/* create CTR nonce */
|
||||
_siv_s2v((nettle_set_key_func*)cmac_aes128_set_key,
|
||||
(nettle_hash_update_func*)cmac_aes128_update,
|
||||
(nettle_hash_digest_func*)cmac_aes128_digest,
|
||||
sizeof(struct cmac_aes128_ctx), ctx->s2vk, alength, adata,
|
||||
nlength, nonce, mlength, dst, siv.b);
|
||||
|
||||
return memeql_sec(siv.b, src, SIV_DIGEST_SIZE);
|
||||
}
|
||||
|
Loading…
Reference in a new issue