mirror of https://github.com/arendst/Tasmota.git
Merge pull request #5964 from s-hadinger/tls_optimized
TLS+AWS IoT optimization for speed, code and memory footprint
This commit is contained in:
commit
48215cd4af
|
@ -0,0 +1,13 @@
|
|||
This library is adapted from bearssl-esp8266 to avoid conflict with the
|
||||
BearSSL headers in Arduino Core.
|
||||
|
||||
To recreate, copy all original 'src/' and 'inc/' into 'src/' lib.
|
||||
|
||||
Then rename the following:
|
||||
- "bearssl with "t_bearssl
|
||||
- "inner with "t_inner
|
||||
- "config with "t_config
|
||||
|
||||
Add the customized files in src/:
|
||||
- t_bearssl_tasmota_config.h
|
||||
- pgmspace_bearssl.h
|
|
@ -0,0 +1,21 @@
|
|||
# Configuration for compiling to an ESP8266 from a UNIX system
|
||||
|
||||
# We are on a Unix system so we assume a Single Unix compatible 'make'
|
||||
# utility, and Unix defaults.
|
||||
include conf/Unix.mk
|
||||
|
||||
# We override the build directory.
|
||||
BUILD = esp8266
|
||||
|
||||
# C compiler, linker, and static library builder.
|
||||
TOOLCHAIN_PREFIX := xtensa-lx106-elf-
|
||||
CC := $(TOOLCHAIN_PREFIX)gcc
|
||||
CFLAGS = -W -Wall -g -O2 -Wpointer-arith -Wl,-EL -nostdlib -mlongcalls -mno-text-section-literals -ffunction-sections -fdata-sections -Werror
|
||||
CFLAGS += -D__ets__ -DICACHE_FLASH -DESP8266 -DBR_SLOW_MUL15=1
|
||||
LD := $(TOOLCHAIN_PREFIX)ld
|
||||
AR := $(TOOLCHAIN_PREFIX)ar
|
||||
|
||||
# We compile only the static library.
|
||||
DLL = no
|
||||
TOOLS = no
|
||||
TESTS = no
|
|
@ -0,0 +1,9 @@
|
|||
name=BearSSL
|
||||
version=0.6
|
||||
author=Thomas Pornin <pornin@bolet.org>
|
||||
maintainer=Earle F. Philhower, III <earlephilhower@yahoo.com>
|
||||
sentence=BearSSL implementation of the SSL/TLS protocol optimized for ESP8266 by Earle F. Philhower, optimized for Tamota by Stephan Hadinger
|
||||
paragraph=
|
||||
category=Other
|
||||
url=https://github.com/earlephilhower/bearssl-esp8266.git
|
||||
architectures=esp8266
|
|
@ -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 "t_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);
|
||||
}
|
|
@ -0,0 +1,525 @@
|
|||
/*
|
||||
* 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 "t_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.
|
||||
*
|
||||
* Upon entry, two situations are acceptable:
|
||||
*
|
||||
* ctx->ptr == 0: there is no data to process in ctx->buf
|
||||
* ctx->ptr == 16: there is a full block of unprocessed data in ctx->buf
|
||||
*
|
||||
* Upon exit, ctx->ptr may be zero only if it was already zero on entry,
|
||||
* and len == 0. In all other situations, ctx->ptr will be non-zero on
|
||||
* exit (and may have value 16).
|
||||
*/
|
||||
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;
|
||||
}
|
||||
if (ctx->ptr == 16) {
|
||||
(*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_capture(const br_eax_context *ctx, br_eax_state *st)
|
||||
{
|
||||
/*
|
||||
* We capture the three OMAC* states _after_ processing the
|
||||
* initial block (assuming that nonce, message and AAD are
|
||||
* all non-empty).
|
||||
*/
|
||||
int i;
|
||||
|
||||
memset(st->st, 0, sizeof st->st);
|
||||
for (i = 0; i < 3; i ++) {
|
||||
unsigned char tmp[16];
|
||||
|
||||
memset(tmp, 0, sizeof tmp);
|
||||
tmp[15] = (unsigned char)i;
|
||||
(*ctx->bctx)->mac(ctx->bctx, st->st[i], tmp, sizeof tmp);
|
||||
}
|
||||
}
|
||||
|
||||
/* 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);
|
||||
|
||||
/*
|
||||
* We use ctx->head[0] as temporary flag to mark that we are
|
||||
* using a "normal" reset().
|
||||
*/
|
||||
ctx->head[0] = 0;
|
||||
}
|
||||
|
||||
/* see bearssl_aead.h */
|
||||
void
|
||||
br_eax_reset_pre_aad(br_eax_context *ctx, const br_eax_state *st,
|
||||
const void *nonce, size_t len)
|
||||
{
|
||||
if (len == 0) {
|
||||
omac_start(ctx, 0);
|
||||
} else {
|
||||
memcpy(ctx->cbcmac, st->st[0], sizeof ctx->cbcmac);
|
||||
ctx->ptr = 0;
|
||||
do_cbcmac_chunk(ctx, nonce, len);
|
||||
}
|
||||
do_pad(ctx);
|
||||
memcpy(ctx->nonce, ctx->cbcmac, sizeof ctx->cbcmac);
|
||||
|
||||
memcpy(ctx->cbcmac, st->st[1], sizeof ctx->cbcmac);
|
||||
ctx->ptr = 0;
|
||||
|
||||
memcpy(ctx->ctr, st->st[2], sizeof ctx->ctr);
|
||||
|
||||
/*
|
||||
* We use ctx->head[0] as a flag to indicate that we use a
|
||||
* a recorded state, with ctx->ctr containing the preprocessed
|
||||
* first block for OMAC^2.
|
||||
*/
|
||||
ctx->head[0] = 1;
|
||||
}
|
||||
|
||||
/* see bearssl_aead.h */
|
||||
void
|
||||
br_eax_reset_post_aad(br_eax_context *ctx, const br_eax_state *st,
|
||||
const void *nonce, size_t len)
|
||||
{
|
||||
if (len == 0) {
|
||||
omac_start(ctx, 0);
|
||||
} else {
|
||||
memcpy(ctx->cbcmac, st->st[0], sizeof ctx->cbcmac);
|
||||
ctx->ptr = 0;
|
||||
do_cbcmac_chunk(ctx, nonce, len);
|
||||
}
|
||||
do_pad(ctx);
|
||||
memcpy(ctx->nonce, ctx->cbcmac, sizeof ctx->cbcmac);
|
||||
memcpy(ctx->ctr, ctx->nonce, sizeof ctx->nonce);
|
||||
|
||||
memcpy(ctx->head, st->st[1], sizeof ctx->head);
|
||||
|
||||
memcpy(ctx->cbcmac, st->st[2], sizeof ctx->cbcmac);
|
||||
ctx->ptr = 0;
|
||||
}
|
||||
|
||||
/* 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)
|
||||
{
|
||||
int from_capture;
|
||||
|
||||
/*
|
||||
* ctx->head[0] may be non-zero if the context was reset with
|
||||
* a pre-AAD captured state. In that case, ctx->ctr[] contains
|
||||
* the state for OMAC^2 _after_ processing the first block.
|
||||
*/
|
||||
from_capture = ctx->head[0];
|
||||
|
||||
/*
|
||||
* 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.
|
||||
* If the context was initialized from a captured state, then
|
||||
* the OMAC^2 value is in the ctr[] array.
|
||||
*/
|
||||
if (from_capture) {
|
||||
memcpy(ctx->cbcmac, ctx->ctr, sizeof ctx->cbcmac);
|
||||
ctx->ptr = 0;
|
||||
} else {
|
||||
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;
|
||||
|
||||
/*
|
||||
* We may have ptr == 0 here if we initialized from a captured
|
||||
* state. In that case, there is no partially consumed block
|
||||
* or unprocessed data.
|
||||
*/
|
||||
if (ptr != 0 && 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.
|
||||
* Exception: when ptr == 0, no block has been produced yet.
|
||||
*/
|
||||
if (ptr != 0) {
|
||||
(*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 PROGMEM = {
|
||||
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
|
||||
};
|
|
@ -0,0 +1,318 @@
|
|||
/*
|
||||
* 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 "t_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->vtable = &br_gcm_vtable;
|
||||
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 */
|
||||
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_trunc(br_gcm_context *ctx, const void *tag, size_t len)
|
||||
{
|
||||
unsigned char tmp[16];
|
||||
size_t u;
|
||||
int x;
|
||||
|
||||
br_gcm_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_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 PROGMEM = {
|
||||
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,
|
||||
(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
|
||||
};
|
|
@ -0,0 +1,44 @@
|
|||
/*
|
||||
* Copyright (c) 2016 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 "t_inner.h"
|
||||
|
||||
/* see inner.h */
|
||||
void
|
||||
br_ccopy(uint32_t ctl, void *dst, const void *src, size_t len)
|
||||
{
|
||||
unsigned char *d;
|
||||
const unsigned char *s;
|
||||
|
||||
d = dst;
|
||||
s = src;
|
||||
while (len -- > 0) {
|
||||
uint32_t x, y;
|
||||
|
||||
x = *s ++;
|
||||
y = *d;
|
||||
*d = MUX(ctl, x, y);
|
||||
d ++;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,38 @@
|
|||
/*
|
||||
* Copyright (c) 2016 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 "t_inner.h"
|
||||
|
||||
/* see inner.h */
|
||||
void
|
||||
br_range_dec16be(uint16_t *v, size_t num, const void *src)
|
||||
{
|
||||
const unsigned char *buf;
|
||||
|
||||
buf = src;
|
||||
while (num -- > 0) {
|
||||
*v ++ = br_dec16be(buf);
|
||||
buf += 2;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,38 @@
|
|||
/*
|
||||
* Copyright (c) 2016 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 "t_inner.h"
|
||||
|
||||
/* see inner.h */
|
||||
void
|
||||
br_range_dec16le(uint16_t *v, size_t num, const void *src)
|
||||
{
|
||||
const unsigned char *buf;
|
||||
|
||||
buf = src;
|
||||
while (num -- > 0) {
|
||||
*v ++ = br_dec16le(buf);
|
||||
buf += 2;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,38 @@
|
|||
/*
|
||||
* Copyright (c) 2016 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 "t_inner.h"
|
||||
|
||||
/* see inner.h */
|
||||
void
|
||||
br_range_dec32be(uint32_t *v, size_t num, const void *src)
|
||||
{
|
||||
const unsigned char *buf;
|
||||
|
||||
buf = src;
|
||||
while (num -- > 0) {
|
||||
*v ++ = br_dec32be(buf);
|
||||
buf += 4;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,38 @@
|
|||
/*
|
||||
* Copyright (c) 2016 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 "t_inner.h"
|
||||
|
||||
/* see inner.h */
|
||||
void
|
||||
br_range_dec32le(uint32_t *v, size_t num, const void *src)
|
||||
{
|
||||
const unsigned char *buf;
|
||||
|
||||
buf = src;
|
||||
while (num -- > 0) {
|
||||
*v ++ = br_dec32le(buf);
|
||||
buf += 4;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,38 @@
|
|||
/*
|
||||
* Copyright (c) 2016 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 "t_inner.h"
|
||||
|
||||
/* see inner.h */
|
||||
void
|
||||
br_range_dec64be(uint64_t *v, size_t num, const void *src)
|
||||
{
|
||||
const unsigned char *buf;
|
||||
|
||||
buf = src;
|
||||
while (num -- > 0) {
|
||||
*v ++ = br_dec64be(buf);
|
||||
buf += 8;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,38 @@
|
|||
/*
|
||||
* Copyright (c) 2016 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 "t_inner.h"
|
||||
|
||||
/* see inner.h */
|
||||
void
|
||||
br_range_dec64le(uint64_t *v, size_t num, const void *src)
|
||||
{
|
||||
const unsigned char *buf;
|
||||
|
||||
buf = src;
|
||||
while (num -- > 0) {
|
||||
*v ++ = br_dec64le(buf);
|
||||
buf += 8;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,38 @@
|
|||
/*
|
||||
* Copyright (c) 2016 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 "t_inner.h"
|
||||
|
||||
/* see inner.h */
|
||||
void
|
||||
br_range_enc16be(void *dst, const uint16_t *v, size_t num)
|
||||
{
|
||||
unsigned char *buf;
|
||||
|
||||
buf = dst;
|
||||
while (num -- > 0) {
|
||||
br_enc16be(buf, *v ++);
|
||||
buf += 2;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,38 @@
|
|||
/*
|
||||
* Copyright (c) 2016 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 "t_inner.h"
|
||||
|
||||
/* see inner.h */
|
||||
void
|
||||
br_range_enc16le(void *dst, const uint16_t *v, size_t num)
|
||||
{
|
||||
unsigned char *buf;
|
||||
|
||||
buf = dst;
|
||||
while (num -- > 0) {
|
||||
br_enc16le(buf, *v ++);
|
||||
buf += 2;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,38 @@
|
|||
/*
|
||||
* Copyright (c) 2016 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 "t_inner.h"
|
||||
|
||||
/* see inner.h */
|
||||
void
|
||||
br_range_enc32be(void *dst, const uint32_t *v, size_t num)
|
||||
{
|
||||
unsigned char *buf;
|
||||
|
||||
buf = dst;
|
||||
while (num -- > 0) {
|
||||
br_enc32be(buf, *v ++);
|
||||
buf += 4;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,38 @@
|
|||
/*
|
||||
* Copyright (c) 2016 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 "t_inner.h"
|
||||
|
||||
/* see inner.h */
|
||||
void
|
||||
br_range_enc32le(void *dst, const uint32_t *v, size_t num)
|
||||
{
|
||||
unsigned char *buf;
|
||||
|
||||
buf = dst;
|
||||
while (num -- > 0) {
|
||||
br_enc32le(buf, *v ++);
|
||||
buf += 4;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,38 @@
|
|||
/*
|
||||
* Copyright (c) 2016 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 "t_inner.h"
|
||||
|
||||
/* see inner.h */
|
||||
void
|
||||
br_range_enc64be(void *dst, const uint64_t *v, size_t num)
|
||||
{
|
||||
unsigned char *buf;
|
||||
|
||||
buf = dst;
|
||||
while (num -- > 0) {
|
||||
br_enc64be(buf, *v ++);
|
||||
buf += 8;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,38 @@
|
|||
/*
|
||||
* Copyright (c) 2016 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 "t_inner.h"
|
||||
|
||||
/* see inner.h */
|
||||
void
|
||||
br_range_enc64le(void *dst, const uint64_t *v, size_t num)
|
||||
{
|
||||
unsigned char *buf;
|
||||
|
||||
buf = dst;
|
||||
while (num -- > 0) {
|
||||
br_enc64le(buf, *v ++);
|
||||
buf += 8;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,536 @@
|
|||
/* Automatically generated code; do not modify directly. */
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
#include <pgmspace_bearssl.h>
|
||||
|
||||
typedef struct {
|
||||
uint32_t *dp;
|
||||
uint32_t *rp;
|
||||
const unsigned char *ip;
|
||||
} t0_context;
|
||||
|
||||
static uint32_t
|
||||
t0_parse7E_unsigned(const unsigned char **p)
|
||||
{
|
||||
uint32_t x;
|
||||
|
||||
x = 0;
|
||||
for (;;) {
|
||||
unsigned y;
|
||||
|
||||
y = pgm_read_byte((*p)++);
|
||||
x = (x << 7) | (uint32_t)(y & 0x7F);
|
||||
if (y < 0x80) {
|
||||
return x;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static int32_t
|
||||
t0_parse7E_signed(const unsigned char **p)
|
||||
{
|
||||
int neg;
|
||||
uint32_t x;
|
||||
|
||||
neg = (pgm_read_byte(*p) >> 6) & 1;
|
||||
x = (uint32_t)-neg;
|
||||
for (;;) {
|
||||
unsigned y;
|
||||
|
||||
y = pgm_read_byte((*p)++);
|
||||
x = (x << 7) | (uint32_t)(y & 0x7F);
|
||||
if (y < 0x80) {
|
||||
if (neg) {
|
||||
return -(int32_t)~x - 1;
|
||||
} else {
|
||||
return (int32_t)x;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#define T0_VBYTE(x, n) (unsigned char)((((uint32_t)(x) >> (n)) & 0x7F) | 0x80)
|
||||
#define T0_FBYTE(x, n) (unsigned char)(((uint32_t)(x) >> (n)) & 0x7F)
|
||||
#define T0_SBYTE(x) (unsigned char)((((uint32_t)(x) >> 28) + 0xF8) ^ 0xF8)
|
||||
#define T0_INT1(x) T0_FBYTE(x, 0)
|
||||
#define T0_INT2(x) T0_VBYTE(x, 7), T0_FBYTE(x, 0)
|
||||
#define T0_INT3(x) T0_VBYTE(x, 14), T0_VBYTE(x, 7), T0_FBYTE(x, 0)
|
||||
#define T0_INT4(x) T0_VBYTE(x, 21), T0_VBYTE(x, 14), T0_VBYTE(x, 7), T0_FBYTE(x, 0)
|
||||
#define T0_INT5(x) T0_SBYTE(x), T0_VBYTE(x, 21), T0_VBYTE(x, 14), T0_VBYTE(x, 7), T0_FBYTE(x, 0)
|
||||
|
||||
/* static const unsigned char t0_datablock[]; */
|
||||
|
||||
|
||||
void br_pem_decoder_init_main(void *t0ctx);
|
||||
|
||||
void br_pem_decoder_run(void *t0ctx);
|
||||
|
||||
|
||||
|
||||
#include "t_inner.h"
|
||||
|
||||
#define CTX ((br_pem_decoder_context *)(void *)((unsigned char *)t0ctx - offsetof(br_pem_decoder_context, cpu)))
|
||||
|
||||
/* see bearssl_pem.h */
|
||||
void
|
||||
br_pem_decoder_init(br_pem_decoder_context *ctx)
|
||||
{
|
||||
memset(ctx, 0, sizeof *ctx);
|
||||
ctx->cpu.dp = &ctx->dp_stack[0];
|
||||
ctx->cpu.rp = &ctx->rp_stack[0];
|
||||
br_pem_decoder_init_main(&ctx->cpu);
|
||||
br_pem_decoder_run(&ctx->cpu);
|
||||
}
|
||||
|
||||
/* see bearssl_pem.h */
|
||||
size_t
|
||||
br_pem_decoder_push(br_pem_decoder_context *ctx,
|
||||
const void *data, size_t len)
|
||||
{
|
||||
if (ctx->event) {
|
||||
return 0;
|
||||
}
|
||||
ctx->hbuf = data;
|
||||
ctx->hlen = len;
|
||||
br_pem_decoder_run(&ctx->cpu);
|
||||
return len - ctx->hlen;
|
||||
}
|
||||
|
||||
/* see bearssl_pem.h */
|
||||
int
|
||||
br_pem_decoder_event(br_pem_decoder_context *ctx)
|
||||
{
|
||||
int event;
|
||||
|
||||
event = ctx->event;
|
||||
ctx->event = 0;
|
||||
return event;
|
||||
}
|
||||
|
||||
|
||||
|
||||
static const unsigned char t0_datablock[] PROGMEM = {
|
||||
|
||||
0x00, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x42, 0x45, 0x47, 0x49, 0x4E, 0x20,
|
||||
0x00, 0x2D, 0x2D, 0x2D, 0x2D, 0x45, 0x4E, 0x44, 0x20, 0x00
|
||||
};
|
||||
|
||||
static const unsigned char t0_codeblock[] PROGMEM = {
|
||||
|
||||
0x00, 0x01, 0x00, 0x09, 0x00, 0x00, 0x01, 0x01, 0x07, 0x00, 0x00, 0x01,
|
||||
0x01, 0x08, 0x00, 0x00, 0x13, 0x13, 0x00, 0x00, 0x01,
|
||||
T0_INT2(offsetof(br_pem_decoder_context, event)), 0x00, 0x00, 0x01,
|
||||
T0_INT2(offsetof(br_pem_decoder_context, name)), 0x00, 0x00, 0x05,
|
||||
0x14, 0x2C, 0x14, 0x01, 0x0A, 0x0D, 0x06, 0x03, 0x13, 0x04, 0x76, 0x01,
|
||||
0x2D, 0x0C, 0x06, 0x05, 0x2E, 0x01, 0x03, 0x2D, 0x00, 0x01, 0x0D, 0x27,
|
||||
0x05, 0x04, 0x01, 0x03, 0x2D, 0x00, 0x15, 0x2E, 0x01, 0x02, 0x2D, 0x00,
|
||||
0x01, 0x01, 0x7F, 0x03, 0x00, 0x25, 0x01, 0x00, 0x18, 0x0D, 0x06, 0x03,
|
||||
0x13, 0x04, 0x3C, 0x01, 0x7F, 0x18, 0x0D, 0x06, 0x13, 0x13, 0x02, 0x00,
|
||||
0x05, 0x06, 0x2E, 0x01, 0x03, 0x2D, 0x04, 0x03, 0x01, 0x7F, 0x23, 0x01,
|
||||
0x00, 0x00, 0x04, 0x23, 0x01, 0x01, 0x18, 0x0D, 0x06, 0x09, 0x13, 0x01,
|
||||
0x00, 0x23, 0x01, 0x00, 0x00, 0x04, 0x14, 0x01, 0x02, 0x18, 0x0D, 0x06,
|
||||
0x06, 0x13, 0x01, 0x7F, 0x00, 0x04, 0x08, 0x13, 0x01, 0x03, 0x2D, 0x01,
|
||||
0x00, 0x00, 0x13, 0x01, 0x00, 0x03, 0x00, 0x04, 0xFF, 0x33, 0x01, 0x2C,
|
||||
0x14, 0x01, 0x2D, 0x0D, 0x06, 0x04, 0x13, 0x01, 0x7F, 0x00, 0x14, 0x31,
|
||||
0x06, 0x02, 0x13, 0x29, 0x14, 0x01, 0x0A, 0x0D, 0x06, 0x04, 0x13, 0x01,
|
||||
0x02, 0x00, 0x16, 0x14, 0x1D, 0x06, 0x05, 0x13, 0x2E, 0x01, 0x03, 0x00,
|
||||
0x03, 0x00, 0x29, 0x14, 0x01, 0x0A, 0x0D, 0x06, 0x04, 0x13, 0x01, 0x03,
|
||||
0x00, 0x16, 0x14, 0x1D, 0x06, 0x05, 0x13, 0x2E, 0x01, 0x03, 0x00, 0x02,
|
||||
0x00, 0x01, 0x06, 0x0A, 0x07, 0x03, 0x00, 0x29, 0x14, 0x01, 0x0A, 0x0D,
|
||||
0x06, 0x04, 0x13, 0x01, 0x03, 0x00, 0x14, 0x01, 0x3D, 0x0D, 0x06, 0x2E,
|
||||
0x13, 0x29, 0x14, 0x01, 0x0A, 0x0D, 0x06, 0x04, 0x13, 0x01, 0x03, 0x00,
|
||||
0x2F, 0x05, 0x04, 0x13, 0x01, 0x03, 0x00, 0x01, 0x3D, 0x0C, 0x06, 0x03,
|
||||
0x01, 0x03, 0x00, 0x02, 0x00, 0x01, 0x0F, 0x10, 0x06, 0x03, 0x01, 0x03,
|
||||
0x00, 0x02, 0x00, 0x01, 0x04, 0x0F, 0x1C, 0x01, 0x01, 0x00, 0x16, 0x14,
|
||||
0x1D, 0x06, 0x05, 0x13, 0x2E, 0x01, 0x03, 0x00, 0x02, 0x00, 0x01, 0x06,
|
||||
0x0A, 0x07, 0x03, 0x00, 0x29, 0x14, 0x01, 0x0A, 0x0D, 0x06, 0x04, 0x13,
|
||||
0x01, 0x03, 0x00, 0x14, 0x01, 0x3D, 0x0D, 0x06, 0x20, 0x13, 0x2F, 0x05,
|
||||
0x03, 0x01, 0x03, 0x00, 0x02, 0x00, 0x01, 0x03, 0x10, 0x06, 0x03, 0x01,
|
||||
0x03, 0x00, 0x02, 0x00, 0x01, 0x0A, 0x0F, 0x1C, 0x02, 0x00, 0x01, 0x02,
|
||||
0x0F, 0x1C, 0x01, 0x01, 0x00, 0x16, 0x14, 0x1D, 0x06, 0x05, 0x13, 0x2E,
|
||||
0x01, 0x03, 0x00, 0x02, 0x00, 0x01, 0x06, 0x0A, 0x07, 0x03, 0x00, 0x02,
|
||||
0x00, 0x01, 0x10, 0x0F, 0x1C, 0x02, 0x00, 0x01, 0x08, 0x0F, 0x1C, 0x02,
|
||||
0x00, 0x1C, 0x01, 0x00, 0x00, 0x00, 0x28, 0x01, 0x01, 0x2D, 0x24, 0x06,
|
||||
0x02, 0x04, 0x7B, 0x04, 0x75, 0x00, 0x14, 0x12, 0x2A, 0x14, 0x05, 0x04,
|
||||
0x20, 0x01, 0x7F, 0x00, 0x2C, 0x2A, 0x14, 0x01, 0x0A, 0x0D, 0x06, 0x05,
|
||||
0x13, 0x20, 0x01, 0x00, 0x00, 0x0D, 0x05, 0x05, 0x13, 0x2E, 0x01, 0x00,
|
||||
0x00, 0x1E, 0x04, 0x5E, 0x00, 0x01, 0x01, 0x27, 0x06, 0x0B, 0x22, 0x01,
|
||||
0x80, 0x7F, 0x2B, 0x14, 0x06, 0x02, 0x30, 0x00, 0x13, 0x04, 0x6E, 0x00,
|
||||
0x2C, 0x14, 0x31, 0x05, 0x01, 0x00, 0x13, 0x04, 0x77, 0x00, 0x14, 0x14,
|
||||
0x01, 0x80, 0x61, 0x0E, 0x1B, 0x01, 0x80, 0x7A, 0x0B, 0x10, 0x06, 0x03,
|
||||
0x01, 0x20, 0x08, 0x00, 0x01, 0x14, 0x03, 0x00, 0x1B, 0x18, 0x05, 0x05,
|
||||
0x20, 0x2E, 0x01, 0x00, 0x00, 0x2C, 0x14, 0x01, 0x0A, 0x0D, 0x06, 0x06,
|
||||
0x20, 0x02, 0x00, 0x1B, 0x08, 0x00, 0x14, 0x01, 0x0D, 0x0D, 0x06, 0x03,
|
||||
0x13, 0x04, 0x03, 0x2A, 0x18, 0x1A, 0x1E, 0x1B, 0x1F, 0x1B, 0x04, 0x59,
|
||||
0x00, 0x19, 0x14, 0x1D, 0x05, 0x01, 0x00, 0x13, 0x11, 0x04, 0x76, 0x00,
|
||||
0x21, 0x1A, 0x11, 0x00, 0x00, 0x2C, 0x01, 0x0A, 0x0C, 0x06, 0x02, 0x04,
|
||||
0x78, 0x00, 0x01, 0x01, 0x7F, 0x03, 0x00, 0x2C, 0x14, 0x01, 0x0A, 0x0C,
|
||||
0x06, 0x09, 0x31, 0x05, 0x04, 0x01, 0x00, 0x03, 0x00, 0x04, 0x70, 0x13,
|
||||
0x02, 0x00, 0x00, 0x00, 0x14, 0x06, 0x14, 0x1F, 0x14, 0x22, 0x07, 0x17,
|
||||
0x01, 0x2D, 0x0C, 0x06, 0x08, 0x22, 0x07, 0x1E, 0x01, 0x00, 0x1B, 0x1A,
|
||||
0x00, 0x04, 0x69, 0x22, 0x1A, 0x00, 0x00, 0x14, 0x01, 0x0A, 0x0C, 0x1B,
|
||||
0x01, 0x20, 0x0B, 0x10, 0x00
|
||||
};
|
||||
|
||||
static const uint16_t t0_caddr[] PROGMEM = {
|
||||
|
||||
0,
|
||||
5,
|
||||
10,
|
||||
15,
|
||||
19,
|
||||
24,
|
||||
29,
|
||||
67,
|
||||
149,
|
||||
384,
|
||||
396,
|
||||
431,
|
||||
450,
|
||||
460,
|
||||
479,
|
||||
523,
|
||||
534,
|
||||
539,
|
||||
549,
|
||||
574,
|
||||
601
|
||||
};
|
||||
|
||||
#define T0_INTERPRETED 29
|
||||
|
||||
#define T0_ENTER(ip, rp, slot) do { \
|
||||
const unsigned char *t0_newip; \
|
||||
uint32_t t0_lnum; \
|
||||
t0_newip = &t0_codeblock[pgm_read_word(&t0_caddr[(slot) - T0_INTERPRETED])]; \
|
||||
t0_lnum = t0_parse7E_unsigned(&t0_newip); \
|
||||
(rp) += t0_lnum; \
|
||||
*((rp) ++) = (uint32_t)((ip) - &t0_codeblock[0]) + (t0_lnum << 16); \
|
||||
(ip) = t0_newip; \
|
||||
} while (0)
|
||||
|
||||
#define T0_DEFENTRY(name, slot) \
|
||||
void \
|
||||
name(void *ctx) \
|
||||
{ \
|
||||
t0_context *t0ctx = ctx; \
|
||||
t0ctx->ip = &t0_codeblock[0]; \
|
||||
T0_ENTER(t0ctx->ip, t0ctx->rp, slot); \
|
||||
}
|
||||
|
||||
T0_DEFENTRY(br_pem_decoder_init_main, 38)
|
||||
|
||||
#define T0_NEXT(t0ipp) (pgm_read_byte((*t0ipp)++))
|
||||
|
||||
void
|
||||
br_pem_decoder_run(void *t0ctx)
|
||||
{
|
||||
uint32_t *dp, *rp;
|
||||
const unsigned char *ip;
|
||||
|
||||
#define T0_LOCAL(x) (*(rp - 2 - (x)))
|
||||
#define T0_POP() (*-- dp)
|
||||
#define T0_POPi() (*(int32_t *)(-- dp))
|
||||
#define T0_PEEK(x) (*(dp - 1 - (x)))
|
||||
#define T0_PEEKi(x) (*(int32_t *)(dp - 1 - (x)))
|
||||
#define T0_PUSH(v) do { *dp = (v); dp ++; } while (0)
|
||||
#define T0_PUSHi(v) do { *(int32_t *)dp = (v); dp ++; } while (0)
|
||||
#define T0_RPOP() (*-- rp)
|
||||
#define T0_RPOPi() (*(int32_t *)(-- rp))
|
||||
#define T0_RPUSH(v) do { *rp = (v); rp ++; } while (0)
|
||||
#define T0_RPUSHi(v) do { *(int32_t *)rp = (v); rp ++; } while (0)
|
||||
#define T0_ROLL(x) do { \
|
||||
size_t t0len = (size_t)(x); \
|
||||
uint32_t t0tmp = *(dp - 1 - t0len); \
|
||||
memmove(dp - t0len - 1, dp - t0len, t0len * sizeof *dp); \
|
||||
*(dp - 1) = t0tmp; \
|
||||
} while (0)
|
||||
#define T0_SWAP() do { \
|
||||
uint32_t t0tmp = *(dp - 2); \
|
||||
*(dp - 2) = *(dp - 1); \
|
||||
*(dp - 1) = t0tmp; \
|
||||
} while (0)
|
||||
#define T0_ROT() do { \
|
||||
uint32_t t0tmp = *(dp - 3); \
|
||||
*(dp - 3) = *(dp - 2); \
|
||||
*(dp - 2) = *(dp - 1); \
|
||||
*(dp - 1) = t0tmp; \
|
||||
} while (0)
|
||||
#define T0_NROT() do { \
|
||||
uint32_t t0tmp = *(dp - 1); \
|
||||
*(dp - 1) = *(dp - 2); \
|
||||
*(dp - 2) = *(dp - 3); \
|
||||
*(dp - 3) = t0tmp; \
|
||||
} while (0)
|
||||
#define T0_PICK(x) do { \
|
||||
uint32_t t0depth = (x); \
|
||||
T0_PUSH(T0_PEEK(t0depth)); \
|
||||
} while (0)
|
||||
#define T0_CO() do { \
|
||||
goto t0_exit; \
|
||||
} while (0)
|
||||
#define T0_RET() goto t0_next
|
||||
|
||||
dp = ((t0_context *)t0ctx)->dp;
|
||||
rp = ((t0_context *)t0ctx)->rp;
|
||||
ip = ((t0_context *)t0ctx)->ip;
|
||||
goto t0_next;
|
||||
for (;;) {
|
||||
uint32_t t0x;
|
||||
|
||||
t0_next:
|
||||
t0x = T0_NEXT(&ip);
|
||||
if (t0x < T0_INTERPRETED) {
|
||||
switch (t0x) {
|
||||
int32_t t0off;
|
||||
|
||||
case 0: /* ret */
|
||||
t0x = T0_RPOP();
|
||||
rp -= (t0x >> 16);
|
||||
t0x &= 0xFFFF;
|
||||
if (t0x == 0) {
|
||||
ip = NULL;
|
||||
goto t0_exit;
|
||||
}
|
||||
ip = &t0_codeblock[t0x];
|
||||
break;
|
||||
case 1: /* literal constant */
|
||||
T0_PUSHi(t0_parse7E_signed(&ip));
|
||||
break;
|
||||
case 2: /* read local */
|
||||
T0_PUSH(T0_LOCAL(t0_parse7E_unsigned(&ip)));
|
||||
break;
|
||||
case 3: /* write local */
|
||||
T0_LOCAL(t0_parse7E_unsigned(&ip)) = T0_POP();
|
||||
break;
|
||||
case 4: /* jump */
|
||||
t0off = t0_parse7E_signed(&ip);
|
||||
ip += t0off;
|
||||
break;
|
||||
case 5: /* jump if */
|
||||
t0off = t0_parse7E_signed(&ip);
|
||||
if (T0_POP()) {
|
||||
ip += t0off;
|
||||
}
|
||||
break;
|
||||
case 6: /* jump if not */
|
||||
t0off = t0_parse7E_signed(&ip);
|
||||
if (!T0_POP()) {
|
||||
ip += t0off;
|
||||
}
|
||||
break;
|
||||
case 7: {
|
||||
/* + */
|
||||
|
||||
uint32_t b = T0_POP();
|
||||
uint32_t a = T0_POP();
|
||||
T0_PUSH(a + b);
|
||||
|
||||
}
|
||||
break;
|
||||
case 8: {
|
||||
/* - */
|
||||
|
||||
uint32_t b = T0_POP();
|
||||
uint32_t a = T0_POP();
|
||||
T0_PUSH(a - b);
|
||||
|
||||
}
|
||||
break;
|
||||
case 9: {
|
||||
/* < */
|
||||
|
||||
int32_t b = T0_POPi();
|
||||
int32_t a = T0_POPi();
|
||||
T0_PUSH(-(uint32_t)(a < b));
|
||||
|
||||
}
|
||||
break;
|
||||
case 10: {
|
||||
/* << */
|
||||
|
||||
int c = (int)T0_POPi();
|
||||
uint32_t x = T0_POP();
|
||||
T0_PUSH(x << c);
|
||||
|
||||
}
|
||||
break;
|
||||
case 11: {
|
||||
/* <= */
|
||||
|
||||
int32_t b = T0_POPi();
|
||||
int32_t a = T0_POPi();
|
||||
T0_PUSH(-(uint32_t)(a <= b));
|
||||
|
||||
}
|
||||
break;
|
||||
case 12: {
|
||||
/* <> */
|
||||
|
||||
uint32_t b = T0_POP();
|
||||
uint32_t a = T0_POP();
|
||||
T0_PUSH(-(uint32_t)(a != b));
|
||||
|
||||
}
|
||||
break;
|
||||
case 13: {
|
||||
/* = */
|
||||
|
||||
uint32_t b = T0_POP();
|
||||
uint32_t a = T0_POP();
|
||||
T0_PUSH(-(uint32_t)(a == b));
|
||||
|
||||
}
|
||||
break;
|
||||
case 14: {
|
||||
/* >= */
|
||||
|
||||
int32_t b = T0_POPi();
|
||||
int32_t a = T0_POPi();
|
||||
T0_PUSH(-(uint32_t)(a >= b));
|
||||
|
||||
}
|
||||
break;
|
||||
case 15: {
|
||||
/* >> */
|
||||
|
||||
int c = (int)T0_POPi();
|
||||
int32_t x = T0_POPi();
|
||||
T0_PUSHi(x >> c);
|
||||
|
||||
}
|
||||
break;
|
||||
case 16: {
|
||||
/* and */
|
||||
|
||||
uint32_t b = T0_POP();
|
||||
uint32_t a = T0_POP();
|
||||
T0_PUSH(a & b);
|
||||
|
||||
}
|
||||
break;
|
||||
case 17: {
|
||||
/* co */
|
||||
T0_CO();
|
||||
}
|
||||
break;
|
||||
case 18: {
|
||||
/* data-get8 */
|
||||
|
||||
size_t addr = T0_POP();
|
||||
T0_PUSH(pgm_read_byte(&t0_datablock[addr]));
|
||||
|
||||
}
|
||||
break;
|
||||
case 19: {
|
||||
/* drop */
|
||||
(void)T0_POP();
|
||||
}
|
||||
break;
|
||||
case 20: {
|
||||
/* dup */
|
||||
T0_PUSH(T0_PEEK(0));
|
||||
}
|
||||
break;
|
||||
case 21: {
|
||||
/* flush-buf */
|
||||
|
||||
if (CTX->ptr > 0) {
|
||||
if (CTX->dest) {
|
||||
CTX->dest(CTX->dest_ctx, CTX->buf, CTX->ptr);
|
||||
}
|
||||
CTX->ptr = 0;
|
||||
}
|
||||
|
||||
}
|
||||
break;
|
||||
case 22: {
|
||||
/* from-base64 */
|
||||
|
||||
uint32_t c = T0_POP();
|
||||
uint32_t p, q, r, z;
|
||||
p = c - 0x41;
|
||||
q = c - 0x61;
|
||||
r = c - 0x30;
|
||||
|
||||
z = ((p + 2) & -LT(p, 26))
|
||||
| ((q + 28) & -LT(q, 26))
|
||||
| ((r + 54) & -LT(r, 10))
|
||||
| (64 & -EQ(c, 0x2B))
|
||||
| (65 & -EQ(c, 0x2F))
|
||||
| EQ(c, 0x3D);
|
||||
T0_PUSHi((int32_t)z - 2);
|
||||
|
||||
}
|
||||
break;
|
||||
case 23: {
|
||||
/* get8 */
|
||||
|
||||
size_t addr = T0_POP();
|
||||
T0_PUSH(*((unsigned char *)CTX + addr));
|
||||
|
||||
}
|
||||
break;
|
||||
case 24: {
|
||||
/* over */
|
||||
T0_PUSH(T0_PEEK(1));
|
||||
}
|
||||
break;
|
||||
case 25: {
|
||||
/* read8-native */
|
||||
|
||||
do {
|
||||
if (CTX->hlen > 0) {
|
||||
uint8_t ch = pgm_read_byte(CTX->hbuf ++);
|
||||
CTX->hlen --;
|
||||
if (ch == '\r') continue; // skip \rs
|
||||
T0_PUSH(ch);
|
||||
break;
|
||||
} else {
|
||||
T0_PUSHi(-1);
|
||||
break;
|
||||
}
|
||||
} while (1);
|
||||
|
||||
}
|
||||
break;
|
||||
case 26: {
|
||||
/* set8 */
|
||||
|
||||
size_t addr = T0_POP();
|
||||
unsigned x = T0_POP();
|
||||
*((unsigned char *)CTX + addr) = x;
|
||||
|
||||
}
|
||||
break;
|
||||
case 27: {
|
||||
/* swap */
|
||||
T0_SWAP();
|
||||
}
|
||||
break;
|
||||
case 28: {
|
||||
/* write8 */
|
||||
|
||||
unsigned char x = (unsigned char)T0_POP();
|
||||
CTX->buf[CTX->ptr ++] = x;
|
||||
if (CTX->ptr == sizeof CTX->buf) {
|
||||
if (CTX->dest) {
|
||||
CTX->dest(CTX->dest_ctx, CTX->buf, sizeof CTX->buf);
|
||||
}
|
||||
CTX->ptr = 0;
|
||||
}
|
||||
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
} else {
|
||||
T0_ENTER(ip, rp, t0x);
|
||||
}
|
||||
}
|
||||
t0_exit:
|
||||
((t0_context *)t0ctx)->dp = dp;
|
||||
((t0_context *)t0ctx)->rp = rp;
|
||||
((t0_context *)t0ctx)->ip = ip;
|
||||
}
|
|
@ -0,0 +1,173 @@
|
|||
/*
|
||||
* Copyright (c) 2018 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 "t_inner.h"
|
||||
|
||||
/*
|
||||
* Get the appropriate Base64 character for a numeric value in the
|
||||
* 0..63 range. This is constant-time.
|
||||
*/
|
||||
static char
|
||||
b64char(uint32_t x)
|
||||
{
|
||||
/*
|
||||
* Values 0 to 25 map to 0x41..0x5A ('A' to 'Z')
|
||||
* Values 26 to 51 map to 0x61..0x7A ('a' to 'z')
|
||||
* Values 52 to 61 map to 0x30..0x39 ('0' to '9')
|
||||
* Value 62 maps to 0x2B ('+')
|
||||
* Value 63 maps to 0x2F ('/')
|
||||
*/
|
||||
uint32_t a, b, c;
|
||||
|
||||
a = x - 26;
|
||||
b = x - 52;
|
||||
c = x - 62;
|
||||
|
||||
/*
|
||||
* Looking at bits 8..15 of values a, b and c:
|
||||
*
|
||||
* x a b c
|
||||
* ---------------------
|
||||
* 0..25 FF FF FF
|
||||
* 26..51 00 FF FF
|
||||
* 52..61 00 00 FF
|
||||
* 62..63 00 00 00
|
||||
*/
|
||||
return (char)(((x + 0x41) & ((a & b & c) >> 8))
|
||||
| ((x + (0x61 - 26)) & ((~a & b & c) >> 8))
|
||||
| ((x - (52 - 0x30)) & ((~a & ~b & c) >> 8))
|
||||
| ((0x2B + ((x & 1) << 2)) & (~(a | b | c) >> 8)));
|
||||
}
|
||||
|
||||
/* see bearssl_pem.h */
|
||||
size_t
|
||||
br_pem_encode(void *dest, const void *data, size_t len,
|
||||
const char *banner, unsigned flags)
|
||||
{
|
||||
size_t dlen, banner_len, lines;
|
||||
char *d;
|
||||
unsigned char *buf;
|
||||
size_t u;
|
||||
int off, lim;
|
||||
|
||||
banner_len = strlen(banner);
|
||||
/* FIXME: try to avoid divisions here, as they may pull
|
||||
an extra libc function. */
|
||||
if ((flags & BR_PEM_LINE64) != 0) {
|
||||
lines = (len + 47) / 48;
|
||||
} else {
|
||||
lines = (len + 56) / 57;
|
||||
}
|
||||
dlen = (banner_len << 1) + 30 + (((len + 2) / 3) << 2)
|
||||
+ lines + 2;
|
||||
if ((flags & BR_PEM_CRLF) != 0) {
|
||||
dlen += lines + 2;
|
||||
}
|
||||
|
||||
if (dest == NULL) {
|
||||
return dlen;
|
||||
}
|
||||
|
||||
d = dest;
|
||||
|
||||
/*
|
||||
* We always move the source data to the end of output buffer;
|
||||
* the encoding process never "catches up" except at the very
|
||||
* end. This also handles all conditions of partial or total
|
||||
* overlap.
|
||||
*/
|
||||
buf = (unsigned char *)d + dlen - len;
|
||||
memmove(buf, data, len);
|
||||
|
||||
memcpy(d, "-----BEGIN ", 11);
|
||||
d += 11;
|
||||
memcpy(d, banner, banner_len);
|
||||
d += banner_len;
|
||||
memcpy(d, "-----", 5);
|
||||
d += 5;
|
||||
if ((flags & BR_PEM_CRLF) != 0) {
|
||||
*d ++ = 0x0D;
|
||||
}
|
||||
*d ++ = 0x0A;
|
||||
|
||||
off = 0;
|
||||
lim = (flags & BR_PEM_LINE64) != 0 ? 16 : 19;
|
||||
for (u = 0; (u + 2) < len; u += 3) {
|
||||
uint32_t w;
|
||||
|
||||
w = ((uint32_t)buf[u] << 16)
|
||||
| ((uint32_t)buf[u + 1] << 8)
|
||||
| (uint32_t)buf[u + 2];
|
||||
*d ++ = b64char(w >> 18);
|
||||
*d ++ = b64char((w >> 12) & 0x3F);
|
||||
*d ++ = b64char((w >> 6) & 0x3F);
|
||||
*d ++ = b64char(w & 0x3F);
|
||||
if (++ off == lim) {
|
||||
off = 0;
|
||||
if ((flags & BR_PEM_CRLF) != 0) {
|
||||
*d ++ = 0x0D;
|
||||
}
|
||||
*d ++ = 0x0A;
|
||||
}
|
||||
}
|
||||
if (u < len) {
|
||||
uint32_t w;
|
||||
|
||||
w = (uint32_t)buf[u] << 16;
|
||||
if (u + 1 < len) {
|
||||
w |= (uint32_t)buf[u + 1] << 8;
|
||||
}
|
||||
*d ++ = b64char(w >> 18);
|
||||
*d ++ = b64char((w >> 12) & 0x3F);
|
||||
if (u + 1 < len) {
|
||||
*d ++ = b64char((w >> 6) & 0x3F);
|
||||
} else {
|
||||
*d ++ = 0x3D;
|
||||
}
|
||||
*d ++ = 0x3D;
|
||||
off ++;
|
||||
}
|
||||
if (off != 0) {
|
||||
if ((flags & BR_PEM_CRLF) != 0) {
|
||||
*d ++ = 0x0D;
|
||||
}
|
||||
*d ++ = 0x0A;
|
||||
}
|
||||
|
||||
memcpy(d, "-----END ", 9);
|
||||
d += 9;
|
||||
memcpy(d, banner, banner_len);
|
||||
d += banner_len;
|
||||
memcpy(d, "-----", 5);
|
||||
d += 5;
|
||||
if ((flags & BR_PEM_CRLF) != 0) {
|
||||
*d ++ = 0x0D;
|
||||
}
|
||||
*d ++ = 0x0A;
|
||||
|
||||
/* Final zero, not counted in returned length. */
|
||||
*d ++ = 0x00;
|
||||
|
||||
return dlen;
|
||||
}
|
|
@ -0,0 +1,121 @@
|
|||
/*
|
||||
* 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 "t_inner.h"
|
||||
|
||||
static const unsigned char *
|
||||
api_generator(int curve, size_t *len)
|
||||
{
|
||||
switch (curve) {
|
||||
case BR_EC_secp256r1:
|
||||
return br_ec_p256_m15.generator(curve, len);
|
||||
case BR_EC_curve25519:
|
||||
return br_ec_c25519_m15.generator(curve, len);
|
||||
default:
|
||||
return br_ec_prime_i15.generator(curve, len);
|
||||
}
|
||||
}
|
||||
|
||||
static const unsigned char *
|
||||
api_order(int curve, size_t *len)
|
||||
{
|
||||
switch (curve) {
|
||||
case BR_EC_secp256r1:
|
||||
return br_ec_p256_m15.order(curve, len);
|
||||
case BR_EC_curve25519:
|
||||
return br_ec_c25519_m15.order(curve, len);
|
||||
default:
|
||||
return br_ec_prime_i15.order(curve, len);
|
||||
}
|
||||
}
|
||||
|
||||
static size_t
|
||||
api_xoff(int curve, size_t *len)
|
||||
{
|
||||
switch (curve) {
|
||||
case BR_EC_secp256r1:
|
||||
return br_ec_p256_m15.xoff(curve, len);
|
||||
case BR_EC_curve25519:
|
||||
return br_ec_c25519_m15.xoff(curve, len);
|
||||
default:
|
||||
return br_ec_prime_i15.xoff(curve, len);
|
||||
}
|
||||
}
|
||||
|
||||
static uint32_t
|
||||
api_mul(unsigned char *G, size_t Glen,
|
||||
const unsigned char *kb, size_t kblen, int curve)
|
||||
{
|
||||
switch (curve) {
|
||||
case BR_EC_secp256r1:
|
||||
return br_ec_p256_m15.mul(G, Glen, kb, kblen, curve);
|
||||
case BR_EC_curve25519:
|
||||
return br_ec_c25519_m15.mul(G, Glen, kb, kblen, curve);
|
||||
default:
|
||||
return br_ec_prime_i15.mul(G, Glen, kb, kblen, curve);
|
||||
}
|
||||
}
|
||||
|
||||
static size_t
|
||||
api_mulgen(unsigned char *R,
|
||||
const unsigned char *x, size_t xlen, int curve)
|
||||
{
|
||||
switch (curve) {
|
||||
case BR_EC_secp256r1:
|
||||
return br_ec_p256_m15.mulgen(R, x, xlen, curve);
|
||||
case BR_EC_curve25519:
|
||||
return br_ec_c25519_m15.mulgen(R, x, xlen, curve);
|
||||
default:
|
||||
return br_ec_prime_i15.mulgen(R, x, xlen, curve);
|
||||
}
|
||||
}
|
||||
|
||||
static uint32_t
|
||||
api_muladd(unsigned char *A, const unsigned char *B, size_t len,
|
||||
const unsigned char *x, size_t xlen,
|
||||
const unsigned char *y, size_t ylen, int curve)
|
||||
{
|
||||
switch (curve) {
|
||||
case BR_EC_secp256r1:
|
||||
return br_ec_p256_m15.muladd(A, B, len,
|
||||
x, xlen, y, ylen, curve);
|
||||
case BR_EC_curve25519:
|
||||
return br_ec_c25519_m15.muladd(A, B, len,
|
||||
x, xlen, y, ylen, curve);
|
||||
default:
|
||||
return br_ec_prime_i15.muladd(A, B, len,
|
||||
x, xlen, y, ylen, curve);
|
||||
}
|
||||
}
|
||||
|
||||
/* see bearssl_ec.h */
|
||||
const br_ec_impl br_ec_all_m15 PROGMEM = {
|
||||
(uint32_t)0x23800000,
|
||||
&api_generator,
|
||||
&api_order,
|
||||
&api_xoff,
|
||||
&api_mul,
|
||||
&api_mulgen,
|
||||
&api_muladd
|
||||
};
|
|
@ -0,0 +1,398 @@
|
|||
/*
|
||||
* 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 "t_inner.h"
|
||||
|
||||
/*
|
||||
* Parameters for the field:
|
||||
* - field modulus p = 2^255-19
|
||||
* - R^2 mod p (R = 2^(15k) for the smallest k such that R >= p)
|
||||
*/
|
||||
|
||||
static const uint16_t C255_P[] = {
|
||||
0x0110,
|
||||
0x7FED, 0x7FFF, 0x7FFF, 0x7FFF, 0x7FFF, 0x7FFF, 0x7FFF, 0x7FFF,
|
||||
0x7FFF, 0x7FFF, 0x7FFF, 0x7FFF, 0x7FFF, 0x7FFF, 0x7FFF, 0x7FFF,
|
||||
0x7FFF
|
||||
};
|
||||
|
||||
#define P0I 0x4A1B
|
||||
|
||||
static const uint16_t C255_R2[] = {
|
||||
0x0110,
|
||||
0x0169, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
|
||||
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
|
||||
0x0000
|
||||
};
|
||||
|
||||
/* obsolete
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
static void
|
||||
print_int_mont(const char *name, const uint16_t *x)
|
||||
{
|
||||
uint16_t y[18];
|
||||
unsigned char tmp[32];
|
||||
size_t u;
|
||||
|
||||
printf("%s = ", name);
|
||||
memcpy(y, x, sizeof y);
|
||||
br_i15_from_monty(y, C255_P, P0I);
|
||||
br_i15_encode(tmp, sizeof tmp, y);
|
||||
for (u = 0; u < sizeof tmp; u ++) {
|
||||
printf("%02X", tmp[u]);
|
||||
}
|
||||
printf("\n");
|
||||
}
|
||||
*/
|
||||
|
||||
static const uint16_t C255_A24[] = {
|
||||
0x0110,
|
||||
0x45D3, 0x0046, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
|
||||
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
|
||||
0x0000
|
||||
};
|
||||
|
||||
static const unsigned char GEN[] PROGMEM = {
|
||||
0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
|
||||
};
|
||||
|
||||
static const unsigned char ORDER[] PROGMEM = {
|
||||
0x7F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
||||
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
||||
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
||||
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF
|
||||
};
|
||||
|
||||
static const unsigned char *
|
||||
api_generator(int curve, size_t *len)
|
||||
{
|
||||
(void)curve;
|
||||
*len = 32;
|
||||
return GEN;
|
||||
}
|
||||
|
||||
static const unsigned char *
|
||||
api_order(int curve, size_t *len)
|
||||
{
|
||||
(void)curve;
|
||||
*len = 32;
|
||||
return ORDER;
|
||||
}
|
||||
|
||||
static size_t
|
||||
api_xoff(int curve, size_t *len)
|
||||
{
|
||||
(void)curve;
|
||||
*len = 32;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
cswap(uint16_t *a, uint16_t *b, uint32_t ctl)
|
||||
{
|
||||
int i;
|
||||
|
||||
ctl = -ctl;
|
||||
for (i = 0; i < 18; i ++) {
|
||||
uint32_t aw, bw, tw;
|
||||
|
||||
aw = a[i];
|
||||
bw = b[i];
|
||||
tw = ctl & (aw ^ bw);
|
||||
a[i] = aw ^ tw;
|
||||
b[i] = bw ^ tw;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
c255_add(uint16_t *d, const uint16_t *a, const uint16_t *b)
|
||||
{
|
||||
uint32_t ctl;
|
||||
uint16_t t[18];
|
||||
|
||||
memcpy_P(t, a, sizeof t);
|
||||
ctl = br_i15_add(t, b, 1);
|
||||
ctl |= NOT(br_i15_sub(t, C255_P, 0));
|
||||
br_i15_sub(t, C255_P, ctl);
|
||||
memcpy(d, t, sizeof t);
|
||||
}
|
||||
|
||||
static void
|
||||
c255_sub(uint16_t *d, const uint16_t *a, const uint16_t *b)
|
||||
{
|
||||
uint16_t t[18];
|
||||
|
||||
memcpy_P(t, a, sizeof t);
|
||||
br_i15_add(t, C255_P, br_i15_sub(t, b, 1));
|
||||
memcpy(d, t, sizeof t);
|
||||
}
|
||||
|
||||
static void
|
||||
c255_mul(uint16_t *d, const uint16_t *a, const uint16_t *b)
|
||||
{
|
||||
uint16_t t[18];
|
||||
|
||||
br_i15_montymul(t, a, b, C255_P, P0I);
|
||||
memcpy(d, t, sizeof t);
|
||||
}
|
||||
|
||||
static void
|
||||
byteswap(unsigned char *G)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < 16; i ++) {
|
||||
unsigned char t;
|
||||
|
||||
t = G[i];
|
||||
G[i] = G[31 - i];
|
||||
G[31 - i] = t;
|
||||
}
|
||||
}
|
||||
|
||||
static uint32_t
|
||||
api_mul(unsigned char *G, size_t Glen,
|
||||
const unsigned char *kb, size_t kblen, int curve)
|
||||
{
|
||||
#define ILEN (18 * sizeof(uint16_t))
|
||||
|
||||
/*
|
||||
* The a[] and b[] arrays have an extra word to allow for
|
||||
* decoding without using br_i15_decode_reduce().
|
||||
*/
|
||||
uint16_t x1[18], x2[18], x3[18], z2[18], z3[18];
|
||||
uint16_t a[19], aa[18], b[19], bb[18];
|
||||
uint16_t c[18], d[18], e[18], da[18], cb[18];
|
||||
unsigned char k[32];
|
||||
uint32_t swap;
|
||||
int i;
|
||||
|
||||
(void)curve;
|
||||
|
||||
/*
|
||||
* Points are encoded over exactly 32 bytes. Multipliers must fit
|
||||
* in 32 bytes as well.
|
||||
* RFC 7748 mandates that the high bit of the last point byte must
|
||||
* be ignored/cleared.
|
||||
*/
|
||||
if (Glen != 32 || kblen > 32) {
|
||||
return 0;
|
||||
}
|
||||
G[31] &= 0x7F;
|
||||
|
||||
/*
|
||||
* Byteswap the point encoding, because it uses little-endian, and
|
||||
* the generic decoding routine uses big-endian.
|
||||
*/
|
||||
byteswap(G);
|
||||
|
||||
/*
|
||||
* Decode the point ('u' coordinate). This should be reduced
|
||||
* modulo p, but we prefer to avoid the dependency on
|
||||
* br_i15_decode_reduce(). Instead, we use br_i15_decode_mod()
|
||||
* with a synthetic modulus of value 2^255 (this must work
|
||||
* since G was truncated to 255 bits), then use a conditional
|
||||
* subtraction. We use br_i15_decode_mod() and not
|
||||
* br_i15_decode(), because the ec_prime_i15 implementation uses
|
||||
* the former but not the latter.
|
||||
* br_i15_decode_reduce(a, G, 32, C255_P);
|
||||
*/
|
||||
br_i15_zero(b, 0x111);
|
||||
b[18] = 1;
|
||||
br_i15_decode_mod(a, G, 32, b);
|
||||
a[0] = 0x110;
|
||||
br_i15_sub(a, C255_P, NOT(br_i15_sub(a, C255_P, 0)));
|
||||
|
||||
/*
|
||||
* Initialise variables x1, x2, z2, x3 and z3. We set all of them
|
||||
* into Montgomery representation.
|
||||
*/
|
||||
br_i15_montymul(x1, a, C255_R2, C255_P, P0I);
|
||||
memcpy(x3, x1, ILEN);
|
||||
br_i15_zero(z2, C255_P[0]);
|
||||
memcpy(x2, z2, ILEN);
|
||||
x2[1] = 19;
|
||||
memcpy(z3, x2, ILEN);
|
||||
|
||||
memset(k, 0, (sizeof k) - kblen);
|
||||
memcpy_P(k + (sizeof k) - kblen, kb, kblen);
|
||||
k[31] &= 0xF8;
|
||||
k[0] &= 0x7F;
|
||||
k[0] |= 0x40;
|
||||
|
||||
/* obsolete
|
||||
print_int_mont("x1", x1);
|
||||
*/
|
||||
|
||||
swap = 0;
|
||||
for (i = 254; i >= 0; i --) {
|
||||
uint32_t kt;
|
||||
|
||||
kt = (k[31 - (i >> 3)] >> (i & 7)) & 1;
|
||||
swap ^= kt;
|
||||
cswap(x2, x3, swap);
|
||||
cswap(z2, z3, swap);
|
||||
swap = kt;
|
||||
|
||||
/* obsolete
|
||||
print_int_mont("x2", x2);
|
||||
print_int_mont("z2", z2);
|
||||
print_int_mont("x3", x3);
|
||||
print_int_mont("z3", z3);
|
||||
*/
|
||||
|
||||
c255_add(a, x2, z2);
|
||||
c255_mul(aa, a, a);
|
||||
c255_sub(b, x2, z2);
|
||||
c255_mul(bb, b, b);
|
||||
c255_sub(e, aa, bb);
|
||||
c255_add(c, x3, z3);
|
||||
c255_sub(d, x3, z3);
|
||||
c255_mul(da, d, a);
|
||||
c255_mul(cb, c, b);
|
||||
|
||||
/* obsolete
|
||||
print_int_mont("a ", a);
|
||||
print_int_mont("aa", aa);
|
||||
print_int_mont("b ", b);
|
||||
print_int_mont("bb", bb);
|
||||
print_int_mont("e ", e);
|
||||
print_int_mont("c ", c);
|
||||
print_int_mont("d ", d);
|
||||
print_int_mont("da", da);
|
||||
print_int_mont("cb", cb);
|
||||
*/
|
||||
|
||||
c255_add(x3, da, cb);
|
||||
c255_mul(x3, x3, x3);
|
||||
c255_sub(z3, da, cb);
|
||||
c255_mul(z3, z3, z3);
|
||||
c255_mul(z3, z3, x1);
|
||||
c255_mul(x2, aa, bb);
|
||||
c255_mul(z2, C255_A24, e);
|
||||
c255_add(z2, z2, aa);
|
||||
c255_mul(z2, e, z2);
|
||||
|
||||
/* obsolete
|
||||
print_int_mont("x2", x2);
|
||||
print_int_mont("z2", z2);
|
||||
print_int_mont("x3", x3);
|
||||
print_int_mont("z3", z3);
|
||||
*/
|
||||
}
|
||||
cswap(x2, x3, swap);
|
||||
cswap(z2, z3, swap);
|
||||
|
||||
/*
|
||||
* Inverse z2 with a modular exponentiation. This is a simple
|
||||
* square-and-multiply algorithm; we mutualise most non-squarings
|
||||
* since the exponent contains almost only ones.
|
||||
*/
|
||||
memcpy(a, z2, ILEN);
|
||||
for (i = 0; i < 15; i ++) {
|
||||
c255_mul(a, a, a);
|
||||
c255_mul(a, a, z2);
|
||||
}
|
||||
memcpy(b, a, ILEN);
|
||||
for (i = 0; i < 14; i ++) {
|
||||
int j;
|
||||
|
||||
for (j = 0; j < 16; j ++) {
|
||||
c255_mul(b, b, b);
|
||||
}
|
||||
c255_mul(b, b, a);
|
||||
}
|
||||
for (i = 14; i >= 0; i --) {
|
||||
c255_mul(b, b, b);
|
||||
if ((0xFFEB >> i) & 1) {
|
||||
c255_mul(b, z2, b);
|
||||
}
|
||||
}
|
||||
c255_mul(b, x2, b);
|
||||
|
||||
/*
|
||||
* To avoid a dependency on br_i15_from_monty(), we use a
|
||||
* Montgomery multiplication with 1.
|
||||
* memcpy(x2, b, ILEN);
|
||||
* br_i15_from_monty(x2, C255_P, P0I);
|
||||
*/
|
||||
br_i15_zero(a, C255_P[0]);
|
||||
a[1] = 1;
|
||||
br_i15_montymul(x2, a, b, C255_P, P0I);
|
||||
|
||||
br_i15_encode(G, 32, x2);
|
||||
byteswap(G);
|
||||
return 1;
|
||||
|
||||
#undef ILEN
|
||||
}
|
||||
|
||||
static size_t
|
||||
api_mulgen(unsigned char *R,
|
||||
const unsigned char *x, size_t xlen, int curve)
|
||||
{
|
||||
const unsigned char *G;
|
||||
size_t Glen;
|
||||
|
||||
G = api_generator(curve, &Glen);
|
||||
memcpy(R, G, Glen);
|
||||
api_mul(R, Glen, x, xlen, curve);
|
||||
return Glen;
|
||||
}
|
||||
|
||||
static uint32_t
|
||||
api_muladd(unsigned char *A, const unsigned char *B, size_t len,
|
||||
const unsigned char *x, size_t xlen,
|
||||
const unsigned char *y, size_t ylen, int curve)
|
||||
{
|
||||
/*
|
||||
* We don't implement this method, since it is used for ECDSA
|
||||
* only, and there is no ECDSA over Curve25519 (which instead
|
||||
* uses EdDSA).
|
||||
*/
|
||||
(void)A;
|
||||
(void)B;
|
||||
(void)len;
|
||||
(void)x;
|
||||
(void)xlen;
|
||||
(void)y;
|
||||
(void)ylen;
|
||||
(void)curve;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* see bearssl_ec.h */
|
||||
const br_ec_impl br_ec_c25519_i15 PROGMEM = {
|
||||
(uint32_t)0x20000000,
|
||||
&api_generator,
|
||||
&api_order,
|
||||
&api_xoff,
|
||||
&api_mul,
|
||||
&api_mulgen,
|
||||
&api_muladd
|
||||
};
|
|
@ -0,0 +1,46 @@
|
|||
/*
|
||||
* 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 "t_inner.h"
|
||||
|
||||
static const unsigned char GEN[] PROGMEM = {
|
||||
0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
|
||||
};
|
||||
|
||||
static const unsigned char ORDER[] PROGMEM = {
|
||||
0x7F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
||||
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
||||
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
||||
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF
|
||||
};
|
||||
|
||||
/* see inner.h */
|
||||
const br_ec_curve_def br_curve25519 = {
|
||||
BR_EC_curve25519,
|
||||
ORDER, sizeof ORDER,
|
||||
GEN, sizeof GEN
|
||||
};
|
|
@ -0,0 +1,36 @@
|
|||
/*
|
||||
* 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 "t_inner.h"
|
||||
|
||||
/* see bearssl_ec.h */
|
||||
const br_ec_impl *
|
||||
br_ec_get_default(void)
|
||||
{
|
||||
#if BR_LOMUL
|
||||
return &br_ec_all_m15;
|
||||
#else
|
||||
return &br_ec_all_m31;
|
||||
#endif
|
||||
}
|
|
@ -0,0 +1,86 @@
|
|||
/*
|
||||
* Copyright (c) 2018 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 "t_inner.h"
|
||||
|
||||
/* see bearssl_ec.h */
|
||||
size_t
|
||||
br_ec_keygen(const br_prng_class **rng_ctx,
|
||||
const br_ec_impl *impl, br_ec_private_key *sk,
|
||||
void *kbuf, int curve)
|
||||
{
|
||||
const unsigned char *order;
|
||||
unsigned char *buf;
|
||||
size_t len;
|
||||
unsigned mask;
|
||||
|
||||
if (curve < 0 || curve >= 32
|
||||
|| ((impl->supported_curves >> curve) & 1) == 0)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
order = impl->order(curve, &len);
|
||||
while (len > 0 && *order == 0) {
|
||||
order ++;
|
||||
len --;
|
||||
}
|
||||
if (kbuf == NULL || len == 0) {
|
||||
return len;
|
||||
}
|
||||
mask = order[0];
|
||||
mask |= (mask >> 1);
|
||||
mask |= (mask >> 2);
|
||||
mask |= (mask >> 4);
|
||||
|
||||
/*
|
||||
* We generate sequences of random bits of the right size, until
|
||||
* the value is strictly lower than the curve order (we also
|
||||
* check for all-zero values, which are invalid).
|
||||
*/
|
||||
buf = kbuf;
|
||||
for (;;) {
|
||||
size_t u;
|
||||
unsigned cc, zz;
|
||||
|
||||
(*rng_ctx)->generate(rng_ctx, buf, len);
|
||||
buf[0] &= mask;
|
||||
cc = 0;
|
||||
u = len;
|
||||
zz = 0;
|
||||
while (u -- > 0) {
|
||||
cc = ((unsigned)(buf[u] - order[u] - cc) >> 8) & 1;
|
||||
zz |= buf[u];
|
||||
}
|
||||
if (cc != 0 && zz != 0) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (sk != NULL) {
|
||||
sk->curve = curve;
|
||||
sk->x = buf;
|
||||
sk->xlen = len;
|
||||
}
|
||||
return len;
|
||||
}
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,822 @@
|
|||
/*
|
||||
* 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 "t_inner.h"
|
||||
|
||||
/*
|
||||
* Parameters for supported curves:
|
||||
* - field modulus p
|
||||
* - R^2 mod p (R = 2^(15k) for the smallest k such that R >= p)
|
||||
* - b*R mod p (b is the second curve equation parameter)
|
||||
*/
|
||||
|
||||
static const uint16_t P256_P[] PROGMEM = {
|
||||
0x0111,
|
||||
0x7FFF, 0x7FFF, 0x7FFF, 0x7FFF, 0x7FFF, 0x7FFF, 0x003F, 0x0000,
|
||||
0x0000, 0x0000, 0x0000, 0x0000, 0x1000, 0x0000, 0x4000, 0x7FFF,
|
||||
0x7FFF, 0x0001
|
||||
};
|
||||
|
||||
static const uint16_t P256_R2[] PROGMEM = {
|
||||
0x0111,
|
||||
0x0000, 0x6000, 0x0000, 0x0000, 0x0000, 0x0000, 0x7FFC, 0x7FFF,
|
||||
0x7FBF, 0x7FFF, 0x7FBF, 0x7FFF, 0x7FFF, 0x7FFF, 0x77FF, 0x7FFF,
|
||||
0x4FFF, 0x0000
|
||||
};
|
||||
|
||||
static const uint16_t P256_B[] PROGMEM = {
|
||||
0x0111,
|
||||
0x770C, 0x5EEF, 0x29C4, 0x3EC4, 0x6273, 0x0486, 0x4543, 0x3993,
|
||||
0x3C01, 0x6B56, 0x212E, 0x57EE, 0x4882, 0x204B, 0x7483, 0x3C16,
|
||||
0x0187, 0x0000
|
||||
};
|
||||
|
||||
static const uint16_t P384_P[] PROGMEM = {
|
||||
0x0199,
|
||||
0x7FFF, 0x7FFF, 0x0003, 0x0000, 0x0000, 0x0000, 0x7FC0, 0x7FFF,
|
||||
0x7EFF, 0x7FFF, 0x7FFF, 0x7FFF, 0x7FFF, 0x7FFF, 0x7FFF, 0x7FFF,
|
||||
0x7FFF, 0x7FFF, 0x7FFF, 0x7FFF, 0x7FFF, 0x7FFF, 0x7FFF, 0x7FFF,
|
||||
0x7FFF, 0x01FF
|
||||
};
|
||||
|
||||
static const uint16_t P384_R2[] PROGMEM = {
|
||||
0x0199,
|
||||
0x1000, 0x0000, 0x0000, 0x7FFF, 0x7FFF, 0x0001, 0x0000, 0x0010,
|
||||
0x0000, 0x0000, 0x0000, 0x7F00, 0x7FFF, 0x01FF, 0x0000, 0x1000,
|
||||
0x0000, 0x2000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
|
||||
0x0000, 0x0000
|
||||
};
|
||||
|
||||
static const uint16_t P384_B[] PROGMEM = {
|
||||
0x0199,
|
||||
0x7333, 0x2096, 0x70D1, 0x2310, 0x3020, 0x6197, 0x1464, 0x35BB,
|
||||
0x70CA, 0x0117, 0x1920, 0x4136, 0x5FC8, 0x5713, 0x4938, 0x7DD2,
|
||||
0x4DD2, 0x4A71, 0x0220, 0x683E, 0x2C87, 0x4DB1, 0x7BFF, 0x6C09,
|
||||
0x0452, 0x0084
|
||||
};
|
||||
|
||||
static const uint16_t P521_P[] PROGMEM = {
|
||||
0x022B,
|
||||
0x7FFF, 0x7FFF, 0x7FFF, 0x7FFF, 0x7FFF, 0x7FFF, 0x7FFF, 0x7FFF,
|
||||
0x7FFF, 0x7FFF, 0x7FFF, 0x7FFF, 0x7FFF, 0x7FFF, 0x7FFF, 0x7FFF,
|
||||
0x7FFF, 0x7FFF, 0x7FFF, 0x7FFF, 0x7FFF, 0x7FFF, 0x7FFF, 0x7FFF,
|
||||
0x7FFF, 0x7FFF, 0x7FFF, 0x7FFF, 0x7FFF, 0x7FFF, 0x7FFF, 0x7FFF,
|
||||
0x7FFF, 0x7FFF, 0x07FF
|
||||
};
|
||||
|
||||
static const uint16_t P521_R2[] PROGMEM = {
|
||||
0x022B,
|
||||
0x0100, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
|
||||
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
|
||||
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
|
||||
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
|
||||
0x0000, 0x0000, 0x0000
|
||||
};
|
||||
|
||||
static const uint16_t P521_B[] PROGMEM = {
|
||||
0x022B,
|
||||
0x7002, 0x6A07, 0x751A, 0x228F, 0x71EF, 0x5869, 0x20F4, 0x1EFC,
|
||||
0x7357, 0x37E0, 0x4EEC, 0x605E, 0x1652, 0x26F6, 0x31FA, 0x4A8F,
|
||||
0x6193, 0x3C2A, 0x3C42, 0x48C7, 0x3489, 0x6771, 0x4C57, 0x5CCD,
|
||||
0x2725, 0x545B, 0x503B, 0x5B42, 0x21A0, 0x2534, 0x687E, 0x70E4,
|
||||
0x1618, 0x27D7, 0x0465
|
||||
};
|
||||
|
||||
typedef struct {
|
||||
const uint16_t *p;
|
||||
const uint16_t *b;
|
||||
const uint16_t *R2;
|
||||
uint16_t p0i;
|
||||
size_t point_len;
|
||||
} curve_params;
|
||||
|
||||
static inline const curve_params *
|
||||
id_to_curve(int curve)
|
||||
{
|
||||
static const curve_params pp[] = {
|
||||
{ P256_P, P256_B, P256_R2, 0x0001, 65 },
|
||||
{ P384_P, P384_B, P384_R2, 0x0001, 97 },
|
||||
{ P521_P, P521_B, P521_R2, 0x0001, 133 }
|
||||
};
|
||||
|
||||
return &pp[curve - BR_EC_secp256r1];
|
||||
}
|
||||
|
||||
#define I15_LEN ((BR_MAX_EC_SIZE + 29) / 15)
|
||||
|
||||
/*
|
||||
* Type for a point in Jacobian coordinates:
|
||||
* -- three values, x, y and z, in Montgomery representation
|
||||
* -- affine coordinates are X = x / z^2 and Y = y / z^3
|
||||
* -- for the point at infinity, z = 0
|
||||
*/
|
||||
typedef struct {
|
||||
uint16_t c[3][I15_LEN];
|
||||
} jacobian;
|
||||
|
||||
/*
|
||||
* We use a custom interpreter that uses a dozen registers, and
|
||||
* only six operations:
|
||||
* MSET(d, a) copy a into d
|
||||
* MADD(d, a) d = d+a (modular)
|
||||
* MSUB(d, a) d = d-a (modular)
|
||||
* MMUL(d, a, b) d = a*b (Montgomery multiplication)
|
||||
* MINV(d, a, b) invert d modulo p; a and b are used as scratch registers
|
||||
* MTZ(d) clear return value if d = 0
|
||||
* Destination of MMUL (d) must be distinct from operands (a and b).
|
||||
* There is no such constraint for MSUB and MADD.
|
||||
*
|
||||
* Registers include the operand coordinates, and temporaries.
|
||||
*/
|
||||
#define MSET(d, a) (0x0000 + ((d) << 8) + ((a) << 4))
|
||||
#define MADD(d, a) (0x1000 + ((d) << 8) + ((a) << 4))
|
||||
#define MSUB(d, a) (0x2000 + ((d) << 8) + ((a) << 4))
|
||||
#define MMUL(d, a, b) (0x3000 + ((d) << 8) + ((a) << 4) + (b))
|
||||
#define MINV(d, a, b) (0x4000 + ((d) << 8) + ((a) << 4) + (b))
|
||||
#define MTZ(d) (0x5000 + ((d) << 8))
|
||||
#define ENDCODE 0
|
||||
|
||||
/*
|
||||
* Registers for the input operands.
|
||||
*/
|
||||
#define P1x 0
|
||||
#define P1y 1
|
||||
#define P1z 2
|
||||
#define P2x 3
|
||||
#define P2y 4
|
||||
#define P2z 5
|
||||
|
||||
/*
|
||||
* Alternate names for the first input operand.
|
||||
*/
|
||||
#define Px 0
|
||||
#define Py 1
|
||||
#define Pz 2
|
||||
|
||||
/*
|
||||
* Temporaries.
|
||||
*/
|
||||
#define t1 6
|
||||
#define t2 7
|
||||
#define t3 8
|
||||
#define t4 9
|
||||
#define t5 10
|
||||
#define t6 11
|
||||
#define t7 12
|
||||
|
||||
/*
|
||||
* Extra scratch registers available when there is no second operand (e.g.
|
||||
* for "double" and "affine").
|
||||
*/
|
||||
#define t8 3
|
||||
#define t9 4
|
||||
#define t10 5
|
||||
|
||||
/*
|
||||
* Doubling formulas are:
|
||||
*
|
||||
* s = 4*x*y^2
|
||||
* m = 3*(x + z^2)*(x - z^2)
|
||||
* x' = m^2 - 2*s
|
||||
* y' = m*(s - x') - 8*y^4
|
||||
* z' = 2*y*z
|
||||
*
|
||||
* If y = 0 (P has order 2) then this yields infinity (z' = 0), as it
|
||||
* should. This case should not happen anyway, because our curves have
|
||||
* prime order, and thus do not contain any point of order 2.
|
||||
*
|
||||
* If P is infinity (z = 0), then again the formulas yield infinity,
|
||||
* which is correct. Thus, this code works for all points.
|
||||
*
|
||||
* Cost: 8 multiplications
|
||||
*/
|
||||
static const uint16_t code_double[] PROGMEM = {
|
||||
/*
|
||||
* Compute z^2 (in t1).
|
||||
*/
|
||||
MMUL(t1, Pz, Pz),
|
||||
|
||||
/*
|
||||
* Compute x-z^2 (in t2) and then x+z^2 (in t1).
|
||||
*/
|
||||
MSET(t2, Px),
|
||||
MSUB(t2, t1),
|
||||
MADD(t1, Px),
|
||||
|
||||
/*
|
||||
* Compute m = 3*(x+z^2)*(x-z^2) (in t1).
|
||||
*/
|
||||
MMUL(t3, t1, t2),
|
||||
MSET(t1, t3),
|
||||
MADD(t1, t3),
|
||||
MADD(t1, t3),
|
||||
|
||||
/*
|
||||
* Compute s = 4*x*y^2 (in t2) and 2*y^2 (in t3).
|
||||
*/
|
||||
MMUL(t3, Py, Py),
|
||||
MADD(t3, t3),
|
||||
MMUL(t2, Px, t3),
|
||||
MADD(t2, t2),
|
||||
|
||||
/*
|
||||
* Compute x' = m^2 - 2*s.
|
||||
*/
|
||||
MMUL(Px, t1, t1),
|
||||
MSUB(Px, t2),
|
||||
MSUB(Px, t2),
|
||||
|
||||
/*
|
||||
* Compute z' = 2*y*z.
|
||||
*/
|
||||
MMUL(t4, Py, Pz),
|
||||
MSET(Pz, t4),
|
||||
MADD(Pz, t4),
|
||||
|
||||
/*
|
||||
* Compute y' = m*(s - x') - 8*y^4. Note that we already have
|
||||
* 2*y^2 in t3.
|
||||
*/
|
||||
MSUB(t2, Px),
|
||||
MMUL(Py, t1, t2),
|
||||
MMUL(t4, t3, t3),
|
||||
MSUB(Py, t4),
|
||||
MSUB(Py, t4),
|
||||
|
||||
ENDCODE
|
||||
};
|
||||
|
||||
/*
|
||||
* Addtions formulas are:
|
||||
*
|
||||
* u1 = x1 * z2^2
|
||||
* u2 = x2 * z1^2
|
||||
* s1 = y1 * z2^3
|
||||
* s2 = y2 * z1^3
|
||||
* h = u2 - u1
|
||||
* r = s2 - s1
|
||||
* x3 = r^2 - h^3 - 2 * u1 * h^2
|
||||
* y3 = r * (u1 * h^2 - x3) - s1 * h^3
|
||||
* z3 = h * z1 * z2
|
||||
*
|
||||
* If both P1 and P2 are infinity, then z1 == 0 and z2 == 0, implying that
|
||||
* z3 == 0, so the result is correct.
|
||||
* If either of P1 or P2 is infinity, but not both, then z3 == 0, which is
|
||||
* not correct.
|
||||
* h == 0 only if u1 == u2; this happens in two cases:
|
||||
* -- if s1 == s2 then P1 and/or P2 is infinity, or P1 == P2
|
||||
* -- if s1 != s2 then P1 + P2 == infinity (but neither P1 or P2 is infinity)
|
||||
*
|
||||
* Thus, the following situations are not handled correctly:
|
||||
* -- P1 = 0 and P2 != 0
|
||||
* -- P1 != 0 and P2 = 0
|
||||
* -- P1 = P2
|
||||
* All other cases are properly computed. However, even in "incorrect"
|
||||
* situations, the three coordinates still are properly formed field
|
||||
* elements.
|
||||
*
|
||||
* The returned flag is cleared if r == 0. This happens in the following
|
||||
* cases:
|
||||
* -- Both points are on the same horizontal line (same Y coordinate).
|
||||
* -- Both points are infinity.
|
||||
* -- One point is infinity and the other is on line Y = 0.
|
||||
* The third case cannot happen with our curves (there is no valid point
|
||||
* on line Y = 0 since that would be a point of order 2). If the two
|
||||
* source points are non-infinity, then remains only the case where the
|
||||
* two points are on the same horizontal line.
|
||||
*
|
||||
* This allows us to detect the "P1 == P2" case, assuming that P1 != 0 and
|
||||
* P2 != 0:
|
||||
* -- If the returned value is not the point at infinity, then it was properly
|
||||
* computed.
|
||||
* -- Otherwise, if the returned flag is 1, then P1+P2 = 0, and the result
|
||||
* is indeed the point at infinity.
|
||||
* -- Otherwise (result is infinity, flag is 0), then P1 = P2 and we should
|
||||
* use the 'double' code.
|
||||
*
|
||||
* Cost: 16 multiplications
|
||||
*/
|
||||
static const uint16_t code_add[] PROGMEM = {
|
||||
/*
|
||||
* Compute u1 = x1*z2^2 (in t1) and s1 = y1*z2^3 (in t3).
|
||||
*/
|
||||
MMUL(t3, P2z, P2z),
|
||||
MMUL(t1, P1x, t3),
|
||||
MMUL(t4, P2z, t3),
|
||||
MMUL(t3, P1y, t4),
|
||||
|
||||
/*
|
||||
* Compute u2 = x2*z1^2 (in t2) and s2 = y2*z1^3 (in t4).
|
||||
*/
|
||||
MMUL(t4, P1z, P1z),
|
||||
MMUL(t2, P2x, t4),
|
||||
MMUL(t5, P1z, t4),
|
||||
MMUL(t4, P2y, t5),
|
||||
|
||||
/*
|
||||
* Compute h = u2 - u1 (in t2) and r = s2 - s1 (in t4).
|
||||
*/
|
||||
MSUB(t2, t1),
|
||||
MSUB(t4, t3),
|
||||
|
||||
/*
|
||||
* Report cases where r = 0 through the returned flag.
|
||||
*/
|
||||
MTZ(t4),
|
||||
|
||||
/*
|
||||
* Compute u1*h^2 (in t6) and h^3 (in t5).
|
||||
*/
|
||||
MMUL(t7, t2, t2),
|
||||
MMUL(t6, t1, t7),
|
||||
MMUL(t5, t7, t2),
|
||||
|
||||
/*
|
||||
* Compute x3 = r^2 - h^3 - 2*u1*h^2.
|
||||
* t1 and t7 can be used as scratch registers.
|
||||
*/
|
||||
MMUL(P1x, t4, t4),
|
||||
MSUB(P1x, t5),
|
||||
MSUB(P1x, t6),
|
||||
MSUB(P1x, t6),
|
||||
|
||||
/*
|
||||
* Compute y3 = r*(u1*h^2 - x3) - s1*h^3.
|
||||
*/
|
||||
MSUB(t6, P1x),
|
||||
MMUL(P1y, t4, t6),
|
||||
MMUL(t1, t5, t3),
|
||||
MSUB(P1y, t1),
|
||||
|
||||
/*
|
||||
* Compute z3 = h*z1*z2.
|
||||
*/
|
||||
MMUL(t1, P1z, P2z),
|
||||
MMUL(P1z, t1, t2),
|
||||
|
||||
ENDCODE
|
||||
};
|
||||
|
||||
/*
|
||||
* Check that the point is on the curve. This code snippet assumes the
|
||||
* following conventions:
|
||||
* -- Coordinates x and y have been freshly decoded in P1 (but not
|
||||
* converted to Montgomery coordinates yet).
|
||||
* -- P2x, P2y and P2z are set to, respectively, R^2, b*R and 1.
|
||||
*/
|
||||
static const uint16_t code_check[] PROGMEM = {
|
||||
|
||||
/* Convert x and y to Montgomery representation. */
|
||||
MMUL(t1, P1x, P2x),
|
||||
MMUL(t2, P1y, P2x),
|
||||
MSET(P1x, t1),
|
||||
MSET(P1y, t2),
|
||||
|
||||
/* Compute x^3 in t1. */
|
||||
MMUL(t2, P1x, P1x),
|
||||
MMUL(t1, P1x, t2),
|
||||
|
||||
/* Subtract 3*x from t1. */
|
||||
MSUB(t1, P1x),
|
||||
MSUB(t1, P1x),
|
||||
MSUB(t1, P1x),
|
||||
|
||||
/* Add b. */
|
||||
MADD(t1, P2y),
|
||||
|
||||
/* Compute y^2 in t2. */
|
||||
MMUL(t2, P1y, P1y),
|
||||
|
||||
/* Compare y^2 with x^3 - 3*x + b; they must match. */
|
||||
MSUB(t1, t2),
|
||||
MTZ(t1),
|
||||
|
||||
/* Set z to 1 (in Montgomery representation). */
|
||||
MMUL(P1z, P2x, P2z),
|
||||
|
||||
ENDCODE
|
||||
};
|
||||
|
||||
/*
|
||||
* Conversion back to affine coordinates. This code snippet assumes that
|
||||
* the z coordinate of P2 is set to 1 (not in Montgomery representation).
|
||||
*/
|
||||
static const uint16_t code_affine[] PROGMEM = {
|
||||
|
||||
/* Save z*R in t1. */
|
||||
MSET(t1, P1z),
|
||||
|
||||
/* Compute z^3 in t2. */
|
||||
MMUL(t2, P1z, P1z),
|
||||
MMUL(t3, P1z, t2),
|
||||
MMUL(t2, t3, P2z),
|
||||
|
||||
/* Invert to (1/z^3) in t2. */
|
||||
MINV(t2, t3, t4),
|
||||
|
||||
/* Compute y. */
|
||||
MSET(t3, P1y),
|
||||
MMUL(P1y, t2, t3),
|
||||
|
||||
/* Compute (1/z^2) in t3. */
|
||||
MMUL(t3, t2, t1),
|
||||
|
||||
/* Compute x. */
|
||||
MSET(t2, P1x),
|
||||
MMUL(P1x, t2, t3),
|
||||
|
||||
ENDCODE
|
||||
};
|
||||
|
||||
static uint32_t
|
||||
run_code(jacobian *P1, const jacobian *P2,
|
||||
const curve_params *cc, const uint16_t *code)
|
||||
{
|
||||
uint32_t r;
|
||||
uint16_t t[13][I15_LEN];
|
||||
size_t u;
|
||||
|
||||
r = 1;
|
||||
|
||||
/*
|
||||
* Copy the two operands in the dedicated registers.
|
||||
*/
|
||||
memcpy(t[P1x], P1->c, 3 * I15_LEN * sizeof(uint16_t));
|
||||
memcpy(t[P2x], P2->c, 3 * I15_LEN * sizeof(uint16_t));
|
||||
|
||||
optimistic_yield(10000);
|
||||
|
||||
/*
|
||||
* Run formulas.
|
||||
*/
|
||||
for (u = 0;; u ++) {
|
||||
unsigned op, d, a, b;
|
||||
|
||||
op = pgm_read_word(&code[u]);
|
||||
if (op == 0) {
|
||||
break;
|
||||
}
|
||||
d = (op >> 8) & 0x0F;
|
||||
a = (op >> 4) & 0x0F;
|
||||
b = op & 0x0F;
|
||||
op >>= 12;
|
||||
switch (op) {
|
||||
uint32_t ctl;
|
||||
size_t plen;
|
||||
unsigned char tp[(BR_MAX_EC_SIZE + 7) >> 3];
|
||||
|
||||
case 0:
|
||||
memcpy(t[d], t[a], I15_LEN * sizeof(uint16_t));
|
||||
break;
|
||||
case 1:
|
||||
ctl = br_i15_add(t[d], t[a], 1);
|
||||
ctl |= NOT(br_i15_sub(t[d], cc->p, 0));
|
||||
br_i15_sub(t[d], cc->p, ctl);
|
||||
break;
|
||||
case 2:
|
||||
br_i15_add(t[d], cc->p, br_i15_sub(t[d], t[a], 1));
|
||||
break;
|
||||
case 3:
|
||||
br_i15_montymul(t[d], t[a], t[b], cc->p, cc->p0i);
|
||||
break;
|
||||
case 4:
|
||||
plen = (pgm_read_word(&cc->p[0]) - (pgm_read_word(&cc->p[0]) >> 4) + 7) >> 3;
|
||||
br_i15_encode(tp, plen, cc->p);
|
||||
tp[plen - 1] -= 2;
|
||||
br_i15_modpow(t[d], tp, plen,
|
||||
cc->p, cc->p0i, t[a], t[b]);
|
||||
break;
|
||||
default:
|
||||
r &= ~br_i15_iszero(t[d]);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Copy back result.
|
||||
*/
|
||||
memcpy(P1->c, t[P1x], 3 * I15_LEN * sizeof(uint16_t));
|
||||
return r;
|
||||
}
|
||||
|
||||
static void
|
||||
set_one(uint16_t *x, const uint16_t *p)
|
||||
{
|
||||
size_t plen;
|
||||
|
||||
plen = (pgm_read_word(&p[0]) + 31) >> 4;
|
||||
memset(x, 0, plen * sizeof *x);
|
||||
x[0] = pgm_read_word(&p[0]);
|
||||
x[1] = 0x0001;
|
||||
}
|
||||
|
||||
static void
|
||||
point_zero(jacobian *P, const curve_params *cc)
|
||||
{
|
||||
memset(P, 0, sizeof *P);
|
||||
P->c[0][0] = P->c[1][0] = P->c[2][0] = pgm_read_word(&cc->p[0]);
|
||||
}
|
||||
|
||||
static inline void
|
||||
point_double(jacobian *P, const curve_params *cc)
|
||||
{
|
||||
run_code(P, P, cc, code_double);
|
||||
}
|
||||
|
||||
static inline uint32_t
|
||||
point_add(jacobian *P1, const jacobian *P2, const curve_params *cc)
|
||||
{
|
||||
return run_code(P1, P2, cc, code_add);
|
||||
}
|
||||
|
||||
static void
|
||||
point_mul(jacobian *P, const unsigned char *x, size_t xlen,
|
||||
const curve_params *cc)
|
||||
{
|
||||
/*
|
||||
* We do a simple double-and-add ladder with a 2-bit window
|
||||
* to make only one add every two doublings. We thus first
|
||||
* precompute 2P and 3P in some local buffers.
|
||||
*
|
||||
* We always perform two doublings and one addition; the
|
||||
* addition is with P, 2P and 3P and is done in a temporary
|
||||
* array.
|
||||
*
|
||||
* The addition code cannot handle cases where one of the
|
||||
* operands is infinity, which is the case at the start of the
|
||||
* ladder. We therefore need to maintain a flag that controls
|
||||
* this situation.
|
||||
*/
|
||||
uint32_t qz;
|
||||
jacobian P2, P3, Q, T, U;
|
||||
|
||||
memcpy(&P2, P, sizeof P2);
|
||||
point_double(&P2, cc);
|
||||
memcpy(&P3, P, sizeof P3);
|
||||
point_add(&P3, &P2, cc);
|
||||
|
||||
point_zero(&Q, cc);
|
||||
qz = 1;
|
||||
while (xlen -- > 0) {
|
||||
int k;
|
||||
|
||||
for (k = 6; k >= 0; k -= 2) {
|
||||
uint32_t bits;
|
||||
uint32_t bnz;
|
||||
|
||||
point_double(&Q, cc);
|
||||
point_double(&Q, cc);
|
||||
memcpy(&T, P, sizeof T);
|
||||
memcpy(&U, &Q, sizeof U);
|
||||
bits = (pgm_read_byte(&*x) >> k) & (uint32_t)3;
|
||||
bnz = NEQ(bits, 0);
|
||||
CCOPY(EQ(bits, 2), &T, &P2, sizeof T);
|
||||
CCOPY(EQ(bits, 3), &T, &P3, sizeof T);
|
||||
point_add(&U, &T, cc);
|
||||
CCOPY(bnz & qz, &Q, &T, sizeof Q);
|
||||
CCOPY(bnz & ~qz, &Q, &U, sizeof Q);
|
||||
qz &= ~bnz;
|
||||
}
|
||||
x ++;
|
||||
}
|
||||
memcpy(P, &Q, sizeof Q);
|
||||
}
|
||||
|
||||
/*
|
||||
* Decode point into Jacobian coordinates. This function does not support
|
||||
* the point at infinity. If the point is invalid then this returns 0, but
|
||||
* the coordinates are still set to properly formed field elements.
|
||||
*/
|
||||
static uint32_t
|
||||
point_decode(jacobian *P, const void *src, size_t len, const curve_params *cc)
|
||||
{
|
||||
/*
|
||||
* Points must use uncompressed format:
|
||||
* -- first byte is 0x04;
|
||||
* -- coordinates X and Y use unsigned big-endian, with the same
|
||||
* length as the field modulus.
|
||||
*
|
||||
* We don't support hybrid format (uncompressed, but first byte
|
||||
* has value 0x06 or 0x07, depending on the least significant bit
|
||||
* of Y) because it is rather useless, and explicitly forbidden
|
||||
* by PKIX (RFC 5480, section 2.2).
|
||||
*
|
||||
* We don't support compressed format either, because it is not
|
||||
* much used in practice (there are or were patent-related
|
||||
* concerns about point compression, which explains the lack of
|
||||
* generalised support). Also, point compression support would
|
||||
* need a bit more code.
|
||||
*/
|
||||
const unsigned char *buf;
|
||||
size_t plen, zlen;
|
||||
uint32_t r;
|
||||
jacobian Q;
|
||||
|
||||
buf = src;
|
||||
point_zero(P, cc);
|
||||
plen = (pgm_read_word(&cc->p[0]) - (pgm_read_word(&cc->p[0]) >> 4) + 7) >> 3;
|
||||
if (len != 1 + (plen << 1)) {
|
||||
return 0;
|
||||
}
|
||||
r = br_i15_decode_mod(P->c[0], buf + 1, plen, cc->p);
|
||||
r &= br_i15_decode_mod(P->c[1], buf + 1 + plen, plen, cc->p);
|
||||
|
||||
/*
|
||||
* Check first byte.
|
||||
*/
|
||||
r &= EQ(pgm_read_byte(&buf[0]), 0x04);
|
||||
/* obsolete
|
||||
r &= EQ(buf[0], 0x04) | (EQ(buf[0] & 0xFE, 0x06)
|
||||
& ~(uint32_t)(buf[0] ^ buf[plen << 1]));
|
||||
*/
|
||||
|
||||
/*
|
||||
* Convert coordinates and check that the point is valid.
|
||||
*/
|
||||
zlen = ((pgm_read_word(&cc->p[0]) + 31) >> 4) * sizeof(uint16_t);
|
||||
memcpy_P(Q.c[0], cc->R2, zlen);
|
||||
memcpy_P(Q.c[1], cc->b, zlen);
|
||||
set_one(Q.c[2], cc->p);
|
||||
r &= ~run_code(P, &Q, cc, code_check);
|
||||
return r;
|
||||
}
|
||||
|
||||
/*
|
||||
* Encode a point. This method assumes that the point is correct and is
|
||||
* not the point at infinity. Encoded size is always 1+2*plen, where
|
||||
* plen is the field modulus length, in bytes.
|
||||
*/
|
||||
static void
|
||||
point_encode(void *dst, const jacobian *P, const curve_params *cc)
|
||||
{
|
||||
unsigned char *buf;
|
||||
size_t plen;
|
||||
jacobian Q, T;
|
||||
|
||||
buf = dst;
|
||||
plen = (pgm_read_word(&cc->p[0]) - (pgm_read_word(&cc->p[0]) >> 4) + 7) >> 3;
|
||||
buf[0] = 0x04;
|
||||
memcpy(&Q, P, sizeof *P);
|
||||
set_one(T.c[2], cc->p);
|
||||
run_code(&Q, &T, cc, code_affine);
|
||||
br_i15_encode(buf + 1, plen, Q.c[0]);
|
||||
br_i15_encode(buf + 1 + plen, plen, Q.c[1]);
|
||||
}
|
||||
|
||||
static const br_ec_curve_def *
|
||||
id_to_curve_def(int curve)
|
||||
{
|
||||
switch (curve) {
|
||||
case BR_EC_secp256r1:
|
||||
return &br_secp256r1;
|
||||
case BR_EC_secp384r1:
|
||||
return &br_secp384r1;
|
||||
case BR_EC_secp521r1:
|
||||
return &br_secp521r1;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static const unsigned char *
|
||||
api_generator(int curve, size_t *len)
|
||||
{
|
||||
const br_ec_curve_def *cd;
|
||||
|
||||
cd = id_to_curve_def(curve);
|
||||
*len = cd->generator_len;
|
||||
return cd->generator;
|
||||
}
|
||||
|
||||
static const unsigned char *
|
||||
api_order(int curve, size_t *len)
|
||||
{
|
||||
const br_ec_curve_def *cd;
|
||||
|
||||
cd = id_to_curve_def(curve);
|
||||
*len = cd->order_len;
|
||||
return cd->order;
|
||||
}
|
||||
|
||||
static size_t
|
||||
api_xoff(int curve, size_t *len)
|
||||
{
|
||||
api_generator(curve, len);
|
||||
*len >>= 1;
|
||||
return 1;
|
||||
}
|
||||
|
||||
static uint32_t
|
||||
api_mul(unsigned char *G, size_t Glen,
|
||||
const unsigned char *x, size_t xlen, int curve)
|
||||
{
|
||||
uint32_t r;
|
||||
const curve_params *cc;
|
||||
jacobian P;
|
||||
|
||||
cc = id_to_curve(curve);
|
||||
r = point_decode(&P, G, Glen, cc);
|
||||
point_mul(&P, x, xlen, cc);
|
||||
if (Glen == cc->point_len) {
|
||||
point_encode(G, &P, cc);
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
||||
static size_t
|
||||
api_mulgen(unsigned char *R,
|
||||
const unsigned char *x, size_t xlen, int curve)
|
||||
{
|
||||
const unsigned char *G;
|
||||
size_t Glen;
|
||||
|
||||
G = api_generator(curve, &Glen);
|
||||
memcpy_P(R, G, Glen);
|
||||
api_mul(R, Glen, x, xlen, curve);
|
||||
return Glen;
|
||||
}
|
||||
|
||||
static uint32_t
|
||||
api_muladd(unsigned char *A, const unsigned char *B, size_t len,
|
||||
const unsigned char *x, size_t xlen,
|
||||
const unsigned char *y, size_t ylen, int curve)
|
||||
{
|
||||
uint32_t r, t, z;
|
||||
const curve_params *cc;
|
||||
jacobian P, Q;
|
||||
|
||||
/*
|
||||
* TODO: see about merging the two ladders. Right now, we do
|
||||
* two independent point multiplications, which is a bit
|
||||
* wasteful of CPU resources (but yields short code).
|
||||
*/
|
||||
|
||||
cc = id_to_curve(curve);
|
||||
r = point_decode(&P, A, len, cc);
|
||||
if (B == NULL) {
|
||||
size_t Glen;
|
||||
|
||||
B = api_generator(curve, &Glen);
|
||||
}
|
||||
r &= point_decode(&Q, B, len, cc);
|
||||
point_mul(&P, x, xlen, cc);
|
||||
point_mul(&Q, y, ylen, cc);
|
||||
|
||||
/*
|
||||
* We want to compute P+Q. Since the base points A and B are distinct
|
||||
* from infinity, and the multipliers are non-zero and lower than the
|
||||
* curve order, then we know that P and Q are non-infinity. This
|
||||
* leaves two special situations to test for:
|
||||
* -- If P = Q then we must use point_double().
|
||||
* -- If P+Q = 0 then we must report an error.
|
||||
*/
|
||||
t = point_add(&P, &Q, cc);
|
||||
point_double(&Q, cc);
|
||||
z = br_i15_iszero(P.c[2]);
|
||||
|
||||
/*
|
||||
* If z is 1 then either P+Q = 0 (t = 1) or P = Q (t = 0). So we
|
||||
* have the following:
|
||||
*
|
||||
* z = 0, t = 0 return P (normal addition)
|
||||
* z = 0, t = 1 return P (normal addition)
|
||||
* z = 1, t = 0 return Q (a 'double' case)
|
||||
* z = 1, t = 1 report an error (P+Q = 0)
|
||||
*/
|
||||
CCOPY(z & ~t, &P, &Q, sizeof Q);
|
||||
point_encode(A, &P, cc);
|
||||
r &= ~(z & t);
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
/* see bearssl_ec.h */
|
||||
const br_ec_impl br_ec_prime_i15 PROGMEM = {
|
||||
(uint32_t)0x03800000,
|
||||
&api_generator,
|
||||
&api_order,
|
||||
&api_xoff,
|
||||
&api_mul,
|
||||
&api_mulgen,
|
||||
&api_muladd
|
||||
};
|
|
@ -0,0 +1,85 @@
|
|||
/*
|
||||
* Copyright (c) 2018 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 "t_inner.h"
|
||||
|
||||
static const unsigned char POINT_LEN[] PROGMEM = {
|
||||
0, /* 0: not a valid curve ID */
|
||||
43, /* sect163k1 */
|
||||
43, /* sect163r1 */
|
||||
43, /* sect163r2 */
|
||||
51, /* sect193r1 */
|
||||
51, /* sect193r2 */
|
||||
61, /* sect233k1 */
|
||||
61, /* sect233r1 */
|
||||
61, /* sect239k1 */
|
||||
73, /* sect283k1 */
|
||||
73, /* sect283r1 */
|
||||
105, /* sect409k1 */
|
||||
105, /* sect409r1 */
|
||||
145, /* sect571k1 */
|
||||
145, /* sect571r1 */
|
||||
41, /* secp160k1 */
|
||||
41, /* secp160r1 */
|
||||
41, /* secp160r2 */
|
||||
49, /* secp192k1 */
|
||||
49, /* secp192r1 */
|
||||
57, /* secp224k1 */
|
||||
57, /* secp224r1 */
|
||||
65, /* secp256k1 */
|
||||
65, /* secp256r1 */
|
||||
97, /* secp384r1 */
|
||||
133, /* secp521r1 */
|
||||
65, /* brainpoolP256r1 */
|
||||
97, /* brainpoolP384r1 */
|
||||
129, /* brainpoolP512r1 */
|
||||
32, /* curve25519 */
|
||||
56, /* curve448 */
|
||||
};
|
||||
|
||||
/* see bearssl_ec.h */
|
||||
size_t
|
||||
br_ec_compute_pub(const br_ec_impl *impl, br_ec_public_key *pk,
|
||||
void *kbuf, const br_ec_private_key *sk)
|
||||
{
|
||||
int curve;
|
||||
size_t len;
|
||||
|
||||
curve = sk->curve;
|
||||
if (curve < 0 || curve >= 32 || curve >= (int)(sizeof POINT_LEN)
|
||||
|| ((impl->supported_curves >> curve) & 1) == 0)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
if (kbuf == NULL) {
|
||||
return pgm_read_byte(&POINT_LEN[curve]);
|
||||
}
|
||||
len = impl->mulgen(kbuf, sk->x, sk->xlen, curve);
|
||||
if (pk != NULL) {
|
||||
pk->curve = curve;
|
||||
pk->q = kbuf;
|
||||
pk->qlen = len;
|
||||
}
|
||||
return len;
|
||||
}
|
|
@ -0,0 +1,51 @@
|
|||
/*
|
||||
* Copyright (c) 2016 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 "t_inner.h"
|
||||
|
||||
static const unsigned char P256_N[] PROGMEM = {
|
||||
0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00,
|
||||
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
||||
0xBC, 0xE6, 0xFA, 0xAD, 0xA7, 0x17, 0x9E, 0x84,
|
||||
0xF3, 0xB9, 0xCA, 0xC2, 0xFC, 0x63, 0x25, 0x51
|
||||
};
|
||||
|
||||
static const unsigned char P256_G[] PROGMEM = {
|
||||
0x04, 0x6B, 0x17, 0xD1, 0xF2, 0xE1, 0x2C, 0x42,
|
||||
0x47, 0xF8, 0xBC, 0xE6, 0xE5, 0x63, 0xA4, 0x40,
|
||||
0xF2, 0x77, 0x03, 0x7D, 0x81, 0x2D, 0xEB, 0x33,
|
||||
0xA0, 0xF4, 0xA1, 0x39, 0x45, 0xD8, 0x98, 0xC2,
|
||||
0x96, 0x4F, 0xE3, 0x42, 0xE2, 0xFE, 0x1A, 0x7F,
|
||||
0x9B, 0x8E, 0xE7, 0xEB, 0x4A, 0x7C, 0x0F, 0x9E,
|
||||
0x16, 0x2B, 0xCE, 0x33, 0x57, 0x6B, 0x31, 0x5E,
|
||||
0xCE, 0xCB, 0xB6, 0x40, 0x68, 0x37, 0xBF, 0x51,
|
||||
0xF5
|
||||
};
|
||||
|
||||
/* see inner.h */
|
||||
const br_ec_curve_def br_secp256r1 PROGMEM = {
|
||||
BR_EC_secp256r1,
|
||||
P256_N, sizeof P256_N,
|
||||
P256_G, sizeof P256_G
|
||||
};
|
|
@ -0,0 +1,57 @@
|
|||
/*
|
||||
* Copyright (c) 2016 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 "t_inner.h"
|
||||
|
||||
static const unsigned char P384_N[] PROGMEM = {
|
||||
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
||||
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
||||
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
||||
0xC7, 0x63, 0x4D, 0x81, 0xF4, 0x37, 0x2D, 0xDF,
|
||||
0x58, 0x1A, 0x0D, 0xB2, 0x48, 0xB0, 0xA7, 0x7A,
|
||||
0xEC, 0xEC, 0x19, 0x6A, 0xCC, 0xC5, 0x29, 0x73
|
||||
};
|
||||
|
||||
static const unsigned char P384_G[] PROGMEM = {
|
||||
0x04, 0xAA, 0x87, 0xCA, 0x22, 0xBE, 0x8B, 0x05,
|
||||
0x37, 0x8E, 0xB1, 0xC7, 0x1E, 0xF3, 0x20, 0xAD,
|
||||
0x74, 0x6E, 0x1D, 0x3B, 0x62, 0x8B, 0xA7, 0x9B,
|
||||
0x98, 0x59, 0xF7, 0x41, 0xE0, 0x82, 0x54, 0x2A,
|
||||
0x38, 0x55, 0x02, 0xF2, 0x5D, 0xBF, 0x55, 0x29,
|
||||
0x6C, 0x3A, 0x54, 0x5E, 0x38, 0x72, 0x76, 0x0A,
|
||||
0xB7, 0x36, 0x17, 0xDE, 0x4A, 0x96, 0x26, 0x2C,
|
||||
0x6F, 0x5D, 0x9E, 0x98, 0xBF, 0x92, 0x92, 0xDC,
|
||||
0x29, 0xF8, 0xF4, 0x1D, 0xBD, 0x28, 0x9A, 0x14,
|
||||
0x7C, 0xE9, 0xDA, 0x31, 0x13, 0xB5, 0xF0, 0xB8,
|
||||
0xC0, 0x0A, 0x60, 0xB1, 0xCE, 0x1D, 0x7E, 0x81,
|
||||
0x9D, 0x7A, 0x43, 0x1D, 0x7C, 0x90, 0xEA, 0x0E,
|
||||
0x5F
|
||||
};
|
||||
|
||||
/* see inner.h */
|
||||
const br_ec_curve_def br_secp384r1 PROGMEM = {
|
||||
BR_EC_secp384r1,
|
||||
P384_N, sizeof P384_N,
|
||||
P384_G, sizeof P384_G
|
||||
};
|
|
@ -0,0 +1,64 @@
|
|||
/*
|
||||
* Copyright (c) 2016 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 "t_inner.h"
|
||||
|
||||
static const unsigned char P521_N[] PROGMEM = {
|
||||
0x01, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
||||
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
||||
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
||||
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
||||
0xFF, 0xFA, 0x51, 0x86, 0x87, 0x83, 0xBF, 0x2F,
|
||||
0x96, 0x6B, 0x7F, 0xCC, 0x01, 0x48, 0xF7, 0x09,
|
||||
0xA5, 0xD0, 0x3B, 0xB5, 0xC9, 0xB8, 0x89, 0x9C,
|
||||
0x47, 0xAE, 0xBB, 0x6F, 0xB7, 0x1E, 0x91, 0x38,
|
||||
0x64, 0x09
|
||||
};
|
||||
|
||||
static const unsigned char P521_G[] PROGMEM = {
|
||||
0x04, 0x00, 0xC6, 0x85, 0x8E, 0x06, 0xB7, 0x04,
|
||||
0x04, 0xE9, 0xCD, 0x9E, 0x3E, 0xCB, 0x66, 0x23,
|
||||
0x95, 0xB4, 0x42, 0x9C, 0x64, 0x81, 0x39, 0x05,
|
||||
0x3F, 0xB5, 0x21, 0xF8, 0x28, 0xAF, 0x60, 0x6B,
|
||||
0x4D, 0x3D, 0xBA, 0xA1, 0x4B, 0x5E, 0x77, 0xEF,
|
||||
0xE7, 0x59, 0x28, 0xFE, 0x1D, 0xC1, 0x27, 0xA2,
|
||||
0xFF, 0xA8, 0xDE, 0x33, 0x48, 0xB3, 0xC1, 0x85,
|
||||
0x6A, 0x42, 0x9B, 0xF9, 0x7E, 0x7E, 0x31, 0xC2,
|
||||
0xE5, 0xBD, 0x66, 0x01, 0x18, 0x39, 0x29, 0x6A,
|
||||
0x78, 0x9A, 0x3B, 0xC0, 0x04, 0x5C, 0x8A, 0x5F,
|
||||
0xB4, 0x2C, 0x7D, 0x1B, 0xD9, 0x98, 0xF5, 0x44,
|
||||
0x49, 0x57, 0x9B, 0x44, 0x68, 0x17, 0xAF, 0xBD,
|
||||
0x17, 0x27, 0x3E, 0x66, 0x2C, 0x97, 0xEE, 0x72,
|
||||
0x99, 0x5E, 0xF4, 0x26, 0x40, 0xC5, 0x50, 0xB9,
|
||||
0x01, 0x3F, 0xAD, 0x07, 0x61, 0x35, 0x3C, 0x70,
|
||||
0x86, 0xA2, 0x72, 0xC2, 0x40, 0x88, 0xBE, 0x94,
|
||||
0x76, 0x9F, 0xD1, 0x66, 0x50
|
||||
};
|
||||
|
||||
/* see inner.h */
|
||||
const br_ec_curve_def br_secp521r1 PROGMEM = {
|
||||
BR_EC_secp521r1,
|
||||
P521_N, sizeof P521_N,
|
||||
P521_G, sizeof P521_G
|
||||
};
|
|
@ -0,0 +1,134 @@
|
|||
/*
|
||||
* Copyright (c) 2016 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 "t_inner.h"
|
||||
|
||||
/* see bearssl_ec.h */
|
||||
size_t
|
||||
br_ecdsa_asn1_to_raw(void *sig, size_t sig_len)
|
||||
{
|
||||
/*
|
||||
* Note: this code is a bit lenient in that it accepts a few
|
||||
* deviations to DER with regards to minimality of encoding of
|
||||
* lengths and integer values. These deviations are still
|
||||
* unambiguous.
|
||||
*
|
||||
* Signature format is a SEQUENCE of two INTEGER values. We
|
||||
* support only integers of less than 127 bytes each (signed
|
||||
* encoding) so the resulting raw signature will have length
|
||||
* at most 254 bytes.
|
||||
*/
|
||||
|
||||
unsigned char *buf, *r, *s;
|
||||
size_t zlen, rlen, slen, off;
|
||||
unsigned char tmp[254];
|
||||
|
||||
buf = sig;
|
||||
if (sig_len < 8) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* First byte is SEQUENCE tag.
|
||||
*/
|
||||
if (buf[0] != 0x30) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* The SEQUENCE length will be encoded over one or two bytes. We
|
||||
* limit the total SEQUENCE contents to 255 bytes, because it
|
||||
* makes things simpler; this is enough for subgroup orders up
|
||||
* to 999 bits.
|
||||
*/
|
||||
zlen = buf[1];
|
||||
if (zlen > 0x80) {
|
||||
if (zlen != 0x81) {
|
||||
return 0;
|
||||
}
|
||||
zlen = buf[2];
|
||||
if (zlen != sig_len - 3) {
|
||||
return 0;
|
||||
}
|
||||
off = 3;
|
||||
} else {
|
||||
if (zlen != sig_len - 2) {
|
||||
return 0;
|
||||
}
|
||||
off = 2;
|
||||
}
|
||||
|
||||
/*
|
||||
* First INTEGER (r).
|
||||
*/
|
||||
if (buf[off ++] != 0x02) {
|
||||
return 0;
|
||||
}
|
||||
rlen = buf[off ++];
|
||||
if (rlen >= 0x80) {
|
||||
return 0;
|
||||
}
|
||||
r = buf + off;
|
||||
off += rlen;
|
||||
|
||||
/*
|
||||
* Second INTEGER (s).
|
||||
*/
|
||||
if (off + 2 > sig_len) {
|
||||
return 0;
|
||||
}
|
||||
if (buf[off ++] != 0x02) {
|
||||
return 0;
|
||||
}
|
||||
slen = buf[off ++];
|
||||
if (slen >= 0x80 || slen != sig_len - off) {
|
||||
return 0;
|
||||
}
|
||||
s = buf + off;
|
||||
|
||||
/*
|
||||
* Removing leading zeros from r and s.
|
||||
*/
|
||||
while (rlen > 0 && *r == 0) {
|
||||
rlen --;
|
||||
r ++;
|
||||
}
|
||||
while (slen > 0 && *s == 0) {
|
||||
slen --;
|
||||
s ++;
|
||||
}
|
||||
|
||||
/*
|
||||
* Compute common length for the two integers, then copy integers
|
||||
* into the temporary buffer, and finally copy it back over the
|
||||
* signature buffer.
|
||||
*/
|
||||
zlen = rlen > slen ? rlen : slen;
|
||||
sig_len = zlen << 1;
|
||||
memset(tmp, 0, sig_len);
|
||||
memcpy(tmp + zlen - rlen, r, rlen);
|
||||
memcpy(tmp + sig_len - slen, s, slen);
|
||||
memcpy(sig, tmp, sig_len);
|
||||
return sig_len;
|
||||
}
|
|
@ -0,0 +1,36 @@
|
|||
/*
|
||||
* 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 "t_inner.h"
|
||||
|
||||
/* see bearssl_ec.h */
|
||||
br_ecdsa_sign
|
||||
br_ecdsa_sign_asn1_get_default(void)
|
||||
{
|
||||
#if BR_LOMUL
|
||||
return &br_ecdsa_i15_sign_asn1;
|
||||
#else
|
||||
return &br_ecdsa_i31_sign_asn1;
|
||||
#endif
|
||||
}
|
|
@ -0,0 +1,36 @@
|
|||
/*
|
||||
* 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 "t_inner.h"
|
||||
|
||||
/* see bearssl_ec.h */
|
||||
br_ecdsa_sign
|
||||
br_ecdsa_sign_raw_get_default(void)
|
||||
{
|
||||
#if BR_LOMUL
|
||||
return &br_ecdsa_i15_sign_raw;
|
||||
#else
|
||||
return &br_ecdsa_i31_sign_raw;
|
||||
#endif
|
||||
}
|
|
@ -0,0 +1,36 @@
|
|||
/*
|
||||
* 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 "t_inner.h"
|
||||
|
||||
/* see bearssl_ec.h */
|
||||
br_ecdsa_vrfy
|
||||
br_ecdsa_vrfy_asn1_get_default(void)
|
||||
{
|
||||
#if BR_LOMUL
|
||||
return &br_ecdsa_i15_vrfy_asn1;
|
||||
#else
|
||||
return &br_ecdsa_i31_vrfy_asn1;
|
||||
#endif
|
||||
}
|
|
@ -0,0 +1,36 @@
|
|||
/*
|
||||
* 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 "t_inner.h"
|
||||
|
||||
/* see bearssl_ec.h */
|
||||
br_ecdsa_vrfy
|
||||
br_ecdsa_vrfy_raw_get_default(void)
|
||||
{
|
||||
#if BR_LOMUL
|
||||
return &br_ecdsa_i15_vrfy_raw;
|
||||
#else
|
||||
return &br_ecdsa_i31_vrfy_raw;
|
||||
#endif
|
||||
}
|
|
@ -0,0 +1,47 @@
|
|||
/*
|
||||
* 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 "t_inner.h"
|
||||
|
||||
/* see inner.h */
|
||||
void
|
||||
br_ecdsa_i15_bits2int(uint16_t *x,
|
||||
const void *src, size_t len, uint32_t ebitlen)
|
||||
{
|
||||
uint32_t bitlen, hbitlen;
|
||||
int sc;
|
||||
|
||||
bitlen = ebitlen - (ebitlen >> 4);
|
||||
hbitlen = (uint32_t)len << 3;
|
||||
if (hbitlen > bitlen) {
|
||||
len = (bitlen + 7) >> 3;
|
||||
sc = (int)((hbitlen - bitlen) & 7);
|
||||
} else {
|
||||
sc = 0;
|
||||
}
|
||||
br_i15_zero(x, ebitlen);
|
||||
br_i15_decode(x, src, len);
|
||||
br_i15_rshift(x, sc);
|
||||
x[0] = ebitlen;
|
||||
}
|
|
@ -0,0 +1,45 @@
|
|||
/*
|
||||
* 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 "t_inner.h"
|
||||
|
||||
#define ORDER_LEN ((BR_MAX_EC_SIZE + 7) >> 3)
|
||||
|
||||
/* see bearssl_ec.h */
|
||||
size_t
|
||||
br_ecdsa_i15_sign_asn1(const br_ec_impl *impl,
|
||||
const br_hash_class *hf, const void *hash_value,
|
||||
const br_ec_private_key *sk, void *sig)
|
||||
{
|
||||
unsigned char rsig[(ORDER_LEN << 1) + 12];
|
||||
size_t sig_len;
|
||||
|
||||
sig_len = br_ecdsa_i15_sign_raw(impl, hf, hash_value, sk, rsig);
|
||||
if (sig_len == 0) {
|
||||
return 0;
|
||||
}
|
||||
sig_len = br_ecdsa_raw_to_asn1(rsig, sig_len);
|
||||
memcpy(sig, rsig, sig_len);
|
||||
return sig_len;
|
||||
}
|
|
@ -0,0 +1,174 @@
|
|||
/*
|
||||
* 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 "t_inner.h"
|
||||
|
||||
#define I15_LEN ((BR_MAX_EC_SIZE + 29) / 15)
|
||||
#define POINT_LEN (1 + (((BR_MAX_EC_SIZE + 7) >> 3) << 1))
|
||||
#define ORDER_LEN ((BR_MAX_EC_SIZE + 7) >> 3)
|
||||
|
||||
/* see bearssl_ec.h */
|
||||
size_t
|
||||
br_ecdsa_i15_sign_raw(const br_ec_impl *impl,
|
||||
const br_hash_class *hf, const void *hash_value,
|
||||
const br_ec_private_key *sk, void *sig)
|
||||
{
|
||||
/*
|
||||
* IMPORTANT: this code is fit only for curves with a prime
|
||||
* order. This is needed so that modular reduction of the X
|
||||
* coordinate of a point can be done with a simple subtraction.
|
||||
* We also rely on the last byte of the curve order to be distinct
|
||||
* from 0 and 1.
|
||||
*/
|
||||
const br_ec_curve_def *cd;
|
||||
uint16_t n[I15_LEN], r[I15_LEN], s[I15_LEN], x[I15_LEN];
|
||||
uint16_t m[I15_LEN], k[I15_LEN], t1[I15_LEN], t2[I15_LEN];
|
||||
unsigned char tt[ORDER_LEN << 1];
|
||||
unsigned char eU[POINT_LEN];
|
||||
size_t hash_len, nlen, ulen;
|
||||
uint16_t n0i;
|
||||
uint32_t ctl;
|
||||
br_hmac_drbg_context drbg;
|
||||
|
||||
/*
|
||||
* If the curve is not supported, then exit with an error.
|
||||
*/
|
||||
if (((impl->supported_curves >> sk->curve) & 1) == 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Get the curve parameters (generator and order).
|
||||
*/
|
||||
switch (sk->curve) {
|
||||
case BR_EC_secp256r1:
|
||||
cd = &br_secp256r1;
|
||||
break;
|
||||
case BR_EC_secp384r1:
|
||||
cd = &br_secp384r1;
|
||||
break;
|
||||
case BR_EC_secp521r1:
|
||||
cd = &br_secp521r1;
|
||||
break;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Get modulus.
|
||||
*/
|
||||
nlen = cd->order_len;
|
||||
br_i15_decode(n, cd->order, nlen);
|
||||
n0i = br_i15_ninv15(n[1]);
|
||||
|
||||
/*
|
||||
* Get private key as an i15 integer. This also checks that the
|
||||
* private key is well-defined (not zero, and less than the
|
||||
* curve order).
|
||||
*/
|
||||
if (!br_i15_decode_mod(x, sk->x, sk->xlen, n)) {
|
||||
return 0;
|
||||
}
|
||||
if (br_i15_iszero(x)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Get hash length.
|
||||
*/
|
||||
hash_len = (hf->desc >> BR_HASHDESC_OUT_OFF) & BR_HASHDESC_OUT_MASK;
|
||||
|
||||
/*
|
||||
* Truncate and reduce the hash value modulo the curve order.
|
||||
*/
|
||||
br_ecdsa_i15_bits2int(m, hash_value, hash_len, n[0]);
|
||||
br_i15_sub(m, n, br_i15_sub(m, n, 0) ^ 1);
|
||||
|
||||
/*
|
||||
* RFC 6979 generation of the "k" value.
|
||||
*
|
||||
* The process uses HMAC_DRBG (with the hash function used to
|
||||
* process the message that is to be signed). The seed is the
|
||||
* concatenation of the encodings of the private key and
|
||||
* the hash value (after truncation and modular reduction).
|
||||
*/
|
||||
br_i15_encode(tt, nlen, x);
|
||||
br_i15_encode(tt + nlen, nlen, m);
|
||||
br_hmac_drbg_init(&drbg, hf, tt, nlen << 1);
|
||||
for (;;) {
|
||||
br_hmac_drbg_generate(&drbg, tt, nlen);
|
||||
br_ecdsa_i15_bits2int(k, tt, nlen, n[0]);
|
||||
if (br_i15_iszero(k)) {
|
||||
continue;
|
||||
}
|
||||
if (br_i15_sub(k, n, 0)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Compute k*G and extract the X coordinate, then reduce it
|
||||
* modulo the curve order. Since we support only curves with
|
||||
* prime order, that reduction is only a matter of computing
|
||||
* a subtraction.
|
||||
*/
|
||||
br_i15_encode(tt, nlen, k);
|
||||
ulen = impl->mulgen(eU, tt, nlen, sk->curve);
|
||||
br_i15_zero(r, n[0]);
|
||||
br_i15_decode(r, &eU[1], ulen >> 1);
|
||||
r[0] = n[0];
|
||||
br_i15_sub(r, n, br_i15_sub(r, n, 0) ^ 1);
|
||||
|
||||
/*
|
||||
* Compute 1/k in double-Montgomery representation. We do so by
|
||||
* first converting _from_ Montgomery representation (twice),
|
||||
* then using a modular exponentiation.
|
||||
*/
|
||||
br_i15_from_monty(k, n, n0i);
|
||||
br_i15_from_monty(k, n, n0i);
|
||||
memcpy_P(tt, cd->order, nlen);
|
||||
tt[nlen - 1] -= 2;
|
||||
br_i15_modpow(k, tt, nlen, n, n0i, t1, t2);
|
||||
|
||||
/*
|
||||
* Compute s = (m+xr)/k (mod n).
|
||||
* The k[] array contains R^2/k (double-Montgomery representation);
|
||||
* we thus can use direct Montgomery multiplications and conversions
|
||||
* from Montgomery, avoiding any call to br_i15_to_monty() (which
|
||||
* is slower).
|
||||
*/
|
||||
br_i15_from_monty(m, n, n0i);
|
||||
br_i15_montymul(t1, x, r, n, n0i);
|
||||
ctl = br_i15_add(t1, m, 1);
|
||||
ctl |= br_i15_sub(t1, n, 0) ^ 1;
|
||||
br_i15_sub(t1, n, ctl);
|
||||
br_i15_montymul(s, t1, k, n, n0i);
|
||||
|
||||
/*
|
||||
* Encode r and s in the signature.
|
||||
*/
|
||||
br_i15_encode(sig, nlen, r);
|
||||
br_i15_encode((unsigned char *)sig + nlen, nlen, s);
|
||||
return nlen << 1;
|
||||
}
|
|
@ -0,0 +1,48 @@
|
|||
/*
|
||||
* 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 "t_inner.h"
|
||||
|
||||
#define FIELD_LEN ((BR_MAX_EC_SIZE + 7) >> 3)
|
||||
|
||||
/* see bearssl_ec.h */
|
||||
uint32_t
|
||||
br_ecdsa_i15_vrfy_asn1(const br_ec_impl *impl,
|
||||
const void *hash, size_t hash_len,
|
||||
const br_ec_public_key *pk,
|
||||
const void *sig, size_t sig_len)
|
||||
{
|
||||
/*
|
||||
* We use a double-sized buffer because a malformed ASN.1 signature
|
||||
* may trigger a size expansion when converting to "raw" format.
|
||||
*/
|
||||
unsigned char rsig[(FIELD_LEN << 2) + 24];
|
||||
|
||||
if (sig_len > ((sizeof rsig) >> 1)) {
|
||||
return 0;
|
||||
}
|
||||
memcpy(rsig, sig, sig_len);
|
||||
sig_len = br_ecdsa_asn1_to_raw(rsig, sig_len);
|
||||
return br_ecdsa_i15_vrfy_raw(impl, hash, hash_len, pk, rsig, sig_len);
|
||||
}
|
|
@ -0,0 +1,166 @@
|
|||
/*
|
||||
* 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 "t_inner.h"
|
||||
|
||||
#define I15_LEN ((BR_MAX_EC_SIZE + 29) / 15)
|
||||
#define POINT_LEN (1 + (((BR_MAX_EC_SIZE + 7) >> 3) << 1))
|
||||
|
||||
/* see bearssl_ec.h */
|
||||
uint32_t
|
||||
br_ecdsa_i15_vrfy_raw(const br_ec_impl *impl,
|
||||
const void *hash, size_t hash_len,
|
||||
const br_ec_public_key *pk,
|
||||
const void *sig, size_t sig_len)
|
||||
{
|
||||
/*
|
||||
* IMPORTANT: this code is fit only for curves with a prime
|
||||
* order. This is needed so that modular reduction of the X
|
||||
* coordinate of a point can be done with a simple subtraction.
|
||||
*/
|
||||
const br_ec_curve_def *cd;
|
||||
uint16_t n[I15_LEN], r[I15_LEN], s[I15_LEN], t1[I15_LEN], t2[I15_LEN];
|
||||
unsigned char tx[(BR_MAX_EC_SIZE + 7) >> 3];
|
||||
unsigned char ty[(BR_MAX_EC_SIZE + 7) >> 3];
|
||||
unsigned char eU[POINT_LEN];
|
||||
size_t nlen, rlen, ulen;
|
||||
uint16_t n0i;
|
||||
uint32_t res;
|
||||
|
||||
/*
|
||||
* If the curve is not supported, then report an error.
|
||||
*/
|
||||
if (((impl->supported_curves >> pk->curve) & 1) == 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Get the curve parameters (generator and order).
|
||||
*/
|
||||
switch (pk->curve) {
|
||||
case BR_EC_secp256r1:
|
||||
cd = &br_secp256r1;
|
||||
break;
|
||||
case BR_EC_secp384r1:
|
||||
cd = &br_secp384r1;
|
||||
break;
|
||||
case BR_EC_secp521r1:
|
||||
cd = &br_secp521r1;
|
||||
break;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Signature length must be even.
|
||||
*/
|
||||
if (sig_len & 1) {
|
||||
return 0;
|
||||
}
|
||||
rlen = sig_len >> 1;
|
||||
|
||||
/*
|
||||
* Public key point must have the proper size for this curve.
|
||||
*/
|
||||
if (pk->qlen != cd->generator_len) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Get modulus; then decode the r and s values. They must be
|
||||
* lower than the modulus, and s must not be null.
|
||||
*/
|
||||
nlen = cd->order_len;
|
||||
br_i15_decode(n, cd->order, nlen);
|
||||
n0i = br_i15_ninv15(n[1]);
|
||||
if (!br_i15_decode_mod(r, sig, rlen, n)) {
|
||||
return 0;
|
||||
}
|
||||
if (!br_i15_decode_mod(s, (const unsigned char *)sig + rlen, rlen, n)) {
|
||||
return 0;
|
||||
}
|
||||
if (br_i15_iszero(s)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Invert s. We do that with a modular exponentiation; we use
|
||||
* the fact that for all the curves we support, the least
|
||||
* significant byte is not 0 or 1, so we can subtract 2 without
|
||||
* any carry to process.
|
||||
* We also want 1/s in Montgomery representation, which can be
|
||||
* done by converting _from_ Montgomery representation before
|
||||
* the inversion (because (1/s)*R = 1/(s/R)).
|
||||
*/
|
||||
br_i15_from_monty(s, n, n0i);
|
||||
memcpy_P(tx, cd->order, nlen);
|
||||
tx[nlen - 1] -= 2;
|
||||
br_i15_modpow(s, tx, nlen, n, n0i, t1, t2);
|
||||
|
||||
/*
|
||||
* Truncate the hash to the modulus length (in bits) and reduce
|
||||
* it modulo the curve order. The modular reduction can be done
|
||||
* with a subtraction since the truncation already reduced the
|
||||
* value to the modulus bit length.
|
||||
*/
|
||||
br_ecdsa_i15_bits2int(t1, hash, hash_len, n[0]);
|
||||
br_i15_sub(t1, n, br_i15_sub(t1, n, 0) ^ 1);
|
||||
|
||||
/*
|
||||
* Multiply the (truncated, reduced) hash value with 1/s, result in
|
||||
* t2, encoded in ty.
|
||||
*/
|
||||
br_i15_montymul(t2, t1, s, n, n0i);
|
||||
br_i15_encode(ty, nlen, t2);
|
||||
|
||||
/*
|
||||
* Multiply r with 1/s, result in t1, encoded in tx.
|
||||
*/
|
||||
br_i15_montymul(t1, r, s, n, n0i);
|
||||
br_i15_encode(tx, nlen, t1);
|
||||
|
||||
/*
|
||||
* Compute the point x*Q + y*G.
|
||||
*/
|
||||
ulen = cd->generator_len;
|
||||
memcpy(eU, pk->q, ulen);
|
||||
res = impl->muladd(eU, NULL, ulen,
|
||||
tx, nlen, ty, nlen, cd->curve);
|
||||
|
||||
/*
|
||||
* Get the X coordinate, reduce modulo the curve order, and
|
||||
* compare with the 'r' value.
|
||||
*
|
||||
* The modular reduction can be done with subtractions because
|
||||
* we work with curves of prime order, so the curve order is
|
||||
* close to the field order (Hasse's theorem).
|
||||
*/
|
||||
br_i15_zero(t1, n[0]);
|
||||
br_i15_decode(t1, &eU[1], ulen >> 1);
|
||||
t1[0] = n[0];
|
||||
br_i15_sub(t1, n, br_i15_sub(t1, n, 0) ^ 1);
|
||||
res &= ~br_i15_sub(t1, r, 1);
|
||||
res &= br_i15_iszero(t1);
|
||||
return res;
|
||||
}
|
|
@ -0,0 +1,121 @@
|
|||
/*
|
||||
* Copyright (c) 2016 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 "t_inner.h"
|
||||
|
||||
/*
|
||||
* Compute ASN.1 encoded length for the provided integer. The ASN.1
|
||||
* encoding is signed, so its leading bit must have value 0; it must
|
||||
* also be of minimal length (so leading bytes of value 0 must be
|
||||
* removed, except if that would contradict the rule about the sign
|
||||
* bit).
|
||||
*/
|
||||
static size_t
|
||||
asn1_int_length(const unsigned char *x, size_t xlen)
|
||||
{
|
||||
while (xlen > 0 && *x == 0) {
|
||||
x ++;
|
||||
xlen --;
|
||||
}
|
||||
if (xlen == 0 || *x >= 0x80) {
|
||||
xlen ++;
|
||||
}
|
||||
return xlen;
|
||||
}
|
||||
|
||||
/* see bearssl_ec.h */
|
||||
size_t
|
||||
br_ecdsa_raw_to_asn1(void *sig, size_t sig_len)
|
||||
{
|
||||
/*
|
||||
* Internal buffer is large enough to accommodate a signature
|
||||
* such that r and s fit on 125 bytes each (signed encoding),
|
||||
* meaning a curve order of up to 999 bits. This is the limit
|
||||
* that ensures "simple" length encodings.
|
||||
*/
|
||||
unsigned char *buf;
|
||||
size_t hlen, rlen, slen, zlen, off;
|
||||
unsigned char tmp[257];
|
||||
|
||||
buf = sig;
|
||||
if ((sig_len & 1) != 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Compute lengths for the two integers.
|
||||
*/
|
||||
hlen = sig_len >> 1;
|
||||
rlen = asn1_int_length(buf, hlen);
|
||||
slen = asn1_int_length(buf + hlen, hlen);
|
||||
if (rlen > 125 || slen > 125) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* SEQUENCE header.
|
||||
*/
|
||||
tmp[0] = 0x30;
|
||||
zlen = rlen + slen + 4;
|
||||
if (zlen >= 0x80) {
|
||||
tmp[1] = 0x81;
|
||||
tmp[2] = zlen;
|
||||
off = 3;
|
||||
} else {
|
||||
tmp[1] = zlen;
|
||||
off = 2;
|
||||
}
|
||||
|
||||
/*
|
||||
* First INTEGER (r).
|
||||
*/
|
||||
tmp[off ++] = 0x02;
|
||||
tmp[off ++] = rlen;
|
||||
if (rlen > hlen) {
|
||||
tmp[off] = 0x00;
|
||||
memcpy(tmp + off + 1, buf, hlen);
|
||||
} else {
|
||||
memcpy(tmp + off, buf + hlen - rlen, rlen);
|
||||
}
|
||||
off += rlen;
|
||||
|
||||
/*
|
||||
* Second INTEGER (s).
|
||||
*/
|
||||
tmp[off ++] = 0x02;
|
||||
tmp[off ++] = slen;
|
||||
if (slen > hlen) {
|
||||
tmp[off] = 0x00;
|
||||
memcpy(tmp + off + 1, buf + hlen, hlen);
|
||||
} else {
|
||||
memcpy(tmp + off, buf + sig_len - slen, slen);
|
||||
}
|
||||
off += slen;
|
||||
|
||||
/*
|
||||
* Return ASN.1 signature.
|
||||
*/
|
||||
memcpy(sig, tmp, off);
|
||||
return off;
|
||||
}
|
|
@ -0,0 +1,84 @@
|
|||
/*
|
||||
* Copyright (c) 2016 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 "t_inner.h"
|
||||
|
||||
/*
|
||||
* This file contains the encoded OID for the standard hash functions.
|
||||
* Such OID appear in, for instance, the PKCS#1 v1.5 padding for RSA
|
||||
* signatures.
|
||||
*/
|
||||
|
||||
static const unsigned char md5_OID[] = {
|
||||
0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x02, 0x05
|
||||
};
|
||||
|
||||
static const unsigned char sha1_OID[] = {
|
||||
0x2B, 0x0E, 0x03, 0x02, 0x1A
|
||||
};
|
||||
|
||||
static const unsigned char sha224_OID[] = {
|
||||
0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x04
|
||||
};
|
||||
|
||||
static const unsigned char sha256_OID[] = {
|
||||
0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x01
|
||||
};
|
||||
|
||||
static const unsigned char sha384_OID[] = {
|
||||
0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x02
|
||||
};
|
||||
|
||||
static const unsigned char sha512_OID[] = {
|
||||
0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x03
|
||||
};
|
||||
|
||||
/* see inner.h */
|
||||
const unsigned char *
|
||||
br_digest_OID(int digest_id, size_t *len)
|
||||
{
|
||||
switch (digest_id) {
|
||||
case br_md5_ID:
|
||||
*len = sizeof md5_OID;
|
||||
return md5_OID;
|
||||
case br_sha1_ID:
|
||||
*len = sizeof sha1_OID;
|
||||
return sha1_OID;
|
||||
case br_sha224_ID:
|
||||
*len = sizeof sha224_OID;
|
||||
return sha224_OID;
|
||||
case br_sha256_ID:
|
||||
*len = sizeof sha256_OID;
|
||||
return sha256_OID;
|
||||
case br_sha384_ID:
|
||||
*len = sizeof sha384_OID;
|
||||
return sha384_OID;
|
||||
case br_sha512_ID:
|
||||
*len = sizeof sha512_OID;
|
||||
return sha512_OID;
|
||||
default:
|
||||
*len = 0;
|
||||
return NULL;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,50 @@
|
|||
/*
|
||||
* Copyright (c) 2016 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 "t_inner.h"
|
||||
|
||||
/* see inner.h */
|
||||
size_t
|
||||
br_digest_size_by_ID(int digest_id)
|
||||
{
|
||||
switch (digest_id) {
|
||||
case br_md5sha1_ID:
|
||||
return br_md5_SIZE + br_sha1_SIZE;
|
||||
case br_md5_ID:
|
||||
return br_md5_SIZE;
|
||||
case br_sha1_ID:
|
||||
return br_sha1_SIZE;
|
||||
case br_sha224_ID:
|
||||
return br_sha224_SIZE;
|
||||
case br_sha256_ID:
|
||||
return br_sha256_SIZE;
|
||||
case br_sha384_ID:
|
||||
return br_sha384_SIZE;
|
||||
case br_sha512_ID:
|
||||
return br_sha512_SIZE;
|
||||
default:
|
||||
/* abort(); */
|
||||
return 0;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,345 @@
|
|||
/*
|
||||
* Copyright (c) 2016 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 "t_inner.h"
|
||||
|
||||
/*
|
||||
* We compute "carryless multiplications" through normal integer
|
||||
* multiplications, masking out enough bits to create "holes" in which
|
||||
* carries may expand without altering our bits; we really use 8 data
|
||||
* bits per 32-bit word, spaced every fourth bit. Accumulated carries
|
||||
* may not exceed 8 in total, which fits in 4 bits.
|
||||
*
|
||||
* It would be possible to use a 3-bit spacing, allowing two operands,
|
||||
* one with 7 non-zero data bits, the other one with 10 or 11 non-zero
|
||||
* data bits; this asymmetric splitting makes the overall code more
|
||||
* complex with thresholds and exceptions, and does not appear to be
|
||||
* worth the effort.
|
||||
*/
|
||||
|
||||
/*
|
||||
* We cannot really autodetect whether multiplications are "slow" or
|
||||
* not. A typical example is the ARM Cortex M0+, which exists in two
|
||||
* versions: one with a 1-cycle multiplication opcode, the other with
|
||||
* a 32-cycle multiplication opcode. They both use exactly the same
|
||||
* architecture and ABI, and cannot be distinguished from each other
|
||||
* at compile-time.
|
||||
*
|
||||
* Since most modern CPU (even embedded CPU) still have fast
|
||||
* multiplications, we use the "fast mul" code by default.
|
||||
*/
|
||||
|
||||
#if BR_SLOW_MUL
|
||||
|
||||
/*
|
||||
* This implementation uses Karatsuba-like reduction to make fewer
|
||||
* integer multiplications (9 instead of 16), at the expense of extra
|
||||
* logical operations (XOR, shifts...). On modern x86 CPU that offer
|
||||
* fast, pipelined multiplications, this code is about twice slower than
|
||||
* the simpler code with 16 multiplications. This tendency may be
|
||||
* reversed on low-end platforms with expensive multiplications.
|
||||
*/
|
||||
|
||||
#define MUL32(h, l, x, y) do { \
|
||||
uint64_t mul32tmp = MUL(x, y); \
|
||||
(h) = (uint32_t)(mul32tmp >> 32); \
|
||||
(l) = (uint32_t)mul32tmp; \
|
||||
} while (0)
|
||||
|
||||
static inline void
|
||||
bmul(uint32_t *hi, uint32_t *lo, uint32_t x, uint32_t y)
|
||||
{
|
||||
uint32_t x0, x1, x2, x3;
|
||||
uint32_t y0, y1, y2, y3;
|
||||
uint32_t a0, a1, a2, a3, a4, a5, a6, a7, a8;
|
||||
uint32_t b0, b1, b2, b3, b4, b5, b6, b7, b8;
|
||||
|
||||
x0 = x & (uint32_t)0x11111111;
|
||||
x1 = x & (uint32_t)0x22222222;
|
||||
x2 = x & (uint32_t)0x44444444;
|
||||
x3 = x & (uint32_t)0x88888888;
|
||||
y0 = y & (uint32_t)0x11111111;
|
||||
y1 = y & (uint32_t)0x22222222;
|
||||
y2 = y & (uint32_t)0x44444444;
|
||||
y3 = y & (uint32_t)0x88888888;
|
||||
|
||||
/*
|
||||
* (x0+W*x1)*(y0+W*y1) -> a0:b0
|
||||
* (x2+W*x3)*(y2+W*y3) -> a3:b3
|
||||
* ((x0+x2)+W*(x1+x3))*((y0+y2)+W*(y1+y3)) -> a6:b6
|
||||
*/
|
||||
a0 = x0;
|
||||
b0 = y0;
|
||||
a1 = x1 >> 1;
|
||||
b1 = y1 >> 1;
|
||||
a2 = a0 ^ a1;
|
||||
b2 = b0 ^ b1;
|
||||
a3 = x2 >> 2;
|
||||
b3 = y2 >> 2;
|
||||
a4 = x3 >> 3;
|
||||
b4 = y3 >> 3;
|
||||
a5 = a3 ^ a4;
|
||||
b5 = b3 ^ b4;
|
||||
a6 = a0 ^ a3;
|
||||
b6 = b0 ^ b3;
|
||||
a7 = a1 ^ a4;
|
||||
b7 = b1 ^ b4;
|
||||
a8 = a6 ^ a7;
|
||||
b8 = b6 ^ b7;
|
||||
|
||||
MUL32(b0, a0, b0, a0);
|
||||
MUL32(b1, a1, b1, a1);
|
||||
MUL32(b2, a2, b2, a2);
|
||||
MUL32(b3, a3, b3, a3);
|
||||
MUL32(b4, a4, b4, a4);
|
||||
MUL32(b5, a5, b5, a5);
|
||||
MUL32(b6, a6, b6, a6);
|
||||
MUL32(b7, a7, b7, a7);
|
||||
MUL32(b8, a8, b8, a8);
|
||||
|
||||
a0 &= (uint32_t)0x11111111;
|
||||
a1 &= (uint32_t)0x11111111;
|
||||
a2 &= (uint32_t)0x11111111;
|
||||
a3 &= (uint32_t)0x11111111;
|
||||
a4 &= (uint32_t)0x11111111;
|
||||
a5 &= (uint32_t)0x11111111;
|
||||
a6 &= (uint32_t)0x11111111;
|
||||
a7 &= (uint32_t)0x11111111;
|
||||
a8 &= (uint32_t)0x11111111;
|
||||
b0 &= (uint32_t)0x11111111;
|
||||
b1 &= (uint32_t)0x11111111;
|
||||
b2 &= (uint32_t)0x11111111;
|
||||
b3 &= (uint32_t)0x11111111;
|
||||
b4 &= (uint32_t)0x11111111;
|
||||
b5 &= (uint32_t)0x11111111;
|
||||
b6 &= (uint32_t)0x11111111;
|
||||
b7 &= (uint32_t)0x11111111;
|
||||
b8 &= (uint32_t)0x11111111;
|
||||
|
||||
a2 ^= a0 ^ a1;
|
||||
b2 ^= b0 ^ b1;
|
||||
a0 ^= (a2 << 1) ^ (a1 << 2);
|
||||
b0 ^= (b2 << 1) ^ (b1 << 2);
|
||||
a5 ^= a3 ^ a4;
|
||||
b5 ^= b3 ^ b4;
|
||||
a3 ^= (a5 << 1) ^ (a4 << 2);
|
||||
b3 ^= (b5 << 1) ^ (b4 << 2);
|
||||
a8 ^= a6 ^ a7;
|
||||
b8 ^= b6 ^ b7;
|
||||
a6 ^= (a8 << 1) ^ (a7 << 2);
|
||||
b6 ^= (b8 << 1) ^ (b7 << 2);
|
||||
a6 ^= a0 ^ a3;
|
||||
b6 ^= b0 ^ b3;
|
||||
*lo = a0 ^ (a6 << 2) ^ (a3 << 4);
|
||||
*hi = b0 ^ (b6 << 2) ^ (b3 << 4) ^ (a6 >> 30) ^ (a3 >> 28);
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
/*
|
||||
* Simple multiplication in GF(2)[X], using 16 integer multiplications.
|
||||
*/
|
||||
|
||||
static inline void
|
||||
bmul(uint32_t *hi, uint32_t *lo, uint32_t x, uint32_t y)
|
||||
{
|
||||
uint32_t x0, x1, x2, x3;
|
||||
uint32_t y0, y1, y2, y3;
|
||||
uint64_t z0, z1, z2, z3;
|
||||
uint64_t z;
|
||||
|
||||
x0 = x & (uint32_t)0x11111111;
|
||||
x1 = x & (uint32_t)0x22222222;
|
||||
x2 = x & (uint32_t)0x44444444;
|
||||
x3 = x & (uint32_t)0x88888888;
|
||||
y0 = y & (uint32_t)0x11111111;
|
||||
y1 = y & (uint32_t)0x22222222;
|
||||
y2 = y & (uint32_t)0x44444444;
|
||||
y3 = y & (uint32_t)0x88888888;
|
||||
z0 = MUL(x0, y0) ^ MUL(x1, y3) ^ MUL(x2, y2) ^ MUL(x3, y1);
|
||||
z1 = MUL(x0, y1) ^ MUL(x1, y0) ^ MUL(x2, y3) ^ MUL(x3, y2);
|
||||
z2 = MUL(x0, y2) ^ MUL(x1, y1) ^ MUL(x2, y0) ^ MUL(x3, y3);
|
||||
z3 = MUL(x0, y3) ^ MUL(x1, y2) ^ MUL(x2, y1) ^ MUL(x3, y0);
|
||||
z0 &= (uint64_t)0x1111111111111111;
|
||||
z1 &= (uint64_t)0x2222222222222222;
|
||||
z2 &= (uint64_t)0x4444444444444444;
|
||||
z3 &= (uint64_t)0x8888888888888888;
|
||||
z = z0 | z1 | z2 | z3;
|
||||
*lo = (uint32_t)z;
|
||||
*hi = (uint32_t)(z >> 32);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
/* see bearssl_hash.h */
|
||||
void
|
||||
br_ghash_ctmul(void *y, const void *h, const void *data, size_t len)
|
||||
{
|
||||
const unsigned char *buf, *hb;
|
||||
unsigned char *yb;
|
||||
uint32_t yw[4];
|
||||
uint32_t hw[4];
|
||||
|
||||
/*
|
||||
* Throughout the loop we handle the y and h values as arrays
|
||||
* of 32-bit words.
|
||||
*/
|
||||
buf = data;
|
||||
yb = y;
|
||||
hb = h;
|
||||
yw[3] = br_dec32be(yb);
|
||||
yw[2] = br_dec32be(yb + 4);
|
||||
yw[1] = br_dec32be(yb + 8);
|
||||
yw[0] = br_dec32be(yb + 12);
|
||||
hw[3] = br_dec32be(hb);
|
||||
hw[2] = br_dec32be(hb + 4);
|
||||
hw[1] = br_dec32be(hb + 8);
|
||||
hw[0] = br_dec32be(hb + 12);
|
||||
while (len > 0) {
|
||||
const unsigned char *src;
|
||||
unsigned char tmp[16];
|
||||
int i;
|
||||
uint32_t a[9], b[9], zw[8];
|
||||
uint32_t c0, c1, c2, c3, d0, d1, d2, d3, e0, e1, e2, e3;
|
||||
|
||||
/*
|
||||
* Get the next 16-byte block (using zero-padding if
|
||||
* necessary).
|
||||
*/
|
||||
if (len >= 16) {
|
||||
src = buf;
|
||||
buf += 16;
|
||||
len -= 16;
|
||||
} else {
|
||||
memcpy(tmp, buf, len);
|
||||
memset(tmp + len, 0, (sizeof tmp) - len);
|
||||
src = tmp;
|
||||
len = 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Decode the block. The GHASH standard mandates
|
||||
* big-endian encoding.
|
||||
*/
|
||||
yw[3] ^= br_dec32be(src);
|
||||
yw[2] ^= br_dec32be(src + 4);
|
||||
yw[1] ^= br_dec32be(src + 8);
|
||||
yw[0] ^= br_dec32be(src + 12);
|
||||
|
||||
/*
|
||||
* We multiply two 128-bit field elements. We use
|
||||
* Karatsuba to turn that into three 64-bit
|
||||
* multiplications, which are themselves done with a
|
||||
* total of nine 32-bit multiplications.
|
||||
*/
|
||||
|
||||
/*
|
||||
* y[0,1]*h[0,1] -> 0..2
|
||||
* y[2,3]*h[2,3] -> 3..5
|
||||
* (y[0,1]+y[2,3])*(h[0,1]+h[2,3]) -> 6..8
|
||||
*/
|
||||
a[0] = yw[0];
|
||||
b[0] = hw[0];
|
||||
a[1] = yw[1];
|
||||
b[1] = hw[1];
|
||||
a[2] = a[0] ^ a[1];
|
||||
b[2] = b[0] ^ b[1];
|
||||
|
||||
a[3] = yw[2];
|
||||
b[3] = hw[2];
|
||||
a[4] = yw[3];
|
||||
b[4] = hw[3];
|
||||
a[5] = a[3] ^ a[4];
|
||||
b[5] = b[3] ^ b[4];
|
||||
|
||||
a[6] = a[0] ^ a[3];
|
||||
b[6] = b[0] ^ b[3];
|
||||
a[7] = a[1] ^ a[4];
|
||||
b[7] = b[1] ^ b[4];
|
||||
a[8] = a[6] ^ a[7];
|
||||
b[8] = b[6] ^ b[7];
|
||||
|
||||
for (i = 0; i < 9; i ++) {
|
||||
bmul(&b[i], &a[i], b[i], a[i]);
|
||||
}
|
||||
|
||||
c0 = a[0];
|
||||
c1 = b[0] ^ a[2] ^ a[0] ^ a[1];
|
||||
c2 = a[1] ^ b[2] ^ b[0] ^ b[1];
|
||||
c3 = b[1];
|
||||
d0 = a[3];
|
||||
d1 = b[3] ^ a[5] ^ a[3] ^ a[4];
|
||||
d2 = a[4] ^ b[5] ^ b[3] ^ b[4];
|
||||
d3 = b[4];
|
||||
e0 = a[6];
|
||||
e1 = b[6] ^ a[8] ^ a[6] ^ a[7];
|
||||
e2 = a[7] ^ b[8] ^ b[6] ^ b[7];
|
||||
e3 = b[7];
|
||||
|
||||
e0 ^= c0 ^ d0;
|
||||
e1 ^= c1 ^ d1;
|
||||
e2 ^= c2 ^ d2;
|
||||
e3 ^= c3 ^ d3;
|
||||
c2 ^= e0;
|
||||
c3 ^= e1;
|
||||
d0 ^= e2;
|
||||
d1 ^= e3;
|
||||
|
||||
/*
|
||||
* GHASH specification has the bits "reversed" (most
|
||||
* significant is in fact least significant), which does
|
||||
* not matter for a carryless multiplication, except that
|
||||
* the 255-bit result must be shifted by 1 bit.
|
||||
*/
|
||||
zw[0] = c0 << 1;
|
||||
zw[1] = (c1 << 1) | (c0 >> 31);
|
||||
zw[2] = (c2 << 1) | (c1 >> 31);
|
||||
zw[3] = (c3 << 1) | (c2 >> 31);
|
||||
zw[4] = (d0 << 1) | (c3 >> 31);
|
||||
zw[5] = (d1 << 1) | (d0 >> 31);
|
||||
zw[6] = (d2 << 1) | (d1 >> 31);
|
||||
zw[7] = (d3 << 1) | (d2 >> 31);
|
||||
|
||||
/*
|
||||
* We now do the reduction modulo the field polynomial
|
||||
* to get back to 128 bits.
|
||||
*/
|
||||
for (i = 0; i < 4; i ++) {
|
||||
uint32_t lw;
|
||||
|
||||
lw = zw[i];
|
||||
zw[i + 4] ^= lw ^ (lw >> 1) ^ (lw >> 2) ^ (lw >> 7);
|
||||
zw[i + 3] ^= (lw << 31) ^ (lw << 30) ^ (lw << 25);
|
||||
}
|
||||
memcpy(yw, zw + 4, sizeof yw);
|
||||
}
|
||||
|
||||
/*
|
||||
* Encode back the result.
|
||||
*/
|
||||
br_enc32be(yb, yw[3]);
|
||||
br_enc32be(yb + 4, yw[2]);
|
||||
br_enc32be(yb + 8, yw[1]);
|
||||
br_enc32be(yb + 12, yw[0]);
|
||||
}
|
|
@ -0,0 +1,251 @@
|
|||
/*
|
||||
* Copyright (c) 2016 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 "t_inner.h"
|
||||
|
||||
/*
|
||||
* This implementation uses 32-bit multiplications, and only the low
|
||||
* 32 bits for each multiplication result. This is meant primarily for
|
||||
* the ARM Cortex M0 and M0+, whose multiplication opcode does not yield
|
||||
* the upper 32 bits; but it might also be useful on architectures where
|
||||
* access to the upper 32 bits requires use of specific registers that
|
||||
* create contention (e.g. on i386, "mul" necessarily outputs the result
|
||||
* in edx:eax, while "imul" can use any registers but is limited to the
|
||||
* low 32 bits).
|
||||
*
|
||||
* The implementation trick that is used here is bit-reversing (bit 0
|
||||
* is swapped with bit 31, bit 1 with bit 30, and so on). In GF(2)[X],
|
||||
* for all values x and y, we have:
|
||||
* rev32(x) * rev32(y) = rev64(x * y)
|
||||
* In other words, if we bit-reverse (over 32 bits) the operands, then we
|
||||
* bit-reverse (over 64 bits) the result.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Multiplication in GF(2)[X], truncated to its low 32 bits.
|
||||
*/
|
||||
static inline uint32_t
|
||||
bmul32(uint32_t x, uint32_t y)
|
||||
{
|
||||
uint32_t x0, x1, x2, x3;
|
||||
uint32_t y0, y1, y2, y3;
|
||||
uint32_t z0, z1, z2, z3;
|
||||
|
||||
x0 = x & (uint32_t)0x11111111;
|
||||
x1 = x & (uint32_t)0x22222222;
|
||||
x2 = x & (uint32_t)0x44444444;
|
||||
x3 = x & (uint32_t)0x88888888;
|
||||
y0 = y & (uint32_t)0x11111111;
|
||||
y1 = y & (uint32_t)0x22222222;
|
||||
y2 = y & (uint32_t)0x44444444;
|
||||
y3 = y & (uint32_t)0x88888888;
|
||||
z0 = (x0 * y0) ^ (x1 * y3) ^ (x2 * y2) ^ (x3 * y1);
|
||||
z1 = (x0 * y1) ^ (x1 * y0) ^ (x2 * y3) ^ (x3 * y2);
|
||||
z2 = (x0 * y2) ^ (x1 * y1) ^ (x2 * y0) ^ (x3 * y3);
|
||||
z3 = (x0 * y3) ^ (x1 * y2) ^ (x2 * y1) ^ (x3 * y0);
|
||||
z0 &= (uint32_t)0x11111111;
|
||||
z1 &= (uint32_t)0x22222222;
|
||||
z2 &= (uint32_t)0x44444444;
|
||||
z3 &= (uint32_t)0x88888888;
|
||||
return z0 | z1 | z2 | z3;
|
||||
}
|
||||
|
||||
/*
|
||||
* Bit-reverse a 32-bit word.
|
||||
*/
|
||||
static uint32_t
|
||||
rev32(uint32_t x)
|
||||
{
|
||||
#define RMS(m, s) do { \
|
||||
x = ((x & (uint32_t)(m)) << (s)) \
|
||||
| ((x >> (s)) & (uint32_t)(m)); \
|
||||
} while (0)
|
||||
|
||||
RMS(0x55555555, 1);
|
||||
RMS(0x33333333, 2);
|
||||
RMS(0x0F0F0F0F, 4);
|
||||
RMS(0x00FF00FF, 8);
|
||||
return (x << 16) | (x >> 16);
|
||||
|
||||
#undef RMS
|
||||
}
|
||||
|
||||
/* see bearssl_hash.h */
|
||||
void
|
||||
br_ghash_ctmul32(void *y, const void *h, const void *data, size_t len)
|
||||
{
|
||||
/*
|
||||
* This implementation is similar to br_ghash_ctmul() except
|
||||
* that we have to do the multiplication twice, with the
|
||||
* "normal" and "bit reversed" operands. Hence we end up with
|
||||
* eighteen 32-bit multiplications instead of nine.
|
||||
*/
|
||||
|
||||
const unsigned char *buf, *hb;
|
||||
unsigned char *yb;
|
||||
uint32_t yw[4];
|
||||
uint32_t hw[4], hwr[4];
|
||||
|
||||
buf = data;
|
||||
yb = y;
|
||||
hb = h;
|
||||
yw[3] = br_dec32be(yb);
|
||||
yw[2] = br_dec32be(yb + 4);
|
||||
yw[1] = br_dec32be(yb + 8);
|
||||
yw[0] = br_dec32be(yb + 12);
|
||||
hw[3] = br_dec32be(hb);
|
||||
hw[2] = br_dec32be(hb + 4);
|
||||
hw[1] = br_dec32be(hb + 8);
|
||||
hw[0] = br_dec32be(hb + 12);
|
||||
hwr[3] = rev32(hw[3]);
|
||||
hwr[2] = rev32(hw[2]);
|
||||
hwr[1] = rev32(hw[1]);
|
||||
hwr[0] = rev32(hw[0]);
|
||||
while (len > 0) {
|
||||
const unsigned char *src;
|
||||
unsigned char tmp[16];
|
||||
int i;
|
||||
uint32_t a[18], b[18], c[18];
|
||||
uint32_t d0, d1, d2, d3, d4, d5, d6, d7;
|
||||
uint32_t zw[8];
|
||||
|
||||
if (len >= 16) {
|
||||
src = buf;
|
||||
buf += 16;
|
||||
len -= 16;
|
||||
} else {
|
||||
memcpy(tmp, buf, len);
|
||||
memset(tmp + len, 0, (sizeof tmp) - len);
|
||||
src = tmp;
|
||||
len = 0;
|
||||
}
|
||||
yw[3] ^= br_dec32be(src);
|
||||
yw[2] ^= br_dec32be(src + 4);
|
||||
yw[1] ^= br_dec32be(src + 8);
|
||||
yw[0] ^= br_dec32be(src + 12);
|
||||
|
||||
/*
|
||||
* We are using Karatsuba: the 128x128 multiplication is
|
||||
* reduced to three 64x64 multiplications, hence nine
|
||||
* 32x32 multiplications. With the bit-reversal trick,
|
||||
* we have to perform 18 32x32 multiplications.
|
||||
*/
|
||||
|
||||
/*
|
||||
* y[0,1]*h[0,1] -> 0,1,4
|
||||
* y[2,3]*h[2,3] -> 2,3,5
|
||||
* (y[0,1]+y[2,3])*(h[0,1]+h[2,3]) -> 6,7,8
|
||||
*/
|
||||
|
||||
a[0] = yw[0];
|
||||
a[1] = yw[1];
|
||||
a[2] = yw[2];
|
||||
a[3] = yw[3];
|
||||
a[4] = a[0] ^ a[1];
|
||||
a[5] = a[2] ^ a[3];
|
||||
a[6] = a[0] ^ a[2];
|
||||
a[7] = a[1] ^ a[3];
|
||||
a[8] = a[6] ^ a[7];
|
||||
|
||||
a[ 9] = rev32(yw[0]);
|
||||
a[10] = rev32(yw[1]);
|
||||
a[11] = rev32(yw[2]);
|
||||
a[12] = rev32(yw[3]);
|
||||
a[13] = a[ 9] ^ a[10];
|
||||
a[14] = a[11] ^ a[12];
|
||||
a[15] = a[ 9] ^ a[11];
|
||||
a[16] = a[10] ^ a[12];
|
||||
a[17] = a[15] ^ a[16];
|
||||
|
||||
b[0] = hw[0];
|
||||
b[1] = hw[1];
|
||||
b[2] = hw[2];
|
||||
b[3] = hw[3];
|
||||
b[4] = b[0] ^ b[1];
|
||||
b[5] = b[2] ^ b[3];
|
||||
b[6] = b[0] ^ b[2];
|
||||
b[7] = b[1] ^ b[3];
|
||||
b[8] = b[6] ^ b[7];
|
||||
|
||||
b[ 9] = hwr[0];
|
||||
b[10] = hwr[1];
|
||||
b[11] = hwr[2];
|
||||
b[12] = hwr[3];
|
||||
b[13] = b[ 9] ^ b[10];
|
||||
b[14] = b[11] ^ b[12];
|
||||
b[15] = b[ 9] ^ b[11];
|
||||
b[16] = b[10] ^ b[12];
|
||||
b[17] = b[15] ^ b[16];
|
||||
|
||||
for (i = 0; i < 18; i ++) {
|
||||
c[i] = bmul32(a[i], b[i]);
|
||||
}
|
||||
|
||||
c[4] ^= c[0] ^ c[1];
|
||||
c[5] ^= c[2] ^ c[3];
|
||||
c[8] ^= c[6] ^ c[7];
|
||||
|
||||
c[13] ^= c[ 9] ^ c[10];
|
||||
c[14] ^= c[11] ^ c[12];
|
||||
c[17] ^= c[15] ^ c[16];
|
||||
|
||||
/*
|
||||
* y[0,1]*h[0,1] -> 0,9^4,1^13,10
|
||||
* y[2,3]*h[2,3] -> 2,11^5,3^14,12
|
||||
* (y[0,1]+y[2,3])*(h[0,1]+h[2,3]) -> 6,15^8,7^17,16
|
||||
*/
|
||||
d0 = c[0];
|
||||
d1 = c[4] ^ (rev32(c[9]) >> 1);
|
||||
d2 = c[1] ^ c[0] ^ c[2] ^ c[6] ^ (rev32(c[13]) >> 1);
|
||||
d3 = c[4] ^ c[5] ^ c[8]
|
||||
^ (rev32(c[10] ^ c[9] ^ c[11] ^ c[15]) >> 1);
|
||||
d4 = c[2] ^ c[1] ^ c[3] ^ c[7]
|
||||
^ (rev32(c[13] ^ c[14] ^ c[17]) >> 1);
|
||||
d5 = c[5] ^ (rev32(c[11] ^ c[10] ^ c[12] ^ c[16]) >> 1);
|
||||
d6 = c[3] ^ (rev32(c[14]) >> 1);
|
||||
d7 = rev32(c[12]) >> 1;
|
||||
|
||||
zw[0] = d0 << 1;
|
||||
zw[1] = (d1 << 1) | (d0 >> 31);
|
||||
zw[2] = (d2 << 1) | (d1 >> 31);
|
||||
zw[3] = (d3 << 1) | (d2 >> 31);
|
||||
zw[4] = (d4 << 1) | (d3 >> 31);
|
||||
zw[5] = (d5 << 1) | (d4 >> 31);
|
||||
zw[6] = (d6 << 1) | (d5 >> 31);
|
||||
zw[7] = (d7 << 1) | (d6 >> 31);
|
||||
|
||||
for (i = 0; i < 4; i ++) {
|
||||
uint32_t lw;
|
||||
|
||||
lw = zw[i];
|
||||
zw[i + 4] ^= lw ^ (lw >> 1) ^ (lw >> 2) ^ (lw >> 7);
|
||||
zw[i + 3] ^= (lw << 31) ^ (lw << 30) ^ (lw << 25);
|
||||
}
|
||||
memcpy(yw, zw + 4, sizeof yw);
|
||||
}
|
||||
br_enc32be(yb, yw[3]);
|
||||
br_enc32be(yb + 4, yw[2]);
|
||||
br_enc32be(yb + 8, yw[1]);
|
||||
br_enc32be(yb + 12, yw[0]);
|
||||
}
|
|
@ -0,0 +1,154 @@
|
|||
/*
|
||||
* Copyright (c) 2016 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 "t_inner.h"
|
||||
|
||||
/*
|
||||
* This is the 64-bit variant of br_ghash_ctmul32(), with 64-bit operands
|
||||
* and bit reversal of 64-bit words.
|
||||
*/
|
||||
|
||||
static inline uint64_t
|
||||
bmul64(uint64_t x, uint64_t y)
|
||||
{
|
||||
uint64_t x0, x1, x2, x3;
|
||||
uint64_t y0, y1, y2, y3;
|
||||
uint64_t z0, z1, z2, z3;
|
||||
|
||||
x0 = x & (uint64_t)0x1111111111111111;
|
||||
x1 = x & (uint64_t)0x2222222222222222;
|
||||
x2 = x & (uint64_t)0x4444444444444444;
|
||||
x3 = x & (uint64_t)0x8888888888888888;
|
||||
y0 = y & (uint64_t)0x1111111111111111;
|
||||
y1 = y & (uint64_t)0x2222222222222222;
|
||||
y2 = y & (uint64_t)0x4444444444444444;
|
||||
y3 = y & (uint64_t)0x8888888888888888;
|
||||
z0 = (x0 * y0) ^ (x1 * y3) ^ (x2 * y2) ^ (x3 * y1);
|
||||
z1 = (x0 * y1) ^ (x1 * y0) ^ (x2 * y3) ^ (x3 * y2);
|
||||
z2 = (x0 * y2) ^ (x1 * y1) ^ (x2 * y0) ^ (x3 * y3);
|
||||
z3 = (x0 * y3) ^ (x1 * y2) ^ (x2 * y1) ^ (x3 * y0);
|
||||
z0 &= (uint64_t)0x1111111111111111;
|
||||
z1 &= (uint64_t)0x2222222222222222;
|
||||
z2 &= (uint64_t)0x4444444444444444;
|
||||
z3 &= (uint64_t)0x8888888888888888;
|
||||
return z0 | z1 | z2 | z3;
|
||||
}
|
||||
|
||||
static uint64_t
|
||||
rev64(uint64_t x)
|
||||
{
|
||||
#define RMS(m, s) do { \
|
||||
x = ((x & (uint64_t)(m)) << (s)) \
|
||||
| ((x >> (s)) & (uint64_t)(m)); \
|
||||
} while (0)
|
||||
|
||||
RMS(0x5555555555555555, 1);
|
||||
RMS(0x3333333333333333, 2);
|
||||
RMS(0x0F0F0F0F0F0F0F0F, 4);
|
||||
RMS(0x00FF00FF00FF00FF, 8);
|
||||
RMS(0x0000FFFF0000FFFF, 16);
|
||||
return (x << 32) | (x >> 32);
|
||||
|
||||
#undef RMS
|
||||
}
|
||||
|
||||
/* see bearssl_ghash.h */
|
||||
void
|
||||
br_ghash_ctmul64(void *y, const void *h, const void *data, size_t len)
|
||||
{
|
||||
const unsigned char *buf, *hb;
|
||||
unsigned char *yb;
|
||||
uint64_t y0, y1;
|
||||
uint64_t h0, h1, h2, h0r, h1r, h2r;
|
||||
|
||||
buf = data;
|
||||
yb = y;
|
||||
hb = h;
|
||||
y1 = br_dec64be(yb);
|
||||
y0 = br_dec64be(yb + 8);
|
||||
h1 = br_dec64be(hb);
|
||||
h0 = br_dec64be(hb + 8);
|
||||
h0r = rev64(h0);
|
||||
h1r = rev64(h1);
|
||||
h2 = h0 ^ h1;
|
||||
h2r = h0r ^ h1r;
|
||||
while (len > 0) {
|
||||
const unsigned char *src;
|
||||
unsigned char tmp[16];
|
||||
uint64_t y0r, y1r, y2, y2r;
|
||||
uint64_t z0, z1, z2, z0h, z1h, z2h;
|
||||
uint64_t v0, v1, v2, v3;
|
||||
|
||||
if (len >= 16) {
|
||||
src = buf;
|
||||
buf += 16;
|
||||
len -= 16;
|
||||
} else {
|
||||
memcpy(tmp, buf, len);
|
||||
memset(tmp + len, 0, (sizeof tmp) - len);
|
||||
src = tmp;
|
||||
len = 0;
|
||||
}
|
||||
y1 ^= br_dec64be(src);
|
||||
y0 ^= br_dec64be(src + 8);
|
||||
|
||||
y0r = rev64(y0);
|
||||
y1r = rev64(y1);
|
||||
y2 = y0 ^ y1;
|
||||
y2r = y0r ^ y1r;
|
||||
|
||||
z0 = bmul64(y0, h0);
|
||||
z1 = bmul64(y1, h1);
|
||||
z2 = bmul64(y2, h2);
|
||||
z0h = bmul64(y0r, h0r);
|
||||
z1h = bmul64(y1r, h1r);
|
||||
z2h = bmul64(y2r, h2r);
|
||||
z2 ^= z0 ^ z1;
|
||||
z2h ^= z0h ^ z1h;
|
||||
z0h = rev64(z0h) >> 1;
|
||||
z1h = rev64(z1h) >> 1;
|
||||
z2h = rev64(z2h) >> 1;
|
||||
|
||||
v0 = z0;
|
||||
v1 = z0h ^ z2;
|
||||
v2 = z1 ^ z2h;
|
||||
v3 = z1h;
|
||||
|
||||
v3 = (v3 << 1) | (v2 >> 63);
|
||||
v2 = (v2 << 1) | (v1 >> 63);
|
||||
v1 = (v1 << 1) | (v0 >> 63);
|
||||
v0 = (v0 << 1);
|
||||
|
||||
v2 ^= v0 ^ (v0 >> 1) ^ (v0 >> 2) ^ (v0 >> 7);
|
||||
v1 ^= (v0 << 63) ^ (v0 << 62) ^ (v0 << 57);
|
||||
v3 ^= v1 ^ (v1 >> 1) ^ (v1 >> 2) ^ (v1 >> 7);
|
||||
v2 ^= (v1 << 63) ^ (v1 << 62) ^ (v1 << 57);
|
||||
|
||||
y0 = v2;
|
||||
y1 = v3;
|
||||
}
|
||||
|
||||
br_enc64be(yb, y1);
|
||||
br_enc64be(yb + 8, y0);
|
||||
}
|
|
@ -0,0 +1,389 @@
|
|||
/*
|
||||
* 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 "t_inner.h"
|
||||
|
||||
/*
|
||||
* This is the GHASH implementation that leverages the pclmulqdq opcode
|
||||
* (from the AES-NI instructions).
|
||||
*/
|
||||
|
||||
#if BR_AES_X86NI
|
||||
|
||||
/*
|
||||
* Test CPU support for PCLMULQDQ.
|
||||
*/
|
||||
static inline int
|
||||
pclmul_supported(void)
|
||||
{
|
||||
/*
|
||||
* Bit mask for features in ECX:
|
||||
* 1 PCLMULQDQ support
|
||||
*/
|
||||
return br_cpuid(0, 0, 0x00000002, 0);
|
||||
}
|
||||
|
||||
/* see bearssl_hash.h */
|
||||
br_ghash
|
||||
br_ghash_pclmul_get(void)
|
||||
{
|
||||
return pclmul_supported() ? &br_ghash_pclmul : 0;
|
||||
}
|
||||
|
||||
BR_TARGETS_X86_UP
|
||||
|
||||
/*
|
||||
* GHASH is defined over elements of GF(2^128) with "full little-endian"
|
||||
* representation: leftmost byte is least significant, and, within each
|
||||
* byte, leftmost _bit_ is least significant. The natural ordering in
|
||||
* x86 is "mixed little-endian": bytes are ordered from least to most
|
||||
* significant, but bits within a byte are in most-to-least significant
|
||||
* order. Going to full little-endian representation would require
|
||||
* reversing bits within each byte, which is doable but expensive.
|
||||
*
|
||||
* Instead, we go to full big-endian representation, by swapping bytes
|
||||
* around, which is done with a single _mm_shuffle_epi8() opcode (it
|
||||
* comes with SSSE3; all CPU that offer pclmulqdq also have SSSE3). We
|
||||
* can use a full big-endian representation because in a carryless
|
||||
* multiplication, we have a nice bit reversal property:
|
||||
*
|
||||
* rev_128(x) * rev_128(y) = rev_255(x * y)
|
||||
*
|
||||
* So by using full big-endian, we still get the right result, except
|
||||
* that it is right-shifted by 1 bit. The left-shift is relatively
|
||||
* inexpensive, and it can be mutualised.
|
||||
*
|
||||
*
|
||||
* Since SSE2 opcodes do not have facilities for shitfting full 128-bit
|
||||
* values with bit precision, we have to break down values into 64-bit
|
||||
* chunks. We number chunks from 0 to 3 in left to right order.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Byte-swap a complete 128-bit value. This normally uses
|
||||
* _mm_shuffle_epi8(), which gets translated to pshufb (an SSSE3 opcode).
|
||||
* However, this crashes old Clang versions, so, for Clang before 3.8,
|
||||
* we use an alternate (and less efficient) version.
|
||||
*/
|
||||
#if BR_CLANG && !BR_CLANG_3_8
|
||||
#define BYTESWAP_DECL
|
||||
#define BYTESWAP_PREP (void)0
|
||||
#define BYTESWAP(x) do { \
|
||||
__m128i byteswap1, byteswap2; \
|
||||
byteswap1 = (x); \
|
||||
byteswap2 = _mm_srli_epi16(byteswap1, 8); \
|
||||
byteswap1 = _mm_slli_epi16(byteswap1, 8); \
|
||||
byteswap1 = _mm_or_si128(byteswap1, byteswap2); \
|
||||
byteswap1 = _mm_shufflelo_epi16(byteswap1, 0x1B); \
|
||||
byteswap1 = _mm_shufflehi_epi16(byteswap1, 0x1B); \
|
||||
(x) = _mm_shuffle_epi32(byteswap1, 0x4E); \
|
||||
} while (0)
|
||||
#else
|
||||
#define BYTESWAP_DECL __m128i byteswap_index;
|
||||
#define BYTESWAP_PREP do { \
|
||||
byteswap_index = _mm_set_epi8( \
|
||||
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15); \
|
||||
} while (0)
|
||||
#define BYTESWAP(x) do { \
|
||||
(x) = _mm_shuffle_epi8((x), byteswap_index); \
|
||||
} while (0)
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Call pclmulqdq. Clang appears to have trouble with the intrinsic, so,
|
||||
* for that compiler, we use inline assembly. Inline assembly is
|
||||
* potentially a bit slower because the compiler does not understand
|
||||
* what the opcode does, and thus cannot optimize instruction
|
||||
* scheduling.
|
||||
*
|
||||
* We use a target of "sse2" only, so that Clang may still handle the
|
||||
* '__m128i' type and allocate SSE2 registers.
|
||||
*/
|
||||
#if BR_CLANG
|
||||
BR_TARGET("sse2")
|
||||
static inline __m128i
|
||||
pclmulqdq00(__m128i x, __m128i y)
|
||||
{
|
||||
__asm__ ("pclmulqdq $0x00, %1, %0" : "+x" (x) : "x" (y));
|
||||
return x;
|
||||
}
|
||||
BR_TARGET("sse2")
|
||||
static inline __m128i
|
||||
pclmulqdq11(__m128i x, __m128i y)
|
||||
{
|
||||
__asm__ ("pclmulqdq $0x11, %1, %0" : "+x" (x) : "x" (y));
|
||||
return x;
|
||||
}
|
||||
#else
|
||||
#define pclmulqdq00(x, y) _mm_clmulepi64_si128(x, y, 0x00)
|
||||
#define pclmulqdq11(x, y) _mm_clmulepi64_si128(x, y, 0x11)
|
||||
#endif
|
||||
|
||||
/*
|
||||
* From a 128-bit value kw, compute kx as the XOR of the two 64-bit
|
||||
* halves of kw (into the right half of kx; left half is unspecified).
|
||||
*/
|
||||
#define BK(kw, kx) do { \
|
||||
kx = _mm_xor_si128(kw, _mm_shuffle_epi32(kw, 0x0E)); \
|
||||
} while (0)
|
||||
|
||||
/*
|
||||
* Combine two 64-bit values (k0:k1) into a 128-bit (kw) value and
|
||||
* the XOR of the two values (kx).
|
||||
*/
|
||||
#define PBK(k0, k1, kw, kx) do { \
|
||||
kw = _mm_unpacklo_epi64(k1, k0); \
|
||||
kx = _mm_xor_si128(k0, k1); \
|
||||
} while (0)
|
||||
|
||||
/*
|
||||
* Left-shift by 1 bit a 256-bit value (in four 64-bit words).
|
||||
*/
|
||||
#define SL_256(x0, x1, x2, x3) do { \
|
||||
x0 = _mm_or_si128( \
|
||||
_mm_slli_epi64(x0, 1), \
|
||||
_mm_srli_epi64(x1, 63)); \
|
||||
x1 = _mm_or_si128( \
|
||||
_mm_slli_epi64(x1, 1), \
|
||||
_mm_srli_epi64(x2, 63)); \
|
||||
x2 = _mm_or_si128( \
|
||||
_mm_slli_epi64(x2, 1), \
|
||||
_mm_srli_epi64(x3, 63)); \
|
||||
x3 = _mm_slli_epi64(x3, 1); \
|
||||
} while (0)
|
||||
|
||||
/*
|
||||
* Perform reduction in GF(2^128). The 256-bit value is in x0..x3;
|
||||
* result is written in x0..x1.
|
||||
*/
|
||||
#define REDUCE_F128(x0, x1, x2, x3) do { \
|
||||
x1 = _mm_xor_si128( \
|
||||
x1, \
|
||||
_mm_xor_si128( \
|
||||
_mm_xor_si128( \
|
||||
x3, \
|
||||
_mm_srli_epi64(x3, 1)), \
|
||||
_mm_xor_si128( \
|
||||
_mm_srli_epi64(x3, 2), \
|
||||
_mm_srli_epi64(x3, 7)))); \
|
||||
x2 = _mm_xor_si128( \
|
||||
_mm_xor_si128( \
|
||||
x2, \
|
||||
_mm_slli_epi64(x3, 63)), \
|
||||
_mm_xor_si128( \
|
||||
_mm_slli_epi64(x3, 62), \
|
||||
_mm_slli_epi64(x3, 57))); \
|
||||
x0 = _mm_xor_si128( \
|
||||
x0, \
|
||||
_mm_xor_si128( \
|
||||
_mm_xor_si128( \
|
||||
x2, \
|
||||
_mm_srli_epi64(x2, 1)), \
|
||||
_mm_xor_si128( \
|
||||
_mm_srli_epi64(x2, 2), \
|
||||
_mm_srli_epi64(x2, 7)))); \
|
||||
x1 = _mm_xor_si128( \
|
||||
_mm_xor_si128( \
|
||||
x1, \
|
||||
_mm_slli_epi64(x2, 63)), \
|
||||
_mm_xor_si128( \
|
||||
_mm_slli_epi64(x2, 62), \
|
||||
_mm_slli_epi64(x2, 57))); \
|
||||
} while (0)
|
||||
|
||||
/*
|
||||
* Square value kw into (dw,dx).
|
||||
*/
|
||||
#define SQUARE_F128(kw, dw, dx) do { \
|
||||
__m128i z0, z1, z2, z3; \
|
||||
z1 = pclmulqdq11(kw, kw); \
|
||||
z3 = pclmulqdq00(kw, kw); \
|
||||
z0 = _mm_shuffle_epi32(z1, 0x0E); \
|
||||
z2 = _mm_shuffle_epi32(z3, 0x0E); \
|
||||
SL_256(z0, z1, z2, z3); \
|
||||
REDUCE_F128(z0, z1, z2, z3); \
|
||||
PBK(z0, z1, dw, dx); \
|
||||
} while (0)
|
||||
|
||||
/* see bearssl_hash.h */
|
||||
BR_TARGET("ssse3,pclmul")
|
||||
void
|
||||
br_ghash_pclmul(void *y, const void *h, const void *data, size_t len)
|
||||
{
|
||||
const unsigned char *buf1, *buf2;
|
||||
unsigned char tmp[64];
|
||||
size_t num4, num1;
|
||||
__m128i yw, h1w, h1x;
|
||||
BYTESWAP_DECL
|
||||
|
||||
/*
|
||||
* We split data into two chunks. First chunk starts at buf1
|
||||
* and contains num4 blocks of 64-byte values. Second chunk
|
||||
* starts at buf2 and contains num1 blocks of 16-byte values.
|
||||
* We want the first chunk to be as large as possible.
|
||||
*/
|
||||
buf1 = data;
|
||||
num4 = len >> 6;
|
||||
len &= 63;
|
||||
buf2 = buf1 + (num4 << 6);
|
||||
num1 = (len + 15) >> 4;
|
||||
if ((len & 15) != 0) {
|
||||
memcpy(tmp, buf2, len);
|
||||
memset(tmp + len, 0, (num1 << 4) - len);
|
||||
buf2 = tmp;
|
||||
}
|
||||
|
||||
/*
|
||||
* Preparatory step for endian conversions.
|
||||
*/
|
||||
BYTESWAP_PREP;
|
||||
|
||||
/*
|
||||
* Load y and h.
|
||||
*/
|
||||
yw = _mm_loadu_si128(y);
|
||||
h1w = _mm_loadu_si128(h);
|
||||
BYTESWAP(yw);
|
||||
BYTESWAP(h1w);
|
||||
BK(h1w, h1x);
|
||||
|
||||
if (num4 > 0) {
|
||||
__m128i h2w, h2x, h3w, h3x, h4w, h4x;
|
||||
__m128i t0, t1, t2, t3;
|
||||
|
||||
/*
|
||||
* Compute h2 = h^2.
|
||||
*/
|
||||
SQUARE_F128(h1w, h2w, h2x);
|
||||
|
||||
/*
|
||||
* Compute h3 = h^3 = h*(h^2).
|
||||
*/
|
||||
t1 = pclmulqdq11(h1w, h2w);
|
||||
t3 = pclmulqdq00(h1w, h2w);
|
||||
t2 = _mm_xor_si128(pclmulqdq00(h1x, h2x),
|
||||
_mm_xor_si128(t1, t3));
|
||||
t0 = _mm_shuffle_epi32(t1, 0x0E);
|
||||
t1 = _mm_xor_si128(t1, _mm_shuffle_epi32(t2, 0x0E));
|
||||
t2 = _mm_xor_si128(t2, _mm_shuffle_epi32(t3, 0x0E));
|
||||
SL_256(t0, t1, t2, t3);
|
||||
REDUCE_F128(t0, t1, t2, t3);
|
||||
PBK(t0, t1, h3w, h3x);
|
||||
|
||||
/*
|
||||
* Compute h4 = h^4 = (h^2)^2.
|
||||
*/
|
||||
SQUARE_F128(h2w, h4w, h4x);
|
||||
|
||||
while (num4 -- > 0) {
|
||||
__m128i aw0, aw1, aw2, aw3;
|
||||
__m128i ax0, ax1, ax2, ax3;
|
||||
|
||||
aw0 = _mm_loadu_si128((void *)(buf1 + 0));
|
||||
aw1 = _mm_loadu_si128((void *)(buf1 + 16));
|
||||
aw2 = _mm_loadu_si128((void *)(buf1 + 32));
|
||||
aw3 = _mm_loadu_si128((void *)(buf1 + 48));
|
||||
BYTESWAP(aw0);
|
||||
BYTESWAP(aw1);
|
||||
BYTESWAP(aw2);
|
||||
BYTESWAP(aw3);
|
||||
buf1 += 64;
|
||||
|
||||
aw0 = _mm_xor_si128(aw0, yw);
|
||||
BK(aw1, ax1);
|
||||
BK(aw2, ax2);
|
||||
BK(aw3, ax3);
|
||||
BK(aw0, ax0);
|
||||
|
||||
t1 = _mm_xor_si128(
|
||||
_mm_xor_si128(
|
||||
pclmulqdq11(aw0, h4w),
|
||||
pclmulqdq11(aw1, h3w)),
|
||||
_mm_xor_si128(
|
||||
pclmulqdq11(aw2, h2w),
|
||||
pclmulqdq11(aw3, h1w)));
|
||||
t3 = _mm_xor_si128(
|
||||
_mm_xor_si128(
|
||||
pclmulqdq00(aw0, h4w),
|
||||
pclmulqdq00(aw1, h3w)),
|
||||
_mm_xor_si128(
|
||||
pclmulqdq00(aw2, h2w),
|
||||
pclmulqdq00(aw3, h1w)));
|
||||
t2 = _mm_xor_si128(
|
||||
_mm_xor_si128(
|
||||
pclmulqdq00(ax0, h4x),
|
||||
pclmulqdq00(ax1, h3x)),
|
||||
_mm_xor_si128(
|
||||
pclmulqdq00(ax2, h2x),
|
||||
pclmulqdq00(ax3, h1x)));
|
||||
t2 = _mm_xor_si128(t2, _mm_xor_si128(t1, t3));
|
||||
t0 = _mm_shuffle_epi32(t1, 0x0E);
|
||||
t1 = _mm_xor_si128(t1, _mm_shuffle_epi32(t2, 0x0E));
|
||||
t2 = _mm_xor_si128(t2, _mm_shuffle_epi32(t3, 0x0E));
|
||||
SL_256(t0, t1, t2, t3);
|
||||
REDUCE_F128(t0, t1, t2, t3);
|
||||
yw = _mm_unpacklo_epi64(t1, t0);
|
||||
}
|
||||
}
|
||||
|
||||
while (num1 -- > 0) {
|
||||
__m128i aw, ax;
|
||||
__m128i t0, t1, t2, t3;
|
||||
|
||||
aw = _mm_loadu_si128((void *)buf2);
|
||||
BYTESWAP(aw);
|
||||
buf2 += 16;
|
||||
|
||||
aw = _mm_xor_si128(aw, yw);
|
||||
BK(aw, ax);
|
||||
|
||||
t1 = pclmulqdq11(aw, h1w);
|
||||
t3 = pclmulqdq00(aw, h1w);
|
||||
t2 = pclmulqdq00(ax, h1x);
|
||||
t2 = _mm_xor_si128(t2, _mm_xor_si128(t1, t3));
|
||||
t0 = _mm_shuffle_epi32(t1, 0x0E);
|
||||
t1 = _mm_xor_si128(t1, _mm_shuffle_epi32(t2, 0x0E));
|
||||
t2 = _mm_xor_si128(t2, _mm_shuffle_epi32(t3, 0x0E));
|
||||
SL_256(t0, t1, t2, t3);
|
||||
REDUCE_F128(t0, t1, t2, t3);
|
||||
yw = _mm_unpacklo_epi64(t1, t0);
|
||||
}
|
||||
|
||||
BYTESWAP(yw);
|
||||
_mm_storeu_si128(y, yw);
|
||||
}
|
||||
|
||||
BR_TARGETS_X86_DOWN
|
||||
|
||||
#else
|
||||
|
||||
/* see bearssl_hash.h */
|
||||
br_ghash
|
||||
br_ghash_pclmul_get(void)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif
|
|
@ -0,0 +1,210 @@
|
|||
/*
|
||||
* Copyright (c) 2016 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 "t_inner.h"
|
||||
|
||||
#define F(B, C, D) ((((C) ^ (D)) & (B)) ^ (D))
|
||||
#define G(B, C, D) ((((C) ^ (B)) & (D)) ^ (C))
|
||||
#define H(B, C, D) ((B) ^ (C) ^ (D))
|
||||
#define I(B, C, D) ((C) ^ ((B) | ~(D)))
|
||||
|
||||
#define ROTL(x, n) (((x) << (n)) | ((x) >> (32 - (n))))
|
||||
|
||||
/* see inner.h */
|
||||
const uint32_t br_md5_IV[4] PROGMEM = {
|
||||
0x67452301, 0xEFCDAB89, 0x98BADCFE, 0x10325476
|
||||
};
|
||||
|
||||
static const uint32_t K[64] PROGMEM = {
|
||||
0xD76AA478, 0xE8C7B756, 0x242070DB, 0xC1BDCEEE,
|
||||
0xF57C0FAF, 0x4787C62A, 0xA8304613, 0xFD469501,
|
||||
0x698098D8, 0x8B44F7AF, 0xFFFF5BB1, 0x895CD7BE,
|
||||
0x6B901122, 0xFD987193, 0xA679438E, 0x49B40821,
|
||||
|
||||
0xF61E2562, 0xC040B340, 0x265E5A51, 0xE9B6C7AA,
|
||||
0xD62F105D, 0x02441453, 0xD8A1E681, 0xE7D3FBC8,
|
||||
0x21E1CDE6, 0xC33707D6, 0xF4D50D87, 0x455A14ED,
|
||||
0xA9E3E905, 0xFCEFA3F8, 0x676F02D9, 0x8D2A4C8A,
|
||||
|
||||
0xFFFA3942, 0x8771F681, 0x6D9D6122, 0xFDE5380C,
|
||||
0xA4BEEA44, 0x4BDECFA9, 0xF6BB4B60, 0xBEBFBC70,
|
||||
0x289B7EC6, 0xEAA127FA, 0xD4EF3085, 0x04881D05,
|
||||
0xD9D4D039, 0xE6DB99E5, 0x1FA27CF8, 0xC4AC5665,
|
||||
|
||||
0xF4292244, 0x432AFF97, 0xAB9423A7, 0xFC93A039,
|
||||
0x655B59C3, 0x8F0CCC92, 0xFFEFF47D, 0x85845DD1,
|
||||
0x6FA87E4F, 0xFE2CE6E0, 0xA3014314, 0x4E0811A1,
|
||||
0xF7537E82, 0xBD3AF235, 0x2AD7D2BB, 0xEB86D391
|
||||
};
|
||||
|
||||
static const unsigned char MP_flash[48] PROGMEM = {
|
||||
1, 6, 11, 0, 5, 10, 15, 4, 9, 14, 3, 8, 13, 2, 7, 12,
|
||||
5, 8, 11, 14, 1, 4, 7, 10, 13, 0, 3, 6, 9, 12, 15, 2,
|
||||
0, 7, 14, 5, 12, 3, 10, 1, 8, 15, 6, 13, 4, 11, 2, 9
|
||||
};
|
||||
|
||||
/* see inner.h */
|
||||
void
|
||||
br_md5_round(const unsigned char *buf, uint32_t *val)
|
||||
{
|
||||
uint32_t m[16];
|
||||
uint32_t a, b, c, d;
|
||||
int i;
|
||||
uint8_t MP[48];
|
||||
memcpy_P(MP, MP_flash, 48);
|
||||
|
||||
a = val[0];
|
||||
b = val[1];
|
||||
c = val[2];
|
||||
d = val[3];
|
||||
/* obsolete
|
||||
for (i = 0; i < 16; i ++) {
|
||||
m[i] = br_dec32le(buf + (i << 2));
|
||||
}
|
||||
*/
|
||||
br_range_dec32le(m, 16, buf);
|
||||
|
||||
for (i = 0; i < 16; i += 4) {
|
||||
a = b + ROTL(a + F(b, c, d) + m[i + 0] + K[i + 0], 7);
|
||||
d = a + ROTL(d + F(a, b, c) + m[i + 1] + K[i + 1], 12);
|
||||
c = d + ROTL(c + F(d, a, b) + m[i + 2] + K[i + 2], 17);
|
||||
b = c + ROTL(b + F(c, d, a) + m[i + 3] + K[i + 3], 22);
|
||||
}
|
||||
for (i = 16; i < 32; i += 4) {
|
||||
a = b + ROTL(a + G(b, c, d) + m[MP[i - 16]] + K[i + 0], 5);
|
||||
d = a + ROTL(d + G(a, b, c) + m[MP[i - 15]] + K[i + 1], 9);
|
||||
c = d + ROTL(c + G(d, a, b) + m[MP[i - 14]] + K[i + 2], 14);
|
||||
b = c + ROTL(b + G(c, d, a) + m[MP[i - 13]] + K[i + 3], 20);
|
||||
}
|
||||
for (i = 32; i < 48; i += 4) {
|
||||
a = b + ROTL(a + H(b, c, d) + m[MP[i - 16]] + K[i + 0], 4);
|
||||
d = a + ROTL(d + H(a, b, c) + m[MP[i - 15]] + K[i + 1], 11);
|
||||
c = d + ROTL(c + H(d, a, b) + m[MP[i - 14]] + K[i + 2], 16);
|
||||
b = c + ROTL(b + H(c, d, a) + m[MP[i - 13]] + K[i + 3], 23);
|
||||
}
|
||||
for (i = 48; i < 64; i += 4) {
|
||||
a = b + ROTL(a + I(b, c, d) + m[MP[i - 16]] + K[i + 0], 6);
|
||||
d = a + ROTL(d + I(a, b, c) + m[MP[i - 15]] + K[i + 1], 10);
|
||||
c = d + ROTL(c + I(d, a, b) + m[MP[i - 14]] + K[i + 2], 15);
|
||||
b = c + ROTL(b + I(c, d, a) + m[MP[i - 13]] + K[i + 3], 21);
|
||||
}
|
||||
|
||||
val[0] += a;
|
||||
val[1] += b;
|
||||
val[2] += c;
|
||||
val[3] += d;
|
||||
}
|
||||
|
||||
/* see bearssl.h */
|
||||
void
|
||||
br_md5_init(br_md5_context *cc)
|
||||
{
|
||||
cc->vtable = &br_md5_vtable;
|
||||
memcpy(cc->val, br_md5_IV, sizeof cc->val);
|
||||
cc->count = 0;
|
||||
}
|
||||
|
||||
/* see bearssl.h */
|
||||
void
|
||||
br_md5_update(br_md5_context *cc, const void *data, size_t len)
|
||||
{
|
||||
const unsigned char *buf;
|
||||
size_t ptr;
|
||||
|
||||
buf = data;
|
||||
ptr = (size_t)cc->count & 63;
|
||||
while (len > 0) {
|
||||
size_t clen;
|
||||
|
||||
clen = 64 - ptr;
|
||||
if (clen > len) {
|
||||
clen = len;
|
||||
}
|
||||
memcpy(cc->buf + ptr, buf, clen);
|
||||
ptr += clen;
|
||||
buf += clen;
|
||||
len -= clen;
|
||||
cc->count += (uint64_t)clen;
|
||||
if (ptr == 64) {
|
||||
br_md5_round(cc->buf, cc->val);
|
||||
ptr = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* see bearssl.h */
|
||||
void
|
||||
br_md5_out(const br_md5_context *cc, void *dst)
|
||||
{
|
||||
unsigned char buf[64];
|
||||
uint32_t val[4];
|
||||
size_t ptr;
|
||||
|
||||
ptr = (size_t)cc->count & 63;
|
||||
memcpy(buf, cc->buf, ptr);
|
||||
memcpy(val, cc->val, sizeof val);
|
||||
buf[ptr ++] = 0x80;
|
||||
if (ptr > 56) {
|
||||
memset(buf + ptr, 0, 64 - ptr);
|
||||
br_md5_round(buf, val);
|
||||
memset(buf, 0, 56);
|
||||
} else {
|
||||
memset(buf + ptr, 0, 56 - ptr);
|
||||
}
|
||||
br_enc64le(buf + 56, cc->count << 3);
|
||||
br_md5_round(buf, val);
|
||||
br_range_enc32le(dst, val, 4);
|
||||
}
|
||||
|
||||
/* see bearssl.h */
|
||||
uint64_t
|
||||
br_md5_state(const br_md5_context *cc, void *dst)
|
||||
{
|
||||
br_range_enc32le(dst, cc->val, 4);
|
||||
return cc->count;
|
||||
}
|
||||
|
||||
/* see bearssl.h */
|
||||
void
|
||||
br_md5_set_state(br_md5_context *cc, const void *stb, uint64_t count)
|
||||
{
|
||||
br_range_dec32le(cc->val, 4, stb);
|
||||
cc->count = count;
|
||||
}
|
||||
|
||||
/* see bearssl.h */
|
||||
const br_hash_class br_md5_vtable PROGMEM = {
|
||||
sizeof(br_md5_context),
|
||||
BR_HASHDESC_ID(br_md5_ID)
|
||||
| BR_HASHDESC_OUT(16)
|
||||
| BR_HASHDESC_STATE(16)
|
||||
| BR_HASHDESC_LBLEN(6)
|
||||
| BR_HASHDESC_MD_PADDING,
|
||||
(void (*)(const br_hash_class **))&br_md5_init,
|
||||
(void (*)(const br_hash_class **, const void *, size_t))&br_md5_update,
|
||||
(void (*)(const br_hash_class *const *, void *))&br_md5_out,
|
||||
(uint64_t (*)(const br_hash_class *const *, void *))&br_md5_state,
|
||||
(void (*)(const br_hash_class **, const void *, uint64_t))
|
||||
&br_md5_set_state
|
||||
};
|
|
@ -0,0 +1,141 @@
|
|||
/*
|
||||
* Copyright (c) 2016 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 "t_inner.h"
|
||||
|
||||
/* see bearssl.h */
|
||||
void
|
||||
br_md5sha1_init(br_md5sha1_context *cc)
|
||||
{
|
||||
cc->vtable = &br_md5sha1_vtable;
|
||||
memcpy(cc->val_md5, br_md5_IV, sizeof cc->val_md5);
|
||||
memcpy(cc->val_sha1, br_sha1_IV, sizeof cc->val_sha1);
|
||||
cc->count = 0;
|
||||
}
|
||||
|
||||
/* see bearssl.h */
|
||||
void
|
||||
br_md5sha1_update(br_md5sha1_context *cc, const void *data, size_t len)
|
||||
{
|
||||
const unsigned char *buf;
|
||||
size_t ptr;
|
||||
|
||||
buf = data;
|
||||
ptr = (size_t)cc->count & 63;
|
||||
while (len > 0) {
|
||||
size_t clen;
|
||||
|
||||
clen = 64 - ptr;
|
||||
if (clen > len) {
|
||||
clen = len;
|
||||
}
|
||||
memcpy(cc->buf + ptr, buf, clen);
|
||||
ptr += clen;
|
||||
buf += clen;
|
||||
len -= clen;
|
||||
cc->count += (uint64_t)clen;
|
||||
if (ptr == 64) {
|
||||
br_md5_round(cc->buf, cc->val_md5);
|
||||
br_sha1_round(cc->buf, cc->val_sha1);
|
||||
ptr = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* see bearssl.h */
|
||||
void
|
||||
br_md5sha1_out(const br_md5sha1_context *cc, void *dst)
|
||||
{
|
||||
unsigned char buf[64];
|
||||
uint32_t val_md5[4];
|
||||
uint32_t val_sha1[5];
|
||||
size_t ptr;
|
||||
unsigned char *out;
|
||||
uint64_t count;
|
||||
|
||||
count = cc->count;
|
||||
ptr = (size_t)count & 63;
|
||||
memcpy(buf, cc->buf, ptr);
|
||||
memcpy(val_md5, cc->val_md5, sizeof val_md5);
|
||||
memcpy(val_sha1, cc->val_sha1, sizeof val_sha1);
|
||||
buf[ptr ++] = 0x80;
|
||||
if (ptr > 56) {
|
||||
memset(buf + ptr, 0, 64 - ptr);
|
||||
br_md5_round(buf, val_md5);
|
||||
br_sha1_round(buf, val_sha1);
|
||||
memset(buf, 0, 56);
|
||||
} else {
|
||||
memset(buf + ptr, 0, 56 - ptr);
|
||||
}
|
||||
count <<= 3;
|
||||
br_enc64le(buf + 56, count);
|
||||
br_md5_round(buf, val_md5);
|
||||
br_enc64be(buf + 56, count);
|
||||
br_sha1_round(buf, val_sha1);
|
||||
out = dst;
|
||||
br_range_enc32le(out, val_md5, 4);
|
||||
br_range_enc32be(out + 16, val_sha1, 5);
|
||||
}
|
||||
|
||||
/* see bearssl.h */
|
||||
uint64_t
|
||||
br_md5sha1_state(const br_md5sha1_context *cc, void *dst)
|
||||
{
|
||||
unsigned char *out;
|
||||
|
||||
out = dst;
|
||||
br_range_enc32le(out, cc->val_md5, 4);
|
||||
br_range_enc32be(out + 16, cc->val_sha1, 5);
|
||||
return cc->count;
|
||||
}
|
||||
|
||||
/* see bearssl.h */
|
||||
void
|
||||
br_md5sha1_set_state(br_md5sha1_context *cc, const void *stb, uint64_t count)
|
||||
{
|
||||
const unsigned char *buf;
|
||||
|
||||
buf = stb;
|
||||
br_range_dec32le(cc->val_md5, 4, buf);
|
||||
br_range_dec32be(cc->val_sha1, 5, buf + 16);
|
||||
cc->count = count;
|
||||
}
|
||||
|
||||
/* see bearssl.h */
|
||||
const br_hash_class br_md5sha1_vtable PROGMEM = {
|
||||
sizeof(br_md5sha1_context),
|
||||
BR_HASHDESC_ID(br_md5sha1_ID)
|
||||
| BR_HASHDESC_OUT(36)
|
||||
| BR_HASHDESC_STATE(36)
|
||||
| BR_HASHDESC_LBLEN(6),
|
||||
(void (*)(const br_hash_class **))&br_md5sha1_init,
|
||||
(void (*)(const br_hash_class **, const void *, size_t))
|
||||
&br_md5sha1_update,
|
||||
(void (*)(const br_hash_class *const *, void *))
|
||||
&br_md5sha1_out,
|
||||
(uint64_t (*)(const br_hash_class *const *, void *))
|
||||
&br_md5sha1_state,
|
||||
(void (*)(const br_hash_class **, const void *, uint64_t))
|
||||
&br_md5sha1_set_state
|
||||
};
|
|
@ -0,0 +1,56 @@
|
|||
/*
|
||||
* Copyright (c) 2018 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 "t_inner.h"
|
||||
|
||||
/* see inner.h */
|
||||
void
|
||||
br_mgf1_xor(void *data, size_t len,
|
||||
const br_hash_class *dig, const void *seed, size_t seed_len)
|
||||
{
|
||||
unsigned char *buf;
|
||||
size_t u, hlen;
|
||||
uint32_t c;
|
||||
|
||||
buf = data;
|
||||
hlen = br_digest_size(dig);
|
||||
for (u = 0, c = 0; u < len; u += hlen, c ++) {
|
||||
br_hash_compat_context hc;
|
||||
unsigned char tmp[64];
|
||||
size_t v;
|
||||
|
||||
hc.vtable = dig;
|
||||
dig->init(&hc.vtable);
|
||||
dig->update(&hc.vtable, seed, seed_len);
|
||||
br_enc32be(tmp, c);
|
||||
dig->update(&hc.vtable, tmp, 4);
|
||||
dig->out(&hc.vtable, tmp);
|
||||
for (v = 0; v < hlen; v ++) {
|
||||
if ((u + v) >= len) {
|
||||
break;
|
||||
}
|
||||
buf[u + v] ^= tmp[v];
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,166 @@
|
|||
/*
|
||||
* Copyright (c) 2016 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 "t_inner.h"
|
||||
|
||||
/*
|
||||
* An aggregate context that is large enough for all supported hash
|
||||
* functions.
|
||||
*/
|
||||
typedef union {
|
||||
const br_hash_class *vtable;
|
||||
br_md5_context md5;
|
||||
br_sha1_context sha1;
|
||||
br_sha224_context sha224;
|
||||
br_sha256_context sha256;
|
||||
br_sha384_context sha384;
|
||||
br_sha512_context sha512;
|
||||
} gen_hash_context;
|
||||
|
||||
/*
|
||||
* Get the offset to the state for a specific hash function within the
|
||||
* context structure. This shall be called only for the supported hash
|
||||
* functions,
|
||||
*/
|
||||
static size_t
|
||||
get_state_offset(int id)
|
||||
{
|
||||
if (id >= 5) {
|
||||
/*
|
||||
* SHA-384 has id 5, and SHA-512 has id 6. Both use
|
||||
* eight 64-bit words for their state.
|
||||
*/
|
||||
return offsetof(br_multihash_context, val_64)
|
||||
+ ((size_t)(id - 5) * (8 * sizeof(uint64_t)));
|
||||
} else {
|
||||
/*
|
||||
* MD5 has id 1, SHA-1 has id 2, SHA-224 has id 3 and
|
||||
* SHA-256 has id 4. They use 32-bit words for their
|
||||
* states (4 words for MD5, 5 for SHA-1, 8 for SHA-224
|
||||
* and 8 for SHA-256).
|
||||
*/
|
||||
unsigned x;
|
||||
|
||||
x = id - 1;
|
||||
x = ((x + (x & (x >> 1))) << 2) + (x >> 1);
|
||||
return offsetof(br_multihash_context, val_32)
|
||||
+ x * sizeof(uint32_t);
|
||||
}
|
||||
}
|
||||
|
||||
/* see bearssl_hash.h */
|
||||
void
|
||||
br_multihash_zero(br_multihash_context *ctx)
|
||||
{
|
||||
/*
|
||||
* This is not standard, but yields very short and efficient code,
|
||||
* and it works "everywhere".
|
||||
*/
|
||||
memset(ctx, 0, sizeof *ctx);
|
||||
}
|
||||
|
||||
/* see bearssl_hash.h */
|
||||
void
|
||||
br_multihash_init(br_multihash_context *ctx)
|
||||
{
|
||||
int i;
|
||||
|
||||
ctx->count = 0;
|
||||
for (i = 1; i <= 6; i ++) {
|
||||
const br_hash_class *hc;
|
||||
|
||||
hc = ctx->impl[i - 1];
|
||||
if (hc != NULL) {
|
||||
gen_hash_context g;
|
||||
|
||||
hc->init(&g.vtable);
|
||||
hc->state(&g.vtable,
|
||||
(unsigned char *)ctx + get_state_offset(i));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* see bearssl_hash.h */
|
||||
void
|
||||
br_multihash_update(br_multihash_context *ctx, const void *data, size_t len)
|
||||
{
|
||||
const unsigned char *buf;
|
||||
size_t ptr;
|
||||
|
||||
buf = data;
|
||||
ptr = (size_t)ctx->count & 127;
|
||||
while (len > 0) {
|
||||
size_t clen;
|
||||
|
||||
clen = 128 - ptr;
|
||||
if (clen > len) {
|
||||
clen = len;
|
||||
}
|
||||
memcpy(ctx->buf + ptr, buf, clen);
|
||||
ptr += clen;
|
||||
buf += clen;
|
||||
len -= clen;
|
||||
ctx->count += (uint64_t)clen;
|
||||
if (ptr == 128) {
|
||||
int i;
|
||||
|
||||
for (i = 1; i <= 6; i ++) {
|
||||
const br_hash_class *hc;
|
||||
|
||||
hc = ctx->impl[i - 1];
|
||||
if (hc != NULL) {
|
||||
gen_hash_context g;
|
||||
unsigned char *state;
|
||||
|
||||
state = (unsigned char *)ctx
|
||||
+ get_state_offset(i);
|
||||
hc->set_state(&g.vtable,
|
||||
state, ctx->count - 128);
|
||||
hc->update(&g.vtable, ctx->buf, 128);
|
||||
hc->state(&g.vtable, state);
|
||||
}
|
||||
}
|
||||
ptr = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* see bearssl_hash.h */
|
||||
size_t
|
||||
br_multihash_out(const br_multihash_context *ctx, int id, void *dst)
|
||||
{
|
||||
const br_hash_class *hc;
|
||||
gen_hash_context g;
|
||||
const unsigned char *state;
|
||||
|
||||
hc = ctx->impl[id - 1];
|
||||
if (hc == NULL) {
|
||||
return 0;
|
||||
}
|
||||
state = (const unsigned char *)ctx + get_state_offset(id);
|
||||
hc->set_state(&g.vtable, state, ctx->count & ~(uint64_t)127);
|
||||
hc->update(&g.vtable, ctx->buf, ctx->count & (uint64_t)127);
|
||||
hc->out(&g.vtable, dst);
|
||||
return (hc->desc >> BR_HASHDESC_OUT_OFF) & BR_HASHDESC_OUT_MASK;
|
||||
}
|
|
@ -0,0 +1,191 @@
|
|||
/*
|
||||
* Copyright (c) 2016 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 "t_inner.h"
|
||||
|
||||
#define F(B, C, D) ((((C) ^ (D)) & (B)) ^ (D))
|
||||
#define G(B, C, D) ((B) ^ (C) ^ (D))
|
||||
#define H(B, C, D) (((D) & (C)) | (((D) | (C)) & (B)))
|
||||
#define I(B, C, D) G(B, C, D)
|
||||
|
||||
#define ROTL(x, n) (((x) << (n)) | ((x) >> (32 - (n))))
|
||||
|
||||
#define K1 ((uint32_t)0x5A827999)
|
||||
#define K2 ((uint32_t)0x6ED9EBA1)
|
||||
#define K3 ((uint32_t)0x8F1BBCDC)
|
||||
#define K4 ((uint32_t)0xCA62C1D6)
|
||||
|
||||
/* see inner.h */
|
||||
const uint32_t br_sha1_IV[5] PROGMEM = {
|
||||
0x67452301, 0xEFCDAB89, 0x98BADCFE, 0x10325476, 0xC3D2E1F0
|
||||
};
|
||||
|
||||
/* see inner.h */
|
||||
void
|
||||
br_sha1_round(const unsigned char *buf, uint32_t *val)
|
||||
{
|
||||
uint32_t m[80];
|
||||
uint32_t a, b, c, d, e;
|
||||
int i;
|
||||
|
||||
a = val[0];
|
||||
b = val[1];
|
||||
c = val[2];
|
||||
d = val[3];
|
||||
e = val[4];
|
||||
br_range_dec32be(m, 16, buf);
|
||||
for (i = 16; i < 80; i ++) {
|
||||
uint32_t x = m[i - 3] ^ m[i - 8] ^ m[i - 14] ^ m[i - 16];
|
||||
m[i] = ROTL(x, 1);
|
||||
}
|
||||
|
||||
for (i = 0; i < 20; i += 5) {
|
||||
e += ROTL(a, 5) + F(b, c, d) + K1 + m[i + 0]; b = ROTL(b, 30);
|
||||
d += ROTL(e, 5) + F(a, b, c) + K1 + m[i + 1]; a = ROTL(a, 30);
|
||||
c += ROTL(d, 5) + F(e, a, b) + K1 + m[i + 2]; e = ROTL(e, 30);
|
||||
b += ROTL(c, 5) + F(d, e, a) + K1 + m[i + 3]; d = ROTL(d, 30);
|
||||
a += ROTL(b, 5) + F(c, d, e) + K1 + m[i + 4]; c = ROTL(c, 30);
|
||||
}
|
||||
for (i = 20; i < 40; i += 5) {
|
||||
e += ROTL(a, 5) + G(b, c, d) + K2 + m[i + 0]; b = ROTL(b, 30);
|
||||
d += ROTL(e, 5) + G(a, b, c) + K2 + m[i + 1]; a = ROTL(a, 30);
|
||||
c += ROTL(d, 5) + G(e, a, b) + K2 + m[i + 2]; e = ROTL(e, 30);
|
||||
b += ROTL(c, 5) + G(d, e, a) + K2 + m[i + 3]; d = ROTL(d, 30);
|
||||
a += ROTL(b, 5) + G(c, d, e) + K2 + m[i + 4]; c = ROTL(c, 30);
|
||||
}
|
||||
for (i = 40; i < 60; i += 5) {
|
||||
e += ROTL(a, 5) + H(b, c, d) + K3 + m[i + 0]; b = ROTL(b, 30);
|
||||
d += ROTL(e, 5) + H(a, b, c) + K3 + m[i + 1]; a = ROTL(a, 30);
|
||||
c += ROTL(d, 5) + H(e, a, b) + K3 + m[i + 2]; e = ROTL(e, 30);
|
||||
b += ROTL(c, 5) + H(d, e, a) + K3 + m[i + 3]; d = ROTL(d, 30);
|
||||
a += ROTL(b, 5) + H(c, d, e) + K3 + m[i + 4]; c = ROTL(c, 30);
|
||||
}
|
||||
for (i = 60; i < 80; i += 5) {
|
||||
e += ROTL(a, 5) + I(b, c, d) + K4 + m[i + 0]; b = ROTL(b, 30);
|
||||
d += ROTL(e, 5) + I(a, b, c) + K4 + m[i + 1]; a = ROTL(a, 30);
|
||||
c += ROTL(d, 5) + I(e, a, b) + K4 + m[i + 2]; e = ROTL(e, 30);
|
||||
b += ROTL(c, 5) + I(d, e, a) + K4 + m[i + 3]; d = ROTL(d, 30);
|
||||
a += ROTL(b, 5) + I(c, d, e) + K4 + m[i + 4]; c = ROTL(c, 30);
|
||||
}
|
||||
|
||||
val[0] += a;
|
||||
val[1] += b;
|
||||
val[2] += c;
|
||||
val[3] += d;
|
||||
val[4] += e;
|
||||
}
|
||||
|
||||
/* see bearssl.h */
|
||||
void
|
||||
br_sha1_init(br_sha1_context *cc)
|
||||
{
|
||||
cc->vtable = &br_sha1_vtable;
|
||||
memcpy(cc->val, br_sha1_IV, sizeof cc->val);
|
||||
cc->count = 0;
|
||||
}
|
||||
|
||||
/* see bearssl.h */
|
||||
void
|
||||
br_sha1_update(br_sha1_context *cc, const void *data, size_t len)
|
||||
{
|
||||
const unsigned char *buf;
|
||||
size_t ptr;
|
||||
|
||||
buf = data;
|
||||
ptr = (size_t)cc->count & 63;
|
||||
while (len > 0) {
|
||||
size_t clen;
|
||||
|
||||
clen = 64 - ptr;
|
||||
if (clen > len) {
|
||||
clen = len;
|
||||
}
|
||||
memcpy(cc->buf + ptr, buf, clen);
|
||||
ptr += clen;
|
||||
buf += clen;
|
||||
len -= clen;
|
||||
cc->count += (uint64_t)clen;
|
||||
if (ptr == 64) {
|
||||
br_sha1_round(cc->buf, cc->val);
|
||||
ptr = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* see bearssl.h */
|
||||
void
|
||||
br_sha1_out(const br_sha1_context *cc, void *dst)
|
||||
{
|
||||
unsigned char buf[64];
|
||||
uint32_t val[5];
|
||||
size_t ptr;
|
||||
|
||||
ptr = (size_t)cc->count & 63;
|
||||
memcpy(buf, cc->buf, ptr);
|
||||
memcpy(val, cc->val, sizeof val);
|
||||
buf[ptr ++] = 0x80;
|
||||
if (ptr > 56) {
|
||||
memset(buf + ptr, 0, 64 - ptr);
|
||||
br_sha1_round(buf, val);
|
||||
memset(buf, 0, 56);
|
||||
} else {
|
||||
memset(buf + ptr, 0, 56 - ptr);
|
||||
}
|
||||
br_enc64be(buf + 56, cc->count << 3);
|
||||
br_sha1_round(buf, val);
|
||||
br_range_enc32be(dst, val, 5);
|
||||
}
|
||||
|
||||
/* see bearssl.h */
|
||||
uint64_t
|
||||
br_sha1_state(const br_sha1_context *cc, void *dst)
|
||||
{
|
||||
br_range_enc32be(dst, cc->val, 5);
|
||||
return cc->count;
|
||||
}
|
||||
|
||||
/* see bearssl.h */
|
||||
void
|
||||
br_sha1_set_state(br_sha1_context *cc, const void *stb, uint64_t count)
|
||||
{
|
||||
br_range_dec32be(cc->val, 5, stb);
|
||||
cc->count = count;
|
||||
}
|
||||
|
||||
/* see bearssl.h */
|
||||
const br_hash_class br_sha1_vtable PROGMEM = {
|
||||
sizeof(br_sha1_context),
|
||||
BR_HASHDESC_ID(br_sha1_ID)
|
||||
| BR_HASHDESC_OUT(20)
|
||||
| BR_HASHDESC_STATE(20)
|
||||
| BR_HASHDESC_LBLEN(6)
|
||||
| BR_HASHDESC_MD_PADDING
|
||||
| BR_HASHDESC_MD_PADDING_BE,
|
||||
(void (*)(const br_hash_class **))&br_sha1_init,
|
||||
(void (*)(const br_hash_class **, const void *, size_t))&br_sha1_update,
|
||||
(void (*)(const br_hash_class *const *, void *))&br_sha1_out,
|
||||
(uint64_t (*)(const br_hash_class *const *, void *))&br_sha1_state,
|
||||
(void (*)(const br_hash_class **, const void *, uint64_t))
|
||||
&br_sha1_set_state
|
||||
};
|
|
@ -0,0 +1,285 @@
|
|||
/*
|
||||
* Copyright (c) 2016 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 "t_inner.h"
|
||||
|
||||
#define CH(X, Y, Z) ((((Y) ^ (Z)) & (X)) ^ (Z))
|
||||
#define MAJ(X, Y, Z) (((Y) & (Z)) | (((Y) | (Z)) & (X)))
|
||||
|
||||
#define ROTR(x, n) (((uint64_t)(x) << (64 - (n))) | ((uint64_t)(x) >> (n)))
|
||||
|
||||
#define BSG5_0(x) (ROTR(x, 28) ^ ROTR(x, 34) ^ ROTR(x, 39))
|
||||
#define BSG5_1(x) (ROTR(x, 14) ^ ROTR(x, 18) ^ ROTR(x, 41))
|
||||
#define SSG5_0(x) (ROTR(x, 1) ^ ROTR(x, 8) ^ (uint64_t)((x) >> 7))
|
||||
#define SSG5_1(x) (ROTR(x, 19) ^ ROTR(x, 61) ^ (uint64_t)((x) >> 6))
|
||||
|
||||
static const uint64_t IV384[8] PROGMEM = {
|
||||
0xCBBB9D5DC1059ED8, 0x629A292A367CD507,
|
||||
0x9159015A3070DD17, 0x152FECD8F70E5939,
|
||||
0x67332667FFC00B31, 0x8EB44A8768581511,
|
||||
0xDB0C2E0D64F98FA7, 0x47B5481DBEFA4FA4
|
||||
};
|
||||
|
||||
static const uint64_t IV512[8] PROGMEM = {
|
||||
0x6A09E667F3BCC908, 0xBB67AE8584CAA73B,
|
||||
0x3C6EF372FE94F82B, 0xA54FF53A5F1D36F1,
|
||||
0x510E527FADE682D1, 0x9B05688C2B3E6C1F,
|
||||
0x1F83D9ABFB41BD6B, 0x5BE0CD19137E2179
|
||||
};
|
||||
|
||||
static const uint64_t K[80] PROGMEM = {
|
||||
0x428A2F98D728AE22, 0x7137449123EF65CD,
|
||||
0xB5C0FBCFEC4D3B2F, 0xE9B5DBA58189DBBC,
|
||||
0x3956C25BF348B538, 0x59F111F1B605D019,
|
||||
0x923F82A4AF194F9B, 0xAB1C5ED5DA6D8118,
|
||||
0xD807AA98A3030242, 0x12835B0145706FBE,
|
||||
0x243185BE4EE4B28C, 0x550C7DC3D5FFB4E2,
|
||||
0x72BE5D74F27B896F, 0x80DEB1FE3B1696B1,
|
||||
0x9BDC06A725C71235, 0xC19BF174CF692694,
|
||||
0xE49B69C19EF14AD2, 0xEFBE4786384F25E3,
|
||||
0x0FC19DC68B8CD5B5, 0x240CA1CC77AC9C65,
|
||||
0x2DE92C6F592B0275, 0x4A7484AA6EA6E483,
|
||||
0x5CB0A9DCBD41FBD4, 0x76F988DA831153B5,
|
||||
0x983E5152EE66DFAB, 0xA831C66D2DB43210,
|
||||
0xB00327C898FB213F, 0xBF597FC7BEEF0EE4,
|
||||
0xC6E00BF33DA88FC2, 0xD5A79147930AA725,
|
||||
0x06CA6351E003826F, 0x142929670A0E6E70,
|
||||
0x27B70A8546D22FFC, 0x2E1B21385C26C926,
|
||||
0x4D2C6DFC5AC42AED, 0x53380D139D95B3DF,
|
||||
0x650A73548BAF63DE, 0x766A0ABB3C77B2A8,
|
||||
0x81C2C92E47EDAEE6, 0x92722C851482353B,
|
||||
0xA2BFE8A14CF10364, 0xA81A664BBC423001,
|
||||
0xC24B8B70D0F89791, 0xC76C51A30654BE30,
|
||||
0xD192E819D6EF5218, 0xD69906245565A910,
|
||||
0xF40E35855771202A, 0x106AA07032BBD1B8,
|
||||
0x19A4C116B8D2D0C8, 0x1E376C085141AB53,
|
||||
0x2748774CDF8EEB99, 0x34B0BCB5E19B48A8,
|
||||
0x391C0CB3C5C95A63, 0x4ED8AA4AE3418ACB,
|
||||
0x5B9CCA4F7763E373, 0x682E6FF3D6B2B8A3,
|
||||
0x748F82EE5DEFB2FC, 0x78A5636F43172F60,
|
||||
0x84C87814A1F0AB72, 0x8CC702081A6439EC,
|
||||
0x90BEFFFA23631E28, 0xA4506CEBDE82BDE9,
|
||||
0xBEF9A3F7B2C67915, 0xC67178F2E372532B,
|
||||
0xCA273ECEEA26619C, 0xD186B8C721C0C207,
|
||||
0xEADA7DD6CDE0EB1E, 0xF57D4F7FEE6ED178,
|
||||
0x06F067AA72176FBA, 0x0A637DC5A2C898A6,
|
||||
0x113F9804BEF90DAE, 0x1B710B35131C471B,
|
||||
0x28DB77F523047D84, 0x32CAAB7B40C72493,
|
||||
0x3C9EBE0A15C9BEBC, 0x431D67C49C100D4C,
|
||||
0x4CC5D4BECB3E42B6, 0x597F299CFC657E2A,
|
||||
0x5FCB6FAB3AD6FAEC, 0x6C44198C4A475817
|
||||
};
|
||||
|
||||
static void
|
||||
sha2big_round(const unsigned char *buf, uint64_t *val)
|
||||
{
|
||||
|
||||
#define SHA2BIG_STEP(A, B, C, D, E, F, G, H, j) do { \
|
||||
uint64_t T1, T2; \
|
||||
T1 = H + BSG5_1(E) + CH(E, F, G) + K[j] + w[j]; \
|
||||
T2 = BSG5_0(A) + MAJ(A, B, C); \
|
||||
D += T1; \
|
||||
H = T1 + T2; \
|
||||
} while (0)
|
||||
|
||||
int i;
|
||||
uint64_t a, b, c, d, e, f, g, h;
|
||||
uint64_t w[80];
|
||||
|
||||
br_range_dec64be(w, 16, buf);
|
||||
for (i = 16; i < 80; i ++) {
|
||||
w[i] = SSG5_1(w[i - 2]) + w[i - 7]
|
||||
+ SSG5_0(w[i - 15]) + w[i - 16];
|
||||
}
|
||||
a = val[0];
|
||||
b = val[1];
|
||||
c = val[2];
|
||||
d = val[3];
|
||||
e = val[4];
|
||||
f = val[5];
|
||||
g = val[6];
|
||||
h = val[7];
|
||||
for (i = 0; i < 80; i += 8) {
|
||||
SHA2BIG_STEP(a, b, c, d, e, f, g, h, i + 0);
|
||||
SHA2BIG_STEP(h, a, b, c, d, e, f, g, i + 1);
|
||||
SHA2BIG_STEP(g, h, a, b, c, d, e, f, i + 2);
|
||||
SHA2BIG_STEP(f, g, h, a, b, c, d, e, i + 3);
|
||||
SHA2BIG_STEP(e, f, g, h, a, b, c, d, i + 4);
|
||||
SHA2BIG_STEP(d, e, f, g, h, a, b, c, i + 5);
|
||||
SHA2BIG_STEP(c, d, e, f, g, h, a, b, i + 6);
|
||||
SHA2BIG_STEP(b, c, d, e, f, g, h, a, i + 7);
|
||||
}
|
||||
val[0] += a;
|
||||
val[1] += b;
|
||||
val[2] += c;
|
||||
val[3] += d;
|
||||
val[4] += e;
|
||||
val[5] += f;
|
||||
val[6] += g;
|
||||
val[7] += h;
|
||||
}
|
||||
|
||||
static void
|
||||
sha2big_update(br_sha384_context *cc, const void *data, size_t len)
|
||||
{
|
||||
const unsigned char *buf;
|
||||
size_t ptr;
|
||||
|
||||
buf = data;
|
||||
ptr = (size_t)cc->count & 127;
|
||||
cc->count += (uint64_t)len;
|
||||
while (len > 0) {
|
||||
size_t clen;
|
||||
|
||||
clen = 128 - ptr;
|
||||
if (clen > len) {
|
||||
clen = len;
|
||||
}
|
||||
memcpy(cc->buf + ptr, buf, clen);
|
||||
ptr += clen;
|
||||
buf += clen;
|
||||
len -= clen;
|
||||
if (ptr == 128) {
|
||||
sha2big_round(cc->buf, cc->val);
|
||||
ptr = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
sha2big_out(const br_sha384_context *cc, void *dst, int num)
|
||||
{
|
||||
unsigned char buf[128];
|
||||
uint64_t val[8];
|
||||
size_t ptr;
|
||||
|
||||
ptr = (size_t)cc->count & 127;
|
||||
memcpy(buf, cc->buf, ptr);
|
||||
memcpy(val, cc->val, sizeof val);
|
||||
buf[ptr ++] = 0x80;
|
||||
if (ptr > 112) {
|
||||
memset(buf + ptr, 0, 128 - ptr);
|
||||
sha2big_round(buf, val);
|
||||
memset(buf, 0, 112);
|
||||
} else {
|
||||
memset(buf + ptr, 0, 112 - ptr);
|
||||
}
|
||||
br_enc64be(buf + 112, cc->count >> 61);
|
||||
br_enc64be(buf + 120, cc->count << 3);
|
||||
sha2big_round(buf, val);
|
||||
br_range_enc64be(dst, val, num);
|
||||
}
|
||||
|
||||
/* see bearssl.h */
|
||||
void
|
||||
br_sha384_init(br_sha384_context *cc)
|
||||
{
|
||||
cc->vtable = &br_sha384_vtable;
|
||||
memcpy(cc->val, IV384, sizeof IV384);
|
||||
cc->count = 0;
|
||||
}
|
||||
|
||||
/* see bearssl.h */
|
||||
void
|
||||
br_sha384_update(br_sha384_context *cc, const void *data, size_t len)
|
||||
{
|
||||
sha2big_update(cc, data, len);
|
||||
}
|
||||
|
||||
/* see bearssl.h */
|
||||
void
|
||||
br_sha384_out(const br_sha384_context *cc, void *dst)
|
||||
{
|
||||
sha2big_out(cc, dst, 6);
|
||||
}
|
||||
|
||||
/* see bearssl.h */
|
||||
uint64_t
|
||||
br_sha384_state(const br_sha384_context *cc, void *dst)
|
||||
{
|
||||
br_range_enc64be(dst, cc->val, 8);
|
||||
return cc->count;
|
||||
}
|
||||
|
||||
/* see bearssl.h */
|
||||
void
|
||||
br_sha384_set_state(br_sha384_context *cc, const void *stb, uint64_t count)
|
||||
{
|
||||
br_range_dec64be(cc->val, 8, stb);
|
||||
cc->count = count;
|
||||
}
|
||||
|
||||
/* see bearssl.h */
|
||||
void
|
||||
br_sha512_init(br_sha512_context *cc)
|
||||
{
|
||||
cc->vtable = &br_sha512_vtable;
|
||||
memcpy(cc->val, IV512, sizeof IV512);
|
||||
cc->count = 0;
|
||||
}
|
||||
|
||||
/* see bearssl.h */
|
||||
void
|
||||
br_sha512_out(const br_sha512_context *cc, void *dst)
|
||||
{
|
||||
sha2big_out(cc, dst, 8);
|
||||
}
|
||||
|
||||
/* see bearssl.h */
|
||||
const br_hash_class br_sha384_vtable PROGMEM = {
|
||||
sizeof(br_sha384_context),
|
||||
BR_HASHDESC_ID(br_sha384_ID)
|
||||
| BR_HASHDESC_OUT(48)
|
||||
| BR_HASHDESC_STATE(64)
|
||||
| BR_HASHDESC_LBLEN(7)
|
||||
| BR_HASHDESC_MD_PADDING
|
||||
| BR_HASHDESC_MD_PADDING_BE
|
||||
| BR_HASHDESC_MD_PADDING_128,
|
||||
(void (*)(const br_hash_class **))&br_sha384_init,
|
||||
(void (*)(const br_hash_class **, const void *, size_t))
|
||||
&br_sha384_update,
|
||||
(void (*)(const br_hash_class *const *, void *))&br_sha384_out,
|
||||
(uint64_t (*)(const br_hash_class *const *, void *))&br_sha384_state,
|
||||
(void (*)(const br_hash_class **, const void *, uint64_t))
|
||||
&br_sha384_set_state
|
||||
};
|
||||
|
||||
/* see bearssl.h */
|
||||
const br_hash_class br_sha512_vtable PROGMEM = {
|
||||
sizeof(br_sha512_context),
|
||||
BR_HASHDESC_ID(br_sha512_ID)
|
||||
| BR_HASHDESC_OUT(64)
|
||||
| BR_HASHDESC_STATE(64)
|
||||
| BR_HASHDESC_LBLEN(7)
|
||||
| BR_HASHDESC_MD_PADDING
|
||||
| BR_HASHDESC_MD_PADDING_BE
|
||||
| BR_HASHDESC_MD_PADDING_128,
|
||||
(void (*)(const br_hash_class **))&br_sha512_init,
|
||||
(void (*)(const br_hash_class **, const void *, size_t))
|
||||
&br_sha512_update,
|
||||
(void (*)(const br_hash_class *const *, void *))&br_sha512_out,
|
||||
(uint64_t (*)(const br_hash_class *const *, void *))&br_sha512_state,
|
||||
(void (*)(const br_hash_class **, const void *, uint64_t))
|
||||
&br_sha512_set_state
|
||||
};
|
|
@ -0,0 +1,341 @@
|
|||
/*
|
||||
* Copyright (c) 2016 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 "t_inner.h"
|
||||
|
||||
#define CH(X, Y, Z) ((((Y) ^ (Z)) & (X)) ^ (Z))
|
||||
#define MAJ(X, Y, Z) (((Y) & (Z)) | (((Y) | (Z)) & (X)))
|
||||
|
||||
#define ROTR(x, n) (((uint32_t)(x) << (32 - (n))) | ((uint32_t)(x) >> (n)))
|
||||
|
||||
#define BSG2_0(x) (ROTR(x, 2) ^ ROTR(x, 13) ^ ROTR(x, 22))
|
||||
#define BSG2_1(x) (ROTR(x, 6) ^ ROTR(x, 11) ^ ROTR(x, 25))
|
||||
#define SSG2_0(x) (ROTR(x, 7) ^ ROTR(x, 18) ^ (uint32_t)((x) >> 3))
|
||||
#define SSG2_1(x) (ROTR(x, 17) ^ ROTR(x, 19) ^ (uint32_t)((x) >> 10))
|
||||
|
||||
/* see inner.h */
|
||||
const uint32_t br_sha224_IV[8] PROGMEM = {
|
||||
0xC1059ED8, 0x367CD507, 0x3070DD17, 0xF70E5939,
|
||||
0xFFC00B31, 0x68581511, 0x64F98FA7, 0xBEFA4FA4
|
||||
};
|
||||
|
||||
/* see inner.h */
|
||||
const uint32_t br_sha256_IV[8] PROGMEM = {
|
||||
0x6A09E667, 0xBB67AE85, 0x3C6EF372, 0xA54FF53A,
|
||||
0x510E527F, 0x9B05688C, 0x1F83D9AB, 0x5BE0CD19
|
||||
};
|
||||
|
||||
static const uint32_t K[64] PROGMEM = {
|
||||
0x428A2F98, 0x71374491, 0xB5C0FBCF, 0xE9B5DBA5,
|
||||
0x3956C25B, 0x59F111F1, 0x923F82A4, 0xAB1C5ED5,
|
||||
0xD807AA98, 0x12835B01, 0x243185BE, 0x550C7DC3,
|
||||
0x72BE5D74, 0x80DEB1FE, 0x9BDC06A7, 0xC19BF174,
|
||||
0xE49B69C1, 0xEFBE4786, 0x0FC19DC6, 0x240CA1CC,
|
||||
0x2DE92C6F, 0x4A7484AA, 0x5CB0A9DC, 0x76F988DA,
|
||||
0x983E5152, 0xA831C66D, 0xB00327C8, 0xBF597FC7,
|
||||
0xC6E00BF3, 0xD5A79147, 0x06CA6351, 0x14292967,
|
||||
0x27B70A85, 0x2E1B2138, 0x4D2C6DFC, 0x53380D13,
|
||||
0x650A7354, 0x766A0ABB, 0x81C2C92E, 0x92722C85,
|
||||
0xA2BFE8A1, 0xA81A664B, 0xC24B8B70, 0xC76C51A3,
|
||||
0xD192E819, 0xD6990624, 0xF40E3585, 0x106AA070,
|
||||
0x19A4C116, 0x1E376C08, 0x2748774C, 0x34B0BCB5,
|
||||
0x391C0CB3, 0x4ED8AA4A, 0x5B9CCA4F, 0x682E6FF3,
|
||||
0x748F82EE, 0x78A5636F, 0x84C87814, 0x8CC70208,
|
||||
0x90BEFFFA, 0xA4506CEB, 0xBEF9A3F7, 0xC67178F2
|
||||
};
|
||||
|
||||
/* see inner.h */
|
||||
void
|
||||
br_sha2small_round(const unsigned char *buf, uint32_t *val)
|
||||
{
|
||||
|
||||
#define SHA2_STEP(A, B, C, D, E, F, G, H, j) do { \
|
||||
uint32_t T1, T2; \
|
||||
T1 = H + BSG2_1(E) + CH(E, F, G) + K[j] + w[j]; \
|
||||
T2 = BSG2_0(A) + MAJ(A, B, C); \
|
||||
D += T1; \
|
||||
H = T1 + T2; \
|
||||
} while (0)
|
||||
|
||||
int i;
|
||||
uint32_t a, b, c, d, e, f, g, h;
|
||||
uint32_t w[64];
|
||||
|
||||
br_range_dec32be(w, 16, buf);
|
||||
for (i = 16; i < 64; i ++) {
|
||||
w[i] = SSG2_1(w[i - 2]) + w[i - 7]
|
||||
+ SSG2_0(w[i - 15]) + w[i - 16];
|
||||
}
|
||||
a = val[0];
|
||||
b = val[1];
|
||||
c = val[2];
|
||||
d = val[3];
|
||||
e = val[4];
|
||||
f = val[5];
|
||||
g = val[6];
|
||||
h = val[7];
|
||||
for (i = 0; i < 64; i += 8) {
|
||||
SHA2_STEP(a, b, c, d, e, f, g, h, i + 0);
|
||||
SHA2_STEP(h, a, b, c, d, e, f, g, i + 1);
|
||||
SHA2_STEP(g, h, a, b, c, d, e, f, i + 2);
|
||||
SHA2_STEP(f, g, h, a, b, c, d, e, i + 3);
|
||||
SHA2_STEP(e, f, g, h, a, b, c, d, i + 4);
|
||||
SHA2_STEP(d, e, f, g, h, a, b, c, i + 5);
|
||||
SHA2_STEP(c, d, e, f, g, h, a, b, i + 6);
|
||||
SHA2_STEP(b, c, d, e, f, g, h, a, i + 7);
|
||||
}
|
||||
val[0] += a;
|
||||
val[1] += b;
|
||||
val[2] += c;
|
||||
val[3] += d;
|
||||
val[4] += e;
|
||||
val[5] += f;
|
||||
val[6] += g;
|
||||
val[7] += h;
|
||||
|
||||
#if 0
|
||||
/* obsolete */
|
||||
#define SHA2_MEXP1(pc) do { \
|
||||
W[pc] = br_dec32be(buf + ((pc) << 2)); \
|
||||
} while (0)
|
||||
|
||||
#define SHA2_MEXP2(pc) do { \
|
||||
W[(pc) & 0x0F] = SSG2_1(W[((pc) - 2) & 0x0F]) \
|
||||
+ W[((pc) - 7) & 0x0F] \
|
||||
+ SSG2_0(W[((pc) - 15) & 0x0F]) + W[(pc) & 0x0F]; \
|
||||
} while (0)
|
||||
|
||||
#define SHA2_STEPn(n, a, b, c, d, e, f, g, h, pc) do { \
|
||||
uint32_t t1, t2; \
|
||||
SHA2_MEXP ## n(pc); \
|
||||
t1 = h + BSG2_1(e) + CH(e, f, g) \
|
||||
+ K[pcount + (pc)] + W[(pc) & 0x0F]; \
|
||||
t2 = BSG2_0(a) + MAJ(a, b, c); \
|
||||
d += t1; \
|
||||
h = t1 + t2; \
|
||||
} while (0)
|
||||
|
||||
#define SHA2_STEP1(a, b, c, d, e, f, g, h, pc) \
|
||||
SHA2_STEPn(1, a, b, c, d, e, f, g, h, pc)
|
||||
#define SHA2_STEP2(a, b, c, d, e, f, g, h, pc) \
|
||||
SHA2_STEPn(2, a, b, c, d, e, f, g, h, pc)
|
||||
|
||||
uint32_t A, B, C, D, E, F, G, H;
|
||||
uint32_t W[16];
|
||||
unsigned pcount;
|
||||
|
||||
A = val[0];
|
||||
B = val[1];
|
||||
C = val[2];
|
||||
D = val[3];
|
||||
E = val[4];
|
||||
F = val[5];
|
||||
G = val[6];
|
||||
H = val[7];
|
||||
pcount = 0;
|
||||
SHA2_STEP1(A, B, C, D, E, F, G, H, 0);
|
||||
SHA2_STEP1(H, A, B, C, D, E, F, G, 1);
|
||||
SHA2_STEP1(G, H, A, B, C, D, E, F, 2);
|
||||
SHA2_STEP1(F, G, H, A, B, C, D, E, 3);
|
||||
SHA2_STEP1(E, F, G, H, A, B, C, D, 4);
|
||||
SHA2_STEP1(D, E, F, G, H, A, B, C, 5);
|
||||
SHA2_STEP1(C, D, E, F, G, H, A, B, 6);
|
||||
SHA2_STEP1(B, C, D, E, F, G, H, A, 7);
|
||||
SHA2_STEP1(A, B, C, D, E, F, G, H, 8);
|
||||
SHA2_STEP1(H, A, B, C, D, E, F, G, 9);
|
||||
SHA2_STEP1(G, H, A, B, C, D, E, F, 10);
|
||||
SHA2_STEP1(F, G, H, A, B, C, D, E, 11);
|
||||
SHA2_STEP1(E, F, G, H, A, B, C, D, 12);
|
||||
SHA2_STEP1(D, E, F, G, H, A, B, C, 13);
|
||||
SHA2_STEP1(C, D, E, F, G, H, A, B, 14);
|
||||
SHA2_STEP1(B, C, D, E, F, G, H, A, 15);
|
||||
for (pcount = 16; pcount < 64; pcount += 16) {
|
||||
SHA2_STEP2(A, B, C, D, E, F, G, H, 0);
|
||||
SHA2_STEP2(H, A, B, C, D, E, F, G, 1);
|
||||
SHA2_STEP2(G, H, A, B, C, D, E, F, 2);
|
||||
SHA2_STEP2(F, G, H, A, B, C, D, E, 3);
|
||||
SHA2_STEP2(E, F, G, H, A, B, C, D, 4);
|
||||
SHA2_STEP2(D, E, F, G, H, A, B, C, 5);
|
||||
SHA2_STEP2(C, D, E, F, G, H, A, B, 6);
|
||||
SHA2_STEP2(B, C, D, E, F, G, H, A, 7);
|
||||
SHA2_STEP2(A, B, C, D, E, F, G, H, 8);
|
||||
SHA2_STEP2(H, A, B, C, D, E, F, G, 9);
|
||||
SHA2_STEP2(G, H, A, B, C, D, E, F, 10);
|
||||
SHA2_STEP2(F, G, H, A, B, C, D, E, 11);
|
||||
SHA2_STEP2(E, F, G, H, A, B, C, D, 12);
|
||||
SHA2_STEP2(D, E, F, G, H, A, B, C, 13);
|
||||
SHA2_STEP2(C, D, E, F, G, H, A, B, 14);
|
||||
SHA2_STEP2(B, C, D, E, F, G, H, A, 15);
|
||||
}
|
||||
val[0] += A;
|
||||
val[1] += B;
|
||||
val[2] += C;
|
||||
val[3] += D;
|
||||
val[4] += E;
|
||||
val[5] += F;
|
||||
val[6] += G;
|
||||
val[7] += H;
|
||||
#endif
|
||||
}
|
||||
|
||||
static void
|
||||
sha2small_update(br_sha224_context *cc, const void *data, size_t len)
|
||||
{
|
||||
const unsigned char *buf;
|
||||
size_t ptr;
|
||||
|
||||
buf = data;
|
||||
ptr = (size_t)cc->count & 63;
|
||||
cc->count += (uint64_t)len;
|
||||
while (len > 0) {
|
||||
size_t clen;
|
||||
|
||||
clen = 64 - ptr;
|
||||
if (clen > len) {
|
||||
clen = len;
|
||||
}
|
||||
memcpy_P(cc->buf + ptr, buf, clen);
|
||||
ptr += clen;
|
||||
buf += clen;
|
||||
len -= clen;
|
||||
if (ptr == 64) {
|
||||
br_sha2small_round(cc->buf, cc->val);
|
||||
ptr = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
sha2small_out(const br_sha224_context *cc, void *dst, int num)
|
||||
{
|
||||
unsigned char buf[64];
|
||||
uint32_t val[8];
|
||||
size_t ptr;
|
||||
|
||||
ptr = (size_t)cc->count & 63;
|
||||
memcpy(buf, cc->buf, ptr);
|
||||
memcpy(val, cc->val, sizeof val);
|
||||
buf[ptr ++] = 0x80;
|
||||
if (ptr > 56) {
|
||||
memset(buf + ptr, 0, 64 - ptr);
|
||||
br_sha2small_round(buf, val);
|
||||
memset(buf, 0, 56);
|
||||
} else {
|
||||
memset(buf + ptr, 0, 56 - ptr);
|
||||
}
|
||||
br_enc64be(buf + 56, cc->count << 3);
|
||||
br_sha2small_round(buf, val);
|
||||
br_range_enc32be(dst, val, num);
|
||||
}
|
||||
|
||||
/* see bearssl.h */
|
||||
void
|
||||
br_sha224_init(br_sha224_context *cc)
|
||||
{
|
||||
cc->vtable = &br_sha224_vtable;
|
||||
memcpy(cc->val, br_sha224_IV, sizeof cc->val);
|
||||
cc->count = 0;
|
||||
}
|
||||
|
||||
/* see bearssl.h */
|
||||
void
|
||||
br_sha224_update(br_sha224_context *cc, const void *data, size_t len)
|
||||
{
|
||||
sha2small_update(cc, data, len);
|
||||
}
|
||||
|
||||
/* see bearssl.h */
|
||||
void
|
||||
br_sha224_out(const br_sha224_context *cc, void *dst)
|
||||
{
|
||||
sha2small_out(cc, dst, 7);
|
||||
}
|
||||
|
||||
/* see bearssl.h */
|
||||
uint64_t
|
||||
br_sha224_state(const br_sha224_context *cc, void *dst)
|
||||
{
|
||||
br_range_enc32be(dst, cc->val, 8);
|
||||
return cc->count;
|
||||
}
|
||||
|
||||
/* see bearssl.h */
|
||||
void
|
||||
br_sha224_set_state(br_sha224_context *cc, const void *stb, uint64_t count)
|
||||
{
|
||||
br_range_dec32be(cc->val, 8, stb);
|
||||
cc->count = count;
|
||||
}
|
||||
|
||||
/* see bearssl.h */
|
||||
void
|
||||
br_sha256_init(br_sha256_context *cc)
|
||||
{
|
||||
cc->vtable = &br_sha256_vtable;
|
||||
memcpy(cc->val, br_sha256_IV, sizeof cc->val);
|
||||
cc->count = 0;
|
||||
}
|
||||
|
||||
/* see bearssl.h */
|
||||
void
|
||||
br_sha256_out(const br_sha256_context *cc, void *dst)
|
||||
{
|
||||
sha2small_out(cc, dst, 8);
|
||||
}
|
||||
|
||||
/* see bearssl.h */
|
||||
const br_hash_class br_sha224_vtable PROGMEM = {
|
||||
sizeof(br_sha224_context),
|
||||
BR_HASHDESC_ID(br_sha224_ID)
|
||||
| BR_HASHDESC_OUT(28)
|
||||
| BR_HASHDESC_STATE(32)
|
||||
| BR_HASHDESC_LBLEN(6)
|
||||
| BR_HASHDESC_MD_PADDING
|
||||
| BR_HASHDESC_MD_PADDING_BE,
|
||||
(void (*)(const br_hash_class **))&br_sha224_init,
|
||||
(void (*)(const br_hash_class **,
|
||||
const void *, size_t))&br_sha224_update,
|
||||
(void (*)(const br_hash_class *const *, void *))&br_sha224_out,
|
||||
(uint64_t (*)(const br_hash_class *const *, void *))&br_sha224_state,
|
||||
(void (*)(const br_hash_class **, const void *, uint64_t))
|
||||
&br_sha224_set_state
|
||||
};
|
||||
|
||||
/* see bearssl.h */
|
||||
const br_hash_class br_sha256_vtable PROGMEM = {
|
||||
sizeof(br_sha256_context),
|
||||
BR_HASHDESC_ID(br_sha256_ID)
|
||||
| BR_HASHDESC_OUT(32)
|
||||
| BR_HASHDESC_STATE(32)
|
||||
| BR_HASHDESC_LBLEN(6)
|
||||
| BR_HASHDESC_MD_PADDING
|
||||
| BR_HASHDESC_MD_PADDING_BE,
|
||||
(void (*)(const br_hash_class **))&br_sha256_init,
|
||||
(void (*)(const br_hash_class **,
|
||||
const void *, size_t))&br_sha256_update,
|
||||
(void (*)(const br_hash_class *const *, void *))&br_sha256_out,
|
||||
(uint64_t (*)(const br_hash_class *const *, void *))&br_sha256_state,
|
||||
(void (*)(const br_hash_class **, const void *, uint64_t))
|
||||
&br_sha256_set_state
|
||||
};
|
|
@ -0,0 +1,46 @@
|
|||
/*
|
||||
* 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 "t_inner.h"
|
||||
|
||||
/* see inner.h */
|
||||
uint32_t
|
||||
br_i15_add(uint16_t *a, const uint16_t *b, uint32_t ctl)
|
||||
{
|
||||
uint32_t cc;
|
||||
size_t u, m;
|
||||
|
||||
cc = 0;
|
||||
m = (a[0] + 31) >> 4;
|
||||
for (u = 1; u < m; u ++) {
|
||||
uint32_t aw, bw, naw;
|
||||
|
||||
aw = a[u];
|
||||
bw = pgm_read_word(&b[u]);
|
||||
naw = aw + bw + cc;
|
||||
cc = naw >> 15;
|
||||
a[u] = MUX(ctl, naw & 0x7FFF, aw);
|
||||
}
|
||||
return cc;
|
||||
}
|
|
@ -0,0 +1,44 @@
|
|||
/*
|
||||
* 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 "t_inner.h"
|
||||
|
||||
/* see inner.h */
|
||||
uint32_t
|
||||
br_i15_bit_length(uint16_t *x, size_t xlen)
|
||||
{
|
||||
uint32_t tw, twk;
|
||||
|
||||
tw = 0;
|
||||
twk = 0;
|
||||
while (xlen -- > 0) {
|
||||
uint32_t w, c;
|
||||
|
||||
c = EQ(tw, 0);
|
||||
w = x[xlen];
|
||||
tw = MUX(c, w, tw);
|
||||
twk = MUX(c, (uint32_t)xlen, twk);
|
||||
}
|
||||
return (twk << 4) + BIT_LENGTH(tw);
|
||||
}
|
|
@ -0,0 +1,124 @@
|
|||
/*
|
||||
* 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 "t_inner.h"
|
||||
|
||||
/* see inner.h */
|
||||
uint32_t
|
||||
br_i15_decode_mod(uint16_t *x, const void *src, size_t len, const uint16_t *m)
|
||||
{
|
||||
/*
|
||||
* Two-pass algorithm: in the first pass, we determine whether the
|
||||
* value fits; in the second pass, we do the actual write.
|
||||
*
|
||||
* During the first pass, 'r' contains the comparison result so
|
||||
* far:
|
||||
* 0x00000000 value is equal to the modulus
|
||||
* 0x00000001 value is greater than the modulus
|
||||
* 0xFFFFFFFF value is lower than the modulus
|
||||
*
|
||||
* Since we iterate starting with the least significant bytes (at
|
||||
* the end of src[]), each new comparison overrides the previous
|
||||
* except when the comparison yields 0 (equal).
|
||||
*
|
||||
* During the second pass, 'r' is either 0xFFFFFFFF (value fits)
|
||||
* or 0x00000000 (value does not fit).
|
||||
*
|
||||
* We must iterate over all bytes of the source, _and_ possibly
|
||||
* some extra virtual bytes (with value 0) so as to cover the
|
||||
* complete modulus as well. We also add 4 such extra bytes beyond
|
||||
* the modulus length because it then guarantees that no accumulated
|
||||
* partial word remains to be processed.
|
||||
*/
|
||||
const unsigned char *buf;
|
||||
size_t mlen, tlen;
|
||||
int pass;
|
||||
uint32_t r;
|
||||
|
||||
buf = src;
|
||||
mlen = (pgm_read_word(&m[0]) + 15) >> 4;
|
||||
tlen = (mlen << 1);
|
||||
if (tlen < len) {
|
||||
tlen = len;
|
||||
}
|
||||
tlen += 4;
|
||||
r = 0;
|
||||
for (pass = 0; pass < 2; pass ++) {
|
||||
size_t u, v;
|
||||
uint32_t acc;
|
||||
int acc_len;
|
||||
|
||||
v = 1;
|
||||
acc = 0;
|
||||
acc_len = 0;
|
||||
for (u = 0; u < tlen; u ++) {
|
||||
uint32_t b;
|
||||
|
||||
if (u < len) {
|
||||
b = pgm_read_byte(&buf[len - 1 - u]);
|
||||
} else {
|
||||
b = 0;
|
||||
}
|
||||
acc |= (b << acc_len);
|
||||
acc_len += 8;
|
||||
if (acc_len >= 15) {
|
||||
uint32_t xw;
|
||||
|
||||
xw = acc & (uint32_t)0x7FFF;
|
||||
acc_len -= 15;
|
||||
acc = b >> (8 - acc_len);
|
||||
if (v <= mlen) {
|
||||
if (pass) {
|
||||
x[v] = r & xw;
|
||||
} else {
|
||||
uint32_t cc;
|
||||
|
||||
cc = (uint32_t)CMP(xw, pgm_read_word(&m[v]));
|
||||
r = MUX(EQ(cc, 0), r, cc);
|
||||
}
|
||||
} else {
|
||||
if (!pass) {
|
||||
r = MUX(EQ(xw, 0), r, 1);
|
||||
}
|
||||
}
|
||||
v ++;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* When we reach this point at the end of the first pass:
|
||||
* r is either 0, 1 or -1; we want to set r to 0 if it
|
||||
* is equal to 0 or 1, and leave it to -1 otherwise.
|
||||
*
|
||||
* When we reach this point at the end of the second pass:
|
||||
* r is either 0 or -1; we want to leave that value
|
||||
* untouched. This is a subcase of the previous.
|
||||
*/
|
||||
r >>= 1;
|
||||
r |= (r << 1);
|
||||
}
|
||||
|
||||
x[0] = pgm_read_word(&m[0]);
|
||||
return r & (uint32_t)1;
|
||||
}
|
|
@ -0,0 +1,56 @@
|
|||
/*
|
||||
* 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 "t_inner.h"
|
||||
|
||||
/* see inner.h */
|
||||
void
|
||||
br_i15_decode(uint16_t *x, const void *src, size_t len)
|
||||
{
|
||||
const unsigned char *buf;
|
||||
size_t v;
|
||||
uint32_t acc;
|
||||
int acc_len;
|
||||
|
||||
buf = src;
|
||||
v = 1;
|
||||
acc = 0;
|
||||
acc_len = 0;
|
||||
while (len -- > 0) {
|
||||
uint32_t b;
|
||||
|
||||
b = pgm_read_byte(&buf[len]);
|
||||
acc |= (b << acc_len);
|
||||
acc_len += 8;
|
||||
if (acc_len >= 15) {
|
||||
x[v ++] = acc & 0x7FFF;
|
||||
acc_len -= 15;
|
||||
acc >>= 15;
|
||||
}
|
||||
}
|
||||
if (acc_len != 0) {
|
||||
x[v ++] = acc;
|
||||
}
|
||||
x[0] = br_i15_bit_length(x + 1, v - 1);
|
||||
}
|
|
@ -0,0 +1,100 @@
|
|||
/*
|
||||
* 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 "t_inner.h"
|
||||
|
||||
/* see inner.h */
|
||||
void
|
||||
br_i15_decode_reduce(uint16_t *x,
|
||||
const void *src, size_t len, const uint16_t *m)
|
||||
{
|
||||
uint32_t m_ebitlen, m_rbitlen;
|
||||
size_t mblen, k;
|
||||
const unsigned char *buf;
|
||||
uint32_t acc;
|
||||
int acc_len;
|
||||
|
||||
/*
|
||||
* Get the encoded bit length.
|
||||
*/
|
||||
m_ebitlen = pgm_read_word(&m[0]);
|
||||
|
||||
/*
|
||||
* Special case for an invalid (null) modulus.
|
||||
*/
|
||||
if (m_ebitlen == 0) {
|
||||
x[0] = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* Clear the destination.
|
||||
*/
|
||||
br_i15_zero(x, m_ebitlen);
|
||||
|
||||
/*
|
||||
* First decode directly as many bytes as possible. This requires
|
||||
* computing the actual bit length.
|
||||
*/
|
||||
m_rbitlen = m_ebitlen >> 4;
|
||||
m_rbitlen = (m_ebitlen & 15) + (m_rbitlen << 4) - m_rbitlen;
|
||||
mblen = (m_rbitlen + 7) >> 3;
|
||||
k = mblen - 1;
|
||||
if (k >= len) {
|
||||
br_i15_decode(x, src, len);
|
||||
x[0] = m_ebitlen;
|
||||
return;
|
||||
}
|
||||
buf = src;
|
||||
br_i15_decode(x, buf, k);
|
||||
x[0] = m_ebitlen;
|
||||
|
||||
/*
|
||||
* Input remaining bytes, using 15-bit words.
|
||||
*/
|
||||
acc = 0;
|
||||
acc_len = 0;
|
||||
while (k < len) {
|
||||
uint32_t v;
|
||||
|
||||
v = pgm_read_byte(&buf[k ++]);
|
||||
acc = (acc << 8) | v;
|
||||
acc_len += 8;
|
||||
if (acc_len >= 15) {
|
||||
br_i15_muladd_small(x, acc >> (acc_len - 15), m);
|
||||
acc_len -= 15;
|
||||
acc &= ~((uint32_t)-1 << acc_len);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* We may have some bits accumulated. We then perform a shift to
|
||||
* be able to inject these bits as a full 15-bit word.
|
||||
*/
|
||||
if (acc_len != 0) {
|
||||
acc = (acc | (x[1] << acc_len)) & 0x7FFF;
|
||||
br_i15_rshift(x, 15 - acc_len);
|
||||
br_i15_muladd_small(x, acc, m);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,56 @@
|
|||
/*
|
||||
* 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 "t_inner.h"
|
||||
|
||||
/* see inner.h */
|
||||
void
|
||||
br_i15_encode(void *dst, size_t len, const uint16_t *x)
|
||||
{
|
||||
unsigned char *buf;
|
||||
size_t u, xlen;
|
||||
uint32_t acc;
|
||||
int acc_len;
|
||||
|
||||
xlen = (pgm_read_word(&x[0]) + 15) >> 4;
|
||||
if (xlen == 0) {
|
||||
memset(dst, 0, len);
|
||||
return;
|
||||
}
|
||||
u = 1;
|
||||
acc = 0;
|
||||
acc_len = 0;
|
||||
buf = dst;
|
||||
while (len -- > 0) {
|
||||
if (acc_len < 8) {
|
||||
if (u <= xlen) {
|
||||
acc += (uint32_t)pgm_read_word(&x[u ++]) << acc_len;
|
||||
}
|
||||
acc_len += 15;
|
||||
}
|
||||
buf[len] = (unsigned char)acc;
|
||||
acc >>= 8;
|
||||
acc_len -= 8;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,59 @@
|
|||
/*
|
||||
* 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 "t_inner.h"
|
||||
|
||||
/* see inner.h */
|
||||
void
|
||||
br_i15_from_monty(uint16_t *x, const uint16_t *m, uint16_t m0i)
|
||||
{
|
||||
size_t len, u, v;
|
||||
|
||||
len = (pgm_read_word(&m[0]) + 15) >> 4;
|
||||
for (u = 0; u < len; u ++) {
|
||||
uint32_t f, cc;
|
||||
|
||||
f = MUL15(x[1], m0i) & 0x7FFF;
|
||||
cc = 0;
|
||||
for (v = 0; v < len; v ++) {
|
||||
uint32_t z;
|
||||
|
||||
z = (uint32_t)x[v + 1] + MUL15(f, pgm_read_word(&m[v + 1])) + cc;
|
||||
cc = z >> 15;
|
||||
if (v != 0) {
|
||||
x[v] = z & 0x7FFF;
|
||||
}
|
||||
}
|
||||
x[len] = cc;
|
||||
}
|
||||
|
||||
/*
|
||||
* We may have to do an extra subtraction, but only if the
|
||||
* value in x[] is indeed greater than or equal to that of m[],
|
||||
* which is why we must do two calls (first call computes the
|
||||
* carry, second call performs the subtraction only if the carry
|
||||
* is 0).
|
||||
*/
|
||||
br_i15_sub(x, m, NOT(br_i15_sub(x, m, 0)));
|
||||
}
|
|
@ -0,0 +1,39 @@
|
|||
/*
|
||||
* 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 "t_inner.h"
|
||||
|
||||
/* see inner.h */
|
||||
uint32_t
|
||||
br_i15_iszero(const uint16_t *x)
|
||||
{
|
||||
uint32_t z;
|
||||
size_t u;
|
||||
|
||||
z = 0;
|
||||
for (u = (pgm_read_word(&x[0]) + 15) >> 4; u > 0; u --) {
|
||||
z |= pgm_read_word(&x[u]);
|
||||
}
|
||||
return ~(z | -z) >> 31;
|
||||
}
|
|
@ -0,0 +1,465 @@
|
|||
/*
|
||||
* Copyright (c) 2018 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 "t_inner.h"
|
||||
|
||||
/*
|
||||
* In this file, we handle big integers with a custom format, i.e.
|
||||
* without the usual one-word header. Value is split into 15-bit words,
|
||||
* each stored in a 16-bit slot (top bit is zero) in little-endian
|
||||
* order. The length (in words) is provided explicitly. In some cases,
|
||||
* the value can be negative (using two's complement representation). In
|
||||
* some cases, the top word is allowed to have a 16th bit.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Negate big integer conditionally. The value consists of 'len' words,
|
||||
* with 15 bits in each word (the top bit of each word should be 0,
|
||||
* except possibly for the last word). If 'ctl' is 1, the negation is
|
||||
* computed; otherwise, if 'ctl' is 0, then the value is unchanged.
|
||||
*/
|
||||
static void
|
||||
cond_negate(uint16_t *a, size_t len, uint32_t ctl)
|
||||
{
|
||||
size_t k;
|
||||
uint32_t cc, xm;
|
||||
|
||||
cc = ctl;
|
||||
xm = 0x7FFF & -ctl;
|
||||
for (k = 0; k < len; k ++) {
|
||||
uint32_t aw;
|
||||
|
||||
aw = a[k];
|
||||
aw = (aw ^ xm) + cc;
|
||||
a[k] = aw & 0x7FFF;
|
||||
cc = (aw >> 15) & 1;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Finish modular reduction. Rules on input parameters:
|
||||
*
|
||||
* if neg = 1, then -m <= a < 0
|
||||
* if neg = 0, then 0 <= a < 2*m
|
||||
*
|
||||
* If neg = 0, then the top word of a[] may use 16 bits.
|
||||
*
|
||||
* Also, modulus m must be odd.
|
||||
*/
|
||||
static void
|
||||
finish_mod(uint16_t *a, size_t len, const uint16_t *m, uint32_t neg)
|
||||
{
|
||||
size_t k;
|
||||
uint32_t cc, xm, ym;
|
||||
|
||||
/*
|
||||
* First pass: compare a (assumed nonnegative) with m.
|
||||
*/
|
||||
cc = 0;
|
||||
for (k = 0; k < len; k ++) {
|
||||
uint32_t aw, mw;
|
||||
|
||||
aw = a[k];
|
||||
mw = pgm_read_word(&m[k]);
|
||||
cc = (aw - mw - cc) >> 31;
|
||||
}
|
||||
|
||||
/*
|
||||
* At this point:
|
||||
* if neg = 1, then we must add m (regardless of cc)
|
||||
* if neg = 0 and cc = 0, then we must subtract m
|
||||
* if neg = 0 and cc = 1, then we must do nothing
|
||||
*/
|
||||
xm = 0x7FFF & -neg;
|
||||
ym = -(neg | (1 - cc));
|
||||
cc = neg;
|
||||
for (k = 0; k < len; k ++) {
|
||||
uint32_t aw, mw;
|
||||
|
||||
aw = a[k];
|
||||
mw = (pgm_read_word(&m[k]) ^ xm) & ym;
|
||||
aw = aw - mw - cc;
|
||||
a[k] = aw & 0x7FFF;
|
||||
cc = aw >> 31;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Compute:
|
||||
* a <- (a*pa+b*pb)/(2^15)
|
||||
* b <- (a*qa+b*qb)/(2^15)
|
||||
* The division is assumed to be exact (i.e. the low word is dropped).
|
||||
* If the final a is negative, then it is negated. Similarly for b.
|
||||
* Returned value is the combination of two bits:
|
||||
* bit 0: 1 if a had to be negated, 0 otherwise
|
||||
* bit 1: 1 if b had to be negated, 0 otherwise
|
||||
*
|
||||
* Factors pa, pb, qa and qb must be at most 2^15 in absolute value.
|
||||
* Source integers a and b must be nonnegative; top word is not allowed
|
||||
* to contain an extra 16th bit.
|
||||
*/
|
||||
static uint32_t
|
||||
co_reduce(uint16_t *a, uint16_t *b, size_t len,
|
||||
int32_t pa, int32_t pb, int32_t qa, int32_t qb)
|
||||
{
|
||||
size_t k;
|
||||
int32_t cca, ccb;
|
||||
uint32_t nega, negb;
|
||||
|
||||
cca = 0;
|
||||
ccb = 0;
|
||||
for (k = 0; k < len; k ++) {
|
||||
uint32_t wa, wb, za, zb;
|
||||
uint16_t tta, ttb;
|
||||
|
||||
/*
|
||||
* Since:
|
||||
* |pa| <= 2^15
|
||||
* |pb| <= 2^15
|
||||
* 0 <= wa <= 2^15 - 1
|
||||
* 0 <= wb <= 2^15 - 1
|
||||
* |cca| <= 2^16 - 1
|
||||
* Then:
|
||||
* |za| <= (2^15-1)*(2^16) + (2^16-1) = 2^31 - 1
|
||||
*
|
||||
* Thus, the new value of cca is such that |cca| <= 2^16 - 1.
|
||||
* The same applies to ccb.
|
||||
*/
|
||||
wa = a[k];
|
||||
wb = b[k];
|
||||
za = wa * (uint32_t)pa + wb * (uint32_t)pb + (uint32_t)cca;
|
||||
zb = wa * (uint32_t)qa + wb * (uint32_t)qb + (uint32_t)ccb;
|
||||
if (k > 0) {
|
||||
a[k - 1] = za & 0x7FFF;
|
||||
b[k - 1] = zb & 0x7FFF;
|
||||
}
|
||||
tta = za >> 15;
|
||||
ttb = zb >> 15;
|
||||
cca = *(int16_t *)&tta;
|
||||
ccb = *(int16_t *)&ttb;
|
||||
}
|
||||
a[len - 1] = (uint16_t)cca;
|
||||
b[len - 1] = (uint16_t)ccb;
|
||||
nega = (uint32_t)cca >> 31;
|
||||
negb = (uint32_t)ccb >> 31;
|
||||
cond_negate(a, len, nega);
|
||||
cond_negate(b, len, negb);
|
||||
return nega | (negb << 1);
|
||||
}
|
||||
|
||||
/*
|
||||
* Compute:
|
||||
* a <- (a*pa+b*pb)/(2^15) mod m
|
||||
* b <- (a*qa+b*qb)/(2^15) mod m
|
||||
*
|
||||
* m0i is equal to -1/m[0] mod 2^15.
|
||||
*
|
||||
* Factors pa, pb, qa and qb must be at most 2^15 in absolute value.
|
||||
* Source integers a and b must be nonnegative; top word is not allowed
|
||||
* to contain an extra 16th bit.
|
||||
*/
|
||||
static void
|
||||
co_reduce_mod(uint16_t *a, uint16_t *b, size_t len,
|
||||
int32_t pa, int32_t pb, int32_t qa, int32_t qb,
|
||||
const uint16_t *m, uint16_t m0i)
|
||||
{
|
||||
size_t k;
|
||||
int32_t cca, ccb, fa, fb;
|
||||
|
||||
cca = 0;
|
||||
ccb = 0;
|
||||
fa = ((a[0] * (uint32_t)pa + b[0] * (uint32_t)pb) * m0i) & 0x7FFF;
|
||||
fb = ((a[0] * (uint32_t)qa + b[0] * (uint32_t)qb) * m0i) & 0x7FFF;
|
||||
for (k = 0; k < len; k ++) {
|
||||
uint32_t wa, wb, za, zb;
|
||||
uint32_t tta, ttb;
|
||||
|
||||
/*
|
||||
* In this loop, carries 'cca' and 'ccb' always fit on
|
||||
* 17 bits (in absolute value).
|
||||
*/
|
||||
wa = a[k];
|
||||
wb = b[k];
|
||||
za = wa * (uint32_t)pa + wb * (uint32_t)pb
|
||||
+ pgm_read_word(&m[k]) * (uint32_t)fa + (uint32_t)cca;
|
||||
zb = wa * (uint32_t)qa + wb * (uint32_t)qb
|
||||
+ pgm_read_word(&m[k]) * (uint32_t)fb + (uint32_t)ccb;
|
||||
if (k > 0) {
|
||||
a[k - 1] = za & 0x7FFF;
|
||||
b[k - 1] = zb & 0x7FFF;
|
||||
}
|
||||
|
||||
/*
|
||||
* The XOR-and-sub construction below does an arithmetic
|
||||
* right shift in a portable way (technically, right-shifting
|
||||
* a negative signed value is implementation-defined in C).
|
||||
*/
|
||||
#define M ((uint32_t)1 << 16)
|
||||
tta = za >> 15;
|
||||
ttb = zb >> 15;
|
||||
tta = (tta ^ M) - M;
|
||||
ttb = (ttb ^ M) - M;
|
||||
cca = *(int32_t *)&tta;
|
||||
ccb = *(int32_t *)&ttb;
|
||||
#undef M
|
||||
}
|
||||
a[len - 1] = (uint32_t)cca;
|
||||
b[len - 1] = (uint32_t)ccb;
|
||||
|
||||
/*
|
||||
* At this point:
|
||||
* -m <= a < 2*m
|
||||
* -m <= b < 2*m
|
||||
* (this is a case of Montgomery reduction)
|
||||
* The top word of 'a' and 'b' may have a 16-th bit set.
|
||||
* We may have to add or subtract the modulus.
|
||||
*/
|
||||
finish_mod(a, len, m, (uint32_t)cca >> 31);
|
||||
finish_mod(b, len, m, (uint32_t)ccb >> 31);
|
||||
}
|
||||
|
||||
/* see inner.h */
|
||||
uint32_t
|
||||
br_i15_moddiv(uint16_t *x, const uint16_t *y, const uint16_t *m, uint16_t m0i,
|
||||
uint16_t *t)
|
||||
{
|
||||
/*
|
||||
* Algorithm is an extended binary GCD. We maintain four values
|
||||
* a, b, u and v, with the following invariants:
|
||||
*
|
||||
* a * x = y * u mod m
|
||||
* b * x = y * v mod m
|
||||
*
|
||||
* Starting values are:
|
||||
*
|
||||
* a = y
|
||||
* b = m
|
||||
* u = x
|
||||
* v = 0
|
||||
*
|
||||
* The formal definition of the algorithm is a sequence of steps:
|
||||
*
|
||||
* - If a is even, then a <- a/2 and u <- u/2 mod m.
|
||||
* - Otherwise, if b is even, then b <- b/2 and v <- v/2 mod m.
|
||||
* - Otherwise, if a > b, then a <- (a-b)/2 and u <- (u-v)/2 mod m.
|
||||
* - Otherwise, b <- (b-a)/2 and v <- (v-u)/2 mod m.
|
||||
*
|
||||
* Algorithm stops when a = b. At that point, they both are equal
|
||||
* to GCD(y,m); the modular division succeeds if that value is 1.
|
||||
* The result of the modular division is then u (or v: both are
|
||||
* equal at that point).
|
||||
*
|
||||
* Each step makes either a or b shrink by at least one bit; hence,
|
||||
* if m has bit length k bits, then 2k-2 steps are sufficient.
|
||||
*
|
||||
*
|
||||
* Though complexity is quadratic in the size of m, the bit-by-bit
|
||||
* processing is not very efficient. We can speed up processing by
|
||||
* remarking that the decisions are taken based only on observation
|
||||
* of the top and low bits of a and b.
|
||||
*
|
||||
* In the loop below, at each iteration, we use the two top words
|
||||
* of a and b, and the low words of a and b, to compute reduction
|
||||
* parameters pa, pb, qa and qb such that the new values for a
|
||||
* and b are:
|
||||
*
|
||||
* a' = (a*pa + b*pb) / (2^15)
|
||||
* b' = (a*qa + b*qb) / (2^15)
|
||||
*
|
||||
* the division being exact.
|
||||
*
|
||||
* Since the choices are based on the top words, they may be slightly
|
||||
* off, requiring an optional correction: if a' < 0, then we replace
|
||||
* pa with -pa, and pb with -pb. The total length of a and b is
|
||||
* thus reduced by at least 14 bits at each iteration.
|
||||
*
|
||||
* The stopping conditions are still the same, though: when a
|
||||
* and b become equal, they must be both odd (since m is odd,
|
||||
* the GCD cannot be even), therefore the next operation is a
|
||||
* subtraction, and one of the values becomes 0. At that point,
|
||||
* nothing else happens, i.e. one value is stuck at 0, and the
|
||||
* other one is the GCD.
|
||||
*/
|
||||
size_t len, k;
|
||||
uint16_t *a, *b, *u, *v;
|
||||
uint32_t num, r;
|
||||
|
||||
len = (pgm_read_word(&m[0]) + 15) >> 4;
|
||||
a = t;
|
||||
b = a + len;
|
||||
u = x + 1;
|
||||
v = b + len;
|
||||
memcpy_P(a, y + 1, len * sizeof *y);
|
||||
memcpy_P(b, m + 1, len * sizeof *m);
|
||||
memset(v, 0, len * sizeof *v);
|
||||
|
||||
/*
|
||||
* Loop below ensures that a and b are reduced by some bits each,
|
||||
* for a total of at least 14 bits.
|
||||
*/
|
||||
for (num = ((pgm_read_word(&m[0]) - (pgm_read_word(&m[0]) >> 4)) << 1) + 14; num >= 14; num -= 14) {
|
||||
size_t j;
|
||||
uint32_t c0, c1;
|
||||
uint32_t a0, a1, b0, b1;
|
||||
uint32_t a_hi, b_hi, a_lo, b_lo;
|
||||
int32_t pa, pb, qa, qb;
|
||||
int i;
|
||||
|
||||
/*
|
||||
* Extract top words of a and b. If j is the highest
|
||||
* index >= 1 such that a[j] != 0 or b[j] != 0, then we want
|
||||
* (a[j] << 15) + a[j - 1], and (b[j] << 15) + b[j - 1].
|
||||
* If a and b are down to one word each, then we use a[0]
|
||||
* and b[0].
|
||||
*/
|
||||
c0 = (uint32_t)-1;
|
||||
c1 = (uint32_t)-1;
|
||||
a0 = 0;
|
||||
a1 = 0;
|
||||
b0 = 0;
|
||||
b1 = 0;
|
||||
j = len;
|
||||
while (j -- > 0) {
|
||||
uint32_t aw, bw;
|
||||
|
||||
aw = a[j];
|
||||
bw = b[j];
|
||||
a0 ^= (a0 ^ aw) & c0;
|
||||
a1 ^= (a1 ^ aw) & c1;
|
||||
b0 ^= (b0 ^ bw) & c0;
|
||||
b1 ^= (b1 ^ bw) & c1;
|
||||
c1 = c0;
|
||||
c0 &= (((aw | bw) + 0xFFFF) >> 16) - (uint32_t)1;
|
||||
}
|
||||
|
||||
/*
|
||||
* If c1 = 0, then we grabbed two words for a and b.
|
||||
* If c1 != 0 but c0 = 0, then we grabbed one word. It
|
||||
* is not possible that c1 != 0 and c0 != 0, because that
|
||||
* would mean that both integers are zero.
|
||||
*/
|
||||
a1 |= a0 & c1;
|
||||
a0 &= ~c1;
|
||||
b1 |= b0 & c1;
|
||||
b0 &= ~c1;
|
||||
a_hi = (a0 << 15) + a1;
|
||||
b_hi = (b0 << 15) + b1;
|
||||
a_lo = a[0];
|
||||
b_lo = b[0];
|
||||
|
||||
/*
|
||||
* Compute reduction factors:
|
||||
*
|
||||
* a' = a*pa + b*pb
|
||||
* b' = a*qa + b*qb
|
||||
*
|
||||
* such that a' and b' are both multiple of 2^15, but are
|
||||
* only marginally larger than a and b.
|
||||
*/
|
||||
pa = 1;
|
||||
pb = 0;
|
||||
qa = 0;
|
||||
qb = 1;
|
||||
for (i = 0; i < 15; i ++) {
|
||||
/*
|
||||
* At each iteration:
|
||||
*
|
||||
* a <- (a-b)/2 if: a is odd, b is odd, a_hi > b_hi
|
||||
* b <- (b-a)/2 if: a is odd, b is odd, a_hi <= b_hi
|
||||
* a <- a/2 if: a is even
|
||||
* b <- b/2 if: a is odd, b is even
|
||||
*
|
||||
* We multiply a_lo and b_lo by 2 at each
|
||||
* iteration, thus a division by 2 really is a
|
||||
* non-multiplication by 2.
|
||||
*/
|
||||
uint32_t r, oa, ob, cAB, cBA, cA;
|
||||
|
||||
/*
|
||||
* cAB = 1 if b must be subtracted from a
|
||||
* cBA = 1 if a must be subtracted from b
|
||||
* cA = 1 if a is divided by 2, 0 otherwise
|
||||
*
|
||||
* Rules:
|
||||
*
|
||||
* cAB and cBA cannot be both 1.
|
||||
* if a is not divided by 2, b is.
|
||||
*/
|
||||
r = GT(a_hi, b_hi);
|
||||
oa = (a_lo >> i) & 1;
|
||||
ob = (b_lo >> i) & 1;
|
||||
cAB = oa & ob & r;
|
||||
cBA = oa & ob & NOT(r);
|
||||
cA = cAB | NOT(oa);
|
||||
|
||||
/*
|
||||
* Conditional subtractions.
|
||||
*/
|
||||
a_lo -= b_lo & -cAB;
|
||||
a_hi -= b_hi & -cAB;
|
||||
pa -= qa & -(int32_t)cAB;
|
||||
pb -= qb & -(int32_t)cAB;
|
||||
b_lo -= a_lo & -cBA;
|
||||
b_hi -= a_hi & -cBA;
|
||||
qa -= pa & -(int32_t)cBA;
|
||||
qb -= pb & -(int32_t)cBA;
|
||||
|
||||
/*
|
||||
* Shifting.
|
||||
*/
|
||||
a_lo += a_lo & (cA - 1);
|
||||
pa += pa & ((int32_t)cA - 1);
|
||||
pb += pb & ((int32_t)cA - 1);
|
||||
a_hi ^= (a_hi ^ (a_hi >> 1)) & -cA;
|
||||
b_lo += b_lo & -cA;
|
||||
qa += qa & -(int32_t)cA;
|
||||
qb += qb & -(int32_t)cA;
|
||||
b_hi ^= (b_hi ^ (b_hi >> 1)) & (cA - 1);
|
||||
}
|
||||
|
||||
/*
|
||||
* Replace a and b with new values a' and b'.
|
||||
*/
|
||||
r = co_reduce(a, b, len, pa, pb, qa, qb);
|
||||
pa -= pa * ((r & 1) << 1);
|
||||
pb -= pb * ((r & 1) << 1);
|
||||
qa -= qa * (r & 2);
|
||||
qb -= qb * (r & 2);
|
||||
co_reduce_mod(u, v, len, pa, pb, qa, qb, m + 1, m0i);
|
||||
}
|
||||
|
||||
/*
|
||||
* Now one of the arrays should be 0, and the other contains
|
||||
* the GCD. If a is 0, then u is 0 as well, and v contains
|
||||
* the division result.
|
||||
* Result is correct if and only if GCD is 1.
|
||||
*/
|
||||
r = (a[0] | b[0]) ^ 1;
|
||||
u[0] |= v[0];
|
||||
for (k = 1; k < len; k ++) {
|
||||
r |= a[k] | b[k];
|
||||
u[k] |= v[k];
|
||||
}
|
||||
return EQ0(r);
|
||||
}
|
|
@ -0,0 +1,50 @@
|
|||
/*
|
||||
* 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 "t_inner.h"
|
||||
|
||||
/* see inner.h */
|
||||
void
|
||||
br_i15_modpow(uint16_t *x,
|
||||
const unsigned char *e, size_t elen,
|
||||
const uint16_t *m, uint16_t m0i, uint16_t *t1, uint16_t *t2)
|
||||
{
|
||||
size_t mlen;
|
||||
unsigned k;
|
||||
|
||||
mlen = ((pgm_read_word(&m[0]) + 31) >> 4) * sizeof m[0];
|
||||
memcpy(t1, x, mlen);
|
||||
br_i15_to_monty(t1, m);
|
||||
br_i15_zero(x, pgm_read_word(&m[0]));
|
||||
x[1] = 1;
|
||||
for (k = 0; k < ((unsigned)elen << 3); k ++) {
|
||||
uint32_t ctl;
|
||||
|
||||
ctl = (pgm_read_byte(&e[elen - 1 - (k >> 3)]) >> (k & 7)) & 1;
|
||||
br_i15_montymul(t2, x, t1, m, m0i);
|
||||
CCOPY(ctl, x, t2, mlen);
|
||||
br_i15_montymul(t2, t1, t1, m, m0i);
|
||||
memcpy(t1, t2, mlen);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,160 @@
|
|||
/*
|
||||
* 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 "t_inner.h"
|
||||
|
||||
/* see inner.h */
|
||||
uint32_t
|
||||
br_i15_modpow_opt(uint16_t *x,
|
||||
const unsigned char *e, size_t elen,
|
||||
const uint16_t *m, uint16_t m0i, uint16_t *tmp, size_t twlen)
|
||||
{
|
||||
size_t mlen, mwlen;
|
||||
uint16_t *t1, *t2, *base;
|
||||
size_t u, v;
|
||||
uint32_t acc;
|
||||
int acc_len, win_len;
|
||||
|
||||
/*
|
||||
* Get modulus size.
|
||||
*/
|
||||
mwlen = (pgm_read_word(&m[0]) + 31) >> 4;
|
||||
mlen = mwlen * sizeof m[0];
|
||||
mwlen += (mwlen & 1);
|
||||
t1 = tmp;
|
||||
t2 = tmp + mwlen;
|
||||
|
||||
/*
|
||||
* Compute possible window size, with a maximum of 5 bits.
|
||||
* When the window has size 1 bit, we use a specific code
|
||||
* that requires only two temporaries. Otherwise, for a
|
||||
* window of k bits, we need 2^k+1 temporaries.
|
||||
*/
|
||||
if (twlen < (mwlen << 1)) {
|
||||
return 0;
|
||||
}
|
||||
for (win_len = 5; win_len > 1; win_len --) {
|
||||
if ((((uint32_t)1 << win_len) + 1) * mwlen <= twlen) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Everything is done in Montgomery representation.
|
||||
*/
|
||||
br_i15_to_monty(x, m);
|
||||
|
||||
/*
|
||||
* Compute window contents. If the window has size one bit only,
|
||||
* then t2 is set to x; otherwise, t2[0] is left untouched, and
|
||||
* t2[k] is set to x^k (for k >= 1).
|
||||
*/
|
||||
if (win_len == 1) {
|
||||
memcpy(t2, x, mlen);
|
||||
} else {
|
||||
memcpy(t2 + mwlen, x, mlen);
|
||||
base = t2 + mwlen;
|
||||
for (u = 2; u < ((unsigned)1 << win_len); u ++) {
|
||||
br_i15_montymul(base + mwlen, base, x, m, m0i);
|
||||
base += mwlen;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* We need to set x to 1, in Montgomery representation. This can
|
||||
* be done efficiently by setting the high word to 1, then doing
|
||||
* one word-sized shift.
|
||||
*/
|
||||
br_i15_zero(x, pgm_read_word(&m[0]));
|
||||
x[(pgm_read_word(&m[0]) + 15) >> 4] = 1;
|
||||
br_i15_muladd_small(x, 0, m);
|
||||
|
||||
/*
|
||||
* We process bits from most to least significant. At each
|
||||
* loop iteration, we have acc_len bits in acc.
|
||||
*/
|
||||
acc = 0;
|
||||
acc_len = 0;
|
||||
while (acc_len > 0 || elen > 0) {
|
||||
int i, k;
|
||||
uint32_t bits;
|
||||
|
||||
/*
|
||||
* Get the next bits.
|
||||
*/
|
||||
k = win_len;
|
||||
if (acc_len < win_len) {
|
||||
if (elen > 0) {
|
||||
acc = (acc << 8) | pgm_read_byte(&*e ++);
|
||||
elen --;
|
||||
acc_len += 8;
|
||||
} else {
|
||||
k = acc_len;
|
||||
}
|
||||
}
|
||||
bits = (acc >> (acc_len - k)) & (((uint32_t)1 << k) - 1);
|
||||
acc_len -= k;
|
||||
|
||||
/*
|
||||
* We could get exactly k bits. Compute k squarings.
|
||||
*/
|
||||
for (i = 0; i < k; i ++) {
|
||||
br_i15_montymul(t1, x, x, m, m0i);
|
||||
memcpy(x, t1, mlen);
|
||||
}
|
||||
|
||||
/*
|
||||
* Window lookup: we want to set t2 to the window
|
||||
* lookup value, assuming the bits are non-zero. If
|
||||
* the window length is 1 bit only, then t2 is
|
||||
* already set; otherwise, we do a constant-time lookup.
|
||||
*/
|
||||
if (win_len > 1) {
|
||||
br_i15_zero(t2, pgm_read_word(&m[0]));
|
||||
base = t2 + mwlen;
|
||||
for (u = 1; u < ((uint32_t)1 << k); u ++) {
|
||||
uint32_t mask;
|
||||
|
||||
mask = -EQ(u, bits);
|
||||
for (v = 1; v < mwlen; v ++) {
|
||||
t2[v] |= mask & base[v];
|
||||
}
|
||||
base += mwlen;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Multiply with the looked-up value. We keep the
|
||||
* product only if the exponent bits are not all-zero.
|
||||
*/
|
||||
br_i15_montymul(t1, x, t2, m, m0i);
|
||||
CCOPY(NEQ(bits, 0), x, t1, mlen);
|
||||
}
|
||||
|
||||
/*
|
||||
* Convert back from Montgomery representation, and exit.
|
||||
*/
|
||||
br_i15_from_monty(x, m, m0i);
|
||||
return 1;
|
||||
}
|
|
@ -0,0 +1,321 @@
|
|||
/*
|
||||
* 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 "t_inner.h"
|
||||
|
||||
/* see inner.h */
|
||||
void
|
||||
br_i15_montymul(uint16_t *d, const uint16_t *x, const uint16_t *y,
|
||||
const uint16_t *m, uint16_t m0i)
|
||||
{
|
||||
size_t len, len4, u, v;
|
||||
uint32_t dh;
|
||||
|
||||
len = (pgm_read_word(&m[0]) + 15) >> 4;
|
||||
len4 = len & ~(size_t)3;
|
||||
br_i15_zero(d, pgm_read_word(&m[0]));
|
||||
dh = 0;
|
||||
for (u = 0; u < len; u ++) {
|
||||
uint32_t f, xu, r, zh;
|
||||
|
||||
xu = pgm_read_word(&x[u + 1]);
|
||||
f = MUL15((d[1] + MUL15(pgm_read_word(&x[u + 1]), pgm_read_word(&y[1]))) & 0x7FFF, m0i)
|
||||
& 0x7FFF;
|
||||
#if BR_ARMEL_CORTEXM_GCC
|
||||
if (len4 != 0) {
|
||||
uint16_t *limit;
|
||||
|
||||
limit = d + len4;
|
||||
asm volatile (
|
||||
"\n\
|
||||
@ carry: r=r2 \n\
|
||||
@ multipliers: xu=r3 f=r4 \n\
|
||||
@ base registers: d+v=r5 y+v=r6 m+v=r7 \n\
|
||||
@ r8 contains 0x7FFF \n\
|
||||
@ r9 contains d+len4 \n\
|
||||
ldr r0, %[limit] \n\
|
||||
ldr r3, %[xu] \n\
|
||||
mov r9, r0 \n\
|
||||
ldr r4, %[f] \n\
|
||||
eor r2, r2 \n\
|
||||
ldr r5, %[d] \n\
|
||||
sub r1, r2, #1 \n\
|
||||
ldr r6, %[y] \n\
|
||||
lsr r1, r1, #17 \n\
|
||||
ldr r7, %[m] \n\
|
||||
mov r8, r1 \n\
|
||||
loop%=: \n\
|
||||
ldrh r0, [r6, #2] \n\
|
||||
ldrh r1, [r7, #2] \n\
|
||||
mul r0, r3 \n\
|
||||
mul r1, r4 \n\
|
||||
add r2, r0, r2 \n\
|
||||
ldrh r0, [r5, #2] \n\
|
||||
add r2, r1, r2 \n\
|
||||
mov r1, r8 \n\
|
||||
add r2, r0, r2 \n\
|
||||
and r1, r2 \n\
|
||||
lsr r2, r2, #15 \n\
|
||||
strh r1, [r5, #0] \n\
|
||||
\n\
|
||||
ldrh r0, [r6, #4] \n\
|
||||
ldrh r1, [r7, #4] \n\
|
||||
mul r0, r3 \n\
|
||||
mul r1, r4 \n\
|
||||
add r2, r0, r2 \n\
|
||||
ldrh r0, [r5, #4] \n\
|
||||
add r2, r1, r2 \n\
|
||||
mov r1, r8 \n\
|
||||
add r2, r0, r2 \n\
|
||||
and r1, r2 \n\
|
||||
lsr r2, r2, #15 \n\
|
||||
strh r1, [r5, #2] \n\
|
||||
\n\
|
||||
ldrh r0, [r6, #6] \n\
|
||||
ldrh r1, [r7, #6] \n\
|
||||
mul r0, r3 \n\
|
||||
mul r1, r4 \n\
|
||||
add r2, r0, r2 \n\
|
||||
ldrh r0, [r5, #6] \n\
|
||||
add r2, r1, r2 \n\
|
||||
mov r1, r8 \n\
|
||||
add r2, r0, r2 \n\
|
||||
and r1, r2 \n\
|
||||
lsr r2, r2, #15 \n\
|
||||
strh r1, [r5, #4] \n\
|
||||
\n\
|
||||
ldrh r0, [r6, #8] \n\
|
||||
ldrh r1, [r7, #8] \n\
|
||||
mul r0, r3 \n\
|
||||
mul r1, r4 \n\
|
||||
add r2, r0, r2 \n\
|
||||
ldrh r0, [r5, #8] \n\
|
||||
add r2, r1, r2 \n\
|
||||
mov r1, r8 \n\
|
||||
add r2, r0, r2 \n\
|
||||
and r1, r2 \n\
|
||||
lsr r2, r2, #15 \n\
|
||||
strh r1, [r5, #6] \n\
|
||||
\n\
|
||||
add r5, r5, #8 \n\
|
||||
add r6, r6, #8 \n\
|
||||
add r7, r7, #8 \n\
|
||||
cmp r5, r9 \n\
|
||||
bne loop%= \n\
|
||||
\n\
|
||||
str r2, %[carry] \n\
|
||||
"
|
||||
: [carry] "=m" (r)
|
||||
: [xu] "m" (xu), [f] "m" (f), [d] "m" (d), [y] "m" (y),
|
||||
[m] "m" (m), [limit] "m" (limit)
|
||||
: "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", "r8", "r9" );
|
||||
} else {
|
||||
r = 0;
|
||||
}
|
||||
v = len4;
|
||||
#else
|
||||
r = 0;
|
||||
const uint16_t *py;
|
||||
const uint16_t *pm;
|
||||
|
||||
py = &y[0]; // addresses of both arrays that will be scanned as uint16_t
|
||||
pm = &m[0];
|
||||
int py_unaligned = (((int)py) & 2) != 0;
|
||||
int pm_unaligned = (((int)pm) & 2) != 0;
|
||||
uint32_t ty, tm; // 32 bits buffers
|
||||
if (!py_unaligned && !pm_unaligned) {
|
||||
// both are aligned to 32 bits, we always skip the first 16 bits
|
||||
ty = *(uint32_t*)py; // pre-load with 32 bits value, next value will be loaded at end of loop iteration
|
||||
tm = *(uint32_t*)pm;
|
||||
for (v = 0; v < len4; v += 4) {
|
||||
uint16_t y1, y2, y3, y4; // we define 4 variables for easy reading
|
||||
uint16_t m1, m2, m3, m4; // but optimizer will collapse them into 1
|
||||
|
||||
uint32_t z;
|
||||
|
||||
y1 = ty >> 16; // v+1, get upper 16 bits current 32 bits
|
||||
m1 = tm >> 16;
|
||||
z = d[v + 1] + MUL15(xu, y1) + MUL15(f, m1) + r;
|
||||
r = z >> 15;
|
||||
d[v + 0] = z & 0x7FFF;
|
||||
//
|
||||
ty = *(uint32_t*)(py = py + 2); // next 32 bits
|
||||
y2 = ty; // get lower 16 bits
|
||||
tm = *(uint32_t*)(pm = pm + 2);
|
||||
m2 = tm;
|
||||
z = d[v + 2] + MUL15(xu, y2) + MUL15(f, m2) + r;
|
||||
r = z >> 15;
|
||||
d[v + 1] = z & 0x7FFF;
|
||||
//
|
||||
y3 = ty >> 16;
|
||||
m3 = tm >> 16;
|
||||
z = d[v + 3] + MUL15(xu, y3) + MUL15(f, m3) + r;
|
||||
r = z >> 15;
|
||||
d[v + 2] = z & 0x7FFF;
|
||||
//
|
||||
ty = *(uint32_t*)(py = py + 2); // next 32 bits
|
||||
y4 = ty; // get lower 16 bits
|
||||
tm = *(uint32_t*)(pm = pm + 2);
|
||||
m4 = tm;
|
||||
z = d[v + 4] + MUL15(xu, y4) + MUL15(f, m4) + r;
|
||||
r = z >> 15;
|
||||
d[v + 3] = z & 0x7FFF;
|
||||
}
|
||||
} else if (!py_unaligned && pm_unaligned) {
|
||||
pm--; // we decrement by 1 because will increment by 2 at beginning of loop
|
||||
ty = *(uint32_t*)py; // pre-load with 32 bits value
|
||||
for (v = 0; v < len4; v += 4) {
|
||||
uint16_t y1, y2, y3, y4;
|
||||
uint16_t m1, m2, m3, m4;
|
||||
uint32_t z;
|
||||
|
||||
y1 = ty >> 16; // +1
|
||||
tm = *(uint32_t*)(pm = pm + 2);
|
||||
m1 = tm;
|
||||
z = d[v + 1] + MUL15(xu, y1) + MUL15(f, m1) + r;
|
||||
r = z >> 15;
|
||||
d[v + 0] = z & 0x7FFF;
|
||||
//
|
||||
ty = *(uint32_t*)(py = py + 2); // next 32 bits
|
||||
y2 = ty;
|
||||
m2 = tm >> 16;
|
||||
z = d[v + 2] + MUL15(xu, y2) + MUL15(f, m2) + r;
|
||||
r = z >> 15;
|
||||
d[v + 1] = z & 0x7FFF;
|
||||
//
|
||||
y3 = ty >> 16;
|
||||
tm = *(uint32_t*)(pm = pm + 2);
|
||||
m3 = tm;
|
||||
z = d[v + 3] + MUL15(xu, y3) + MUL15(f, m3) + r;
|
||||
r = z >> 15;
|
||||
d[v + 2] = z & 0x7FFF;
|
||||
//
|
||||
ty = *(uint32_t*)(py = py + 2); // next 32 bits
|
||||
y4 = ty;
|
||||
m4 = tm >> 16;
|
||||
z = d[v + 4] + MUL15(xu, y4) + MUL15(f, m4) + r;
|
||||
r = z >> 15;
|
||||
d[v + 3] = z & 0x7FFF;
|
||||
}
|
||||
} else if (py_unaligned && !pm_unaligned) { // buggy
|
||||
// py unaligned, pm aligned
|
||||
py--;
|
||||
tm = *(uint32_t*)pm;
|
||||
for (v = 0; v < len4; v += 4) {
|
||||
uint16_t y1, y2, y3, y4;
|
||||
uint16_t m1, m2, m3, m4;
|
||||
uint32_t z;
|
||||
|
||||
ty = *(uint32_t*)(py = py + 2); // next 32 bits
|
||||
y1 = ty;
|
||||
m1 = tm >> 16;
|
||||
z = d[v + 1] + MUL15(xu, y1) + MUL15(f, m1) + r;
|
||||
r = z >> 15;
|
||||
d[v + 0] = z & 0x7FFF;
|
||||
//
|
||||
y2 = ty >> 16;
|
||||
tm = *(uint32_t*)(pm = pm + 2);
|
||||
m2 = tm;
|
||||
z = d[v + 2] + MUL15(xu, y2) + MUL15(f, m2) + r;
|
||||
r = z >> 15;
|
||||
d[v + 1] = z & 0x7FFF;
|
||||
//
|
||||
ty = *(uint32_t*)(py = py + 2); // next 32 bits
|
||||
y3 = ty;
|
||||
m3 = tm >> 16;
|
||||
z = d[v + 3] + MUL15(xu, y3) + MUL15(f, m3) + r;
|
||||
r = z >> 15;
|
||||
d[v + 2] = z & 0x7FFF;
|
||||
//
|
||||
y4 = ty >> 16;
|
||||
tm = *(uint32_t*)(pm = pm + 2);
|
||||
m4 = tm;
|
||||
z = d[v + 4] + MUL15(xu, y4) + MUL15(f, m4) + r;
|
||||
r = z >> 15;
|
||||
d[v + 3] = z & 0x7FFF;
|
||||
}
|
||||
} else { // if (py_unaligned && pm_unaligned) {
|
||||
// py unaligned, pm unaligned
|
||||
py--;
|
||||
pm--;
|
||||
for (v = 0; v < len4; v += 4) {
|
||||
uint16_t y1, y2, y3, y4;
|
||||
uint16_t m1, m2, m3, m4;
|
||||
uint32_t z;
|
||||
|
||||
ty = *(uint32_t*)(py = py + 2); // next 32 bits
|
||||
y1 = ty; // +1
|
||||
tm = *(uint32_t*)(pm = pm + 2);
|
||||
m1 = tm;
|
||||
z = d[v + 1] + MUL15(xu, y1) + MUL15(f, m1) + r;
|
||||
r = z >> 15;
|
||||
d[v + 0] = z & 0x7FFF;
|
||||
//
|
||||
y2 = ty >> 16;
|
||||
m2 = tm >> 16;
|
||||
z = d[v + 2] + MUL15(xu, y2) + MUL15(f, m2) + r;
|
||||
r = z >> 15;
|
||||
d[v + 1] = z & 0x7FFF;
|
||||
//
|
||||
ty = *(uint32_t*)(py = py + 2); // next 32 bits
|
||||
y3 = ty;
|
||||
tm = *(uint32_t*)(pm = pm + 2);
|
||||
m3 = tm;
|
||||
z = d[v + 3] + MUL15(xu, y3) + MUL15(f, m3) + r;
|
||||
r = z >> 15;
|
||||
d[v + 2] = z & 0x7FFF;
|
||||
//
|
||||
y4 = ty >> 16;
|
||||
m4 = tm >> 16;
|
||||
z = d[v + 4] + MUL15(xu, y4) + MUL15(f, m4) + r;
|
||||
r = z >> 15;
|
||||
d[v + 3] = z & 0x7FFF;
|
||||
}
|
||||
}
|
||||
#endif // BR_ARMEL_CORTEXM_GCC
|
||||
for (; v < len; v ++) {
|
||||
uint32_t z;
|
||||
|
||||
z = d[v + 1] + MUL15(xu, pgm_read_word(&y[v + 1]))
|
||||
+ MUL15(f, pgm_read_word(&m[v + 1])) + r;
|
||||
r = z >> 15;
|
||||
d[v + 0] = z & 0x7FFF;
|
||||
}
|
||||
|
||||
zh = dh + r;
|
||||
d[len] = zh & 0x7FFF;
|
||||
dh = zh >> 15;
|
||||
}
|
||||
|
||||
/*
|
||||
* Restore the bit length (it was overwritten in the loop above).
|
||||
*/
|
||||
d[0] = pgm_read_word(&m[0]);
|
||||
|
||||
/*
|
||||
* d[] may be greater than m[], but it is still lower than twice
|
||||
* the modulus.
|
||||
*/
|
||||
br_i15_sub(d, m, NEQ(dh, 0) | NOT(br_i15_sub(d, m, 0)));
|
||||
}
|
|
@ -0,0 +1,61 @@
|
|||
/*
|
||||
* 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 "t_inner.h"
|
||||
|
||||
/* see inner.h */
|
||||
void
|
||||
br_i15_mulacc(uint16_t *d, const uint16_t *a, const uint16_t *b)
|
||||
{
|
||||
size_t alen, blen, u;
|
||||
unsigned dl, dh;
|
||||
|
||||
alen = (pgm_read_word(&a[0]) + 15) >> 4;
|
||||
blen = (pgm_read_word(&b[0]) + 15) >> 4;
|
||||
|
||||
/*
|
||||
* Announced bit length of d[] will be the sum of the announced
|
||||
* bit lengths of a[] and b[]; but the lengths are encoded.
|
||||
*/
|
||||
dl = (pgm_read_word(&a[0]) & 15) + (pgm_read_word(&b[0]) & 15);
|
||||
dh = (pgm_read_word(&a[0]) >> 4) + (pgm_read_word(&b[0]) >> 4);
|
||||
d[0] = (dh << 4) + dl + (~(uint32_t)(dl - 15) >> 31);
|
||||
|
||||
for (u = 0; u < blen; u ++) {
|
||||
uint32_t f;
|
||||
size_t v;
|
||||
uint32_t cc;
|
||||
|
||||
f = pgm_read_word(&b[1 + u]);
|
||||
cc = 0;
|
||||
for (v = 0; v < alen; v ++) {
|
||||
uint32_t z;
|
||||
|
||||
z = (uint32_t)d[1 + u + v] + MUL15(f, pgm_read_word(&a[1 + v])) + cc;
|
||||
cc = z >> 15;
|
||||
d[1 + u + v] = z & 0x7FFF;
|
||||
}
|
||||
d[1 + u + alen] = cc;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,173 @@
|
|||
/*
|
||||
* 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 "t_inner.h"
|
||||
|
||||
/*
|
||||
* Constant-time division. The divisor must not be larger than 16 bits,
|
||||
* and the quotient must fit on 17 bits.
|
||||
*/
|
||||
static uint32_t
|
||||
divrem16(uint32_t x, uint32_t d, uint32_t *r)
|
||||
{
|
||||
int i;
|
||||
uint32_t q;
|
||||
|
||||
q = 0;
|
||||
d <<= 16;
|
||||
for (i = 16; i >= 0; i --) {
|
||||
uint32_t ctl;
|
||||
|
||||
ctl = LE(d, x);
|
||||
q |= ctl << i;
|
||||
x -= (-ctl) & d;
|
||||
d >>= 1;
|
||||
}
|
||||
if (r != NULL) {
|
||||
*r = x;
|
||||
}
|
||||
return q;
|
||||
}
|
||||
|
||||
/* see inner.h */
|
||||
void
|
||||
br_i15_muladd_small(uint16_t *x, uint16_t z, const uint16_t *m)
|
||||
{
|
||||
/*
|
||||
* Constant-time: we accept to leak the exact bit length of the
|
||||
* modulus m.
|
||||
*/
|
||||
unsigned m_bitlen, mblr;
|
||||
size_t u, mlen;
|
||||
uint32_t hi, a0, a, b, q;
|
||||
uint32_t cc, tb, over, under;
|
||||
|
||||
/*
|
||||
* Simple case: the modulus fits on one word.
|
||||
*/
|
||||
m_bitlen = pgm_read_word(&m[0]);
|
||||
if (m_bitlen == 0) {
|
||||
return;
|
||||
}
|
||||
if (m_bitlen <= 15) {
|
||||
uint32_t rem;
|
||||
|
||||
divrem16(((uint32_t)x[1] << 15) | z, pgm_read_word(&m[1]), &rem);
|
||||
x[1] = rem;
|
||||
return;
|
||||
}
|
||||
mlen = (m_bitlen + 15) >> 4;
|
||||
mblr = m_bitlen & 15;
|
||||
|
||||
/*
|
||||
* Principle: we estimate the quotient (x*2^15+z)/m by
|
||||
* doing a 30/15 division with the high words.
|
||||
*
|
||||
* Let:
|
||||
* w = 2^15
|
||||
* a = (w*a0 + a1) * w^N + a2
|
||||
* b = b0 * w^N + b2
|
||||
* such that:
|
||||
* 0 <= a0 < w
|
||||
* 0 <= a1 < w
|
||||
* 0 <= a2 < w^N
|
||||
* w/2 <= b0 < w
|
||||
* 0 <= b2 < w^N
|
||||
* a < w*b
|
||||
* I.e. the two top words of a are a0:a1, the top word of b is
|
||||
* b0, we ensured that b0 is "full" (high bit set), and a is
|
||||
* such that the quotient q = a/b fits on one word (0 <= q < w).
|
||||
*
|
||||
* If a = b*q + r (with 0 <= r < q), then we can estimate q by
|
||||
* using a division on the top words:
|
||||
* a0*w + a1 = b0*u + v (with 0 <= v < b0)
|
||||
* Then the following holds:
|
||||
* 0 <= u <= w
|
||||
* u-2 <= q <= u
|
||||
*/
|
||||
hi = x[mlen];
|
||||
if (mblr == 0) {
|
||||
a0 = x[mlen];
|
||||
memmove(x + 2, x + 1, (mlen - 1) * sizeof *x);
|
||||
x[1] = z;
|
||||
a = (a0 << 15) + x[mlen];
|
||||
b = pgm_read_word(&m[mlen]);
|
||||
} else {
|
||||
a0 = (x[mlen] << (15 - mblr)) | (x[mlen - 1] >> mblr);
|
||||
memmove(x + 2, x + 1, (mlen - 1) * sizeof *x);
|
||||
x[1] = z;
|
||||
a = (a0 << 15) | (((x[mlen] << (15 - mblr))
|
||||
| (x[mlen - 1] >> mblr)) & 0x7FFF);
|
||||
b = (pgm_read_word(&m[mlen]) << (15 - mblr)) | (pgm_read_word(&m[mlen - 1]) >> mblr);
|
||||
}
|
||||
q = divrem16(a, b, NULL);
|
||||
|
||||
/*
|
||||
* We computed an estimate for q, but the real one may be q,
|
||||
* q-1 or q-2; moreover, the division may have returned a value
|
||||
* 8000 or even 8001 if the two high words were identical, and
|
||||
* we want to avoid values beyond 7FFF. We thus adjust q so
|
||||
* that the "true" multiplier will be q+1, q or q-1, and q is
|
||||
* in the 0000..7FFF range.
|
||||
*/
|
||||
q = MUX(EQ(b, a0), 0x7FFF, q - 1 + ((q - 1) >> 31));
|
||||
|
||||
/*
|
||||
* We subtract q*m from x (x has an extra high word of value 'hi').
|
||||
* Since q may be off by 1 (in either direction), we may have to
|
||||
* add or subtract m afterwards.
|
||||
*
|
||||
* The 'tb' flag will be true (1) at the end of the loop if the
|
||||
* result is greater than or equal to the modulus (not counting
|
||||
* 'hi' or the carry).
|
||||
*/
|
||||
cc = 0;
|
||||
tb = 1;
|
||||
for (u = 1; u <= mlen; u ++) {
|
||||
uint32_t mw, zl, xw, nxw;
|
||||
|
||||
mw = pgm_read_word(&m[u]);
|
||||
zl = MUL15(mw, q) + cc;
|
||||
cc = zl >> 15;
|
||||
zl &= 0x7FFF;
|
||||
xw = x[u];
|
||||
nxw = xw - zl;
|
||||
cc += nxw >> 31;
|
||||
nxw &= 0x7FFF;
|
||||
x[u] = nxw;
|
||||
tb = MUX(EQ(nxw, mw), tb, GT(nxw, mw));
|
||||
}
|
||||
|
||||
/*
|
||||
* If we underestimated q, then either cc < hi (one extra bit
|
||||
* beyond the top array word), or cc == hi and tb is true (no
|
||||
* extra bit, but the result is not lower than the modulus).
|
||||
*
|
||||
* If we overestimated q, then cc > hi.
|
||||
*/
|
||||
over = GT(cc, hi);
|
||||
under = ~over & (tb | LT(cc, hi));
|
||||
br_i15_add(x, m, over);
|
||||
br_i15_sub(x, m, under);
|
||||
}
|
|
@ -0,0 +1,38 @@
|
|||
/*
|
||||
* 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 "t_inner.h"
|
||||
|
||||
/* see inner.h */
|
||||
uint16_t
|
||||
br_i15_ninv15(uint16_t x)
|
||||
{
|
||||
uint32_t y;
|
||||
|
||||
y = 2 - x;
|
||||
y = MUL15(y, 2 - MUL15(x, y));
|
||||
y = MUL15(y, 2 - MUL15(x, y));
|
||||
y = MUL15(y, 2 - MUL15(x, y));
|
||||
return MUX(x & 1, -y, 0) & 0x7FFF;
|
||||
}
|
|
@ -0,0 +1,66 @@
|
|||
/*
|
||||
* 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 "t_inner.h"
|
||||
|
||||
/* see inner.h */
|
||||
void
|
||||
br_i15_reduce(uint16_t *x, const uint16_t *a, const uint16_t *m)
|
||||
{
|
||||
uint32_t m_bitlen, a_bitlen;
|
||||
size_t mlen, alen, u;
|
||||
|
||||
m_bitlen = pgm_read_word(&m[0]);
|
||||
mlen = (m_bitlen + 15) >> 4;
|
||||
|
||||
x[0] = m_bitlen;
|
||||
if (m_bitlen == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* If the source is shorter, then simply copy all words from a[]
|
||||
* and zero out the upper words.
|
||||
*/
|
||||
a_bitlen = pgm_read_word(&a[0]);
|
||||
alen = (a_bitlen + 15) >> 4;
|
||||
if (a_bitlen < m_bitlen) {
|
||||
memcpy_P(x + 1, a + 1, alen * sizeof *a);
|
||||
for (u = alen; u < mlen; u ++) {
|
||||
x[u + 1] = 0;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* The source length is at least equal to that of the modulus.
|
||||
* We must thus copy N-1 words, and input the remaining words
|
||||
* one by one.
|
||||
*/
|
||||
memcpy_P(x + 1, a + 2 + (alen - mlen), (mlen - 1) * sizeof *a);
|
||||
x[mlen] = 0;
|
||||
for (u = 1 + alen - mlen; u > 0; u --) {
|
||||
br_i15_muladd_small(x, pgm_read_word(&a[u]), m);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,47 @@
|
|||
/*
|
||||
* 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 "t_inner.h"
|
||||
|
||||
/* see inner.h */
|
||||
void
|
||||
br_i15_rshift(uint16_t *x, int count)
|
||||
{
|
||||
size_t u, len;
|
||||
unsigned r;
|
||||
|
||||
len = (x[0] + 15) >> 4;
|
||||
if (len == 0) {
|
||||
return;
|
||||
}
|
||||
r = x[1] >> count;
|
||||
for (u = 2; u <= len; u ++) {
|
||||
unsigned w;
|
||||
|
||||
w = x[u];
|
||||
x[u - 1] = ((w << (15 - count)) | r) & 0x7FFF;
|
||||
r = w >> count;
|
||||
}
|
||||
x[len] = r;
|
||||
}
|
|
@ -0,0 +1,46 @@
|
|||
/*
|
||||
* 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 "t_inner.h"
|
||||
|
||||
/* see inner.h */
|
||||
uint32_t
|
||||
br_i15_sub(uint16_t *a, const uint16_t *b, uint32_t ctl)
|
||||
{
|
||||
uint32_t cc;
|
||||
size_t u, m;
|
||||
|
||||
cc = 0;
|
||||
m = (a[0] + 31) >> 4;
|
||||
for (u = 1; u < m; u ++) {
|
||||
uint32_t aw, bw, naw;
|
||||
|
||||
aw = a[u];
|
||||
bw = pgm_read_word(&b[u]);
|
||||
naw = aw - bw - cc;
|
||||
cc = naw >> 31;
|
||||
a[u] = MUX(ctl, naw & 0x7FFF, aw);
|
||||
}
|
||||
return cc;
|
||||
}
|
|
@ -0,0 +1,36 @@
|
|||
/*
|
||||
* 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 "t_inner.h"
|
||||
|
||||
/* see inner.h */
|
||||
void
|
||||
br_i15_to_monty(uint16_t *x, const uint16_t *m)
|
||||
{
|
||||
unsigned k;
|
||||
|
||||
for (k = (pgm_read_word(&m[0]) + 15) >> 4; k > 0; k --) {
|
||||
br_i15_muladd_small(x, 0, m);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,107 @@
|
|||
/*
|
||||
* Copyright (c) 2018 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 "t_inner.h"
|
||||
|
||||
const unsigned char br_hkdf_no_salt = 0;
|
||||
|
||||
/* see bearssl_kdf.h */
|
||||
void
|
||||
br_hkdf_init(br_hkdf_context *hc, const br_hash_class *digest_vtable,
|
||||
const void *salt, size_t salt_len)
|
||||
{
|
||||
br_hmac_key_context kc;
|
||||
unsigned char tmp[64];
|
||||
|
||||
if (salt == BR_HKDF_NO_SALT) {
|
||||
salt = tmp;
|
||||
salt_len = br_digest_size(digest_vtable);
|
||||
memset(tmp, 0, salt_len);
|
||||
}
|
||||
br_hmac_key_init(&kc, digest_vtable, salt, salt_len);
|
||||
br_hmac_init(&hc->u.hmac_ctx, &kc, 0);
|
||||
hc->dig_len = br_hmac_size(&hc->u.hmac_ctx);
|
||||
}
|
||||
|
||||
/* see bearssl_kdf.h */
|
||||
void
|
||||
br_hkdf_inject(br_hkdf_context *hc, const void *ikm, size_t ikm_len)
|
||||
{
|
||||
br_hmac_update(&hc->u.hmac_ctx, ikm, ikm_len);
|
||||
}
|
||||
|
||||
/* see bearssl_kdf.h */
|
||||
void
|
||||
br_hkdf_flip(br_hkdf_context *hc)
|
||||
{
|
||||
unsigned char tmp[64];
|
||||
|
||||
br_hmac_out(&hc->u.hmac_ctx, tmp);
|
||||
br_hmac_key_init(&hc->u.prk_ctx,
|
||||
br_hmac_get_digest(&hc->u.hmac_ctx), tmp, hc->dig_len);
|
||||
hc->ptr = hc->dig_len;
|
||||
hc->chunk_num = 0;
|
||||
}
|
||||
|
||||
/* see bearssl_kdf.h */
|
||||
size_t
|
||||
br_hkdf_produce(br_hkdf_context *hc,
|
||||
const void *info, size_t info_len, void *out, size_t out_len)
|
||||
{
|
||||
size_t tlen;
|
||||
|
||||
tlen = 0;
|
||||
while (out_len > 0) {
|
||||
size_t clen;
|
||||
|
||||
if (hc->ptr == hc->dig_len) {
|
||||
br_hmac_context hmac_ctx;
|
||||
unsigned char x;
|
||||
|
||||
hc->chunk_num ++;
|
||||
if (hc->chunk_num == 256) {
|
||||
return tlen;
|
||||
}
|
||||
x = hc->chunk_num;
|
||||
br_hmac_init(&hmac_ctx, &hc->u.prk_ctx, 0);
|
||||
if (x != 1) {
|
||||
br_hmac_update(&hmac_ctx, hc->buf, hc->dig_len);
|
||||
}
|
||||
br_hmac_update(&hmac_ctx, info, info_len);
|
||||
br_hmac_update(&hmac_ctx, &x, 1);
|
||||
br_hmac_out(&hmac_ctx, hc->buf);
|
||||
hc->ptr = 0;
|
||||
}
|
||||
clen = hc->dig_len - hc->ptr;
|
||||
if (clen > out_len) {
|
||||
clen = out_len;
|
||||
}
|
||||
memcpy(out, hc->buf + hc->ptr, clen);
|
||||
out = (unsigned char *)out + clen;
|
||||
out_len -= clen;
|
||||
hc->ptr += clen;
|
||||
tlen += clen;
|
||||
}
|
||||
return tlen;
|
||||
}
|
|
@ -0,0 +1,590 @@
|
|||
/*
|
||||
* Copyright (c) 2018 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 "t_inner.h"
|
||||
|
||||
/*
|
||||
* Round constants.
|
||||
*/
|
||||
static const uint64_t RC[] PROGMEM = {
|
||||
0x0000000000000001, 0x0000000000008082,
|
||||
0x800000000000808A, 0x8000000080008000,
|
||||
0x000000000000808B, 0x0000000080000001,
|
||||
0x8000000080008081, 0x8000000000008009,
|
||||
0x000000000000008A, 0x0000000000000088,
|
||||
0x0000000080008009, 0x000000008000000A,
|
||||
0x000000008000808B, 0x800000000000008B,
|
||||
0x8000000000008089, 0x8000000000008003,
|
||||
0x8000000000008002, 0x8000000000000080,
|
||||
0x000000000000800A, 0x800000008000000A,
|
||||
0x8000000080008081, 0x8000000000008080,
|
||||
0x0000000080000001, 0x8000000080008008
|
||||
};
|
||||
|
||||
/*
|
||||
* XOR a block of data into the provided state. This supports only
|
||||
* blocks whose length is a multiple of 64 bits.
|
||||
*/
|
||||
static void
|
||||
xor_block(uint64_t *A, const void *data, size_t rate)
|
||||
{
|
||||
size_t u;
|
||||
|
||||
for (u = 0; u < rate; u += 8) {
|
||||
A[u >> 3] ^= br_dec64le((const unsigned char *)data + u);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Process a block with the provided data. The data length must be a
|
||||
* multiple of 8 (in bytes); normally, this is the "rate".
|
||||
*/
|
||||
static void
|
||||
process_block(uint64_t *A)
|
||||
{
|
||||
uint64_t t0, t1, t2, t3, t4;
|
||||
uint64_t tt0, tt1, tt2, tt3;
|
||||
uint64_t t, kt;
|
||||
uint64_t c0, c1, c2, c3, c4, bnn;
|
||||
int j;
|
||||
|
||||
/*
|
||||
* Compute the 24 rounds. This loop is partially unrolled (each
|
||||
* iteration computes two rounds).
|
||||
*/
|
||||
for (j = 0; j < 24; j += 2) {
|
||||
|
||||
tt0 = A[ 1] ^ A[ 6];
|
||||
tt1 = A[11] ^ A[16];
|
||||
tt0 ^= A[21] ^ tt1;
|
||||
tt0 = (tt0 << 1) | (tt0 >> 63);
|
||||
tt2 = A[ 4] ^ A[ 9];
|
||||
tt3 = A[14] ^ A[19];
|
||||
tt0 ^= A[24];
|
||||
tt2 ^= tt3;
|
||||
t0 = tt0 ^ tt2;
|
||||
|
||||
tt0 = A[ 2] ^ A[ 7];
|
||||
tt1 = A[12] ^ A[17];
|
||||
tt0 ^= A[22] ^ tt1;
|
||||
tt0 = (tt0 << 1) | (tt0 >> 63);
|
||||
tt2 = A[ 0] ^ A[ 5];
|
||||
tt3 = A[10] ^ A[15];
|
||||
tt0 ^= A[20];
|
||||
tt2 ^= tt3;
|
||||
t1 = tt0 ^ tt2;
|
||||
|
||||
tt0 = A[ 3] ^ A[ 8];
|
||||
tt1 = A[13] ^ A[18];
|
||||
tt0 ^= A[23] ^ tt1;
|
||||
tt0 = (tt0 << 1) | (tt0 >> 63);
|
||||
tt2 = A[ 1] ^ A[ 6];
|
||||
tt3 = A[11] ^ A[16];
|
||||
tt0 ^= A[21];
|
||||
tt2 ^= tt3;
|
||||
t2 = tt0 ^ tt2;
|
||||
|
||||
tt0 = A[ 4] ^ A[ 9];
|
||||
tt1 = A[14] ^ A[19];
|
||||
tt0 ^= A[24] ^ tt1;
|
||||
tt0 = (tt0 << 1) | (tt0 >> 63);
|
||||
tt2 = A[ 2] ^ A[ 7];
|
||||
tt3 = A[12] ^ A[17];
|
||||
tt0 ^= A[22];
|
||||
tt2 ^= tt3;
|
||||
t3 = tt0 ^ tt2;
|
||||
|
||||
tt0 = A[ 0] ^ A[ 5];
|
||||
tt1 = A[10] ^ A[15];
|
||||
tt0 ^= A[20] ^ tt1;
|
||||
tt0 = (tt0 << 1) | (tt0 >> 63);
|
||||
tt2 = A[ 3] ^ A[ 8];
|
||||
tt3 = A[13] ^ A[18];
|
||||
tt0 ^= A[23];
|
||||
tt2 ^= tt3;
|
||||
t4 = tt0 ^ tt2;
|
||||
|
||||
A[ 0] = A[ 0] ^ t0;
|
||||
A[ 5] = A[ 5] ^ t0;
|
||||
A[10] = A[10] ^ t0;
|
||||
A[15] = A[15] ^ t0;
|
||||
A[20] = A[20] ^ t0;
|
||||
A[ 1] = A[ 1] ^ t1;
|
||||
A[ 6] = A[ 6] ^ t1;
|
||||
A[11] = A[11] ^ t1;
|
||||
A[16] = A[16] ^ t1;
|
||||
A[21] = A[21] ^ t1;
|
||||
A[ 2] = A[ 2] ^ t2;
|
||||
A[ 7] = A[ 7] ^ t2;
|
||||
A[12] = A[12] ^ t2;
|
||||
A[17] = A[17] ^ t2;
|
||||
A[22] = A[22] ^ t2;
|
||||
A[ 3] = A[ 3] ^ t3;
|
||||
A[ 8] = A[ 8] ^ t3;
|
||||
A[13] = A[13] ^ t3;
|
||||
A[18] = A[18] ^ t3;
|
||||
A[23] = A[23] ^ t3;
|
||||
A[ 4] = A[ 4] ^ t4;
|
||||
A[ 9] = A[ 9] ^ t4;
|
||||
A[14] = A[14] ^ t4;
|
||||
A[19] = A[19] ^ t4;
|
||||
A[24] = A[24] ^ t4;
|
||||
A[ 5] = (A[ 5] << 36) | (A[ 5] >> (64 - 36));
|
||||
A[10] = (A[10] << 3) | (A[10] >> (64 - 3));
|
||||
A[15] = (A[15] << 41) | (A[15] >> (64 - 41));
|
||||
A[20] = (A[20] << 18) | (A[20] >> (64 - 18));
|
||||
A[ 1] = (A[ 1] << 1) | (A[ 1] >> (64 - 1));
|
||||
A[ 6] = (A[ 6] << 44) | (A[ 6] >> (64 - 44));
|
||||
A[11] = (A[11] << 10) | (A[11] >> (64 - 10));
|
||||
A[16] = (A[16] << 45) | (A[16] >> (64 - 45));
|
||||
A[21] = (A[21] << 2) | (A[21] >> (64 - 2));
|
||||
A[ 2] = (A[ 2] << 62) | (A[ 2] >> (64 - 62));
|
||||
A[ 7] = (A[ 7] << 6) | (A[ 7] >> (64 - 6));
|
||||
A[12] = (A[12] << 43) | (A[12] >> (64 - 43));
|
||||
A[17] = (A[17] << 15) | (A[17] >> (64 - 15));
|
||||
A[22] = (A[22] << 61) | (A[22] >> (64 - 61));
|
||||
A[ 3] = (A[ 3] << 28) | (A[ 3] >> (64 - 28));
|
||||
A[ 8] = (A[ 8] << 55) | (A[ 8] >> (64 - 55));
|
||||
A[13] = (A[13] << 25) | (A[13] >> (64 - 25));
|
||||
A[18] = (A[18] << 21) | (A[18] >> (64 - 21));
|
||||
A[23] = (A[23] << 56) | (A[23] >> (64 - 56));
|
||||
A[ 4] = (A[ 4] << 27) | (A[ 4] >> (64 - 27));
|
||||
A[ 9] = (A[ 9] << 20) | (A[ 9] >> (64 - 20));
|
||||
A[14] = (A[14] << 39) | (A[14] >> (64 - 39));
|
||||
A[19] = (A[19] << 8) | (A[19] >> (64 - 8));
|
||||
A[24] = (A[24] << 14) | (A[24] >> (64 - 14));
|
||||
bnn = ~A[12];
|
||||
kt = A[ 6] | A[12];
|
||||
c0 = A[ 0] ^ kt;
|
||||
kt = bnn | A[18];
|
||||
c1 = A[ 6] ^ kt;
|
||||
kt = A[18] & A[24];
|
||||
c2 = A[12] ^ kt;
|
||||
kt = A[24] | A[ 0];
|
||||
c3 = A[18] ^ kt;
|
||||
kt = A[ 0] & A[ 6];
|
||||
c4 = A[24] ^ kt;
|
||||
A[ 0] = c0;
|
||||
A[ 6] = c1;
|
||||
A[12] = c2;
|
||||
A[18] = c3;
|
||||
A[24] = c4;
|
||||
bnn = ~A[22];
|
||||
kt = A[ 9] | A[10];
|
||||
c0 = A[ 3] ^ kt;
|
||||
kt = A[10] & A[16];
|
||||
c1 = A[ 9] ^ kt;
|
||||
kt = A[16] | bnn;
|
||||
c2 = A[10] ^ kt;
|
||||
kt = A[22] | A[ 3];
|
||||
c3 = A[16] ^ kt;
|
||||
kt = A[ 3] & A[ 9];
|
||||
c4 = A[22] ^ kt;
|
||||
A[ 3] = c0;
|
||||
A[ 9] = c1;
|
||||
A[10] = c2;
|
||||
A[16] = c3;
|
||||
A[22] = c4;
|
||||
bnn = ~A[19];
|
||||
kt = A[ 7] | A[13];
|
||||
c0 = A[ 1] ^ kt;
|
||||
kt = A[13] & A[19];
|
||||
c1 = A[ 7] ^ kt;
|
||||
kt = bnn & A[20];
|
||||
c2 = A[13] ^ kt;
|
||||
kt = A[20] | A[ 1];
|
||||
c3 = bnn ^ kt;
|
||||
kt = A[ 1] & A[ 7];
|
||||
c4 = A[20] ^ kt;
|
||||
A[ 1] = c0;
|
||||
A[ 7] = c1;
|
||||
A[13] = c2;
|
||||
A[19] = c3;
|
||||
A[20] = c4;
|
||||
bnn = ~A[17];
|
||||
kt = A[ 5] & A[11];
|
||||
c0 = A[ 4] ^ kt;
|
||||
kt = A[11] | A[17];
|
||||
c1 = A[ 5] ^ kt;
|
||||
kt = bnn | A[23];
|
||||
c2 = A[11] ^ kt;
|
||||
kt = A[23] & A[ 4];
|
||||
c3 = bnn ^ kt;
|
||||
kt = A[ 4] | A[ 5];
|
||||
c4 = A[23] ^ kt;
|
||||
A[ 4] = c0;
|
||||
A[ 5] = c1;
|
||||
A[11] = c2;
|
||||
A[17] = c3;
|
||||
A[23] = c4;
|
||||
bnn = ~A[ 8];
|
||||
kt = bnn & A[14];
|
||||
c0 = A[ 2] ^ kt;
|
||||
kt = A[14] | A[15];
|
||||
c1 = bnn ^ kt;
|
||||
kt = A[15] & A[21];
|
||||
c2 = A[14] ^ kt;
|
||||
kt = A[21] | A[ 2];
|
||||
c3 = A[15] ^ kt;
|
||||
kt = A[ 2] & A[ 8];
|
||||
c4 = A[21] ^ kt;
|
||||
A[ 2] = c0;
|
||||
A[ 8] = c1;
|
||||
A[14] = c2;
|
||||
A[15] = c3;
|
||||
A[21] = c4;
|
||||
A[ 0] = A[ 0] ^ RC[j + 0];
|
||||
|
||||
tt0 = A[ 6] ^ A[ 9];
|
||||
tt1 = A[ 7] ^ A[ 5];
|
||||
tt0 ^= A[ 8] ^ tt1;
|
||||
tt0 = (tt0 << 1) | (tt0 >> 63);
|
||||
tt2 = A[24] ^ A[22];
|
||||
tt3 = A[20] ^ A[23];
|
||||
tt0 ^= A[21];
|
||||
tt2 ^= tt3;
|
||||
t0 = tt0 ^ tt2;
|
||||
|
||||
tt0 = A[12] ^ A[10];
|
||||
tt1 = A[13] ^ A[11];
|
||||
tt0 ^= A[14] ^ tt1;
|
||||
tt0 = (tt0 << 1) | (tt0 >> 63);
|
||||
tt2 = A[ 0] ^ A[ 3];
|
||||
tt3 = A[ 1] ^ A[ 4];
|
||||
tt0 ^= A[ 2];
|
||||
tt2 ^= tt3;
|
||||
t1 = tt0 ^ tt2;
|
||||
|
||||
tt0 = A[18] ^ A[16];
|
||||
tt1 = A[19] ^ A[17];
|
||||
tt0 ^= A[15] ^ tt1;
|
||||
tt0 = (tt0 << 1) | (tt0 >> 63);
|
||||
tt2 = A[ 6] ^ A[ 9];
|
||||
tt3 = A[ 7] ^ A[ 5];
|
||||
tt0 ^= A[ 8];
|
||||
tt2 ^= tt3;
|
||||
t2 = tt0 ^ tt2;
|
||||
|
||||
tt0 = A[24] ^ A[22];
|
||||
tt1 = A[20] ^ A[23];
|
||||
tt0 ^= A[21] ^ tt1;
|
||||
tt0 = (tt0 << 1) | (tt0 >> 63);
|
||||
tt2 = A[12] ^ A[10];
|
||||
tt3 = A[13] ^ A[11];
|
||||
tt0 ^= A[14];
|
||||
tt2 ^= tt3;
|
||||
t3 = tt0 ^ tt2;
|
||||
|
||||
tt0 = A[ 0] ^ A[ 3];
|
||||
tt1 = A[ 1] ^ A[ 4];
|
||||
tt0 ^= A[ 2] ^ tt1;
|
||||
tt0 = (tt0 << 1) | (tt0 >> 63);
|
||||
tt2 = A[18] ^ A[16];
|
||||
tt3 = A[19] ^ A[17];
|
||||
tt0 ^= A[15];
|
||||
tt2 ^= tt3;
|
||||
t4 = tt0 ^ tt2;
|
||||
|
||||
A[ 0] = A[ 0] ^ t0;
|
||||
A[ 3] = A[ 3] ^ t0;
|
||||
A[ 1] = A[ 1] ^ t0;
|
||||
A[ 4] = A[ 4] ^ t0;
|
||||
A[ 2] = A[ 2] ^ t0;
|
||||
A[ 6] = A[ 6] ^ t1;
|
||||
A[ 9] = A[ 9] ^ t1;
|
||||
A[ 7] = A[ 7] ^ t1;
|
||||
A[ 5] = A[ 5] ^ t1;
|
||||
A[ 8] = A[ 8] ^ t1;
|
||||
A[12] = A[12] ^ t2;
|
||||
A[10] = A[10] ^ t2;
|
||||
A[13] = A[13] ^ t2;
|
||||
A[11] = A[11] ^ t2;
|
||||
A[14] = A[14] ^ t2;
|
||||
A[18] = A[18] ^ t3;
|
||||
A[16] = A[16] ^ t3;
|
||||
A[19] = A[19] ^ t3;
|
||||
A[17] = A[17] ^ t3;
|
||||
A[15] = A[15] ^ t3;
|
||||
A[24] = A[24] ^ t4;
|
||||
A[22] = A[22] ^ t4;
|
||||
A[20] = A[20] ^ t4;
|
||||
A[23] = A[23] ^ t4;
|
||||
A[21] = A[21] ^ t4;
|
||||
A[ 3] = (A[ 3] << 36) | (A[ 3] >> (64 - 36));
|
||||
A[ 1] = (A[ 1] << 3) | (A[ 1] >> (64 - 3));
|
||||
A[ 4] = (A[ 4] << 41) | (A[ 4] >> (64 - 41));
|
||||
A[ 2] = (A[ 2] << 18) | (A[ 2] >> (64 - 18));
|
||||
A[ 6] = (A[ 6] << 1) | (A[ 6] >> (64 - 1));
|
||||
A[ 9] = (A[ 9] << 44) | (A[ 9] >> (64 - 44));
|
||||
A[ 7] = (A[ 7] << 10) | (A[ 7] >> (64 - 10));
|
||||
A[ 5] = (A[ 5] << 45) | (A[ 5] >> (64 - 45));
|
||||
A[ 8] = (A[ 8] << 2) | (A[ 8] >> (64 - 2));
|
||||
A[12] = (A[12] << 62) | (A[12] >> (64 - 62));
|
||||
A[10] = (A[10] << 6) | (A[10] >> (64 - 6));
|
||||
A[13] = (A[13] << 43) | (A[13] >> (64 - 43));
|
||||
A[11] = (A[11] << 15) | (A[11] >> (64 - 15));
|
||||
A[14] = (A[14] << 61) | (A[14] >> (64 - 61));
|
||||
A[18] = (A[18] << 28) | (A[18] >> (64 - 28));
|
||||
A[16] = (A[16] << 55) | (A[16] >> (64 - 55));
|
||||
A[19] = (A[19] << 25) | (A[19] >> (64 - 25));
|
||||
A[17] = (A[17] << 21) | (A[17] >> (64 - 21));
|
||||
A[15] = (A[15] << 56) | (A[15] >> (64 - 56));
|
||||
A[24] = (A[24] << 27) | (A[24] >> (64 - 27));
|
||||
A[22] = (A[22] << 20) | (A[22] >> (64 - 20));
|
||||
A[20] = (A[20] << 39) | (A[20] >> (64 - 39));
|
||||
A[23] = (A[23] << 8) | (A[23] >> (64 - 8));
|
||||
A[21] = (A[21] << 14) | (A[21] >> (64 - 14));
|
||||
bnn = ~A[13];
|
||||
kt = A[ 9] | A[13];
|
||||
c0 = A[ 0] ^ kt;
|
||||
kt = bnn | A[17];
|
||||
c1 = A[ 9] ^ kt;
|
||||
kt = A[17] & A[21];
|
||||
c2 = A[13] ^ kt;
|
||||
kt = A[21] | A[ 0];
|
||||
c3 = A[17] ^ kt;
|
||||
kt = A[ 0] & A[ 9];
|
||||
c4 = A[21] ^ kt;
|
||||
A[ 0] = c0;
|
||||
A[ 9] = c1;
|
||||
A[13] = c2;
|
||||
A[17] = c3;
|
||||
A[21] = c4;
|
||||
bnn = ~A[14];
|
||||
kt = A[22] | A[ 1];
|
||||
c0 = A[18] ^ kt;
|
||||
kt = A[ 1] & A[ 5];
|
||||
c1 = A[22] ^ kt;
|
||||
kt = A[ 5] | bnn;
|
||||
c2 = A[ 1] ^ kt;
|
||||
kt = A[14] | A[18];
|
||||
c3 = A[ 5] ^ kt;
|
||||
kt = A[18] & A[22];
|
||||
c4 = A[14] ^ kt;
|
||||
A[18] = c0;
|
||||
A[22] = c1;
|
||||
A[ 1] = c2;
|
||||
A[ 5] = c3;
|
||||
A[14] = c4;
|
||||
bnn = ~A[23];
|
||||
kt = A[10] | A[19];
|
||||
c0 = A[ 6] ^ kt;
|
||||
kt = A[19] & A[23];
|
||||
c1 = A[10] ^ kt;
|
||||
kt = bnn & A[ 2];
|
||||
c2 = A[19] ^ kt;
|
||||
kt = A[ 2] | A[ 6];
|
||||
c3 = bnn ^ kt;
|
||||
kt = A[ 6] & A[10];
|
||||
c4 = A[ 2] ^ kt;
|
||||
A[ 6] = c0;
|
||||
A[10] = c1;
|
||||
A[19] = c2;
|
||||
A[23] = c3;
|
||||
A[ 2] = c4;
|
||||
bnn = ~A[11];
|
||||
kt = A[ 3] & A[ 7];
|
||||
c0 = A[24] ^ kt;
|
||||
kt = A[ 7] | A[11];
|
||||
c1 = A[ 3] ^ kt;
|
||||
kt = bnn | A[15];
|
||||
c2 = A[ 7] ^ kt;
|
||||
kt = A[15] & A[24];
|
||||
c3 = bnn ^ kt;
|
||||
kt = A[24] | A[ 3];
|
||||
c4 = A[15] ^ kt;
|
||||
A[24] = c0;
|
||||
A[ 3] = c1;
|
||||
A[ 7] = c2;
|
||||
A[11] = c3;
|
||||
A[15] = c4;
|
||||
bnn = ~A[16];
|
||||
kt = bnn & A[20];
|
||||
c0 = A[12] ^ kt;
|
||||
kt = A[20] | A[ 4];
|
||||
c1 = bnn ^ kt;
|
||||
kt = A[ 4] & A[ 8];
|
||||
c2 = A[20] ^ kt;
|
||||
kt = A[ 8] | A[12];
|
||||
c3 = A[ 4] ^ kt;
|
||||
kt = A[12] & A[16];
|
||||
c4 = A[ 8] ^ kt;
|
||||
A[12] = c0;
|
||||
A[16] = c1;
|
||||
A[20] = c2;
|
||||
A[ 4] = c3;
|
||||
A[ 8] = c4;
|
||||
A[ 0] = A[ 0] ^ RC[j + 1];
|
||||
t = A[ 5];
|
||||
A[ 5] = A[18];
|
||||
A[18] = A[11];
|
||||
A[11] = A[10];
|
||||
A[10] = A[ 6];
|
||||
A[ 6] = A[22];
|
||||
A[22] = A[20];
|
||||
A[20] = A[12];
|
||||
A[12] = A[19];
|
||||
A[19] = A[15];
|
||||
A[15] = A[24];
|
||||
A[24] = A[ 8];
|
||||
A[ 8] = t;
|
||||
t = A[ 1];
|
||||
A[ 1] = A[ 9];
|
||||
A[ 9] = A[14];
|
||||
A[14] = A[ 2];
|
||||
A[ 2] = A[13];
|
||||
A[13] = A[23];
|
||||
A[23] = A[ 4];
|
||||
A[ 4] = A[21];
|
||||
A[21] = A[16];
|
||||
A[16] = A[ 3];
|
||||
A[ 3] = A[17];
|
||||
A[17] = A[ 7];
|
||||
A[ 7] = t;
|
||||
}
|
||||
}
|
||||
|
||||
/* see bearssl_kdf.h */
|
||||
void
|
||||
br_shake_init(br_shake_context *sc, int security_level)
|
||||
{
|
||||
sc->rate = 200 - (size_t)(security_level >> 2);
|
||||
sc->dptr = 0;
|
||||
memset(sc->A, 0, sizeof sc->A);
|
||||
sc->A[ 1] = ~(uint64_t)0;
|
||||
sc->A[ 2] = ~(uint64_t)0;
|
||||
sc->A[ 8] = ~(uint64_t)0;
|
||||
sc->A[12] = ~(uint64_t)0;
|
||||
sc->A[17] = ~(uint64_t)0;
|
||||
sc->A[20] = ~(uint64_t)0;
|
||||
}
|
||||
|
||||
/* see bearssl_kdf.h */
|
||||
void
|
||||
br_shake_inject(br_shake_context *sc, const void *data, size_t len)
|
||||
{
|
||||
const unsigned char *buf;
|
||||
size_t rate, dptr;
|
||||
|
||||
buf = data;
|
||||
rate = sc->rate;
|
||||
dptr = sc->dptr;
|
||||
while (len > 0) {
|
||||
size_t clen;
|
||||
|
||||
clen = rate - dptr;
|
||||
if (clen > len) {
|
||||
clen = len;
|
||||
}
|
||||
memcpy(sc->dbuf + dptr, buf, clen);
|
||||
dptr += clen;
|
||||
buf += clen;
|
||||
len -= clen;
|
||||
if (dptr == rate) {
|
||||
xor_block(sc->A, sc->dbuf, rate);
|
||||
process_block(sc->A);
|
||||
dptr = 0;
|
||||
}
|
||||
}
|
||||
sc->dptr = dptr;
|
||||
}
|
||||
|
||||
/* see bearssl_kdf.h */
|
||||
void
|
||||
br_shake_flip(br_shake_context *sc)
|
||||
{
|
||||
/*
|
||||
* We apply padding and pre-XOR the value into the state. We
|
||||
* set dptr to the end of the buffer, so that first call to
|
||||
* shake_extract() will process the block.
|
||||
*/
|
||||
if ((sc->dptr + 1) == sc->rate) {
|
||||
sc->dbuf[sc->dptr ++] = 0x9F;
|
||||
} else {
|
||||
sc->dbuf[sc->dptr ++] = 0x1F;
|
||||
memset(sc->dbuf + sc->dptr, 0x00, sc->rate - sc->dptr - 1);
|
||||
sc->dbuf[sc->rate - 1] = 0x80;
|
||||
sc->dptr = sc->rate;
|
||||
}
|
||||
xor_block(sc->A, sc->dbuf, sc->rate);
|
||||
}
|
||||
|
||||
/* see bearssl_kdf.h */
|
||||
void
|
||||
br_shake_produce(br_shake_context *sc, void *out, size_t len)
|
||||
{
|
||||
unsigned char *buf;
|
||||
size_t dptr, rate;
|
||||
|
||||
buf = out;
|
||||
dptr = sc->dptr;
|
||||
rate = sc->rate;
|
||||
while (len > 0) {
|
||||
size_t clen;
|
||||
|
||||
if (dptr == rate) {
|
||||
unsigned char *dbuf;
|
||||
uint64_t *A;
|
||||
|
||||
A = sc->A;
|
||||
dbuf = sc->dbuf;
|
||||
process_block(A);
|
||||
br_enc64le(dbuf + 0, A[ 0]);
|
||||
br_enc64le(dbuf + 8, ~A[ 1]);
|
||||
br_enc64le(dbuf + 16, ~A[ 2]);
|
||||
br_enc64le(dbuf + 24, A[ 3]);
|
||||
br_enc64le(dbuf + 32, A[ 4]);
|
||||
br_enc64le(dbuf + 40, A[ 5]);
|
||||
br_enc64le(dbuf + 48, A[ 6]);
|
||||
br_enc64le(dbuf + 56, A[ 7]);
|
||||
br_enc64le(dbuf + 64, ~A[ 8]);
|
||||
br_enc64le(dbuf + 72, A[ 9]);
|
||||
br_enc64le(dbuf + 80, A[10]);
|
||||
br_enc64le(dbuf + 88, A[11]);
|
||||
br_enc64le(dbuf + 96, ~A[12]);
|
||||
br_enc64le(dbuf + 104, A[13]);
|
||||
br_enc64le(dbuf + 112, A[14]);
|
||||
br_enc64le(dbuf + 120, A[15]);
|
||||
br_enc64le(dbuf + 128, A[16]);
|
||||
br_enc64le(dbuf + 136, ~A[17]);
|
||||
br_enc64le(dbuf + 144, A[18]);
|
||||
br_enc64le(dbuf + 152, A[19]);
|
||||
br_enc64le(dbuf + 160, ~A[20]);
|
||||
br_enc64le(dbuf + 168, A[21]);
|
||||
br_enc64le(dbuf + 176, A[22]);
|
||||
br_enc64le(dbuf + 184, A[23]);
|
||||
br_enc64le(dbuf + 192, A[24]);
|
||||
dptr = 0;
|
||||
}
|
||||
clen = rate - dptr;
|
||||
if (clen > len) {
|
||||
clen = len;
|
||||
}
|
||||
memcpy(buf, sc->dbuf + dptr, clen);
|
||||
dptr += clen;
|
||||
buf += clen;
|
||||
len -= clen;
|
||||
}
|
||||
sc->dptr = dptr;
|
||||
}
|
|
@ -0,0 +1,122 @@
|
|||
/*
|
||||
* Copyright (c) 2016 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 "t_inner.h"
|
||||
|
||||
static inline size_t
|
||||
block_size(const br_hash_class *dig)
|
||||
{
|
||||
unsigned ls;
|
||||
|
||||
ls = (unsigned)(dig->desc >> BR_HASHDESC_LBLEN_OFF)
|
||||
& BR_HASHDESC_LBLEN_MASK;
|
||||
return (size_t)1 << ls;
|
||||
}
|
||||
|
||||
static void
|
||||
process_key(const br_hash_class **hc, void *ks,
|
||||
const void *key, size_t key_len, unsigned bb)
|
||||
{
|
||||
unsigned char tmp[256];
|
||||
size_t blen, u;
|
||||
|
||||
blen = block_size(*hc);
|
||||
memcpy(tmp, key, key_len);
|
||||
for (u = 0; u < key_len; u ++) {
|
||||
tmp[u] ^= (unsigned char)bb;
|
||||
}
|
||||
memset(tmp + key_len, bb, blen - key_len);
|
||||
(*hc)->init(hc);
|
||||
(*hc)->update(hc, tmp, blen);
|
||||
(*hc)->state(hc, ks);
|
||||
}
|
||||
|
||||
/* see bearssl.h */
|
||||
void
|
||||
br_hmac_key_init(br_hmac_key_context *kc,
|
||||
const br_hash_class *dig, const void *key, size_t key_len)
|
||||
{
|
||||
br_hash_compat_context hc;
|
||||
unsigned char kbuf[64];
|
||||
|
||||
kc->dig_vtable = dig;
|
||||
hc.vtable = dig;
|
||||
if (key_len > block_size(dig)) {
|
||||
dig->init(&hc.vtable);
|
||||
dig->update(&hc.vtable, key, key_len);
|
||||
dig->out(&hc.vtable, kbuf);
|
||||
key = kbuf;
|
||||
key_len = br_digest_size(dig);
|
||||
}
|
||||
process_key(&hc.vtable, kc->ksi, key, key_len, 0x36);
|
||||
process_key(&hc.vtable, kc->kso, key, key_len, 0x5C);
|
||||
}
|
||||
|
||||
/* see bearssl.h */
|
||||
void
|
||||
br_hmac_init(br_hmac_context *ctx,
|
||||
const br_hmac_key_context *kc, size_t out_len)
|
||||
{
|
||||
const br_hash_class *dig;
|
||||
size_t blen, hlen;
|
||||
|
||||
dig = kc->dig_vtable;
|
||||
blen = block_size(dig);
|
||||
dig->init(&ctx->dig.vtable);
|
||||
dig->set_state(&ctx->dig.vtable, kc->ksi, (uint64_t)blen);
|
||||
memcpy(ctx->kso, kc->kso, sizeof kc->kso);
|
||||
hlen = br_digest_size(dig);
|
||||
if (out_len > 0 && out_len < hlen) {
|
||||
hlen = out_len;
|
||||
}
|
||||
ctx->out_len = hlen;
|
||||
}
|
||||
|
||||
/* see bearssl.h */
|
||||
void
|
||||
br_hmac_update(br_hmac_context *ctx, const void *data, size_t len)
|
||||
{
|
||||
ctx->dig.vtable->update(&ctx->dig.vtable, data, len);
|
||||
}
|
||||
|
||||
/* see bearssl.h */
|
||||
size_t
|
||||
br_hmac_out(const br_hmac_context *ctx, void *out)
|
||||
{
|
||||
const br_hash_class *dig;
|
||||
br_hash_compat_context hc;
|
||||
unsigned char tmp[64];
|
||||
size_t blen, hlen;
|
||||
|
||||
dig = ctx->dig.vtable;
|
||||
dig->out(&ctx->dig.vtable, tmp);
|
||||
blen = block_size(dig);
|
||||
dig->init(&hc.vtable);
|
||||
dig->set_state(&hc.vtable, ctx->kso, (uint64_t)blen);
|
||||
hlen = br_digest_size(dig);
|
||||
dig->update(&hc.vtable, tmp, hlen);
|
||||
dig->out(&hc.vtable, tmp);
|
||||
memcpy(out, tmp, ctx->out_len);
|
||||
return ctx->out_len;
|
||||
}
|
|
@ -0,0 +1,193 @@
|
|||
/*
|
||||
* Copyright (c) 2016 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 "t_inner.h"
|
||||
|
||||
static inline size_t
|
||||
hash_size(const br_hash_class *dig)
|
||||
{
|
||||
return (unsigned)(dig->desc >> BR_HASHDESC_OUT_OFF)
|
||||
& BR_HASHDESC_OUT_MASK;
|
||||
}
|
||||
|
||||
static inline size_t
|
||||
block_size(const br_hash_class *dig)
|
||||
{
|
||||
unsigned ls;
|
||||
|
||||
ls = (unsigned)(dig->desc >> BR_HASHDESC_LBLEN_OFF)
|
||||
& BR_HASHDESC_LBLEN_MASK;
|
||||
return (size_t)1 << ls;
|
||||
}
|
||||
|
||||
/* see bearssl.h */
|
||||
size_t
|
||||
br_hmac_outCT(const br_hmac_context *ctx,
|
||||
const void *data, size_t len, size_t min_len, size_t max_len,
|
||||
void *out)
|
||||
{
|
||||
/*
|
||||
* Method implemented here is inspired from the descriptions on:
|
||||
* https://www.imperialviolet.org/2013/02/04/luckythirteen.html
|
||||
*
|
||||
* Principle: we input bytes one by one. We use a MUX to push
|
||||
* padding bytes instead of data bytes when appropriate. At each
|
||||
* block limit, we get the current hash function state: this is
|
||||
* a potential output, since we handle MD padding ourselves.
|
||||
*
|
||||
* be 1 for big-endian, 0 for little-endian
|
||||
* po minimal MD padding length
|
||||
* bs block size (always a power of 2)
|
||||
* hlen hash output size
|
||||
*/
|
||||
|
||||
const br_hash_class *dig;
|
||||
br_hash_compat_context hc;
|
||||
int be;
|
||||
uint32_t po, bs;
|
||||
uint32_t kr, km, kl, kz, u;
|
||||
uint64_t count, ncount, bit_len;
|
||||
unsigned char tmp1[64], tmp2[64];
|
||||
size_t hlen;
|
||||
|
||||
/*
|
||||
* Copy the current hash context.
|
||||
*/
|
||||
hc = ctx->dig;
|
||||
|
||||
/*
|
||||
* Get function-specific information.
|
||||
*/
|
||||
dig = hc.vtable;
|
||||
be = (dig->desc & BR_HASHDESC_MD_PADDING_BE) != 0;
|
||||
po = 9;
|
||||
if (dig->desc & BR_HASHDESC_MD_PADDING_128) {
|
||||
po += 8;
|
||||
}
|
||||
bs = block_size(dig);
|
||||
hlen = hash_size(dig);
|
||||
|
||||
/*
|
||||
* Get current input length and compute total bit length.
|
||||
*/
|
||||
count = dig->state(&hc.vtable, tmp1);
|
||||
bit_len = (count + (uint64_t)len) << 3;
|
||||
|
||||
/*
|
||||
* We can input the blocks that we are sure we will use.
|
||||
* This offers better performance (no MUX for these blocks)
|
||||
* and also ensures that the remaining lengths fit on 32 bits.
|
||||
*/
|
||||
ncount = (count + (uint64_t)min_len) & ~(uint64_t)(bs - 1);
|
||||
if (ncount > count) {
|
||||
size_t zlen;
|
||||
|
||||
zlen = (size_t)(ncount - count);
|
||||
dig->update(&hc.vtable, data, zlen);
|
||||
data = (const unsigned char *)data + zlen;
|
||||
len -= zlen;
|
||||
max_len -= zlen;
|
||||
count = ncount;
|
||||
}
|
||||
|
||||
/*
|
||||
* At that point:
|
||||
* -- 'count' contains the number of bytes already processed
|
||||
* (in total).
|
||||
* -- We must input 'len' bytes. 'min_len' is unimportant: we
|
||||
* used it to know how many full blocks we could process
|
||||
* directly. Now only len and max_len matter.
|
||||
*
|
||||
* We compute kr, kl, kz and km.
|
||||
* kr number of input bytes already in the current block
|
||||
* km index of the first byte after the end of the last padding
|
||||
* block, if length is max_len
|
||||
* kz index of the last byte of the actual last padding block
|
||||
* kl index of the start of the encoded length
|
||||
*
|
||||
* km, kz and kl are counted from the current offset in the
|
||||
* input data.
|
||||
*/
|
||||
kr = (uint32_t)count & (bs - 1);
|
||||
kz = ((kr + (uint32_t)len + po + bs - 1) & ~(bs - 1)) - 1 - kr;
|
||||
kl = kz - 7;
|
||||
km = ((kr + (uint32_t)max_len + po + bs - 1) & ~(bs - 1)) - kr;
|
||||
|
||||
/*
|
||||
* We must now process km bytes. For index u from 0 to km-1:
|
||||
* d is from data[] if u < max_len, 0x00 otherwise
|
||||
* e is an encoded length byte or 0x00, depending on u
|
||||
* The tests for d and e need not be constant-time, since
|
||||
* they relate only to u and max_len, not to the actual length.
|
||||
*
|
||||
* Actual input length is then:
|
||||
* d if u < len
|
||||
* 0x80 if u == len
|
||||
* 0x00 if u > len and u < kl
|
||||
* e if u >= kl
|
||||
*
|
||||
* Hash state is obtained whenever we reach a full block. This
|
||||
* is the result we want if and only if u == kz.
|
||||
*/
|
||||
memset(tmp2, 0, sizeof tmp2);
|
||||
for (u = 0; u < km; u ++) {
|
||||
uint32_t v;
|
||||
uint32_t d, e, x0, x1;
|
||||
unsigned char x[1];
|
||||
|
||||
d = (u < max_len) ? ((const unsigned char *)data)[u] : 0x00;
|
||||
v = (kr + u) & (bs - 1);
|
||||
if (v >= (bs - 8)) {
|
||||
unsigned j;
|
||||
|
||||
j = (v - (bs - 8)) << 3;
|
||||
if (be) {
|
||||
e = (uint32_t)(bit_len >> (56 - j));
|
||||
} else {
|
||||
e = (uint32_t)(bit_len >> j);
|
||||
}
|
||||
e &= 0xFF;
|
||||
} else {
|
||||
e = 0x00;
|
||||
}
|
||||
x0 = MUX(EQ(u, (uint32_t)len), 0x80, d);
|
||||
x1 = MUX(LT(u, kl), 0x00, e);
|
||||
x[0] = MUX(LE(u, (uint32_t)len), x0, x1);
|
||||
dig->update(&hc.vtable, x, 1);
|
||||
if (v == (bs - 1)) {
|
||||
dig->state(&hc.vtable, tmp1);
|
||||
CCOPY(EQ(u, kz), tmp2, tmp1, hlen);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Inner hash output is in tmp2[]; we finish processing.
|
||||
*/
|
||||
dig->init(&hc.vtable);
|
||||
dig->set_state(&hc.vtable, ctx->kso, (uint64_t)bs);
|
||||
dig->update(&hc.vtable, tmp2, hlen);
|
||||
dig->out(&hc.vtable, tmp2);
|
||||
memcpy(out, tmp2, ctx->out_len);
|
||||
return ctx->out_len;
|
||||
}
|
|
@ -0,0 +1,119 @@
|
|||
/* pgmspace_bearssl.h - Accessor utilities/types for accessing PROGMEM data */
|
||||
|
||||
//#pragma GCC optimize ("O2") // -Os is the default, forcing -O2 for BearSSL
|
||||
//#define PGM_READ_UNALIGNED 0 // all calls are aligned, take the optimized version
|
||||
//#include <sys/pgmspace.h>
|
||||
|
||||
|
||||
#ifndef _PGMSPACE_BEARSSL_H_
|
||||
#define _PGMSPACE_BEARSSL_H_
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#ifndef ICACHE_RODATA_ATTR
|
||||
#define ICACHE_RODATA_ATTR __attribute__((section(".irom.text")))
|
||||
#endif
|
||||
#ifndef PROGMEM
|
||||
// The following two macros cause a parameter to be enclosed in quotes
|
||||
// by the preopressor (i.e. for concatenating ints to strings)
|
||||
#define __STRINGIZE_NX(A) #A
|
||||
#define __STRINGIZE(A) __STRINGIZE_NX(A)
|
||||
// Since __section__ is supposed to be only use for global variables,
|
||||
// there could be conflicts when a static/inlined function has them in the
|
||||
// same file as a non-static PROGMEM object.
|
||||
// Ref: https://gcc.gnu.org/onlinedocs/gcc-3.2/gcc/Variable-Attributes.html
|
||||
// Place each progmem object into its own named section, avoiding conflicts
|
||||
#define PROGMEM __attribute__((section( "\".irom.text." __FILE__ "." __STRINGIZE(__LINE__) "." __STRINGIZE(__COUNTER__) "\"")))
|
||||
#endif
|
||||
#ifndef PGM_P
|
||||
#define PGM_P const char *
|
||||
#endif
|
||||
#ifndef PGM_VOID_P
|
||||
#define PGM_VOID_P const void *
|
||||
#endif
|
||||
|
||||
// PSTR() macro modified to start on a 32-bit boundary. This adds on average
|
||||
// 1.5 bytes/string, but in return memcpy_P and strcpy_P will work 4~8x faster
|
||||
#ifndef PSTR
|
||||
#define PSTR(s) (__extension__({static const char __c[] __attribute__((__aligned__(4))) PROGMEM = (s); &__c[0];}))
|
||||
#endif
|
||||
|
||||
// Flash memory must be read using 32 bit aligned addresses else a processor
|
||||
// exception will be triggered.
|
||||
// The order within the 32 bit values are:
|
||||
// --------------
|
||||
// b3, b2, b1, b0
|
||||
// w1, w0
|
||||
|
||||
#define pgm_read_with_offset(addr, res) \
|
||||
asm("extui %0, %1, 0, 2\n" /* Extract offset within word (in bytes) */ \
|
||||
"sub %1, %1, %0\n" /* Subtract offset from addr, yielding an aligned address */ \
|
||||
"l32i.n %1, %1, 0x0\n" /* Load word from aligned address */ \
|
||||
"slli %0, %0, 3\n" /* Mulitiply offset by 8, yielding an offset in bits */ \
|
||||
"ssr %0\n" /* Prepare to shift by offset (in bits) */ \
|
||||
"srl %0, %1\n" /* Shift right; now the requested byte is the first one */ \
|
||||
:"=r"(res), "=r"(addr) \
|
||||
:"1"(addr) \
|
||||
:);
|
||||
|
||||
static inline uint8_t pgm_read_byte_inlined(const void* addr) {
|
||||
register uint32_t res;
|
||||
pgm_read_with_offset(addr, res);
|
||||
return (uint8_t) res; /* This masks the lower byte from the returned word */
|
||||
}
|
||||
|
||||
/* Although this says "word", it's actually 16 bit, i.e. half word on Xtensa */
|
||||
static inline uint16_t pgm_read_word_inlined(const void* addr) {
|
||||
register uint32_t res;
|
||||
pgm_read_with_offset(addr, res);
|
||||
return (uint16_t) res; /* This masks the lower half-word from the returned word */
|
||||
}
|
||||
|
||||
#define pgm_read_byte(addr) pgm_read_byte_inlined(addr)
|
||||
#define pgm_read_word(addr) pgm_read_word_inlined(addr)
|
||||
#ifdef __cplusplus
|
||||
#define pgm_read_dword(addr) (*reinterpret_cast<const uint32_t*>(addr))
|
||||
#define pgm_read_float(addr) (*reinterpret_cast<const float*>(addr))
|
||||
#define pgm_read_ptr(addr) (*reinterpret_cast<const void* const *>(addr))
|
||||
#else
|
||||
#define pgm_read_dword(addr) (*(const uint32_t*)(addr))
|
||||
#define pgm_read_float(addr) (*(const float*)(addr))
|
||||
#define pgm_read_ptr(addr) (*(const void* const*)(addr))
|
||||
#endif
|
||||
|
||||
#define pgm_read_byte_near(addr) pgm_read_byte(addr)
|
||||
#define pgm_read_word_near(addr) pgm_read_word(addr)
|
||||
#define pgm_read_dword_near(addr) pgm_read_dword(addr)
|
||||
#define pgm_read_float_near(addr) pgm_read_float(addr)
|
||||
#define pgm_read_ptr_near(addr) pgm_read_ptr(addr)
|
||||
#define pgm_read_byte_far(addr) pgm_read_byte(addr)
|
||||
#define pgm_read_word_far(addr) pgm_read_word(addr)
|
||||
#define pgm_read_dword_far(addr) pgm_read_dword(addr)
|
||||
#define pgm_read_float_far(addr) pgm_read_float(addr)
|
||||
#define pgm_read_ptr_far(addr) pgm_read_ptr(addr)
|
||||
|
||||
#define _SFR_BYTE(n) (n)
|
||||
|
||||
#ifdef __PROG_TYPES_COMPAT__
|
||||
|
||||
typedef void prog_void;
|
||||
typedef char prog_char;
|
||||
typedef unsigned char prog_uchar;
|
||||
typedef int8_t prog_int8_t;
|
||||
typedef uint8_t prog_uint8_t;
|
||||
typedef int16_t prog_int16_t;
|
||||
typedef uint16_t prog_uint16_t;
|
||||
typedef int32_t prog_int32_t;
|
||||
typedef uint32_t prog_uint32_t;
|
||||
|
||||
#endif // defined(__PROG_TYPES_COMPAT__)
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
|
@ -0,0 +1,206 @@
|
|||
/*
|
||||
* Copyright (c) 2018 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 "t_inner.h"
|
||||
|
||||
/* see bearssl_rand.h */
|
||||
void
|
||||
br_aesctr_drbg_init(br_aesctr_drbg_context *ctx,
|
||||
const br_block_ctr_class *aesctr,
|
||||
const void *seed, size_t len)
|
||||
{
|
||||
unsigned char tmp[16];
|
||||
|
||||
ctx->vtable = &br_aesctr_drbg_vtable;
|
||||
memset(tmp, 0, sizeof tmp);
|
||||
aesctr->init(&ctx->sk.vtable, tmp, 16);
|
||||
ctx->cc = 0;
|
||||
br_aesctr_drbg_update(ctx, seed, len);
|
||||
}
|
||||
|
||||
/* see bearssl_rand.h */
|
||||
void
|
||||
br_aesctr_drbg_generate(br_aesctr_drbg_context *ctx, void *out, size_t len)
|
||||
{
|
||||
unsigned char *buf;
|
||||
unsigned char iv[12];
|
||||
|
||||
buf = out;
|
||||
memset(iv, 0, sizeof iv);
|
||||
while (len > 0) {
|
||||
size_t clen;
|
||||
|
||||
/*
|
||||
* We generate data by blocks of at most 65280 bytes. This
|
||||
* allows for unambiguously testing the counter overflow
|
||||
* condition; also, it should work on 16-bit architectures
|
||||
* (where 'size_t' is 16 bits only).
|
||||
*/
|
||||
clen = len;
|
||||
if (clen > 65280) {
|
||||
clen = 65280;
|
||||
}
|
||||
|
||||
/*
|
||||
* We make sure that the counter won't exceed the configured
|
||||
* limit.
|
||||
*/
|
||||
if ((uint32_t)(ctx->cc + ((clen + 15) >> 4)) > 32768) {
|
||||
clen = (32768 - ctx->cc) << 4;
|
||||
if (clen > len) {
|
||||
clen = len;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Run CTR.
|
||||
*/
|
||||
memset(buf, 0, clen);
|
||||
ctx->cc = ctx->sk.vtable->run(&ctx->sk.vtable,
|
||||
iv, ctx->cc, buf, clen);
|
||||
buf += clen;
|
||||
len -= clen;
|
||||
|
||||
/*
|
||||
* Every 32768 blocks, we force a state update.
|
||||
*/
|
||||
if (ctx->cc >= 32768) {
|
||||
br_aesctr_drbg_update(ctx, NULL, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* see bearssl_rand.h */
|
||||
void
|
||||
br_aesctr_drbg_update(br_aesctr_drbg_context *ctx, const void *seed, size_t len)
|
||||
{
|
||||
/*
|
||||
* We use a Hirose construction on AES-256 to make a hash function.
|
||||
* Function definition:
|
||||
* - running state consists in two 16-byte blocks G and H
|
||||
* - initial values of G and H are conventional
|
||||
* - there is a fixed block-sized constant C
|
||||
* - for next data block m:
|
||||
* set AES key to H||m
|
||||
* G' = E(G) xor G
|
||||
* H' = E(G xor C) xor G xor C
|
||||
* G <- G', H <- H'
|
||||
* - once all blocks have been processed, output is H||G
|
||||
*
|
||||
* Constants:
|
||||
* G_init = B6 B6 ... B6
|
||||
* H_init = A5 A5 ... A5
|
||||
* C = 01 00 ... 00
|
||||
*
|
||||
* With this hash function h(), we compute the new state as
|
||||
* follows:
|
||||
* - produce a state-dependent value s as encryption of an
|
||||
* all-one block with AES and the current key
|
||||
* - compute the new key as the first 128 bits of h(s||seed)
|
||||
*
|
||||
* Original Hirose article:
|
||||
* https://www.iacr.org/archive/fse2006/40470213/40470213.pdf
|
||||
*/
|
||||
|
||||
unsigned char s[16], iv[12];
|
||||
unsigned char G[16], H[16];
|
||||
int first;
|
||||
|
||||
/*
|
||||
* Use an all-one IV to get a fresh output block that depends on the
|
||||
* current seed.
|
||||
*/
|
||||
memset(iv, 0xFF, sizeof iv);
|
||||
memset(s, 0, 16);
|
||||
ctx->sk.vtable->run(&ctx->sk.vtable, iv, 0xFFFFFFFF, s, 16);
|
||||
|
||||
/*
|
||||
* Set G[] and H[] to conventional start values.
|
||||
*/
|
||||
memset(G, 0xB6, sizeof G);
|
||||
memset(H, 0x5A, sizeof H);
|
||||
|
||||
/*
|
||||
* Process the concatenation of the current state and the seed
|
||||
* with the custom hash function.
|
||||
*/
|
||||
first = 1;
|
||||
for (;;) {
|
||||
unsigned char tmp[32];
|
||||
unsigned char newG[16];
|
||||
|
||||
/*
|
||||
* Assemble new key H||m into tmp[].
|
||||
*/
|
||||
memcpy(tmp, H, 16);
|
||||
if (first) {
|
||||
memcpy(tmp + 16, s, 16);
|
||||
first = 0;
|
||||
} else {
|
||||
size_t clen;
|
||||
|
||||
if (len == 0) {
|
||||
break;
|
||||
}
|
||||
clen = len < 16 ? len : 16;
|
||||
memcpy(tmp + 16, seed, clen);
|
||||
memset(tmp + 16 + clen, 0, 16 - clen);
|
||||
seed = (const unsigned char *)seed + clen;
|
||||
len -= clen;
|
||||
}
|
||||
ctx->sk.vtable->init(&ctx->sk.vtable, tmp, 32);
|
||||
|
||||
/*
|
||||
* Compute new G and H values.
|
||||
*/
|
||||
memcpy(iv, G, 12);
|
||||
memcpy(newG, G, 16);
|
||||
ctx->sk.vtable->run(&ctx->sk.vtable, iv,
|
||||
br_dec32be(G + 12), newG, 16);
|
||||
iv[0] ^= 0x01;
|
||||
memcpy(H, G, 16);
|
||||
H[0] ^= 0x01;
|
||||
ctx->sk.vtable->run(&ctx->sk.vtable, iv,
|
||||
br_dec32be(G + 12), H, 16);
|
||||
memcpy(G, newG, 16);
|
||||
}
|
||||
|
||||
/*
|
||||
* Output hash value is H||G. We truncate it to its first 128 bits,
|
||||
* i.e. H; that's our new AES key.
|
||||
*/
|
||||
ctx->sk.vtable->init(&ctx->sk.vtable, H, 16);
|
||||
ctx->cc = 0;
|
||||
}
|
||||
|
||||
/* see bearssl_rand.h */
|
||||
const br_prng_class br_aesctr_drbg_vtable = {
|
||||
sizeof(br_aesctr_drbg_context),
|
||||
(void (*)(const br_prng_class **, const void *, const void *, size_t))
|
||||
&br_aesctr_drbg_init,
|
||||
(void (*)(const br_prng_class **, void *, size_t))
|
||||
&br_aesctr_drbg_generate,
|
||||
(void (*)(const br_prng_class **, const void *, size_t))
|
||||
&br_aesctr_drbg_update
|
||||
};
|
|
@ -0,0 +1,157 @@
|
|||
/*
|
||||
* Copyright (c) 2016 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 "t_inner.h"
|
||||
|
||||
/* see bearssl.h */
|
||||
void
|
||||
br_hmac_drbg_init(br_hmac_drbg_context *ctx,
|
||||
const br_hash_class *digest_class, const void *seed, size_t len)
|
||||
{
|
||||
size_t hlen;
|
||||
|
||||
ctx->vtable = &br_hmac_drbg_vtable;
|
||||
hlen = br_digest_size(digest_class);
|
||||
memset(ctx->K, 0x00, hlen);
|
||||
memset(ctx->V, 0x01, hlen);
|
||||
ctx->digest_class = digest_class;
|
||||
br_hmac_drbg_update(ctx, seed, len);
|
||||
}
|
||||
|
||||
/* see bearssl.h */
|
||||
void
|
||||
br_hmac_drbg_generate(br_hmac_drbg_context *ctx, void *out, size_t len)
|
||||
{
|
||||
const br_hash_class *dig;
|
||||
br_hmac_key_context kc;
|
||||
br_hmac_context hc;
|
||||
size_t hlen;
|
||||
unsigned char *buf;
|
||||
unsigned char x;
|
||||
|
||||
dig = ctx->digest_class;
|
||||
hlen = br_digest_size(dig);
|
||||
br_hmac_key_init(&kc, dig, ctx->K, hlen);
|
||||
buf = out;
|
||||
while (len > 0) {
|
||||
size_t clen;
|
||||
|
||||
br_hmac_init(&hc, &kc, 0);
|
||||
br_hmac_update(&hc, ctx->V, hlen);
|
||||
br_hmac_out(&hc, ctx->V);
|
||||
clen = hlen;
|
||||
if (clen > len) {
|
||||
clen = len;
|
||||
}
|
||||
memcpy(buf, ctx->V, clen);
|
||||
buf += clen;
|
||||
len -= clen;
|
||||
}
|
||||
|
||||
/*
|
||||
* To prepare the state for the next request, we should call
|
||||
* br_hmac_drbg_update() with an empty additional seed. However,
|
||||
* we already have an initialized HMAC context with the right
|
||||
* initial key, and we don't want to push another one on the
|
||||
* stack, so we inline that update() call here.
|
||||
*/
|
||||
br_hmac_init(&hc, &kc, 0);
|
||||
br_hmac_update(&hc, ctx->V, hlen);
|
||||
x = 0x00;
|
||||
br_hmac_update(&hc, &x, 1);
|
||||
br_hmac_out(&hc, ctx->K);
|
||||
br_hmac_key_init(&kc, dig, ctx->K, hlen);
|
||||
br_hmac_init(&hc, &kc, 0);
|
||||
br_hmac_update(&hc, ctx->V, hlen);
|
||||
br_hmac_out(&hc, ctx->V);
|
||||
}
|
||||
|
||||
/* see bearssl.h */
|
||||
void
|
||||
br_hmac_drbg_update(br_hmac_drbg_context *ctx, const void *seed, size_t len)
|
||||
{
|
||||
const br_hash_class *dig;
|
||||
br_hmac_key_context kc;
|
||||
br_hmac_context hc;
|
||||
size_t hlen;
|
||||
unsigned char x;
|
||||
|
||||
dig = ctx->digest_class;
|
||||
hlen = br_digest_size(dig);
|
||||
|
||||
/*
|
||||
* 1. K = HMAC(K, V || 0x00 || seed)
|
||||
*/
|
||||
br_hmac_key_init(&kc, dig, ctx->K, hlen);
|
||||
br_hmac_init(&hc, &kc, 0);
|
||||
br_hmac_update(&hc, ctx->V, hlen);
|
||||
x = 0x00;
|
||||
br_hmac_update(&hc, &x, 1);
|
||||
br_hmac_update(&hc, seed, len);
|
||||
br_hmac_out(&hc, ctx->K);
|
||||
br_hmac_key_init(&kc, dig, ctx->K, hlen);
|
||||
|
||||
/*
|
||||
* 2. V = HMAC(K, V)
|
||||
*/
|
||||
br_hmac_init(&hc, &kc, 0);
|
||||
br_hmac_update(&hc, ctx->V, hlen);
|
||||
br_hmac_out(&hc, ctx->V);
|
||||
|
||||
/*
|
||||
* 3. If the additional seed is empty, then stop here.
|
||||
*/
|
||||
if (len == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* 4. K = HMAC(K, V || 0x01 || seed)
|
||||
*/
|
||||
br_hmac_init(&hc, &kc, 0);
|
||||
br_hmac_update(&hc, ctx->V, hlen);
|
||||
x = 0x01;
|
||||
br_hmac_update(&hc, &x, 1);
|
||||
br_hmac_update(&hc, seed, len);
|
||||
br_hmac_out(&hc, ctx->K);
|
||||
br_hmac_key_init(&kc, dig, ctx->K, hlen);
|
||||
|
||||
/*
|
||||
* 5. V = HMAC(K, V)
|
||||
*/
|
||||
br_hmac_init(&hc, &kc, 0);
|
||||
br_hmac_update(&hc, ctx->V, hlen);
|
||||
br_hmac_out(&hc, ctx->V);
|
||||
}
|
||||
|
||||
/* see bearssl.h */
|
||||
const br_prng_class br_hmac_drbg_vtable PROGMEM = {
|
||||
sizeof(br_hmac_drbg_context),
|
||||
(void (*)(const br_prng_class **, const void *, const void *, size_t))
|
||||
&br_hmac_drbg_init,
|
||||
(void (*)(const br_prng_class **, void *, size_t))
|
||||
&br_hmac_drbg_generate,
|
||||
(void (*)(const br_prng_class **, const void *, size_t))
|
||||
&br_hmac_drbg_update
|
||||
};
|
|
@ -0,0 +1,195 @@
|
|||
/*
|
||||
* 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 "t_inner.h"
|
||||
|
||||
#if BR_USE_URANDOM
|
||||
#include <sys/types.h>
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
#include <errno.h>
|
||||
#endif
|
||||
|
||||
#if BR_USE_WIN32_RAND
|
||||
#include <windows.h>
|
||||
#include <wincrypt.h>
|
||||
#pragma comment(lib, "advapi32")
|
||||
#endif
|
||||
|
||||
#if BR_RDRAND
|
||||
BR_TARGETS_X86_UP
|
||||
BR_TARGET("rdrnd")
|
||||
static int
|
||||
seeder_rdrand(const br_prng_class **ctx)
|
||||
{
|
||||
unsigned char tmp[32];
|
||||
size_t u;
|
||||
|
||||
for (u = 0; u < sizeof tmp; u += sizeof(uint32_t)) {
|
||||
int j;
|
||||
uint32_t x;
|
||||
|
||||
/*
|
||||
* We use the 32-bit intrinsic so that code is compatible
|
||||
* with both 32-bit and 64-bit architectures.
|
||||
*
|
||||
* Intel recommends trying at least 10 times in case of
|
||||
* failure.
|
||||
*/
|
||||
for (j = 0; j < 10; j ++) {
|
||||
if (_rdrand32_step(&x)) {
|
||||
goto next_word;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
next_word:
|
||||
br_enc32le(tmp + u, x);
|
||||
}
|
||||
(*ctx)->update(ctx, tmp, sizeof tmp);
|
||||
return 1;
|
||||
}
|
||||
BR_TARGETS_X86_DOWN
|
||||
|
||||
static int
|
||||
rdrand_supported(void)
|
||||
{
|
||||
/*
|
||||
* The RDRND support is bit 30 of ECX, as returned by CPUID.
|
||||
*/
|
||||
return br_cpuid(0, 0, 0x40000000, 0);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#if BR_USE_URANDOM
|
||||
static int
|
||||
seeder_urandom(const br_prng_class **ctx)
|
||||
{
|
||||
int f;
|
||||
|
||||
f = open("/dev/urandom", O_RDONLY);
|
||||
if (f >= 0) {
|
||||
unsigned char tmp[32];
|
||||
size_t u;
|
||||
|
||||
for (u = 0; u < sizeof tmp;) {
|
||||
ssize_t len;
|
||||
|
||||
len = read(f, tmp + u, (sizeof tmp) - u);
|
||||
if (len < 0) {
|
||||
if (errno == EINTR) {
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
}
|
||||
u += (size_t)len;
|
||||
}
|
||||
close(f);
|
||||
if (u == sizeof tmp) {
|
||||
(*ctx)->update(ctx, tmp, sizeof tmp);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if BR_USE_WIN32_RAND
|
||||
static int
|
||||
seeder_win32(const br_prng_class **ctx)
|
||||
{
|
||||
HCRYPTPROV hp;
|
||||
|
||||
if (CryptAcquireContext(&hp, 0, 0, PROV_RSA_FULL,
|
||||
CRYPT_VERIFYCONTEXT | CRYPT_SILENT))
|
||||
{
|
||||
BYTE buf[32];
|
||||
BOOL r;
|
||||
|
||||
r = CryptGenRandom(hp, sizeof buf, buf);
|
||||
CryptReleaseContext(hp, 0);
|
||||
if (r) {
|
||||
(*ctx)->update(ctx, buf, sizeof buf);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if BR_USE_ESP8266_RAND
|
||||
extern uint32_t phy_get_rand(void); // From the ESP8266 SDK
|
||||
|
||||
static int
|
||||
seeder_esp8266(const br_prng_class **ctx)
|
||||
{
|
||||
uint32_t tmp[32 / sizeof(uint32_t)];
|
||||
size_t i;
|
||||
|
||||
for (i=0; i<sizeof(tmp)/sizeof(tmp[0]); i++) {
|
||||
tmp[i] = phy_get_rand();
|
||||
}
|
||||
|
||||
(*ctx)->update(ctx, tmp, sizeof tmp);
|
||||
|
||||
return 1;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* see bearssl_rand.h */
|
||||
|
||||
br_prng_seeder
|
||||
br_prng_seeder_system(const char **name)
|
||||
{
|
||||
#if BR_RDRAND
|
||||
if (rdrand_supported()) {
|
||||
if (name != NULL) {
|
||||
*name = "rdrand";
|
||||
}
|
||||
return &seeder_rdrand;
|
||||
}
|
||||
#endif
|
||||
#if BR_USE_URANDOM
|
||||
if (name != NULL) {
|
||||
*name = "urandom";
|
||||
}
|
||||
return &seeder_urandom;
|
||||
#elif BR_USE_WIN32_RAND
|
||||
if (name != NULL) {
|
||||
*name = "win32";
|
||||
}
|
||||
return &seeder_win32;
|
||||
#elif BR_USE_ESP8266_RAND
|
||||
if (name != NULL) {
|
||||
*name = "esp8266";
|
||||
}
|
||||
return &seeder_esp8266;
|
||||
#else
|
||||
if (name != NULL) {
|
||||
*name = "none";
|
||||
}
|
||||
return 0;
|
||||
#endif
|
||||
}
|
|
@ -0,0 +1,38 @@
|
|||
/*
|
||||
* Copyright (c) 2018 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 "t_inner.h"
|
||||
|
||||
/* see bearssl_rsa.h */
|
||||
br_rsa_keygen
|
||||
br_rsa_keygen_get_default(void)
|
||||
{
|
||||
#if BR_INT128 || BR_UMUL128
|
||||
return &br_rsa_i62_keygen;
|
||||
#elif BR_LOMUL
|
||||
return &br_rsa_i15_keygen;
|
||||
#else
|
||||
return &br_rsa_i31_keygen;
|
||||
#endif
|
||||
}
|
|
@ -0,0 +1,36 @@
|
|||
/*
|
||||
* Copyright (c) 2018 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 "t_inner.h"
|
||||
|
||||
/* see bearssl_rsa.h */
|
||||
br_rsa_compute_modulus
|
||||
br_rsa_compute_modulus_get_default(void)
|
||||
{
|
||||
#if BR_LOMUL
|
||||
return &br_rsa_i15_compute_modulus;
|
||||
#else
|
||||
return &br_rsa_i31_compute_modulus;
|
||||
#endif
|
||||
}
|
|
@ -0,0 +1,38 @@
|
|||
/*
|
||||
* Copyright (c) 2018 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 "t_inner.h"
|
||||
|
||||
/* see bearssl_rsa.h */
|
||||
br_rsa_oaep_decrypt
|
||||
br_rsa_oaep_decrypt_get_default(void)
|
||||
{
|
||||
#if BR_INT128 || BR_UMUL128
|
||||
return &br_rsa_i62_oaep_decrypt;
|
||||
#elif BR_LOMUL
|
||||
return &br_rsa_i15_oaep_decrypt;
|
||||
#else
|
||||
return &br_rsa_i31_oaep_decrypt;
|
||||
#endif
|
||||
}
|
|
@ -0,0 +1,38 @@
|
|||
/*
|
||||
* Copyright (c) 2018 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 "t_inner.h"
|
||||
|
||||
/* see bearssl_rsa.h */
|
||||
br_rsa_oaep_encrypt
|
||||
br_rsa_oaep_encrypt_get_default(void)
|
||||
{
|
||||
#if BR_INT128 || BR_UMUL128
|
||||
return &br_rsa_i62_oaep_encrypt;
|
||||
#elif BR_LOMUL
|
||||
return &br_rsa_i15_oaep_encrypt;
|
||||
#else
|
||||
return &br_rsa_i31_oaep_encrypt;
|
||||
#endif
|
||||
}
|
|
@ -0,0 +1,38 @@
|
|||
/*
|
||||
* 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 "t_inner.h"
|
||||
|
||||
/* see bearssl_rsa.h */
|
||||
br_rsa_pkcs1_sign
|
||||
br_rsa_pkcs1_sign_get_default(void)
|
||||
{
|
||||
#if BR_INT128 || BR_UMUL128
|
||||
return &br_rsa_i62_pkcs1_sign;
|
||||
#elif BR_LOMUL
|
||||
return &br_rsa_i15_pkcs1_sign;
|
||||
#else
|
||||
return &br_rsa_i31_pkcs1_sign;
|
||||
#endif
|
||||
}
|
|
@ -0,0 +1,38 @@
|
|||
/*
|
||||
* 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 "t_inner.h"
|
||||
|
||||
/* see bearssl_rsa.h */
|
||||
br_rsa_pkcs1_vrfy
|
||||
br_rsa_pkcs1_vrfy_get_default(void)
|
||||
{
|
||||
#if BR_INT128 || BR_UMUL128
|
||||
return &br_rsa_i62_pkcs1_vrfy;
|
||||
#elif BR_LOMUL
|
||||
return &br_rsa_i15_pkcs1_vrfy;
|
||||
#else
|
||||
return &br_rsa_i31_pkcs1_vrfy;
|
||||
#endif
|
||||
}
|
|
@ -0,0 +1,38 @@
|
|||
/*
|
||||
* 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 "t_inner.h"
|
||||
|
||||
/* see bearssl_rsa.h */
|
||||
br_rsa_private
|
||||
br_rsa_private_get_default(void)
|
||||
{
|
||||
#if BR_INT128 || BR_UMUL128
|
||||
return &br_rsa_i62_private;
|
||||
#elif BR_LOMUL
|
||||
return &br_rsa_i15_private;
|
||||
#else
|
||||
return &br_rsa_i31_private;
|
||||
#endif
|
||||
}
|
|
@ -0,0 +1,36 @@
|
|||
/*
|
||||
* Copyright (c) 2018 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 "t_inner.h"
|
||||
|
||||
/* see bearssl_rsa.h */
|
||||
br_rsa_compute_privexp
|
||||
br_rsa_compute_privexp_get_default(void)
|
||||
{
|
||||
#if BR_LOMUL
|
||||
return &br_rsa_i15_compute_privexp;
|
||||
#else
|
||||
return &br_rsa_i31_compute_privexp;
|
||||
#endif
|
||||
}
|
|
@ -0,0 +1,38 @@
|
|||
/*
|
||||
* Copyright (c) 2018 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 "t_inner.h"
|
||||
|
||||
/* see bearssl_rsa.h */
|
||||
br_rsa_pss_sign
|
||||
br_rsa_pss_sign_get_default(void)
|
||||
{
|
||||
#if BR_INT128 || BR_UMUL128
|
||||
return &br_rsa_i62_pss_sign;
|
||||
#elif BR_LOMUL
|
||||
return &br_rsa_i15_pss_sign;
|
||||
#else
|
||||
return &br_rsa_i31_pss_sign;
|
||||
#endif
|
||||
}
|
|
@ -0,0 +1,38 @@
|
|||
/*
|
||||
* Copyright (c) 2018 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 "t_inner.h"
|
||||
|
||||
/* see bearssl_rsa.h */
|
||||
br_rsa_pss_vrfy
|
||||
br_rsa_pss_vrfy_get_default(void)
|
||||
{
|
||||
#if BR_INT128 || BR_UMUL128
|
||||
return &br_rsa_i62_pss_vrfy;
|
||||
#elif BR_LOMUL
|
||||
return &br_rsa_i15_pss_vrfy;
|
||||
#else
|
||||
return &br_rsa_i31_pss_vrfy;
|
||||
#endif
|
||||
}
|
|
@ -0,0 +1,38 @@
|
|||
/*
|
||||
* 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 "t_inner.h"
|
||||
|
||||
/* see bearssl_rsa.h */
|
||||
br_rsa_public
|
||||
br_rsa_public_get_default(void)
|
||||
{
|
||||
#if BR_INT128 || BR_UMUL128
|
||||
return &br_rsa_i62_public;
|
||||
#elif BR_LOMUL
|
||||
return &br_rsa_i15_public;
|
||||
#else
|
||||
return &br_rsa_i31_public;
|
||||
#endif
|
||||
}
|
|
@ -0,0 +1,36 @@
|
|||
/*
|
||||
* Copyright (c) 2018 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 "t_inner.h"
|
||||
|
||||
/* see bearssl_rsa.h */
|
||||
br_rsa_compute_pubexp
|
||||
br_rsa_compute_pubexp_get_default(void)
|
||||
{
|
||||
#if BR_LOMUL
|
||||
return &br_rsa_i15_compute_pubexp;
|
||||
#else
|
||||
return &br_rsa_i31_compute_pubexp;
|
||||
#endif
|
||||
}
|
|
@ -0,0 +1,585 @@
|
|||
/*
|
||||
* Copyright (c) 2018 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 "t_inner.h"
|
||||
|
||||
/*
|
||||
* Make a random integer of the provided size. The size is encoded.
|
||||
* The header word is untouched.
|
||||
*/
|
||||
static void
|
||||
mkrand(const br_prng_class **rng, uint16_t *x, uint32_t esize)
|
||||
{
|
||||
size_t u, len;
|
||||
unsigned m;
|
||||
|
||||
len = (esize + 15) >> 4;
|
||||
(*rng)->generate(rng, x + 1, len * sizeof(uint16_t));
|
||||
for (u = 1; u < len; u ++) {
|
||||
x[u] &= 0x7FFF;
|
||||
}
|
||||
m = esize & 15;
|
||||
if (m == 0) {
|
||||
x[len] &= 0x7FFF;
|
||||
} else {
|
||||
x[len] &= 0x7FFF >> (15 - m);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* This is the big-endian unsigned representation of the product of
|
||||
* all small primes from 13 to 1481.
|
||||
*/
|
||||
static const unsigned char SMALL_PRIMES[] PROGMEM = {
|
||||
0x2E, 0xAB, 0x92, 0xD1, 0x8B, 0x12, 0x47, 0x31, 0x54, 0x0A,
|
||||
0x99, 0x5D, 0x25, 0x5E, 0xE2, 0x14, 0x96, 0x29, 0x1E, 0xB7,
|
||||
0x78, 0x70, 0xCC, 0x1F, 0xA5, 0xAB, 0x8D, 0x72, 0x11, 0x37,
|
||||
0xFB, 0xD8, 0x1E, 0x3F, 0x5B, 0x34, 0x30, 0x17, 0x8B, 0xE5,
|
||||
0x26, 0x28, 0x23, 0xA1, 0x8A, 0xA4, 0x29, 0xEA, 0xFD, 0x9E,
|
||||
0x39, 0x60, 0x8A, 0xF3, 0xB5, 0xA6, 0xEB, 0x3F, 0x02, 0xB6,
|
||||
0x16, 0xC3, 0x96, 0x9D, 0x38, 0xB0, 0x7D, 0x82, 0x87, 0x0C,
|
||||
0xF7, 0xBE, 0x24, 0xE5, 0x5F, 0x41, 0x04, 0x79, 0x76, 0x40,
|
||||
0xE7, 0x00, 0x22, 0x7E, 0xB5, 0x85, 0x7F, 0x8D, 0x01, 0x50,
|
||||
0xE9, 0xD3, 0x29, 0x42, 0x08, 0xB3, 0x51, 0x40, 0x7B, 0xD7,
|
||||
0x8D, 0xCC, 0x10, 0x01, 0x64, 0x59, 0x28, 0xB6, 0x53, 0xF3,
|
||||
0x50, 0x4E, 0xB1, 0xF2, 0x58, 0xCD, 0x6E, 0xF5, 0x56, 0x3E,
|
||||
0x66, 0x2F, 0xD7, 0x07, 0x7F, 0x52, 0x4C, 0x13, 0x24, 0xDC,
|
||||
0x8E, 0x8D, 0xCC, 0xED, 0x77, 0xC4, 0x21, 0xD2, 0xFD, 0x08,
|
||||
0xEA, 0xD7, 0xC0, 0x5C, 0x13, 0x82, 0x81, 0x31, 0x2F, 0x2B,
|
||||
0x08, 0xE4, 0x80, 0x04, 0x7A, 0x0C, 0x8A, 0x3C, 0xDC, 0x22,
|
||||
0xE4, 0x5A, 0x7A, 0xB0, 0x12, 0x5E, 0x4A, 0x76, 0x94, 0x77,
|
||||
0xC2, 0x0E, 0x92, 0xBA, 0x8A, 0xA0, 0x1F, 0x14, 0x51, 0x1E,
|
||||
0x66, 0x6C, 0x38, 0x03, 0x6C, 0xC7, 0x4A, 0x4B, 0x70, 0x80,
|
||||
0xAF, 0xCA, 0x84, 0x51, 0xD8, 0xD2, 0x26, 0x49, 0xF5, 0xA8,
|
||||
0x5E, 0x35, 0x4B, 0xAC, 0xCE, 0x29, 0x92, 0x33, 0xB7, 0xA2,
|
||||
0x69, 0x7D, 0x0C, 0xE0, 0x9C, 0xDB, 0x04, 0xD6, 0xB4, 0xBC,
|
||||
0x39, 0xD7, 0x7F, 0x9E, 0x9D, 0x78, 0x38, 0x7F, 0x51, 0x54,
|
||||
0x50, 0x8B, 0x9E, 0x9C, 0x03, 0x6C, 0xF5, 0x9D, 0x2C, 0x74,
|
||||
0x57, 0xF0, 0x27, 0x2A, 0xC3, 0x47, 0xCA, 0xB9, 0xD7, 0x5C,
|
||||
0xFF, 0xC2, 0xAC, 0x65, 0x4E, 0xBD
|
||||
};
|
||||
|
||||
/*
|
||||
* We need temporary values for at least 7 integers of the same size
|
||||
* as a factor (including header word); more space helps with performance
|
||||
* (in modular exponentiations), but we much prefer to remain under
|
||||
* 2 kilobytes in total, to save stack space. The macro TEMPS below
|
||||
* exceeds 1024 (which is a count in 16-bit words) when BR_MAX_RSA_SIZE
|
||||
* is greater than 4350 (default value is 4096, so the 2-kB limit is
|
||||
* maintained unless BR_MAX_RSA_SIZE was modified).
|
||||
*/
|
||||
#define MAX(x, y) ((x) > (y) ? (x) : (y))
|
||||
#define TEMPS MAX(1024, 7 * ((((BR_MAX_RSA_SIZE + 1) >> 1) + 29) / 15))
|
||||
|
||||
/*
|
||||
* Perform trial division on a candidate prime. This computes
|
||||
* y = SMALL_PRIMES mod x, then tries to compute y/y mod x. The
|
||||
* br_i15_moddiv() function will report an error if y is not invertible
|
||||
* modulo x. Returned value is 1 on success (none of the small primes
|
||||
* divides x), 0 on error (a non-trivial GCD is obtained).
|
||||
*
|
||||
* This function assumes that x is odd.
|
||||
*/
|
||||
static uint32_t
|
||||
trial_divisions(const uint16_t *x, uint16_t *t)
|
||||
{
|
||||
uint16_t *y;
|
||||
uint16_t x0i;
|
||||
unsigned char small_primes_ram[sizeof SMALL_PRIMES];
|
||||
memcpy_P(small_primes_ram, SMALL_PRIMES, sizeof SMALL_PRIMES);
|
||||
|
||||
y = t;
|
||||
t += 1 + ((x[0] + 15) >> 4);
|
||||
x0i = br_i15_ninv15(x[1]);
|
||||
br_i15_decode_reduce(y, SMALL_PRIMES, sizeof SMALL_PRIMES, x);
|
||||
return br_i15_moddiv(y, y, x, x0i, t);
|
||||
}
|
||||
|
||||
/*
|
||||
* Perform n rounds of Miller-Rabin on the candidate prime x. This
|
||||
* function assumes that x = 3 mod 4.
|
||||
*
|
||||
* Returned value is 1 on success (all rounds completed successfully),
|
||||
* 0 otherwise.
|
||||
*/
|
||||
static uint32_t
|
||||
miller_rabin(const br_prng_class **rng, const uint16_t *x, int n,
|
||||
uint16_t *t, size_t tlen)
|
||||
{
|
||||
/*
|
||||
* Since x = 3 mod 4, the Miller-Rabin test is simple:
|
||||
* - get a random base a (such that 1 < a < x-1)
|
||||
* - compute z = a^((x-1)/2) mod x
|
||||
* - if z != 1 and z != x-1, the number x is composite
|
||||
*
|
||||
* We generate bases 'a' randomly with a size which is
|
||||
* one bit less than x, which ensures that a < x-1. It
|
||||
* is not useful to verify that a > 1 because the probability
|
||||
* that we get a value a equal to 0 or 1 is much smaller
|
||||
* than the probability of our Miller-Rabin tests not to
|
||||
* detect a composite, which is already quite smaller than the
|
||||
* probability of the hardware misbehaving and return a
|
||||
* composite integer because of some glitch (e.g. bad RAM
|
||||
* or ill-timed cosmic ray).
|
||||
*/
|
||||
unsigned char *xm1d2;
|
||||
size_t xlen, xm1d2_len, xm1d2_len_u16, u;
|
||||
uint32_t asize;
|
||||
unsigned cc;
|
||||
uint16_t x0i;
|
||||
|
||||
/*
|
||||
* Compute (x-1)/2 (encoded).
|
||||
*/
|
||||
xm1d2 = (unsigned char *)t;
|
||||
xm1d2_len = ((x[0] - (x[0] >> 4)) + 7) >> 3;
|
||||
br_i15_encode(xm1d2, xm1d2_len, x);
|
||||
cc = 0;
|
||||
for (u = 0; u < xm1d2_len; u ++) {
|
||||
unsigned w;
|
||||
|
||||
w = xm1d2[u];
|
||||
xm1d2[u] = (unsigned char)((w >> 1) | cc);
|
||||
cc = w << 7;
|
||||
}
|
||||
|
||||
/*
|
||||
* We used some words of the provided buffer for (x-1)/2.
|
||||
*/
|
||||
xm1d2_len_u16 = (xm1d2_len + 1) >> 1;
|
||||
t += xm1d2_len_u16;
|
||||
tlen -= xm1d2_len_u16;
|
||||
|
||||
xlen = (x[0] + 15) >> 4;
|
||||
asize = x[0] - 1 - EQ0(x[0] & 15);
|
||||
x0i = br_i15_ninv15(x[1]);
|
||||
while (n -- > 0) {
|
||||
uint16_t *a;
|
||||
uint32_t eq1, eqm1;
|
||||
|
||||
/*
|
||||
* Generate a random base. We don't need the base to be
|
||||
* really uniform modulo x, so we just get a random
|
||||
* number which is one bit shorter than x.
|
||||
*/
|
||||
a = t;
|
||||
a[0] = x[0];
|
||||
a[xlen] = 0;
|
||||
mkrand(rng, a, asize);
|
||||
|
||||
/*
|
||||
* Compute a^((x-1)/2) mod x. We assume here that the
|
||||
* function will not fail (the temporary array is large
|
||||
* enough).
|
||||
*/
|
||||
br_i15_modpow_opt(a, xm1d2, xm1d2_len,
|
||||
x, x0i, t + 1 + xlen, tlen - 1 - xlen);
|
||||
|
||||
/*
|
||||
* We must obtain either 1 or x-1. Note that x is odd,
|
||||
* hence x-1 differs from x only in its low word (no
|
||||
* carry).
|
||||
*/
|
||||
eq1 = a[1] ^ 1;
|
||||
eqm1 = a[1] ^ (x[1] - 1);
|
||||
for (u = 2; u <= xlen; u ++) {
|
||||
eq1 |= a[u];
|
||||
eqm1 |= a[u] ^ x[u];
|
||||
}
|
||||
|
||||
if ((EQ0(eq1) | EQ0(eqm1)) == 0) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Create a random prime of the provided size. 'size' is the _encoded_
|
||||
* bit length. The two top bits and the two bottom bits are set to 1.
|
||||
*/
|
||||
static void
|
||||
mkprime(const br_prng_class **rng, uint16_t *x, uint32_t esize,
|
||||
uint32_t pubexp, uint16_t *t, size_t tlen)
|
||||
{
|
||||
size_t len;
|
||||
|
||||
x[0] = esize;
|
||||
len = (esize + 15) >> 4;
|
||||
for (;;) {
|
||||
size_t u;
|
||||
uint32_t m3, m5, m7, m11;
|
||||
int rounds;
|
||||
|
||||
/*
|
||||
* Generate random bits. We force the two top bits and the
|
||||
* two bottom bits to 1.
|
||||
*/
|
||||
mkrand(rng, x, esize);
|
||||
if ((esize & 15) == 0) {
|
||||
x[len] |= 0x6000;
|
||||
} else if ((esize & 15) == 1) {
|
||||
x[len] |= 0x0001;
|
||||
x[len - 1] |= 0x4000;
|
||||
} else {
|
||||
x[len] |= 0x0003 << ((esize & 15) - 2);
|
||||
}
|
||||
x[1] |= 0x0003;
|
||||
|
||||
/*
|
||||
* Trial division with low primes (3, 5, 7 and 11). We
|
||||
* use the following properties:
|
||||
*
|
||||
* 2^2 = 1 mod 3
|
||||
* 2^4 = 1 mod 5
|
||||
* 2^3 = 1 mod 7
|
||||
* 2^10 = 1 mod 11
|
||||
*/
|
||||
m3 = 0;
|
||||
m5 = 0;
|
||||
m7 = 0;
|
||||
m11 = 0;
|
||||
for (u = 0; u < len; u ++) {
|
||||
uint32_t w;
|
||||
|
||||
w = x[1 + u];
|
||||
m3 += w << (u & 1);
|
||||
m3 = (m3 & 0xFF) + (m3 >> 8);
|
||||
m5 += w << ((4 - u) & 3);
|
||||
m5 = (m5 & 0xFF) + (m5 >> 8);
|
||||
m7 += w;
|
||||
m7 = (m7 & 0x1FF) + (m7 >> 9);
|
||||
m11 += w << (5 & -(u & 1));
|
||||
m11 = (m11 & 0x3FF) + (m11 >> 10);
|
||||
}
|
||||
|
||||
/*
|
||||
* Maximum values of m* at this point:
|
||||
* m3: 511
|
||||
* m5: 2310
|
||||
* m7: 510
|
||||
* m11: 2047
|
||||
* We use the same properties to make further reductions.
|
||||
*/
|
||||
|
||||
m3 = (m3 & 0x0F) + (m3 >> 4); /* max: 46 */
|
||||
m3 = (m3 & 0x0F) + (m3 >> 4); /* max: 16 */
|
||||
m3 = ((m3 * 43) >> 5) & 3;
|
||||
|
||||
m5 = (m5 & 0xFF) + (m5 >> 8); /* max: 263 */
|
||||
m5 = (m5 & 0x0F) + (m5 >> 4); /* max: 30 */
|
||||
m5 = (m5 & 0x0F) + (m5 >> 4); /* max: 15 */
|
||||
m5 -= 10 & -GT(m5, 9);
|
||||
m5 -= 5 & -GT(m5, 4);
|
||||
|
||||
m7 = (m7 & 0x3F) + (m7 >> 6); /* max: 69 */
|
||||
m7 = (m7 & 7) + (m7 >> 3); /* max: 14 */
|
||||
m7 = ((m7 * 147) >> 7) & 7;
|
||||
|
||||
/*
|
||||
* 2^5 = 32 = -1 mod 11.
|
||||
*/
|
||||
m11 = (m11 & 0x1F) + 66 - (m11 >> 5); /* max: 97 */
|
||||
m11 -= 88 & -GT(m11, 87);
|
||||
m11 -= 44 & -GT(m11, 43);
|
||||
m11 -= 22 & -GT(m11, 21);
|
||||
m11 -= 11 & -GT(m11, 10);
|
||||
|
||||
/*
|
||||
* If any of these modulo is 0, then the candidate is
|
||||
* not prime. Also, if pubexp is 3, 5, 7 or 11, and the
|
||||
* corresponding modulus is 1, then the candidate must
|
||||
* be rejected, because we need e to be invertible
|
||||
* modulo p-1. We can use simple comparisons here
|
||||
* because they won't leak information on a candidate
|
||||
* that we keep, only on one that we reject (and is thus
|
||||
* not secret).
|
||||
*/
|
||||
if (m3 == 0 || m5 == 0 || m7 == 0 || m11 == 0) {
|
||||
continue;
|
||||
}
|
||||
if ((pubexp == 3 && m3 == 1)
|
||||
|| (pubexp == 5 && m5 == 1)
|
||||
|| (pubexp == 7 && m7 == 1)
|
||||
|| (pubexp == 11 && m11 == 1))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
/*
|
||||
* More trial divisions.
|
||||
*/
|
||||
if (!trial_divisions(x, t)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
/*
|
||||
* Miller-Rabin algorithm. Since we selected a random
|
||||
* integer, not a maliciously crafted integer, we can use
|
||||
* relatively few rounds to lower the risk of a false
|
||||
* positive (i.e. declaring prime a non-prime) under
|
||||
* 2^(-80). It is not useful to lower the probability much
|
||||
* below that, since that would be substantially below
|
||||
* the probability of the hardware misbehaving. Sufficient
|
||||
* numbers of rounds are extracted from the Handbook of
|
||||
* Applied Cryptography, note 4.49 (page 149).
|
||||
*
|
||||
* Since we work on the encoded size (esize), we need to
|
||||
* compare with encoded thresholds.
|
||||
*/
|
||||
if (esize < 320) {
|
||||
rounds = 12;
|
||||
} else if (esize < 480) {
|
||||
rounds = 9;
|
||||
} else if (esize < 693) {
|
||||
rounds = 6;
|
||||
} else if (esize < 906) {
|
||||
rounds = 4;
|
||||
} else if (esize < 1386) {
|
||||
rounds = 3;
|
||||
} else {
|
||||
rounds = 2;
|
||||
}
|
||||
|
||||
if (miller_rabin(rng, x, rounds, t, tlen)) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Let p be a prime (p > 2^33, p = 3 mod 4). Let m = (p-1)/2, provided
|
||||
* as parameter (with announced bit length equal to that of p). This
|
||||
* function computes d = 1/e mod p-1 (for an odd integer e). Returned
|
||||
* value is 1 on success, 0 on error (an error is reported if e is not
|
||||
* invertible modulo p-1).
|
||||
*
|
||||
* The temporary buffer (t) must have room for at least 4 integers of
|
||||
* the size of p.
|
||||
*/
|
||||
static uint32_t
|
||||
invert_pubexp(uint16_t *d, const uint16_t *m, uint32_t e, uint16_t *t)
|
||||
{
|
||||
uint16_t *f;
|
||||
uint32_t r;
|
||||
|
||||
f = t;
|
||||
t += 1 + ((m[0] + 15) >> 4);
|
||||
|
||||
/*
|
||||
* Compute d = 1/e mod m. Since p = 3 mod 4, m is odd.
|
||||
*/
|
||||
br_i15_zero(d, m[0]);
|
||||
d[1] = 1;
|
||||
br_i15_zero(f, m[0]);
|
||||
f[1] = e & 0x7FFF;
|
||||
f[2] = (e >> 15) & 0x7FFF;
|
||||
f[3] = e >> 30;
|
||||
r = br_i15_moddiv(d, f, m, br_i15_ninv15(m[1]), t);
|
||||
|
||||
/*
|
||||
* We really want d = 1/e mod p-1, with p = 2m. By the CRT,
|
||||
* the result is either the d we got, or d + m.
|
||||
*
|
||||
* Let's write e*d = 1 + k*m, for some integer k. Integers e
|
||||
* and m are odd. If d is odd, then e*d is odd, which implies
|
||||
* that k must be even; in that case, e*d = 1 + (k/2)*2m, and
|
||||
* thus d is already fine. Conversely, if d is even, then k
|
||||
* is odd, and we must add m to d in order to get the correct
|
||||
* result.
|
||||
*/
|
||||
br_i15_add(d, m, (uint32_t)(1 - (d[1] & 1)));
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
/*
|
||||
* Swap two buffers in RAM. They must be disjoint.
|
||||
*/
|
||||
static void
|
||||
bufswap(void *b1, void *b2, size_t len)
|
||||
{
|
||||
size_t u;
|
||||
unsigned char *buf1, *buf2;
|
||||
|
||||
buf1 = b1;
|
||||
buf2 = b2;
|
||||
for (u = 0; u < len; u ++) {
|
||||
unsigned w;
|
||||
|
||||
w = buf1[u];
|
||||
buf1[u] = buf2[u];
|
||||
buf2[u] = w;
|
||||
}
|
||||
}
|
||||
|
||||
/* see bearssl_rsa.h */
|
||||
uint32_t
|
||||
br_rsa_i15_keygen(const br_prng_class **rng,
|
||||
br_rsa_private_key *sk, void *kbuf_priv,
|
||||
br_rsa_public_key *pk, void *kbuf_pub,
|
||||
unsigned size, uint32_t pubexp)
|
||||
{
|
||||
uint32_t esize_p, esize_q;
|
||||
size_t plen, qlen, tlen;
|
||||
uint16_t *p, *q, *t;
|
||||
uint16_t tmp[TEMPS];
|
||||
uint32_t r;
|
||||
|
||||
if (size < BR_MIN_RSA_SIZE || size > BR_MAX_RSA_SIZE) {
|
||||
return 0;
|
||||
}
|
||||
if (pubexp == 0) {
|
||||
pubexp = 3;
|
||||
} else if (pubexp == 1 || (pubexp & 1) == 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
esize_p = (size + 1) >> 1;
|
||||
esize_q = size - esize_p;
|
||||
sk->n_bitlen = size;
|
||||
sk->p = kbuf_priv;
|
||||
sk->plen = (esize_p + 7) >> 3;
|
||||
sk->q = sk->p + sk->plen;
|
||||
sk->qlen = (esize_q + 7) >> 3;
|
||||
sk->dp = sk->q + sk->qlen;
|
||||
sk->dplen = sk->plen;
|
||||
sk->dq = sk->dp + sk->dplen;
|
||||
sk->dqlen = sk->qlen;
|
||||
sk->iq = sk->dq + sk->dqlen;
|
||||
sk->iqlen = sk->plen;
|
||||
|
||||
if (pk != NULL) {
|
||||
pk->n = kbuf_pub;
|
||||
pk->nlen = (size + 7) >> 3;
|
||||
pk->e = pk->n + pk->nlen;
|
||||
pk->elen = 4;
|
||||
br_enc32be(pk->e, pubexp);
|
||||
while (*pk->e == 0) {
|
||||
pk->e ++;
|
||||
pk->elen --;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* We now switch to encoded sizes.
|
||||
*
|
||||
* floor((x * 17477) / (2^18)) is equal to floor(x/15) for all
|
||||
* integers x from 0 to 23833.
|
||||
*/
|
||||
esize_p += MUL15(esize_p, 17477) >> 18;
|
||||
esize_q += MUL15(esize_q, 17477) >> 18;
|
||||
plen = (esize_p + 15) >> 4;
|
||||
qlen = (esize_q + 15) >> 4;
|
||||
p = tmp;
|
||||
q = p + 1 + plen;
|
||||
t = q + 1 + qlen;
|
||||
tlen = ((sizeof tmp) / sizeof(uint16_t)) - (2 + plen + qlen);
|
||||
|
||||
/*
|
||||
* When looking for primes p and q, we temporarily divide
|
||||
* candidates by 2, in order to compute the inverse of the
|
||||
* public exponent.
|
||||
*/
|
||||
|
||||
for (;;) {
|
||||
mkprime(rng, p, esize_p, pubexp, t, tlen);
|
||||
br_i15_rshift(p, 1);
|
||||
if (invert_pubexp(t, p, pubexp, t + 1 + plen)) {
|
||||
br_i15_add(p, p, 1);
|
||||
p[1] |= 1;
|
||||
br_i15_encode(sk->p, sk->plen, p);
|
||||
br_i15_encode(sk->dp, sk->dplen, t);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
for (;;) {
|
||||
mkprime(rng, q, esize_q, pubexp, t, tlen);
|
||||
br_i15_rshift(q, 1);
|
||||
if (invert_pubexp(t, q, pubexp, t + 1 + qlen)) {
|
||||
br_i15_add(q, q, 1);
|
||||
q[1] |= 1;
|
||||
br_i15_encode(sk->q, sk->qlen, q);
|
||||
br_i15_encode(sk->dq, sk->dqlen, t);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* If p and q have the same size, then it is possible that q > p
|
||||
* (when the target modulus size is odd, we generate p with a
|
||||
* greater bit length than q). If q > p, we want to swap p and q
|
||||
* (and also dp and dq) for two reasons:
|
||||
* - The final step below (inversion of q modulo p) is easier if
|
||||
* p > q.
|
||||
* - While BearSSL's RSA code is perfectly happy with RSA keys such
|
||||
* that p < q, some other implementations have restrictions and
|
||||
* require p > q.
|
||||
*
|
||||
* Note that we can do a simple non-constant-time swap here,
|
||||
* because the only information we leak here is that we insist on
|
||||
* returning p and q such that p > q, which is not a secret.
|
||||
*/
|
||||
if (esize_p == esize_q && br_i15_sub(p, q, 0) == 1) {
|
||||
bufswap(p, q, (1 + plen) * sizeof *p);
|
||||
bufswap(sk->p, sk->q, sk->plen);
|
||||
bufswap(sk->dp, sk->dq, sk->dplen);
|
||||
}
|
||||
|
||||
/*
|
||||
* We have produced p, q, dp and dq. We can now compute iq = 1/d mod p.
|
||||
*
|
||||
* We ensured that p >= q, so this is just a matter of updating the
|
||||
* header word for q (and possibly adding an extra word).
|
||||
*
|
||||
* Theoretically, the call below may fail, in case we were
|
||||
* extraordinarily unlucky, and p = q. Another failure case is if
|
||||
* Miller-Rabin failed us _twice_, and p and q are non-prime and
|
||||
* have a factor is common. We report the error mostly because it
|
||||
* is cheap and we can, but in practice this never happens (or, at
|
||||
* least, it happens way less often than hardware glitches).
|
||||
*/
|
||||
q[0] = p[0];
|
||||
if (plen > qlen) {
|
||||
q[plen] = 0;
|
||||
t ++;
|
||||
tlen --;
|
||||
}
|
||||
br_i15_zero(t, p[0]);
|
||||
t[1] = 1;
|
||||
r = br_i15_moddiv(t, q, p, br_i15_ninv15(p[1]), t + 1 + plen);
|
||||
br_i15_encode(sk->iq, sk->iqlen, t);
|
||||
|
||||
/*
|
||||
* Compute the public modulus too, if required.
|
||||
*/
|
||||
if (pk != NULL) {
|
||||
br_i15_zero(t, p[0]);
|
||||
br_i15_mulacc(t, p, q);
|
||||
br_i15_encode(pk->n, pk->nlen, t);
|
||||
}
|
||||
|
||||
return r;
|
||||
}
|
|
@ -0,0 +1,99 @@
|
|||
/*
|
||||
* Copyright (c) 2018 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 "t_inner.h"
|
||||
|
||||
/* see bearssl_rsa.h */
|
||||
size_t
|
||||
br_rsa_i15_compute_modulus(void *n, const br_rsa_private_key *sk)
|
||||
{
|
||||
uint16_t tmp[4 * (((BR_MAX_RSA_SIZE / 2) + 14) / 15) + 5];
|
||||
uint16_t *t, *p, *q;
|
||||
const unsigned char *pbuf, *qbuf;
|
||||
size_t nlen, plen, qlen, tlen;
|
||||
|
||||
/*
|
||||
* Compute actual byte and lengths for p and q.
|
||||
*/
|
||||
pbuf = sk->p;
|
||||
plen = sk->plen;
|
||||
while (plen > 0 && *pbuf == 0) {
|
||||
pbuf ++;
|
||||
plen --;
|
||||
}
|
||||
qbuf = sk->q;
|
||||
qlen = sk->qlen;
|
||||
while (qlen > 0 && *qbuf == 0) {
|
||||
qbuf ++;
|
||||
qlen --;
|
||||
}
|
||||
|
||||
t = tmp;
|
||||
tlen = (sizeof tmp) / (sizeof tmp[0]);
|
||||
|
||||
/*
|
||||
* Decode p.
|
||||
*/
|
||||
if ((15 * tlen) < (plen << 3) + 15) {
|
||||
return 0;
|
||||
}
|
||||
br_i15_decode(t, pbuf, plen);
|
||||
p = t;
|
||||
plen = (p[0] + 31) >> 4;
|
||||
t += plen;
|
||||
tlen -= plen;
|
||||
|
||||
/*
|
||||
* Decode q.
|
||||
*/
|
||||
if ((15 * tlen) < (qlen << 3) + 15) {
|
||||
return 0;
|
||||
}
|
||||
br_i15_decode(t, qbuf, qlen);
|
||||
q = t;
|
||||
qlen = (q[0] + 31) >> 4;
|
||||
t += qlen;
|
||||
tlen -= qlen;
|
||||
|
||||
/*
|
||||
* Computation can proceed only if we have enough room for the
|
||||
* modulus.
|
||||
*/
|
||||
if (tlen < (plen + qlen + 1)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Private key already contains the modulus bit length, from which
|
||||
* we can infer the output length. Even if n is NULL, we still had
|
||||
* to decode p and q to make sure that the product can be computed.
|
||||
*/
|
||||
nlen = (sk->n_bitlen + 7) >> 3;
|
||||
if (n != NULL) {
|
||||
br_i15_zero(t, p[0]);
|
||||
br_i15_mulacc(t, p, q);
|
||||
br_i15_encode(n, nlen, t);
|
||||
}
|
||||
return nlen;
|
||||
}
|
|
@ -0,0 +1,41 @@
|
|||
/*
|
||||
* Copyright (c) 2018 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 "t_inner.h"
|
||||
|
||||
/* see bearssl_rsa.h */
|
||||
uint32_t
|
||||
br_rsa_i15_oaep_decrypt(const br_hash_class *dig,
|
||||
const void *label, size_t label_len,
|
||||
const br_rsa_private_key *sk, void *data, size_t *len)
|
||||
{
|
||||
uint32_t r;
|
||||
|
||||
if (*len != ((sk->n_bitlen + 7) >> 3)) {
|
||||
return 0;
|
||||
}
|
||||
r = br_rsa_i15_private(data, sk);
|
||||
r &= br_rsa_oaep_unpad(dig, label, label_len, data, len);
|
||||
return r;
|
||||
}
|
|
@ -0,0 +1,44 @@
|
|||
/*
|
||||
* Copyright (c) 2018 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 "t_inner.h"
|
||||
|
||||
/* see bearssl_rsa.h */
|
||||
size_t
|
||||
br_rsa_i15_oaep_encrypt(
|
||||
const br_prng_class **rnd, const br_hash_class *dig,
|
||||
const void *label, size_t label_len,
|
||||
const br_rsa_public_key *pk,
|
||||
void *dst, size_t dst_max_len,
|
||||
const void *src, size_t src_len)
|
||||
{
|
||||
size_t dlen;
|
||||
|
||||
dlen = br_rsa_oaep_pad(rnd, dig, label, label_len,
|
||||
pk, dst, dst_max_len, src, src_len);
|
||||
if (dlen == 0) {
|
||||
return 0;
|
||||
}
|
||||
return dlen & -(size_t)br_rsa_i15_public(dst, dlen, pk);
|
||||
}
|
|
@ -0,0 +1,37 @@
|
|||
/*
|
||||
* 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 "t_inner.h"
|
||||
|
||||
/* see bearssl_rsa.h */
|
||||
uint32_t
|
||||
br_rsa_i15_pkcs1_sign(const unsigned char *hash_oid,
|
||||
const unsigned char *hash, size_t hash_len,
|
||||
const br_rsa_private_key *sk, unsigned char *x)
|
||||
{
|
||||
if (!br_rsa_pkcs1_sig_pad(hash_oid, hash, hash_len, sk->n_bitlen, x)) {
|
||||
return 0;
|
||||
}
|
||||
return br_rsa_i15_private(x, sk);
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue