strongswan/src/libstrongswan/plugins/sha3/sha3_keccak.c

499 lines
11 KiB
C
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/*
* Copyright (C) 2015-2016 Andreas Steffen
* HSR Hochschule fuer Technik Rapperswil
*
* Based on the implementation by the Keccak, Keyak and Ketje Teams, namely,
* Guido Bertoni, Joan Daemen, Michaël Peeters, Gilles Van Assche and
* Ronny Van Keer, hereby denoted as "the implementer".
*
* To the extent possible under law, the implementer has waived all copyright
* and related or neighboring rights to the source code in this file.
* http://creativecommons.org/publicdomain/zero/1.0/
*/
#include <string.h>
#include "sha3_keccak.h"
typedef struct private_sha3_keccak_t private_sha3_keccak_t;
#define KECCAK_STATE_SIZE 200 /* bytes */
#define KECCAK_MAX_RATE 168 /* bytes */
static const uint64_t round_constants[] = {
0x0000000000000001ULL,
0x0000000000008082ULL,
0x800000000000808aULL,
0x8000000080008000ULL,
0x000000000000808bULL,
0x0000000080000001ULL,
0x8000000080008081ULL,
0x8000000000008009ULL,
0x000000000000008aULL,
0x0000000000000088ULL,
0x0000000080008009ULL,
0x000000008000000aULL,
0x000000008000808bULL,
0x800000000000008bULL,
0x8000000000008089ULL,
0x8000000000008003ULL,
0x8000000000008002ULL,
0x8000000000000080ULL,
0x000000000000800aULL,
0x800000008000000aULL,
0x8000000080008081ULL,
0x8000000000008080ULL,
0x0000000080000001ULL,
0x8000000080008008ULL
};
/**
* Private data structure with hashing context for SHA-3
*/
struct private_sha3_keccak_t {
/**
* Public interface for this hasher.
*/
sha3_keccak_t public;
/**
* Internal state of 1600 bits as defined by FIPS-202
*/
uint8_t state[KECCAK_STATE_SIZE];
/**
* Rate in bytes
*/
u_int rate;
/**
* Rate input buffer
*/
uint8_t rate_buffer[KECCAK_MAX_RATE];
/**
* Index pointing to the current position in the rate buffer
*/
u_int rate_index;
/**
* Suffix delimiting the input message
*/
uint8_t delimited_suffix;
};
#if BYTE_ORDER != LITTLE_ENDIAN
/**
* Function to load a 64-bit value using the little-endian (LE) convention.
* On a LE platform, this could be greatly simplified using a cast.
*/
static uint64_t load64(const uint8_t *x)
{
int i;
uint64_t u = 0;
for (i = 7; i >= 0; --i)
{
u <<= 8;
u |= x[i];
}
return u;
}
/**
* Function to store a 64-bit value using the little-endian (LE) convention.
* On a LE platform, this could be greatly simplified using a cast.
*/
static void store64(uint8_t *x, uint64_t u)
{
u_int i;
for (i = 0; i < 8; ++i)
{
x[i] = u;
u >>= 8;
}
}
/**
* Function to XOR into a 64-bit value using the little-endian (LE) convention.
* On a LE platform, this could be greatly simplified using a cast.
*/
static void xor64(uint8_t *x, uint64_t u)
{
u_int i;
for (i = 0; i < 8; ++i)
{
x[i] ^= u;
u >>= 8;
}
}
#endif
/**
* Some macros used by the Keccak-f[1600] permutation.
*/
#define ROL64(a, offset) ((((uint64_t)a) << offset) ^ (((uint64_t)a) >> (64-offset)))
#if BYTE_ORDER == LITTLE_ENDIAN
#define readLane(i) (((uint64_t*)state)[i])
#define writeLane(i, lane) (((uint64_t*)state)[i]) = (lane)
#define XORLane(i, lane) (((uint64_t*)state)[i]) ^= (lane)
#elif BYTE_ORDER == BIG_ENDIAN
#define readLane(i) load64((uint8_t*)state+sizeof(uint64_t)*i)
#define writeLane(i, lane) store64((uint8_t*)state+sizeof(uint64_t)*i, lane)
#define XORLane(i, lane) xor64((uint8_t*)state+sizeof(uint64_t)*i, lane)
#endif
/**
* Function that computes the Keccak-f[1600] permutation on the given state.
*/
static void keccak_f1600_state_permute(void *state)
{
int round;
for (round = 0; round < 24; round++)
{
{ /* θ step (see [Keccak Reference, Section 2.3.2]) */
uint64_t C[5], D;
/* Compute the parity of the columns */
C[0] = readLane(0) ^ readLane( 5) ^ readLane(10)
^ readLane(15) ^ readLane(20);
C[1] = readLane(1) ^ readLane( 6) ^ readLane(11)
^ readLane(16) ^ readLane(21);
C[2] = readLane(2) ^ readLane( 7) ^ readLane(12)
^ readLane(17) ^ readLane(22);
C[3] = readLane(3) ^ readLane( 8) ^ readLane(13)
^ readLane(18) ^ readLane(23);
C[4] = readLane(4) ^ readLane( 9) ^ readLane(14)
^ readLane(19) ^ readLane(24);
/* Compute and add the θ effect to the whole column */
D = C[4] ^ ROL64(C[1], 1);
XORLane( 0, D);
XORLane( 5, D);
XORLane(10, D);
XORLane(15, D);
XORLane(20, D);
D = C[0] ^ ROL64(C[2], 1);
XORLane( 1, D);
XORLane( 6, D);
XORLane(11, D);
XORLane(16, D);
XORLane(21, D);
D = C[1] ^ ROL64(C[3], 1);
XORLane( 2, D);
XORLane( 7, D);
XORLane(12, D);
XORLane(17, D);
XORLane(22, D);
D = C[2] ^ ROL64(C[4], 1);
XORLane( 3, D);
XORLane( 8, D);
XORLane(13, D);
XORLane(18, D);
XORLane(23, D);
D = C[3] ^ ROL64(C[0], 1);
XORLane( 4, D);
XORLane( 9, D);
XORLane(14, D);
XORLane(19, D);
XORLane(24, D);
}
{ /* ρ and π steps (see [Keccak Reference, Sections 2.3.3 and 2.3.4]) */
uint64_t t1, t2;
t1 = readLane( 1);
t2 = readLane(10);
writeLane(10, ROL64(t1, 1));
t1 = readLane( 7);
writeLane( 7, ROL64(t2, 3));
t2 = readLane(11);
writeLane(11, ROL64(t1, 6));
t1 = readLane(17);
writeLane(17, ROL64(t2, 10));
t2 = readLane(18);
writeLane(18, ROL64(t1, 15));
t1 = readLane( 3);
writeLane( 3, ROL64(t2, 21));
t2 = readLane( 5);
writeLane( 5, ROL64(t1, 28));
t1 = readLane(16);
writeLane(16, ROL64(t2, 36));
t2 = readLane( 8);
writeLane( 8, ROL64(t1, 45));
t1 = readLane(21);
writeLane(21, ROL64(t2, 55));
t2 = readLane(24);
writeLane(24, ROL64(t1, 2));
t1 = readLane( 4);
writeLane( 4, ROL64(t2, 14));
t2 = readLane(15);
writeLane(15, ROL64(t1, 27));
t1 = readLane(23);
writeLane(23, ROL64(t2, 41));
t2 = readLane(19);
writeLane(19, ROL64(t1, 56));
t1 = readLane(13);
writeLane(13, ROL64(t2, 8));
t2 = readLane(12);
writeLane(12, ROL64(t1, 25));
t1 = readLane( 2);
writeLane( 2, ROL64(t2, 43));
t2 = readLane(20);
writeLane(20, ROL64(t1, 62));
t1 = readLane(14);
writeLane(14, ROL64(t2, 18));
t2 = readLane(22);
writeLane(22, ROL64(t1, 39));
t1 = readLane( 9);
writeLane( 9, ROL64(t2, 61));
t2 = readLane( 6);
writeLane( 6, ROL64(t1, 20));
writeLane( 1, ROL64(t2, 44));
}
{ /* χ step (see [Keccak Reference, Section 2.3.1]) */
uint64_t t[5];
t[0] = readLane(0);
t[1] = readLane(1);
t[2] = readLane(2);
t[3] = readLane(3);
t[4] = readLane(4);
writeLane(0, t[0] ^ ((~t[1]) & t[2]));
writeLane(1, t[1] ^ ((~t[2]) & t[3]));
writeLane(2, t[2] ^ ((~t[3]) & t[4]));
writeLane(3, t[3] ^ ((~t[4]) & t[0]));
writeLane(4, t[4] ^ ((~t[0]) & t[1]));
t[0] = readLane(5);
t[1] = readLane(6);
t[2] = readLane(7);
t[3] = readLane(8);
t[4] = readLane(9);
writeLane(5, t[0] ^ ((~t[1]) & t[2]));
writeLane(6, t[1] ^ ((~t[2]) & t[3]));
writeLane(7, t[2] ^ ((~t[3]) & t[4]));
writeLane(8, t[3] ^ ((~t[4]) & t[0]));
writeLane(9, t[4] ^ ((~t[0]) & t[1]));
t[0] = readLane(10);
t[1] = readLane(11);
t[2] = readLane(12);
t[3] = readLane(13);
t[4] = readLane(14);
writeLane(10, t[0] ^ ((~t[1]) & t[2]));
writeLane(11, t[1] ^ ((~t[2]) & t[3]));
writeLane(12, t[2] ^ ((~t[3]) & t[4]));
writeLane(13, t[3] ^ ((~t[4]) & t[0]));
writeLane(14, t[4] ^ ((~t[0]) & t[1]));
t[0] = readLane(15);
t[1] = readLane(16);
t[2] = readLane(17);
t[3] = readLane(18);
t[4] = readLane(19);
writeLane(15, t[0] ^ ((~t[1]) & t[2]));
writeLane(16, t[1] ^ ((~t[2]) & t[3]));
writeLane(17, t[2] ^ ((~t[3]) & t[4]));
writeLane(18, t[3] ^ ((~t[4]) & t[0]));
writeLane(19, t[4] ^ ((~t[0]) & t[1]));
t[0] = readLane(20);
t[1] = readLane(21);
t[2] = readLane(22);
t[3] = readLane(23);
t[4] = readLane(24);
writeLane(20, t[0] ^ ((~t[1]) & t[2]));
writeLane(21, t[1] ^ ((~t[2]) & t[3]));
writeLane(22, t[2] ^ ((~t[3]) & t[4]));
writeLane(23, t[3] ^ ((~t[4]) & t[0]));
writeLane(24, t[4] ^ ((~t[0]) & t[1]));
}
{ /* ι step (see [Keccak Reference, Section 2.3.5]) */
XORLane(0, round_constants[round]);
}
}
}
METHOD(sha3_keccak_t, get_rate, u_int,
private_sha3_keccak_t *this)
{
return this->rate;
}
METHOD(sha3_keccak_t, reset, void,
private_sha3_keccak_t *this)
{
memset(this->state, 0x00, KECCAK_STATE_SIZE);
this->rate_index = 0;
}
METHOD(sha3_keccak_t, absorb, void,
private_sha3_keccak_t *this, chunk_t data)
{
uint64_t *buffer_lanes, *state_lanes;
size_t len, rate_lanes;
int i;
buffer_lanes = (uint64_t*)this->rate_buffer;
state_lanes = (uint64_t*)this->state;
rate_lanes = this->rate / sizeof(uint64_t);
while (data.len)
{
len = min(data.len, this->rate - this->rate_index);
memcpy(this->rate_buffer + this->rate_index, data.ptr, len);
this->rate_index += len;
data.ptr += len;
data.len -= len;
if (this->rate_index == this->rate)
{
for (i = 0; i < rate_lanes; i++)
{
state_lanes[i] ^= buffer_lanes[i];
}
this->rate_index = 0;
keccak_f1600_state_permute(this->state);
}
}
}
METHOD(sha3_keccak_t, finalize, void,
private_sha3_keccak_t *this)
{
uint64_t *buffer_lanes, *state_lanes;
size_t rate_lanes, remainder;
int i;
/* Add the delimitedSuffix as the first bit of padding */
this->rate_buffer[this->rate_index++] = this->delimited_suffix;
buffer_lanes = (uint64_t*)this->rate_buffer;
state_lanes = (uint64_t*)this->state;
rate_lanes = this->rate_index / sizeof(uint64_t);
remainder = this->rate_index - rate_lanes * sizeof(uint64_t);
if (remainder)
{
memset(this->rate_buffer + this->rate_index, 0x00,
sizeof(uint64_t) - remainder);
rate_lanes++;
}
for (i = 0; i < rate_lanes; i++)
{
state_lanes[i] ^= buffer_lanes[i];
}
/* Add the second bit of padding */
this->state[this->rate - 1] ^= 0x80;
/* Switch to the squeezing phase */
keccak_f1600_state_permute(this->state);
this->rate_index = 0;
}
METHOD(sha3_keccak_t, squeeze, void,
private_sha3_keccak_t *this, size_t out_len, uint8_t *out)
{
size_t index = 0, len;
while (index < out_len)
{
if (this->rate_index == this->rate)
{
keccak_f1600_state_permute(this->state);
this->rate_index = 0;
}
len = min(out_len - index, this->rate - this->rate_index);
memcpy(out, &this->state[this->rate_index], len);
out += len;
index += len;
this->rate_index += len;
}
}
METHOD(sha3_keccak_t, destroy, void,
private_sha3_keccak_t *this)
{
free(this);
}
/*
* Described in header.
*/
sha3_keccak_t *sha3_keccak_create(u_int capacity, uint8_t delimited_suffix)
{
private_sha3_keccak_t *this;
int rate;
rate = KECCAK_STATE_SIZE - capacity;
if (rate <= 0 || rate > KECCAK_MAX_RATE)
{
return NULL;
}
INIT(this,
.public = {
.get_rate = _get_rate,
.reset = _reset,
.absorb = _absorb,
.finalize = _finalize,
.squeeze = _squeeze,
.destroy = _destroy,
},
.rate = rate,
.delimited_suffix = delimited_suffix,
);
return &this->public;
}