Commit 34aef19b authored by Niels Möller's avatar Niels Möller

Implemented umac.

parent c6f38f5f
2013-04-11 Niels Möller <nisse@lysator.liu.se>
Initial implementation of umac.
* umac.h: New file.
* umac-nh.c: New file.
* umac-nh-n.c: New file.
* umac-poly64.c: New file.
* umac-poly128.c: New file.
* umac-l2.c: New file.
* umac-l3.c: New file.
* Makefile.in (nettle_SOURCES): Added umac source files.
(HEADERS): Added umac.h.
* testsuite/umac-test.c: New file.
* testsuite/Makefile.in (TS_NETTLE_SOURCES): Added umac-test.c.
* ecc-mul-a.c (ecc_mul_a): Avoid using mp_bitcnt_t, for
compatibility with older GMP versions.
* ecc-mul-g.c (ecc_mul_g): Likewise.
......
......@@ -96,6 +96,9 @@ nettle_SOURCES = aes-decrypt-internal.c aes-decrypt.c \
serpent-set-key.c serpent-encrypt.c serpent-decrypt.c \
serpent-meta.c \
twofish.c twofish-meta.c \
umac-nh.c umac-nh-n.c umac-l2.c umac-l3.c \
umac-poly64.c umac-poly128.c umac-set-key.c \
umac32.c umac64.c umac96.c umac128.c \
yarrow256.c yarrow_key_event.c \
buffer.c buffer-init.c realloc.c \
nettle-meta-hashes.c nettle-meta-ciphers.c \
......@@ -152,7 +155,7 @@ HEADERS = aes.h arcfour.h arctwo.h asn1.h bignum.h blowfish.h \
pgp.h pkcs1.h realloc.h ripemd160.h rsa.h rsa-compat.h \
salsa20.h sexp.h \
serpent.h sha.h sha1.h sha2.h sha3.h twofish.h \
yarrow.h
umac.h yarrow.h
INSTALL_HEADERS = $(HEADERS) nettle-stdint.h
......
......@@ -106,6 +106,9 @@ gcm-test$(EXEEXT): gcm-test.$(OBJEXT)
hmac-test$(EXEEXT): hmac-test.$(OBJEXT)
$(LINK) hmac-test.$(OBJEXT) $(TEST_OBJS) -o hmac-test$(EXEEXT)
umac-test$(EXEEXT): umac-test.$(OBJEXT)
$(LINK) umac-test.$(OBJEXT) $(TEST_OBJS) -o umac-test$(EXEEXT)
meta-hash-test$(EXEEXT): meta-hash-test.$(OBJEXT)
$(LINK) meta-hash-test.$(OBJEXT) $(TEST_OBJS) -o meta-hash-test$(EXEEXT)
......
......@@ -25,7 +25,7 @@ TS_NETTLE_SOURCES = aes-test.c arcfour-test.c arctwo-test.c \
sha3-384-test.c sha3-512-test.c \
serpent-test.c twofish-test.c \
knuth-lfib-test.c \
cbc-test.c ctr-test.c gcm-test.c hmac-test.c \
cbc-test.c ctr-test.c gcm-test.c hmac-test.c umac-test.c \
meta-hash-test.c meta-cipher-test.c meta-armor-test.c \
buffer-test.c yarrow-test.c pbkdf2-test.c
......
This diff is collapsed.
/* umac-l2.c
*/
/* nettle, low-level cryptographics library
*
* Copyright (C) 2013 Niels Möller
*
* The nettle library is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation; either version 2.1 of the License, or (at your
* option) any later version.
*
* The nettle library 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 Lesser General Public
* License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with the nettle library; see the file COPYING.LIB. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
* MA 02111-1301, USA.
*/
#if HAVE_CONFIG_H
# include "config.h"
#endif
#include <assert.h>
#include <string.h>
#include "umac.h"
#include "macros.h"
/* Same mask applied to low and high halves */
#define KEY_MASK 0x01ffffffUL
#if WORDS_BIGENDIAN
#define BE_SWAP32(x) x
#else
#define BE_SWAP32(x) \
((ROTL32(8, x) & 0x00FF00FFUL) | \
(ROTL32(24, x) & 0xFF00FF00UL))
#endif
void
_umac_l2_init (unsigned size, uint32_t *k)
{
unsigned i;
for (i = 0; i < size; i++)
{
uint32_t w = k[i];
w = BE_SWAP32 (w);
k[i] = w & KEY_MASK;
}
}
void
_umac_l2(const uint32_t *key, uint64_t *state, unsigned n,
unsigned count, uint64_t *prev, const uint64_t *m)
{
unsigned i;
if (count == 0)
memcpy (prev, m, n * sizeof(*m));
else if (count == 1)
for (i = 0; i < n; i++, key += 6)
{
uint64_t y = _umac_poly64 (key[0], key[1], 1, prev[i]);
state[2*i+1] = _umac_poly64 (key[0], key[1], y, m[i]);
}
else if (count < UMAC_POLY64_BLOCKS)
for (i = 0; i < n; i++, key += 6)
state[2*i+1] = _umac_poly64 (key[0], key[1], state[2*i+1], m[i]);
else if (count % 2 == 0)
{
if (count == UMAC_POLY64_BLOCKS)
for (i = 0, key += 2; i < n; i++, key += 6)
{
uint64_t y = state[2*i+1];
if (y >= UMAC_P64)
y -= UMAC_P64;
state[2*i] = 0;
state[2*i+1] = 1;
_umac_poly128 (key, state + 2*i, 0, y);
memcpy (prev, m, n * sizeof(*m));
}
memcpy (prev, m, n * sizeof(*m));
}
else
for (i = 0, key += 2; i < n; i++, key += 6)
_umac_poly128 (key, state + 2*i, prev[i], m[i]);
}
void
_umac_l2_final(const uint32_t *key, uint64_t *state, unsigned n,
unsigned count, uint64_t *prev)
{
unsigned i;
assert (count > 0);
if (count == 1)
for (i = 0; i < n; i++)
{
*state++ = 0;
*state++ = *prev++;
}
else if (count <= UMAC_POLY64_BLOCKS)
for (i = 0; i < n; i++)
{
uint64_t y;
*state++ = 0;
y = *state;
if (y >= UMAC_P64)
y -= UMAC_P64;
*state++ = y;
}
else
{
uint64_t pad = (uint64_t) 1 << 63;
if (count % 2 == 1)
for (i = 0, key += 2; i < n; i++, key += 6)
_umac_poly128 (key, state + 2*i, prev[i], pad);
else
for (i = 0, key += 2; i < n; i++, key += 6)
_umac_poly128 (key, state + 2*i, pad, 0);
for (i = 0; i < n; i++, state += 2)
{
uint64_t yh, yl;
yh = state[0];
yl = state[1];
if (yh == UMAC_P128_HI && yl >= UMAC_P128_LO)
{
state[0] = 0;
state[1] = yl -= UMAC_P128_LO;
}
}
}
}
/* umac-l3.c
*/
/* nettle, low-level cryptographics library
*
* Copyright (C) 2013 Niels Möller
*
* The nettle library is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation; either version 2.1 of the License, or (at your
* option) any later version.
*
* The nettle library 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 Lesser General Public
* License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with the nettle library; see the file COPYING.LIB. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
* MA 02111-1301, USA.
*/
#if HAVE_CONFIG_H
# include "config.h"
#endif
#include "umac.h"
#include "macros.h"
/* 2^36 - 5 */
#define P 0x0000000FFFFFFFFBULL
#if WORDS_BIGENDIAN
#define BE_SWAP64(x) x
#else
#define BE_SWAP64(x) \
(((x & 0xff) << 56) \
| ((x & 0xff00) << 40) \
| ((x & 0xff0000) << 24) \
| ((x & 0xff000000) << 8) \
| ((x >> 8) & 0xff000000) \
| ((x >> 24) & 0xff0000) \
| ((x >> 40) & 0xff00) \
| (x >> 56) )
#endif
void
_umac_l3_init (unsigned size, uint64_t *k)
{
unsigned i;
for (i = 0; i < size; i++)
{
uint64_t w = k[i];
w = BE_SWAP64 (w);
k[i] = w % P;
}
}
static uint64_t
umac_l3_word (const uint64_t *k, uint64_t w)
{
unsigned i;
uint64_t y;
/* Since it's easiest to process the input word from the low end,
* loop over keys in reverse order. */
for (i = y = 0; i < 4; i++, w >>= 16)
y += (w & 0xffff) * k[3-i];
return y;
}
uint32_t
_umac_l3 (const uint64_t *key_1, uint32_t key_2, const uint64_t *m)
{
uint32_t y = (umac_l3_word (key_1, m[0])
+ umac_l3_word (key_1 + 4, m[1])) % P;
y ^= key_2;
#if !WORDS_BIGENDIAN
y = ((ROTL32(8, y) & 0x00FF00FFUL)
| (ROTL32(24, y) & 0xFF00FF00UL));
#endif
return y;
}
/* umac-nh-n.c
*/
/* nettle, low-level cryptographics library
*
* Copyright (C) 2013 Niels Möller
*
* The nettle library is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation; either version 2.1 of the License, or (at your
* option) any later version.
*
* The nettle library 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 Lesser General Public
* License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with the nettle library; see the file COPYING.LIB. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
* MA 02111-1301, USA.
*/
#if HAVE_CONFIG_H
# include "config.h"
#endif
#include "umac.h"
/* FIXME: Single pass over the input */
void
_umac_nh_n (uint64_t *out, unsigned n, const uint32_t *key,
unsigned length, const uint8_t *msg)
{
unsigned i;
for (i = 0; i < n; i++)
out[i] = _umac_nh (key + 4*i, length, msg);
}
/* umac-nh.c
*/
/* nettle, low-level cryptographics library
*
* Copyright (C) 2013 Niels Möller
*
* The nettle library is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation; either version 2.1 of the License, or (at your
* option) any later version.
*
* The nettle library 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 Lesser General Public
* License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with the nettle library; see the file COPYING.LIB. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
* MA 02111-1301, USA.
*/
#if HAVE_CONFIG_H
# include "config.h"
#endif
#include <assert.h>
#include "umac.h"
#include "macros.h"
uint64_t
_umac_nh (const uint32_t *key, unsigned length, const uint8_t *msg)
{
uint64_t y;
assert (length > 0);
assert (length <= 1024);
assert (length % 32 == 0);
for (y = 0; length > 0; length -= 32, msg += 32, key += 8)
{
uint32_t a, b;
a = LE_READ_UINT32 (msg) + key[0];
b = LE_READ_UINT32 (msg + 16) + key[4];
y += (uint64_t) a * b;
a = LE_READ_UINT32 (msg + 4) + key[1];
b = LE_READ_UINT32 (msg + 20) + key[5];
y += (uint64_t) a * b;
a = LE_READ_UINT32 (msg + 8) + key[2];
b = LE_READ_UINT32 (msg + 24) + key[6];
y += (uint64_t) a * b;
a = LE_READ_UINT32 (msg + 12) + key[3];
b = LE_READ_UINT32 (msg + 28) + key[7];
y += (uint64_t) a * b;
}
return y;
}
/* umac-poly128.c
*/
/* nettle, low-level cryptographics library
*
* Copyright (C) 2013 Niels Möller
*
* The nettle library is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation; either version 2.1 of the License, or (at your
* option) any later version.
*
* The nettle library 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 Lesser General Public
* License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with the nettle library; see the file COPYING.LIB. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
* MA 02111-1301, USA.
*/
#if HAVE_CONFIG_H
# include "config.h"
#endif
#include <assert.h>
#include "umac.h"
#define HI(x) (x >> 32)
#define LO(x) (x & 0xffffffffUL)
static void
poly128_mul (const uint32_t *k, uint64_t *y)
{
uint64_t y0,y1,y2,y3,p0,p1,p2,p3,m0,m1,m2;
y0 = LO (y[1]);
y1 = HI (y[1]);
y2 = LO (y[0]);
y3 = HI (y[0]);
p0 = y0 * k[3];
m0 = y0 * k[2] + y1 * k[3];
p1 = y0 * k[1] + y1 * k[2] + y2 * k[3];
m1 = y0 * k[0] + y1 * k[1] + y2 * k[2] + y3 * k[3];
p2 = y1 * k[0] + y2 * k[1] + y3 * k[2];
m2 = y2 * k[0] + y3 * k[1];
p3 = y3 * k[0];
/* Collaps to 4 64-bit words,
+---+---+---+---+
| p3| p2| p1| p0|
+-+-+-+-+-+-+-+-+
+ | m2| m1| m0|
-+-+-+-+-+-+-+-+-+
*/
/* But it's convenient to reduce (p3,p2,p1,p0) and (m2,m1,m0) mod p first.*/
m1 += UMAC_P128_OFFSET * HI(p3);
p1 += UMAC_P128_OFFSET * (LO(p3) + HI(m2));
m0 += UMAC_P128_OFFSET * (HI(p2) + LO(m2));
p0 += UMAC_P128_OFFSET * (LO(p2) + HI(m1));
/* Left to add
+---+---+
| p1| p0|
+-+-+-+-+
m1| m0|
+-+---+
*/
/* First add high parts, with no possibilities for carries */
p1 += m0 >> 32;
m0 <<= 32;
m1 <<= 32;
/* Remains:
+---+---+
| p1| p0|
+-+-+---+
+| m1| m0|
-+---+---+
*/
p0 += m0;
p1 += (p0 < m0);
p1 += m1;
if (p1 < m1)
{
p0 += UMAC_P128_OFFSET;
p1 += (p0 < UMAC_P128_OFFSET);
}
y[0] = p1;
y[1] = p0;
}
void
_umac_poly128 (const uint32_t *k, uint64_t *y, uint64_t mh, uint64_t ml)
{
uint64_t yh, yl, cy;
if ( (mh >> 32) == 0xffffffff)
{
poly128_mul (k, y);
if (y[1] > 0)
y[1]--;
else if (y[0] > 0)
{
y[0]--;
y[1] = UMAC_P128_HI;
}
else
{
y[0] = UMAC_P128_HI;
y[1] = UMAC_P128_LO-1;
}
mh -= (ml < UMAC_P128_OFFSET);
ml -= UMAC_P128_OFFSET;
}
assert (mh < UMAC_P128_HI || ml < UMAC_P128_LO);
poly128_mul (k, y);
yl = y[1] + ml;
cy = (yl < ml);
yh = y[0] + cy;
cy = (yh < cy);
yh += mh;
cy += (yh < mh);
assert (cy <= 1);
if (cy)
{
yl += UMAC_P128_OFFSET;
yh += yl < UMAC_P128_OFFSET;
}
y[0] = yh;
y[1] = yl;
}
/* umac-poly64.c
*/
/* nettle, low-level cryptographics library
*
* Copyright (C) 2013 Niels Möller
*
* The nettle library is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation; either version 2.1 of the License, or (at your
* option) any later version.
*
* The nettle library 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 Lesser General Public
* License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with the nettle library; see the file COPYING.LIB. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
* MA 02111-1301, USA.
*/
#if HAVE_CONFIG_H
# include "config.h"
#endif
#include <assert.h>
#include "umac.h"
static uint64_t
poly64_mul (uint32_t kh, uint32_t kl, uint64_t y)
{
uint64_t yl, yh, pl, ph, ml, mh;
yl = y & 0xffffffff;
yh = y >> 32;
pl = yl * kl;
ph = yh * kh;
ml = yh * kl + yl * kh; /* No overflow, thanks to special form */
mh = ml >> 32;
ml <<= 32;
pl += ml;
ph += mh + (pl < ml);
/* Reduce, using 2^64 = UMAC_P64_OFFSET (mod p) */
assert (ph < ((uint64_t) 1 << 57));
ph *= UMAC_P64_OFFSET;
pl += ph;
if (pl < ph)
pl += UMAC_P64_OFFSET;
return pl;
}
uint64_t
_umac_poly64 (uint32_t kh, uint32_t kl, uint64_t y, uint64_t m)
{
if ( (m >> 32) == 0xffffffff)
{
y = poly64_mul (kh, kl, y);
if (y == 0)
y = UMAC_P64 - 1;
else
y--;
m -= UMAC_P64_OFFSET;
}
y = poly64_mul (kh, kl, y);
y += m;
if (y < m)
y += UMAC_P64_OFFSET;
return y;
}
/* umac-set-key.c
*/
/* nettle, low-level cryptographics library
*
* Copyright (C) 2013 Niels Möller
*
* The nettle library is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation; either version 2.1 of the License, or (at your
* option) any later version.
*
* The nettle library 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 Lesser General Public
* License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with the nettle library; see the file COPYING.LIB. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
* MA 02111-1301, USA.
*/
#if HAVE_CONFIG_H
# include "config.h"
#endif
#include <string.h>
#include "umac.h"
#include "macros.h"
static void
umac_kdf (struct aes_ctx *aes, unsigned index, unsigned length, uint8_t *dst)
{
uint8_t block[AES_BLOCK_SIZE];
uint64_t count;
WRITE_UINT64 (block, (uint64_t) index);
for (count = 1; length >= AES_BLOCK_SIZE;
length -= AES_BLOCK_SIZE, dst += AES_BLOCK_SIZE, count++)
{
WRITE_UINT64 (block + 8, count);
aes_encrypt (aes, AES_BLOCK_SIZE, dst, block);
}
if (length > 0)
{
WRITE_UINT64 (block + 8, count);
aes_encrypt (aes, AES_BLOCK_SIZE, block, block);
memcpy (dst, block, length);
}
}
#if WORDS_BIGENDIAN
#define BE_SWAP32(x) x
#define BE_SWAP32_N(x)
#else
#define BE_SWAP32(x) \
((ROTL32(8, x) & 0x00FF00FFUL) | \
(ROTL32(24, x) & 0xFF00FF00UL))
#define BE_SWAP32_N(n, x) do { \
unsigned be_i; \
for (be_i = 0; be_i < n; be_i++) \
{ \
uint32_t be_x = (x)[be_i]; \
(x)[be_i] = BE_SWAP32 (be_x); \
} \
} while (0)
#endif
void
_umac_set_key (uint32_t *l1_key, uint32_t *l2_key,
uint64_t *l3_key1, uint32_t *l3_key2,
struct aes_ctx *aes, const uint8_t *key, unsigned n)
{
unsigned size;
uint8_t buffer[UMAC_KEY_SIZE];
aes_set_encrypt_key (aes, UMAC_KEY_SIZE, key);
size = UMAC_BLOCK_SIZE / 4 + 4*(n-1);
umac_kdf (aes, 1, size * sizeof(uint32_t), (uint8_t *) l1_key);
BE_SWAP32_N (size, l1_key);
size = 6*n;
umac_kdf (aes, 2, size * sizeof(uint32_t), (uint8_t *) l2_key);
_umac_l2_init (size, l2_key);
size = 8*n;
umac_kdf (aes, 3, size * sizeof(uint64_t), (uint8_t *) l3_key1);
_umac_l3_init (size, l3_key1);
umac_kdf (aes, 4, n * sizeof(uint32_t), (uint8_t *) l3_key2);
BE_SWAP32_N (n, l3_key2);
umac_kdf (aes, 0, UMAC_KEY_SIZE, buffer);
aes_set_encrypt_key (aes, UMAC_KEY_SIZE, buffer);
}