Merge pull request #1391 from ClassiCube/SSL4

Start moving more platforms over to using own HTTP client + BearSSL + OS specific fallback certificate validation
This commit is contained in:
UnknownShadow200 2025-06-28 15:14:54 +10:00 committed by GitHub
commit f95507b448
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
137 changed files with 412 additions and 19474 deletions

View File

@ -41,15 +41,17 @@ jobs:
id: compile
shell: bash
env:
COMMON_FLAGS: "-O1 -s -fno-stack-protector -fno-math-errno -Qn -Werror"
LIBS: "-lm -lpthread -lX11 -lXi -lGL -lexecinfo"
SRCS: "src/*.c third_party/bearssl/src/*.c"
COMMON_FLAGS: "-O1 -s -fno-stack-protector -fno-math-errno -Qn -Werror -Ithird_party/bearssl/inc"
PLAT32_FLAGS: "-fno-pie -fvisibility=hidden -fcf-protection=none -rdynamic -I freebsd32/include -L freebsd32/lib"
PLAT64_FLAGS: "-fno-pie -fvisibility=hidden -fcf-protection=none -rdynamic -I freebsd64/include -L freebsd64/lib"
run: |
LATEST_FLAG=-DCC_COMMIT_SHA=\"${GITHUB_SHA::9}\"
cd src
i386-freebsd11-clang *.c ${{ env.COMMON_FLAGS }} ${{ env.PLAT32_FLAGS }} $LATEST_FLAG -o cc-fbsd32-gl1 -lm -lpthread -lX11 -lXi -lGL -lexecinfo
x86_64-freebsd11-clang *.c ${{ env.COMMON_FLAGS }} ${{ env.PLAT64_FLAGS }} $LATEST_FLAG -o cc-fbsd64-gl1 -lm -lpthread -lX11 -lXi -lGL -lexecinfo
i386-freebsd11-clang ${{ env.SRCS }} ${{ env.COMMON_FLAGS }} ${{ env.PLAT32_FLAGS }} $LATEST_FLAG -o cc-fbsd32-gl1 ${{ env.LIBS }}
x86_64-freebsd11-clang ${{ env.SRCS }} ${{ env.COMMON_FLAGS }} ${{ env.PLAT64_FLAGS }} $LATEST_FLAG -o cc-fbsd64-gl1 ${{ env.LIBS }}
# otherwise notify_failure doesn't work
@ -67,13 +69,13 @@ jobs:
- uses: ./.github/actions/upload_build
if: ${{ always() && steps.compile.outcome == 'success' }}
with:
SOURCE_FILE: 'src/cc-fbsd32-gl1'
SOURCE_FILE: 'cc-fbsd32-gl1'
DEST_NAME: 'ClassiCube-FreeBSD-32'
- uses: ./.github/actions/upload_build
if: ${{ always() && steps.compile.outcome == 'success' }}
with:
SOURCE_FILE: 'src/cc-fbsd64-gl1'
SOURCE_FILE: 'cc-fbsd64-gl1'
DEST_NAME: 'ClassiCube-FreeBSD-64'

View File

@ -23,11 +23,11 @@ jobs:
- name: Compile haiku build
id: compile
env:
COMMON_FLAGS: "-O1 -s -fno-stack-protector -fno-math-errno -Qn -Werror"
LIBS: "-lm -lGL -lnetwork -lstdc++ -lbe -lgame -ltracker"
SRCS: "src/*.c src/Platform_BeOS.cpp src/Window_BeOS.cpp third_party/bearssl/src/*.c"
COMMON_FLAGS: "-O1 -s -fno-stack-protector -fno-math-errno -Qn -Werror -Ithird_party/bearssl/inc"
run: |
cd src
x86_64-unknown-haiku-gcc *.c Platform_BeOS.cpp Window_BeOS.cpp -o ClassiCube-haiku ${{ env.COMMON_FLAGS }} -lm -lGL -lnetwork -lstdc++ -lbe -lgame -ltracker
x86_64-unknown-haiku-gcc ${{ env.SRCS }} -o ClassiCube-haiku ${{ env.COMMON_FLAGS }} ${{ env.LIBS }}
- uses: ./.github/actions/notify_failure
if: ${{ always() && steps.compile.outcome == 'failure' }}
@ -39,7 +39,7 @@ jobs:
- uses: ./.github/actions/upload_build
if: ${{ always() && steps.compile.outcome == 'success' }}
with:
SOURCE_FILE: 'src/ClassiCube-haiku'
SOURCE_FILE: 'ClassiCube-haiku'
DEST_NAME: 'ClassiCube-haiku'

View File

@ -41,14 +41,15 @@ jobs:
shell: bash
id: compile
env:
COMMON_FLAGS: "-O1 -s -fno-stack-protector -fno-math-errno -Qn -Werror"
LIBS: "-lX11 -lXi -lpthread -lGL -lm -ldl"
SRCS: "src/*.c third_party/bearssl/src/*.c"
COMMON_FLAGS: "-O1 -s -fno-stack-protector -fno-math-errno -Qn -Werror -Ithird_party/bearssl/inc"
NIX32_FLAGS: "-no-pie -fno-pie -m32 -fvisibility=hidden -fcf-protection=none -rdynamic -L ../lib -Wl,--unresolved-symbols=ignore-in-shared-libs"
run: |
LATEST_FLAG=-DCC_COMMIT_SHA=\"${GITHUB_SHA::9}\"
cd src
gcc *.c ${{ env.COMMON_FLAGS }} ${{ env.NIX32_FLAGS }} $LATEST_FLAG -o cc-nix32-gl1 -lX11 -lXi -lpthread -lGL -lm -ldl
gcc *.c ${{ env.COMMON_FLAGS }} ${{ env.NIX32_FLAGS }} $LATEST_FLAG -DCC_GFX_BACKEND=CC_GFX_BACKEND_GL2 -o cc-nix32-gl2 -lX11 -lXi -lpthread -lGL -lm -ldl
gcc ${{ env.SRCS }} ${{ env.COMMON_FLAGS }} ${{ env.NIX32_FLAGS }} $LATEST_FLAG -o cc-nix32-gl1 ${{ env.LIBS }}
gcc ${{ env.SRCS }} ${{ env.COMMON_FLAGS }} ${{ env.NIX32_FLAGS }} $LATEST_FLAG -DCC_GFX_BACKEND=CC_GFX_BACKEND_GL2 -o cc-nix32-gl2 ${{ env.LIBS }}
- uses: ./.github/actions/notify_failure
@ -61,13 +62,13 @@ jobs:
- uses: ./.github/actions/upload_build
if: ${{ always() && steps.compile.outcome == 'success' }}
with:
SOURCE_FILE: 'src/cc-nix32-gl1'
SOURCE_FILE: 'cc-nix32-gl1'
DEST_NAME: 'ClassiCube-Linux32-OpenGL'
- uses: ./.github/actions/upload_build
if: ${{ always() && steps.compile.outcome == 'success' }}
with:
SOURCE_FILE: 'src/cc-nix32-gl2'
SOURCE_FILE: 'cc-nix32-gl2'
DEST_NAME: 'ClassiCube-Linux32-ModernGL'
@ -103,16 +104,17 @@ jobs:
- name: Compile 64 bit Linux builds
shell: bash
id: compile
env:
COMMON_FLAGS: "-O1 -s -fno-stack-protector -fno-math-errno -Qn -Werror"
env:
LIBS: "-lX11 -lXi -lpthread -lGL -lm -ldl"
SRCS: "src/*.c third_party/bearssl/src/*.c"
COMMON_FLAGS: "-O1 -s -fno-stack-protector -fno-math-errno -Qn -Werror -Ithird_party/bearssl/inc""
NIX64_FLAGS: "-no-pie -fno-pie -m64 -fvisibility=hidden -fcf-protection=none -rdynamic -L ../lib -Wl,--unresolved-symbols=ignore-in-shared-libs"
run: |
LATEST_FLAG=-DCC_COMMIT_SHA=\"${GITHUB_SHA::9}\"
cd src
gcc *.c ${{ env.COMMON_FLAGS }} ${{ env.NIX64_FLAGS }} $LATEST_FLAG -o cc-nix64-gl1 -lX11 -lXi -lpthread -lGL -lm -ldl
gcc *.c ${{ env.COMMON_FLAGS }} ${{ env.NIX64_FLAGS }} $LATEST_FLAG -DCC_GFX_BACKEND=CC_GFX_BACKEND_GL2 -o cc-nix64-gl2 -lX11 -lXi -lpthread -lGL -lm -ldl
#gcc *.c ${{ env.COMMON_FLAGS }} ${{ env.NIX64_FLAGS }} $LATEST_FLAG -DCC_GFX_BACKEND=CC_GFX_BACKEND_GL2 -DCC_WIN_BACKEND=CC_WIN_BACKEND_SDL2 -o cc-sdl64-gl2 -lSDL2 -lpthread -lGL -lm -ldl
gcc ${{ env.SRCS }} ${{ env.COMMON_FLAGS }} ${{ env.NIX64_FLAGS }} $LATEST_FLAG -o cc-nix64-gl1 ${{ env.LIBS }}
gcc ${{ env.SRCS }} ${{ env.COMMON_FLAGS }} ${{ env.NIX64_FLAGS }} $LATEST_FLAG -DCC_GFX_BACKEND=CC_GFX_BACKEND_GL2 -o cc-nix64-gl2 ${{ env.LIBS }}
#gcc ${{ env.SRCS }} ${{ env.COMMON_FLAGS }} ${{ env.NIX64_FLAGS }} $LATEST_FLAG -DCC_GFX_BACKEND=CC_GFX_BACKEND_GL2 -DCC_WIN_BACKEND=CC_WIN_BACKEND_SDL2 -o cc-sdl64-gl2 -lSDL2 ${{ env.LIBS }}
- uses: ./.github/actions/notify_failure
@ -125,19 +127,19 @@ jobs:
- uses: ./.github/actions/upload_build
if: ${{ always() && steps.compile.outcome == 'success' }}
with:
SOURCE_FILE: 'src/cc-nix64-gl1'
SOURCE_FILE: 'cc-nix64-gl1'
DEST_NAME: 'ClassiCube-Linux64-OpenGL'
- uses: ./.github/actions/upload_build
if: ${{ always() && steps.compile.outcome == 'success' }}
with:
SOURCE_FILE: 'src/cc-nix64-gl2'
SOURCE_FILE: 'cc-nix64-gl2'
DEST_NAME: 'ClassiCube-Linux64-ModernGL'
- uses: ./.github/actions/upload_build
if: ${{ always() && steps.compile.outcome == 'success' }}
with:
SOURCE_FILE: 'src/cc-sdl64-gl2'
SOURCE_FILE: 'cc-sdl64-gl2'
DEST_NAME: 'ClassiCube-Linux64-SDL2'

View File

@ -35,14 +35,14 @@ jobs:
id: compile
shell: bash
env:
COMMON_FLAGS: "-O1 -s -fno-stack-protector -fno-math-errno -Qn -Werror"
LIBS: "-lm -lpthread -lX11 -lXi -lGL -lexecinfo"
SRCS: "src/*.c third_party/bearssl/src/*.c"
COMMON_FLAGS: "-O1 -s -fno-stack-protector -fno-math-errno -Qn -Werror -Wl,-R/usr/X11R7/lib -Ithird_party/bearssl/inc"
PLAT64_FLAGS: "-fno-pie -fvisibility=hidden -fcf-protection=none -rdynamic -I netbsd64/include -L netbsd64/lib -Wl,--unresolved-symbols=ignore-in-shared-libs"
run: |
LATEST_FLAG=-DCC_COMMIT_SHA=\"${GITHUB_SHA::9}\"
echo $LATEST_FLAG
cd src
x86_64-unknown-netbsd-gcc *.c ${{ env.COMMON_FLAGS }} ${{ env.PLAT64_FLAGS }} $LATEST_FLAG -o cc-netbsd64-gl1 -lm -lpthread -lX11 -lXi -lGL -lexecinfo
x86_64-unknown-netbsd-gcc ${{ env.SRCS }} ${{ env.COMMON_FLAGS }} ${{ env.PLAT64_FLAGS }} $LATEST_FLAG -o cc-netbsd64-gl1 ${{ env.LIBS }}
- uses: ./.github/actions/notify_failure
@ -55,7 +55,7 @@ jobs:
- uses: ./.github/actions/upload_build
if: ${{ always() && steps.compile.outcome == 'success' }}
with:
SOURCE_FILE: 'src/cc-netbsd64-gl1'
SOURCE_FILE: 'cc-netbsd64-gl1'
DEST_NAME: 'ClassiCube-NetBSD-64'

View File

@ -73,11 +73,13 @@ endif
ifeq ($(PLAT),linux)
LIBS = -lX11 -lXi -lpthread -lGL -ldl
BUILD_DIR = build/linux
BEARSSL = 1
endif
ifeq ($(PLAT),sunos)
LIBS = -lsocket -lX11 -lXi -lGL
BUILD_DIR = build/solaris
BEARSSL = 1
endif
ifeq ($(PLAT),hp-ux)
@ -85,6 +87,7 @@ ifeq ($(PLAT),hp-ux)
LDFLAGS =
LIBS = -lm -lX11 -lXi -lXext -L/opt/graphics/OpenGL/lib -lGL -lpthread
BUILD_DIR = build/hpux
BEARSSL = 1
endif
ifeq ($(PLAT),darwin)
@ -100,6 +103,7 @@ ifeq ($(PLAT),freebsd)
LDFLAGS = -L /usr/local/lib -rdynamic
LIBS = -lexecinfo -lGL -lX11 -lXi -lpthread
BUILD_DIR = build/freebsd
BEARSSL = 1
endif
ifeq ($(PLAT),openbsd)
@ -107,13 +111,15 @@ ifeq ($(PLAT),openbsd)
LDFLAGS = -L /usr/X11R6/lib -L /usr/local/lib -rdynamic
LIBS = -lexecinfo -lGL -lX11 -lXi -lpthread
BUILD_DIR = build/openbsd
BEARSSL = 1
endif
ifeq ($(PLAT),netbsd)
CFLAGS += -I /usr/X11R7/include -I /usr/pkg/include
LDFLAGS = -L /usr/X11R7/lib -L /usr/pkg/lib -rdynamic
LDFLAGS = -L /usr/X11R7/lib -L /usr/pkg/lib -rdynamic -Wl,-R/usr/X11R7/lib
LIBS = -lexecinfo -lGL -lX11 -lXi -lpthread
BUILD_DIR = build/netbsd
BEARSSL = 1
endif
ifeq ($(PLAT),dragonfly)
@ -121,6 +127,7 @@ ifeq ($(PLAT),dragonfly)
LDFLAGS = -L /usr/local/lib -rdynamic
LIBS = -lexecinfo -lGL -lX11 -lXi -lpthread
BUILD_DIR = build/flybsd
BEARSSL = 1
endif
ifeq ($(PLAT),haiku)
@ -130,6 +137,7 @@ ifeq ($(PLAT),haiku)
LINK = $(CXX)
LIBS = -lGL -lnetwork -lbe -lgame -ltracker
BUILD_DIR = build/haiku
BEARSSL = 1
endif
ifeq ($(PLAT),beos)
@ -145,12 +153,14 @@ endif
ifeq ($(PLAT),serenityos)
LIBS = -lgl -lSDL2
BUILD_DIR = build/serenity
BEARSSL = 1
endif
ifeq ($(PLAT),irix)
CC = gcc
LIBS = -lGL -lX11 -lXi -lpthread -ldl
BUILD_DIR = build/irix
BEARSSL = 1
endif
ifeq ($(PLAT),dos)

View File

@ -2,6 +2,8 @@ Although most of the code is platform-independent, some per-platform functionali
By default `Core.h` tries to automatically define appropriate backends for your system. Define ```CC_BUILD_MANUAL``` to disable this.
Note: Updating doesn't work properly in Windows 95 or Windows 98
## Before you start
* IEEE floating-point support is required. (Can be emulated in software, but will affect performance)
* The `int` data type must be 32-bits.
@ -12,39 +14,6 @@ By default `Core.h` tries to automatically define appropriate backends for your
In summary, the codebase can theroetically be ported to any modern-ish hardware, but not stuff like a UNIVAC machine, the SuperFX chip on the SNES, or an 8-bit microcontroller.
## Supported platforms
#### Tier 1 support
These platforms are regularly tested on and have executables automatically compiled for.
|Platform|Testing|Support|
|--------|-------|-----|
|Windows x86/x64 | Mostly tested on 7+ | Should work in all Windows versions
|macOS x86/x64 | Mostly tested on 10.12 | Should work in all macOS versions since 10.3
|Linux x86/x64 | Mostly tested on Linux Mint | Should work in most Linux distributions
|Web client | Mostly tested in Chrome | Should work in all browsers with WebGL (including IE)
Note: Updating doesn't work properly in Windows 95 or Windows 98
#### Tier 2 support
The game has been compiled and run on these platforms before. It may or may not still compile for them.
I don't really test these platforms at all, only when I suspect some changes to the code might impact them.
|Platform|Machine|Notes|
|--------|-------|-----|
|macOS x86 | macOS 10.4 |
|FreeBSD x86 | FreeBSD | x64 should work too |
|NetBSD x86 | NetBSD | x64 should work too |
|OpenBSD x86 | OpenBSD | x64 should work too |
|Solaris x86 | OpenIndiana | x64 should work too |
|macOS PPC | macOS 10.3 | PPC64 completely untested |
|Linux PPC | Debian | Issues with colour channels incorrectly swapped? |
|Linux ARM | Raspberry pi | ARM64 should work too |
|Linux SPARC | Debian | Didn't really work due to lack of 24-bit colours |
|Linux Alpha | Debian |
|HaikuOS | Nightly |
## Porting
Listed below are the requirements for implementing each platform-dependent file.<br>
@ -116,3 +85,9 @@ Define:
- ```DEFAULT_NET_BACKEND CC_NET_BACKEND_LIBCURL``` - use libcurl for HTTP
Supporting connection reuse is highly recommended. (but not required)
### SSL
SSL and TLS support, plus basic certificate validation
Define:
- ```DEFAULT_SSL_BACKEND CC_SSL_BACKEND_BEARSSL``` - use BearSSL for SSL/TLS

View File

@ -144,8 +144,8 @@ Compiling with TCC:
1. Install X11, XInput2, and OpenGL development libraries if necessary. <br>
For Ubuntu, these are the `libx11-dev`, `libxi-dev` and `libgl1-mesa-dev` packages
2. Run either:
* `make linux` or
* `cc -fno-math-errno src/*.c -o ClassiCube -rdynamic -lpthread -lX11 -lXi -lGL -ldl`
* `make linux` - produces a simple non-optimised executable, easier to debug
* `make linux RELEASE=1` - produces an optimised executable, harder to debug
##### Cross compiling for Windows (32 bit):
1. Install MinGW-w64 if necessary. (Ubuntu: `gcc-mingw-w64` package)
@ -163,8 +163,8 @@ Although the regular linux compiliation flags will work fine, to take full advan
## Compiling - macOS
1. Install a C compiler if necessary. The easiest way of obtaining one is by installing **Xcode**.
2. Run either:
* `make darwin` or
* `cc -fno-math-errno src/*.c src/*.m -o ClassiCube -framework Cocoa -framework OpenGL -framework IOKit -lobjc`
* `make darwin` - produces a simple non-optimised executable, easier to debug
* `make darwin RELEASE=1` - produces an optimised executable, harder to debug
##### Using Xcode GUI
@ -323,66 +323,66 @@ Run `make saturn`. You'll need [libyaul](https://github.com/yaul-org/libyaul)
#### FreeBSD
1. Install `libxi`, `libexecinfo`, `curl` and `openal-soft` packages if needed
1. Install `gmake`, `libxi`, `libexecinfo`, `openssl` and `openal-soft` packages if needed
2. Run either:
* `make freebsd` or
* `cc src/*.c -o ClassiCube -I /usr/local/include -L /usr/local/lib -lm -lpthread -lX11 -lXi -lGL -lexecinfo`
* `gmake freebsd` - produces a simple non-optimised executable, easier to debug
* `gmake freebsd RELEASE=1` - produces an optimised executable, harder to debug
#### OpenBSD
1. Install `libexecinfo`, `curl` and `openal` packages if needed
1. Install `gmake`, `libexecinfo`, `openssl` and `openal` packages if needed
2. Run either:
* `make openbsd` or
* `cc src/*.c -o ClassiCube -I /usr/X11R6/include -I /usr/local/include -L /usr/X11R6/lib -L /usr/local/lib -lm -lpthread -lX11 -lXi -lGL -lexecinfo`
* `gmake openbsd` - produces a simple non-optimised executable, easier to debug
* `gmake openbsd RELEASE=1` - produces an optimised executable, harder to debug
#### NetBSD
1. Install `libexecinfo`, `curl` and `openal-soft` packages if needed
1. Install `gmake`, `libexecinfo`, `openssl` and `openal-soft` packages if needed
2. Run either:
* `make netbsd` or
* `cc src/*.c -o ClassiCube -I /usr/X11R7/include -I /usr/pkg/include -L /usr/X11R7/lib -L /usr/pkg/lib -lpthread -lX11 -lXi -lGL -lexecinfo`
* `gmake netbsd` - produces a simple non-optimised executable, easier to debug
* `gmake netbsd RELEASE=1` - produces an optimised executable, harder to debug
#### DragonflyBSD
1. Install `libxi`, `libexecinfo`, `curl` and `openal-soft` packages if needed
1. Install `gmake`, `libxi`, `libexecinfo`, `openssl` and `openal-soft` packages if needed
2. Run either:
* `make dragonfly` or
* `cc src/*.c -o ClassiCube -I /usr/local/include -L /usr/local/lib -lm -lpthread -lX11 -lXi -lGL -lexecinfo`
* `gmake dragonfly` - produces a simple non-optimised executable, easier to debug
* `gmake dragonfly RELEASE=1` - produces an optimised executable, harder to debug
#### Solaris
1. Install required packages if needed
2. Run either:
* `make sunos` or
* `gcc -fno-math-errno src/*.c -o ClassiCube -lsocket -lX11 -lXi -lGL`
* `make sunos` - produces a simple non-optimised executable, easier to debug
* `make sunos RELEASE=1` - produces an optimised executable, harder to debug
#### Haiku
1. Install `gcc`, `haiku_devel`, `openal_devel` packages if needed
2. Run either:
* `make haiku` or
* `cc -fno-math-errno src/*.c src/*.cpp -o ClassiCube -lGL -lnetwork -lstdc++ -lbe -lgame -ltracker`
* `make haiku` - produces a simple non-optimised executable, easier to debug
* `make haiku RELEASE=1` - produces an optimised executable, harder to debug
#### BeOS
1. Install a C compiler
2. Run either:
* `make beos` or
* `cc -fno-math-errno src/*.c src/*.cpp -o ClassiCube -lGL -lbe -lgame -ltracker`
* `make beos` - produces a simple non-optimised executable, easier to debug
* `make beos RELEASE=1` - produces an optimised executable, harder to debug
#### IRIX
1. Install required packages if needed
2. Run either:
* `make irix` or
* gcc -fno-math-errno src/*.c -o ClassiCube -lGL -lX11 -lXi -lpthread -ldl`
* `make irix` - produces a simple non-optimised executable, easier to debug
* `make irix RELEASE=1` - produces an optimised executable, harder to debug
#### SerenityOS
1. Install SDL2 port if needed
2. Run either:
* `make serenityos` or
* `cc src/*.c -o ClassiCube -lgl -lSDL2`
* `make serenityos` - produces a simple non-optimised executable, easier to debug
* `make serenityos RELEASE=1` - produces an optimised executable, harder to debug
#### Classic Mac OS

192
src/Certs.c Normal file
View File

@ -0,0 +1,192 @@
#include "Certs.h"
#if CC_CTX_BACKEND == CC_CRT_BACKEND_NONE
void CertsBackend_Init(void) { }
void Certs_BeginChain(struct X509CertContext* ctx) { }
void Certs_FreeChain( struct X509CertContext* ctx) { }
int Certs_VerifyChain(struct X509CertContext* ctx) { return ERR_NOT_SUPPORTED; }
void Certs_BeginCert( struct X509CertContext* ctx, int size) { }
void Certs_AppendCert(struct X509CertContext* ctx, const void* data, int len) { }
void Certs_FinishCert(struct X509CertContext* ctx) { }
#else
#include "Platform.h"
#include "String.h"
#include "Stream.h"
void Certs_BeginCert( struct X509CertContext* ctx, int size) {
void* data;
ctx->cert = NULL;
/* Should never happen, but never know */
if (ctx->numCerts >= X509_MAX_CERTS) return;
data = Mem_TryAllocCleared(1, size);
if (!data) return;
ctx->cert = &ctx->certs[ctx->numCerts++];
ctx->cert->data = data;
ctx->cert->offset = 0;
}
void Certs_AppendCert(struct X509CertContext* ctx, const void* data, int len) {
if (!ctx->cert) return;
Mem_Copy((char*)ctx->cert->data + ctx->cert->offset, data, len);
ctx->cert->offset += len;
}
void Certs_FinishCert(struct X509CertContext* ctx) {
}
void Certs_BeginChain(struct X509CertContext* ctx) {
ctx->cert = NULL;
ctx->numCerts = 0;
}
void Certs_FreeChain( struct X509CertContext* ctx) {
int i;
for (i = 0; i < ctx->numCerts; i++)
{
Mem_Free(ctx->certs[i].data);
}
ctx->numCerts = 0;
}
#if CC_CRT_BACKEND == CC_CRT_BACKEND_OPENSSL
#include "Errors.h"
#include "Funcs.h"
/* === BEGIN OPENSSL HEADERS === */
typedef struct X509_ X509;
typedef struct X509_STORE_ X509_STORE;
typedef struct X509_STORE_CTX_ X509_STORE_CTX;
typedef struct OPENSSL_STACK_ OPENSSL_STACK;
typedef void (*OPENSSL_PopFunc)(void* data);
static OPENSSL_STACK* (*_OPENSSL_sk_new_null)(void);
int (*_OPENSSL_sk_push)(OPENSSL_STACK* st, const void* data);
void (*_OPENSSL_sk_pop_free)(OPENSSL_STACK* st, OPENSSL_PopFunc func);
static X509* (*_d2i_X509)(X509** px, const unsigned char** in, int len);
static X509* (*_X509_new)(void);
static void (*_X509_free)(X509* a);
static X509_STORE* (*_X509_STORE_new)(void);
static int (*_X509_STORE_set_default_paths)(X509_STORE* ctx);
static int (*_X509_verify_cert)(X509_STORE_CTX* ctx);
static const char* (*_X509_verify_cert_error_string)(long n);
static X509_STORE_CTX* (*_X509_STORE_CTX_new)(void);
static void (*_X509_STORE_CTX_free)(X509_STORE_CTX* ctx);
static int (*_X509_STORE_CTX_get_error)(X509_STORE_CTX* ctx);
static int (*_X509_STORE_CTX_init)(X509_STORE_CTX* ctx, X509_STORE* store,
X509* x509, OPENSSL_STACK* chain);
/* === END OPENSSL HEADERS === */
#if defined CC_BUILD_WIN
static const cc_string cryptoLib = String_FromConst("libcrypto.dll");
#elif defined CC_BUILD_HAIKU
static const cc_string cryptoLib = String_FromConst("libcrypto.so.3");
static const cc_string cryptoAlt = String_FromConst("libcrypto.so");
#else
static const cc_string cryptoLib = String_FromConst("libcrypto.so");
static const cc_string cryptoAlt = String_FromConst("libcrypto.so.3");
#endif
static X509_STORE* store;
static cc_bool ossl_loaded;
void CertsBackend_Init(void) {
static const struct DynamicLibSym funcs[] = {
DynamicLib_ReqSym(OPENSSL_sk_new_null),
DynamicLib_ReqSym(OPENSSL_sk_push),
DynamicLib_ReqSym(OPENSSL_sk_pop_free),
DynamicLib_ReqSym(d2i_X509),
DynamicLib_ReqSym(X509_new),
DynamicLib_ReqSym(X509_free),
DynamicLib_ReqSym(X509_STORE_new),
DynamicLib_ReqSym(X509_STORE_set_default_paths),
DynamicLib_ReqSym(X509_STORE_CTX_new),
DynamicLib_ReqSym(X509_STORE_CTX_free),
DynamicLib_ReqSym(X509_STORE_CTX_get_error),
DynamicLib_ReqSym(X509_STORE_CTX_init),
DynamicLib_ReqSym(X509_verify_cert),
DynamicLib_ReqSym(X509_verify_cert_error_string),
};
void* lib;
ossl_loaded = DynamicLib_LoadAll(&cryptoLib, funcs, Array_Elems(funcs), &lib);
if (!lib) {
ossl_loaded = DynamicLib_LoadAll(&cryptoAlt, funcs, Array_Elems(funcs), &lib);
}
}
static X509* ToOpenSSLCert(struct X509Cert* cert) {
const unsigned char* data = cert->data;
return _d2i_X509(NULL, &data, cert->offset);
}
int Certs_VerifyChain(struct X509CertContext* chain) {
OPENSSL_STACK* inter;
X509_STORE_CTX* ctx;
int i, status, ret;
X509* cur;
X509* cert;
if (!ossl_loaded) return ERR_NOT_SUPPORTED;
/* Delay creating X509 store until necessary */
if (!store) {
store = _X509_STORE_new();
if (!store) return ERR_OUT_OF_MEMORY;
_X509_STORE_set_default_paths(store);
}
Platform_Log1("VERIFY CHAIN: %i", &chain->numCerts);
if (!chain->numCerts) return ERR_INVALID_ARGUMENT;
/* End/Leaf certificate */
cert = ToOpenSSLCert(&chain->certs[0]);
if (!cert) return ERR_OUT_OF_MEMORY;
inter = _OPENSSL_sk_new_null();
if (!inter) return ERR_OUT_OF_MEMORY;
/* Intermediate certificates */
for (i = 1; i < chain->numCerts; i++)
{
cur = ToOpenSSLCert(&chain->certs[i]);
if (cur) _OPENSSL_sk_push(inter, cur);
}
ctx = _X509_STORE_CTX_new();
_X509_STORE_CTX_init(ctx, store, cert, inter);
status = _X509_verify_cert(ctx);
if (status == 1) {
Platform_LogConst("Certificate verified");
ret = 0;
} else {
int err = _X509_STORE_CTX_get_error(ctx);
Platform_LogConst(_X509_verify_cert_error_string(err));
ret = -1;
}
_X509_STORE_CTX_free(ctx);
_OPENSSL_sk_pop_free(inter, (OPENSSL_PopFunc)_X509_free);
_X509_free(cert);
return ret;
}
#endif
#endif

34
src/Certs.h Normal file
View File

@ -0,0 +1,34 @@
#ifndef CC_CERT_H
#define CC_CERT_H
#include "Core.h"
CC_BEGIN_HEADER
/*
Validates an X509 certificate chain for verifying a SSL/TLS connection.
Copyright 2014-2025 ClassiCube | Licensed under BSD-3
*/
void CertsBackend_Init(void);
#define X509_MAX_CERTS 10
struct X509Cert {
void* data;
int offset;
};
struct X509CertContext {
struct X509Cert certs[X509_MAX_CERTS];
struct X509Cert* cert;
int numCerts;
};
void Certs_BeginChain( struct X509CertContext* ctx);
void Certs_FreeChain( struct X509CertContext* ctx);
int Certs_VerifyChain(struct X509CertContext* ctx);
void Certs_BeginCert( struct X509CertContext* ctx, int size);
void Certs_AppendCert(struct X509CertContext* ctx, const void* data, int len);
void Certs_FinishCert(struct X509CertContext* ctx);
CC_END_HEADER
#endif

View File

@ -153,6 +153,9 @@ typedef cc_uint8 cc_bool;
#define CC_NET_BACKEND_BUILTIN 1
#define CC_NET_BACKEND_LIBCURL 2
#define CC_CRT_BACKEND_NONE 1
#define CC_CRT_BACKEND_OPENSSL 2
#define CC_AUD_BACKEND_OPENAL 1
#define CC_AUD_BACKEND_WINMM 2
#define CC_AUD_BACKEND_OPENSLES 3
@ -226,7 +229,9 @@ typedef cc_uint8 cc_bool;
#elif defined __serenity__
#define CC_BUILD_SERENITY
#define CC_BUILD_POSIX
#define DEFAULT_NET_BACKEND CC_NET_BACKEND_LIBCURL
#define DEFAULT_NET_BACKEND CC_NET_BACKEND_BUILTIN
#define DEFAULT_SSL_BACKEND CC_SSL_BACKEND_BEARSSL
#define DEFAULT_CRT_BACKEND CC_CRT_BACKEND_OPENSSL
#define DEFAULT_AUD_BACKEND CC_AUD_BACKEND_OPENAL
#define DEFAULT_GFX_BACKEND CC_GFX_BACKEND_GL1
#define DEFAULT_WIN_BACKEND CC_WIN_BACKEND_SDL2
@ -255,7 +260,9 @@ typedef cc_uint8 cc_bool;
#define CC_BUILD_LINUX
#define CC_BUILD_POSIX
#define CC_BUILD_XINPUT2
#define DEFAULT_NET_BACKEND CC_NET_BACKEND_LIBCURL
#define DEFAULT_NET_BACKEND CC_NET_BACKEND_BUILTIN
#define DEFAULT_SSL_BACKEND CC_SSL_BACKEND_BEARSSL
#define DEFAULT_CRT_BACKEND CC_CRT_BACKEND_OPENSSL
#define DEFAULT_AUD_BACKEND CC_AUD_BACKEND_OPENAL
#define DEFAULT_WIN_BACKEND CC_WIN_BACKEND_X11
#if defined CC_BUILD_RPI
@ -297,7 +304,9 @@ typedef cc_uint8 cc_bool;
#define CC_BUILD_SOLARIS
#define CC_BUILD_POSIX
#define CC_BUILD_XINPUT2
#define DEFAULT_NET_BACKEND CC_NET_BACKEND_LIBCURL
#define DEFAULT_NET_BACKEND CC_NET_BACKEND_BUILTIN
#define DEFAULT_SSL_BACKEND CC_SSL_BACKEND_BEARSSL
#define DEFAULT_CRT_BACKEND CC_CRT_BACKEND_OPENSSL
#define DEFAULT_AUD_BACKEND CC_AUD_BACKEND_OPENAL
#define DEFAULT_GFX_BACKEND CC_GFX_BACKEND_GL1
#define DEFAULT_WIN_BACKEND CC_WIN_BACKEND_X11
@ -316,7 +325,9 @@ typedef cc_uint8 cc_bool;
#define CC_BUILD_POSIX
#define CC_BUILD_BSD
#define CC_BUILD_XINPUT2
#define DEFAULT_NET_BACKEND CC_NET_BACKEND_LIBCURL
#define DEFAULT_NET_BACKEND CC_NET_BACKEND_BUILTIN
#define DEFAULT_SSL_BACKEND CC_SSL_BACKEND_BEARSSL
#define DEFAULT_CRT_BACKEND CC_CRT_BACKEND_OPENSSL
#define DEFAULT_AUD_BACKEND CC_AUD_BACKEND_OPENAL
#define DEFAULT_GFX_BACKEND CC_GFX_BACKEND_GL1
#define DEFAULT_WIN_BACKEND CC_WIN_BACKEND_X11
@ -325,7 +336,9 @@ typedef cc_uint8 cc_bool;
#define CC_BUILD_POSIX
#define CC_BUILD_BSD
#define CC_BUILD_XINPUT2
#define DEFAULT_NET_BACKEND CC_NET_BACKEND_LIBCURL
#define DEFAULT_NET_BACKEND CC_NET_BACKEND_BUILTIN
#define DEFAULT_SSL_BACKEND CC_SSL_BACKEND_BEARSSL
#define DEFAULT_CRT_BACKEND CC_CRT_BACKEND_OPENSSL
#define DEFAULT_AUD_BACKEND CC_AUD_BACKEND_OPENAL
#define DEFAULT_GFX_BACKEND CC_GFX_BACKEND_GL1
#define DEFAULT_WIN_BACKEND CC_WIN_BACKEND_X11
@ -334,7 +347,9 @@ typedef cc_uint8 cc_bool;
#define CC_BUILD_POSIX
#define CC_BUILD_BSD
#define CC_BUILD_XINPUT2
#define DEFAULT_NET_BACKEND CC_NET_BACKEND_LIBCURL
#define DEFAULT_NET_BACKEND CC_NET_BACKEND_BUILTIN
#define DEFAULT_SSL_BACKEND CC_SSL_BACKEND_BEARSSL
#define DEFAULT_CRT_BACKEND CC_CRT_BACKEND_OPENSSL
#define DEFAULT_AUD_BACKEND CC_AUD_BACKEND_OPENAL
#define DEFAULT_GFX_BACKEND CC_GFX_BACKEND_GL1
#define DEFAULT_WIN_BACKEND CC_WIN_BACKEND_X11
@ -342,7 +357,9 @@ typedef cc_uint8 cc_bool;
#define CC_BUILD_HAIKU
#define CC_BUILD_POSIX
#define CC_BACKTRACE_BUILTIN
#define DEFAULT_NET_BACKEND CC_NET_BACKEND_LIBCURL
#define DEFAULT_NET_BACKEND CC_NET_BACKEND_BUILTIN
#define DEFAULT_SSL_BACKEND CC_SSL_BACKEND_BEARSSL
#define DEFAULT_CRT_BACKEND CC_CRT_BACKEND_OPENSSL
#define DEFAULT_AUD_BACKEND CC_AUD_BACKEND_OPENAL
#define DEFAULT_GFX_BACKEND CC_GFX_BACKEND_GL1
#define DEFAULT_WIN_BACKEND CC_WIN_BACKEND_BEOS
@ -359,7 +376,9 @@ typedef cc_uint8 cc_bool;
#define CC_BUILD_IRIX
#define CC_BUILD_POSIX
#define CC_BIG_ENDIAN
#define DEFAULT_NET_BACKEND CC_NET_BACKEND_LIBCURL
#define DEFAULT_NET_BACKEND CC_NET_BACKEND_BUILTIN
#define DEFAULT_SSL_BACKEND CC_SSL_BACKEND_BEARSSL
#define DEFAULT_CRT_BACKEND CC_CRT_BACKEND_OPENSSL
#define DEFAULT_AUD_BACKEND CC_AUD_BACKEND_OPENAL
#define DEFAULT_GFX_BACKEND CC_GFX_BACKEND_GL1
#define DEFAULT_WIN_BACKEND CC_WIN_BACKEND_X11
@ -525,7 +544,9 @@ typedef cc_uint8 cc_bool;
#define CC_BUILD_OS2
#define CC_BUILD_POSIX
#define CC_BUILD_FREETYPE
#define DEFAULT_NET_BACKEND CC_NET_BACKEND_LIBCURL
#define DEFAULT_NET_BACKEND CC_NET_BACKEND_BUILTIN
#define DEFAULT_SSL_BACKEND CC_SSL_BACKEND_BEARSSL
#define DEFAULT_CRT_BACKEND CC_CRT_BACKEND_OPENSSL
#define DEFAULT_GFX_BACKEND CC_GFX_BACKEND_SOFTGPU
#define DEFAULT_WIN_BACKEND CC_WIN_BACKEND_OS2
#elif defined PLAT_SATURN
@ -597,6 +618,9 @@ typedef cc_uint8 cc_bool;
#if defined DEFAULT_SSL_BACKEND && !defined CC_SSL_BACKEND
#define CC_SSL_BACKEND DEFAULT_SSL_BACKEND
#endif
#if defined DEFAULT_CRT_BACKEND && !defined CC_CRT_BACKEND
#define CC_CRT_BACKEND DEFAULT_CRT_BACKEND
#endif
#if defined DEFAULT_NET_BACKEND && !defined CC_NET_BACKEND
#define CC_NET_BACKEND DEFAULT_NET_BACKEND
#endif

View File

@ -1249,7 +1249,7 @@ void Logger_FailToStart(const char* raw_msg) {
#include <unwind.h>
static _Unwind_Reason_Code UnwindFrame(struct _Unwind_Context* ctx, void* arg) {
cc_uintptr addr = _Unwind_GetIP(ctx);
cc_uintptr addr = (cc_uintptr)_Unwind_GetIP(ctx);
if (!addr) return _URC_END_OF_STACK;
DumpFrame((cc_string*)arg, (void*)addr);

View File

@ -406,17 +406,53 @@ cc_result SSL_Free(void* ctx_) {
}
#elif CC_SSL_BACKEND == CC_SSL_BACKEND_BEARSSL
#include "String.h"
#include "Certs.h"
#include "bearssl.h"
#include "../misc/certs/certs.h"
// https://github.com/unkaktus/bearssl/blob/master/samples/client_basic.c#L283
#define SSL_ERROR_SHIFT 0xB5510000
static br_x509_class cert_verifier_vtable;
typedef struct SSLContext {
br_x509_minimal_context xc;
br_ssl_client_context sc;
struct X509CertContext x509;
unsigned char iobuf[BR_SSL_BUFSIZE_BIDI];
br_sslio_context ioc;
cc_result readError, writeError;
cc_socket socket;
} SSLContext;
static cc_bool _verifyCerts;
static unsigned cert_verifier_end_chain(const br_x509_class** ctx) {
unsigned r = br_x509_minimal_vtable.end_chain(ctx);
static void x509_start_cert(const br_x509_class** ctx, uint32_t length) {
struct SSLContext* ssl = (struct SSLContext*)ctx;
br_x509_minimal_vtable.start_cert(ctx, length);
Certs_BeginCert(&ssl->x509, length);
}
static void x509_append(const br_x509_class** ctx, const unsigned char* buf, size_t len) {
struct SSLContext* ssl = (struct SSLContext*)ctx;
br_x509_minimal_vtable.append(ctx, buf, len);
Certs_AppendCert(&ssl->x509, buf, len);
}
static void x509_end_cert(const br_x509_class** ctx) {
struct SSLContext* ssl = (struct SSLContext*)ctx;
br_x509_minimal_vtable.end_cert(ctx);
Certs_FinishCert(&ssl->x509);
}
static void x509_start_chain(const br_x509_class** ctx, const char* server_name) {
struct SSLContext* ssl = (struct SSLContext*)ctx;
br_x509_minimal_vtable.start_chain(ctx, server_name);
Certs_BeginChain(&ssl->x509);
}
static unsigned x509_maybe_skip_verify(unsigned r) {
/* User selected to not care about certificate authenticity */
if (r == BR_ERR_X509_NOT_TRUSTED && !_verifyCerts) return 0;
@ -434,20 +470,36 @@ static unsigned cert_verifier_end_chain(const br_x509_class** ctx) {
return r;
}
typedef struct SSLContext {
br_x509_minimal_context xc;
br_ssl_client_context sc;
unsigned char iobuf[BR_SSL_BUFSIZE_BIDI];
br_sslio_context ioc;
cc_result readError, writeError;
cc_socket socket;
} SSLContext;
static unsigned x509_end_chain(const br_x509_class** ctx) {
struct SSLContext* ssl = (struct SSLContext*)ctx;
unsigned r = br_x509_minimal_vtable.end_chain(ctx);
r = x509_maybe_skip_verify(r);
/* Fallback to system specific certificate validation */
if (r == BR_ERR_X509_NOT_TRUSTED && Certs_VerifyChain(&ssl->x509) == 0) r = 0;
Certs_FreeChain(&ssl->x509);
return r;
}
static const br_x509_pkey* x509_get_pkey(const br_x509_class*const* ctx, unsigned* usages) {
return br_x509_minimal_vtable.get_pkey(ctx, usages);
}
static const br_x509_class cert_verifier_vtable = {
sizeof(br_x509_minimal_context),
x509_start_chain,
x509_start_cert,
x509_append,
x509_end_cert,
x509_end_chain,
x509_get_pkey
};
void SSLBackend_Init(cc_bool verifyCerts) {
_verifyCerts = verifyCerts;
cert_verifier_vtable = br_x509_minimal_vtable;
cert_verifier_vtable.end_chain = cert_verifier_end_chain;
CertsBackend_Init();
}
cc_bool SSLBackend_DescribeError(cc_result res, cc_string* dst) {

View File

@ -39,7 +39,6 @@
* | :-------------- | :------------------------------------------------ |
* | bearssl_hash.h | Hash functions |
* | bearssl_hmac.h | HMAC |
* | bearssl_kdf.h | Key Derivation Functions |
* | bearssl_rand.h | Pseudorandom byte generators |
* | bearssl_prf.h | PRF implementations (for SSL/TLS) |
* | bearssl_block.h | Symmetric encryption |
@ -48,7 +47,6 @@
* | bearssl_ec.h | Elliptic curves support (including ECDSA) |
* | bearssl_ssl.h | SSL/TLS engine interface |
* | bearssl_x509.h | X.509 certificate decoding and validation |
* | bearssl_pem.h | Base64/PEM decoding support functions |
*
* Applications using BearSSL are supposed to simply include `bearssl.h`
* as follows:
@ -130,7 +128,6 @@
#include "bearssl_hash.h"
#include "bearssl_hmac.h"
#include "bearssl_kdf.h"
#include "bearssl_rand.h"
#include "bearssl_prf.h"
#include "bearssl_block.h"
@ -139,49 +136,5 @@
#include "bearssl_ec.h"
#include "bearssl_ssl.h"
#include "bearssl_x509.h"
#include "bearssl_pem.h"
#ifdef __cplusplus
extern "C" {
#endif
/** \brief Type for a configuration option.
*
* A "configuration option" is a value that is selected when the BearSSL
* library itself is compiled. Most options are boolean; their value is
* then either 1 (option is enabled) or 0 (option is disabled). Some
* values have other integer values. Option names correspond to macro
* names. Some of the options can be explicitly set in the internal
* `"config.h"` file.
*/
typedef struct {
/** \brief Configurable option name. */
const char *name;
/** \brief Configurable option value. */
long value;
} br_config_option;
/** \brief Get configuration report.
*
* This function returns compiled configuration options, each as a
* 'long' value. Names match internal macro names, in particular those
* that can be set in the `"config.h"` inner file. For boolean options,
* the numerical value is 1 if enabled, 0 if disabled. For maximum
* key sizes, values are expressed in bits.
*
* The returned array is terminated by an entry whose `name` is `NULL`.
*
* \return the configuration report.
*/
const br_config_option *br_get_config(void);
/* ======================================================================= */
/** \brief Version feature: support for time callback. */
#define BR_FEATURE_X509_TIME_CALLBACK 1
#ifdef __cplusplus
}
#endif
#endif

View File

@ -299,13 +299,6 @@ extern "C" {
* | aes_ct | AES | 16 | 16, 24 and 32 |
* | aes_ct64 | AES | 16 | 16, 24 and 32 |
* | aes_x86ni | AES | 16 | 16, 24 and 32 |
* | des_ct | DES/3DES | 8 | 8, 16 and 24 |
* | des_tab | DES/3DES | 8 | 8, 16 and 24 |
*
* **Note:** DES/3DES nominally uses keys of 64, 128 and 192 bits (i.e. 8,
* 16 and 24 bytes), but some of the bits are ignored by the algorithm, so
* the _effective_ key lengths, from a security point of view, are 56,
* 112 and 168 bits, respectively.
*
* `aes_big` is a "classical" AES implementation, using tables. It
* is fast but not constant-time, since it makes data-dependent array
@ -334,12 +327,6 @@ extern "C" {
* `aes_x86ni` exists only on x86 architectures (32-bit and 64-bit). It
* uses the AES-NI opcodes when available.
*
* `des_tab` is a classic, table-based implementation of DES/3DES. It
* is not constant-time.
*
* `des_ct` is an constant-time implementation of DES/3DES. It is
* substantially slower than `des_tab`.
*
* ## ChaCha20 and Poly1305
*
* ChaCha20 is a stream cipher. Poly1305 is a MAC algorithm. They
@ -364,19 +351,9 @@ extern "C" {
* construction, where the Poly1305 part is performed with mixed 32-bit
* multiplications (operands are 32-bit, result is 64-bit).
*
* `poly1305_ctmul32` implements ChaCha20+Poly1305 using pure 32-bit
* multiplications (32-bit operands, 32-bit result). It is slower than
* `poly1305_ctmul`, except on some specific architectures such as
* the ARM Cortex M0+.
*
* `poly1305_ctmulq` implements ChaCha20+Poly1305 with mixed 64-bit
* multiplications (operands are 64-bit, result is 128-bit) on 64-bit
* platforms that support such operations.
*
* `poly1305_i15` implements ChaCha20+Poly1305 with the generic "i15"
* big integer implementation. It is meant mostly for testing purposes,
* although it can help with saving a few hundred bytes of code footprint
* on systems where code size is scarce.
*/
/**
@ -1908,215 +1885,6 @@ typedef union {
br_aes_x86ni_ctrcbc_keys c_x86ni;
} br_aes_gen_ctrcbc_keys;
/*
* Traditional, table-based implementation for DES/3DES. Since tables are
* used, cache-timing attacks are conceptually possible.
*/
/** \brief DES/3DES block size (8 bytes). */
#define br_des_tab_BLOCK_SIZE 8
/**
* \brief Context for DES subkeys (`des_tab` implementation, CBC encryption).
*
* First field is a pointer to the vtable; it is set by the initialisation
* function. Other fields are not supposed to be accessed by user code.
*/
typedef struct {
/** \brief Pointer to vtable for this context. */
const br_block_cbcenc_class *vtable;
#ifndef BR_DOXYGEN_IGNORE
uint32_t skey[96];
unsigned num_rounds;
#endif
} br_des_tab_cbcenc_keys;
/**
* \brief Context for DES subkeys (`des_tab` implementation, CBC decryption).
*
* First field is a pointer to the vtable; it is set by the initialisation
* function. Other fields are not supposed to be accessed by user code.
*/
typedef struct {
/** \brief Pointer to vtable for this context. */
const br_block_cbcdec_class *vtable;
#ifndef BR_DOXYGEN_IGNORE
uint32_t skey[96];
unsigned num_rounds;
#endif
} br_des_tab_cbcdec_keys;
/**
* \brief Class instance for DES CBC encryption (`des_tab` implementation).
*/
extern const br_block_cbcenc_class br_des_tab_cbcenc_vtable;
/**
* \brief Class instance for DES CBC decryption (`des_tab` implementation).
*/
extern const br_block_cbcdec_class br_des_tab_cbcdec_vtable;
/**
* \brief Context initialisation (key schedule) for DES CBC encryption
* (`des_tab` implementation).
*
* \param ctx context to initialise.
* \param key secret key.
* \param len secret key length (in bytes).
*/
void br_des_tab_cbcenc_init(br_des_tab_cbcenc_keys *ctx,
const void *key, size_t len);
/**
* \brief Context initialisation (key schedule) for DES CBC decryption
* (`des_tab` implementation).
*
* \param ctx context to initialise.
* \param key secret key.
* \param len secret key length (in bytes).
*/
void br_des_tab_cbcdec_init(br_des_tab_cbcdec_keys *ctx,
const void *key, size_t len);
/**
* \brief CBC encryption with DES (`des_tab` implementation).
*
* \param ctx context (already initialised).
* \param iv IV (updated).
* \param data data to encrypt (updated).
* \param len data length (in bytes, MUST be multiple of 8).
*/
void br_des_tab_cbcenc_run(const br_des_tab_cbcenc_keys *ctx, void *iv,
void *data, size_t len);
/**
* \brief CBC decryption with DES (`des_tab` implementation).
*
* \param ctx context (already initialised).
* \param iv IV (updated).
* \param data data to decrypt (updated).
* \param len data length (in bytes, MUST be multiple of 8).
*/
void br_des_tab_cbcdec_run(const br_des_tab_cbcdec_keys *ctx, void *iv,
void *data, size_t len);
/*
* Constant-time implementation for DES/3DES. It is substantially slower
* (by a factor of about 4x), but also immune to cache-timing attacks.
*/
/** \brief DES/3DES block size (8 bytes). */
#define br_des_ct_BLOCK_SIZE 8
/**
* \brief Context for DES subkeys (`des_ct` implementation, CBC encryption).
*
* First field is a pointer to the vtable; it is set by the initialisation
* function. Other fields are not supposed to be accessed by user code.
*/
typedef struct {
/** \brief Pointer to vtable for this context. */
const br_block_cbcenc_class *vtable;
#ifndef BR_DOXYGEN_IGNORE
uint32_t skey[96];
unsigned num_rounds;
#endif
} br_des_ct_cbcenc_keys;
/**
* \brief Context for DES subkeys (`des_ct` implementation, CBC decryption).
*
* First field is a pointer to the vtable; it is set by the initialisation
* function. Other fields are not supposed to be accessed by user code.
*/
typedef struct {
/** \brief Pointer to vtable for this context. */
const br_block_cbcdec_class *vtable;
#ifndef BR_DOXYGEN_IGNORE
uint32_t skey[96];
unsigned num_rounds;
#endif
} br_des_ct_cbcdec_keys;
/**
* \brief Class instance for DES CBC encryption (`des_ct` implementation).
*/
extern const br_block_cbcenc_class br_des_ct_cbcenc_vtable;
/**
* \brief Class instance for DES CBC decryption (`des_ct` implementation).
*/
extern const br_block_cbcdec_class br_des_ct_cbcdec_vtable;
/**
* \brief Context initialisation (key schedule) for DES CBC encryption
* (`des_ct` implementation).
*
* \param ctx context to initialise.
* \param key secret key.
* \param len secret key length (in bytes).
*/
void br_des_ct_cbcenc_init(br_des_ct_cbcenc_keys *ctx,
const void *key, size_t len);
/**
* \brief Context initialisation (key schedule) for DES CBC decryption
* (`des_ct` implementation).
*
* \param ctx context to initialise.
* \param key secret key.
* \param len secret key length (in bytes).
*/
void br_des_ct_cbcdec_init(br_des_ct_cbcdec_keys *ctx,
const void *key, size_t len);
/**
* \brief CBC encryption with DES (`des_ct` implementation).
*
* \param ctx context (already initialised).
* \param iv IV (updated).
* \param data data to encrypt (updated).
* \param len data length (in bytes, MUST be multiple of 8).
*/
void br_des_ct_cbcenc_run(const br_des_ct_cbcenc_keys *ctx, void *iv,
void *data, size_t len);
/**
* \brief CBC decryption with DES (`des_ct` implementation).
*
* \param ctx context (already initialised).
* \param iv IV (updated).
* \param data data to decrypt (updated).
* \param len data length (in bytes, MUST be multiple of 8).
*/
void br_des_ct_cbcdec_run(const br_des_ct_cbcdec_keys *ctx, void *iv,
void *data, size_t len);
/*
* These structures are large enough to accommodate subkeys for all
* DES/3DES implementations.
*/
/**
* \brief Aggregate structure large enough to be used as context for
* subkeys (CBC encryption) for all DES implementations.
*/
typedef union {
const br_block_cbcenc_class *vtable;
br_des_tab_cbcenc_keys tab;
br_des_ct_cbcenc_keys ct;
} br_des_gen_cbcenc_keys;
/**
* \brief Aggregate structure large enough to be used as context for
* subkeys (CBC decryption) for all DES implementations.
*/
typedef union {
const br_block_cbcdec_class *vtable;
br_des_tab_cbcdec_keys c_tab;
br_des_ct_cbcdec_keys c_ct;
} br_des_gen_cbcdec_keys;
/**
* \brief Type for a ChaCha20 implementation.
*
@ -2234,50 +2002,6 @@ void br_poly1305_ctmul_run(const void *key, const void *iv,
void *data, size_t len, const void *aad, size_t aad_len,
void *tag, br_chacha20_run ichacha, int encrypt);
/**
* \brief ChaCha20+Poly1305 AEAD implementation (pure 32-bit multiplications).
*
* \see br_poly1305_run
*
* \param key secret key (32 bytes).
* \param iv nonce (12 bytes).
* \param data data to encrypt or decrypt.
* \param len data length (in bytes).
* \param aad additional authenticated data.
* \param aad_len length of additional authenticated data (in bytes).
* \param tag output buffer for the authentication tag.
* \param ichacha implementation of ChaCha20.
* \param encrypt non-zero for encryption, zero for decryption.
*/
void br_poly1305_ctmul32_run(const void *key, const void *iv,
void *data, size_t len, const void *aad, size_t aad_len,
void *tag, br_chacha20_run ichacha, int encrypt);
/**
* \brief ChaCha20+Poly1305 AEAD implementation (i15).
*
* This implementation relies on the generic big integer code "i15"
* (which uses pure 32-bit multiplications). As such, it may save a
* little code footprint in a context where "i15" is already included
* (e.g. for elliptic curves or for RSA); however, it is also
* substantially slower than the ctmul and ctmul32 implementations.
*
* \see br_poly1305_run
*
* \param key secret key (32 bytes).
* \param iv nonce (12 bytes).
* \param data data to encrypt or decrypt.
* \param len data length (in bytes).
* \param aad additional authenticated data.
* \param aad_len length of additional authenticated data (in bytes).
* \param tag output buffer for the authentication tag.
* \param ichacha implementation of ChaCha20.
* \param encrypt non-zero for encryption, zero for decryption.
*/
void br_poly1305_i15_run(const void *key, const void *iv,
void *data, size_t len, const void *aad, size_t aad_len,
void *tag, br_chacha20_run ichacha, int encrypt);
/**
* \brief ChaCha20+Poly1305 AEAD implementation (ctmulq).
*

View File

@ -423,25 +423,6 @@ typedef struct {
*/
extern const br_ec_impl br_ec_prime_i31;
/**
* \brief EC implementation "i15".
*
* This implementation internally uses generic code for modular integers,
* with a representation as sequences of 15-bit words. It supports secp256r1,
* secp384r1 and secp521r1 (aka NIST curves P-256, P-384 and P-521).
*/
extern const br_ec_impl br_ec_prime_i15;
/**
* \brief EC implementation "m15" for P-256.
*
* This implementation uses specialised code for curve secp256r1 (also
* known as NIST P-256), with optional Karatsuba decomposition, and fast
* modular reduction thanks to the field modulus special format. Only
* 32-bit multiplications are used (with 32-bit results, not 64-bit).
*/
extern const br_ec_impl br_ec_p256_m15;
/**
* \brief EC implementation "m31" for P-256.
*
@ -487,20 +468,6 @@ extern const br_ec_impl br_ec_p256_m64;
*/
const br_ec_impl *br_ec_p256_m64_get(void);
/**
* \brief EC implementation "i15" (generic code) for Curve25519.
*
* This implementation uses the generic code for modular integers (with
* 15-bit words) to support Curve25519. Due to the specificities of the
* curve definition, the following applies:
*
* - `muladd()` is not implemented (the function returns 0 systematically).
* - `order()` returns 2^255-1, since the point multiplication algorithm
* accepts any 32-bit integer as input (it clears the top bit and low
* three bits systematically).
*/
extern const br_ec_impl br_ec_c25519_i15;
/**
* \brief EC implementation "i31" (generic code) for Curve25519.
*
@ -515,20 +482,6 @@ extern const br_ec_impl br_ec_c25519_i15;
*/
extern const br_ec_impl br_ec_c25519_i31;
/**
* \brief EC implementation "m15" (specialised code) for Curve25519.
*
* This implementation uses custom code relying on multiplication of
* integers up to 15 bits. Due to the specificities of the curve
* definition, the following applies:
*
* - `muladd()` is not implemented (the function returns 0 systematically).
* - `order()` returns 2^255-1, since the point multiplication algorithm
* accepts any 32-bit integer as input (it clears the top bit and low
* three bits systematically).
*/
extern const br_ec_impl br_ec_c25519_m15;
/**
* \brief EC implementation "m31" (specialised code) for Curve25519.
*
@ -591,17 +544,6 @@ extern const br_ec_impl br_ec_c25519_m64;
*/
const br_ec_impl *br_ec_c25519_m64_get(void);
/**
* \brief Aggregate EC implementation "m15".
*
* This implementation is a wrapper for:
*
* - `br_ec_c25519_m15` for Curve25519
* - `br_ec_p256_m15` for NIST P-256
* - `br_ec_prime_i15` for other curves (NIST P-384 and NIST-P512)
*/
extern const br_ec_impl br_ec_all_m15;
/**
* \brief Aggregate EC implementation "m31".
*
@ -777,72 +719,6 @@ uint32_t br_ecdsa_i31_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);
/**
* \brief ECDSA signature generator, "i15" implementation, "asn1" format.
*
* \see br_ecdsa_sign()
*
* \param impl EC implementation to use.
* \param hf hash function used to process the data.
* \param hash_value signed data (hashed).
* \param sk EC private key.
* \param sig destination buffer.
* \return the signature length (in bytes), or 0 on error.
*/
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);
/**
* \brief ECDSA signature generator, "i15" implementation, "raw" format.
*
* \see br_ecdsa_sign()
*
* \param impl EC implementation to use.
* \param hf hash function used to process the data.
* \param hash_value signed data (hashed).
* \param sk EC private key.
* \param sig destination buffer.
* \return the signature length (in bytes), or 0 on error.
*/
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);
/**
* \brief ECDSA signature verifier, "i15" implementation, "asn1" format.
*
* \see br_ecdsa_vrfy()
*
* \param impl EC implementation to use.
* \param hash signed data (hashed).
* \param hash_len hash value length (in bytes).
* \param pk EC public key.
* \param sig signature.
* \param sig_len signature length (in bytes).
* \return 1 on success, 0 on error.
*/
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);
/**
* \brief ECDSA signature verifier, "i15" implementation, "raw" format.
*
* \see br_ecdsa_vrfy()
*
* \param impl EC implementation to use.
* \param hash signed data (hashed).
* \param hash_len hash value length (in bytes).
* \param pk EC public key.
* \param sig signature.
* \param sig_len signature length (in bytes).
* \return 1 on success, 0 on error.
*/
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);
/**
* \brief Get "default" ECDSA implementation (signer, asn1 format).
*

View File

@ -1256,22 +1256,6 @@ typedef void (*br_ghash)(void *y, const void *h, const void *data, size_t len);
*/
void br_ghash_ctmul(void *y, const void *h, const void *data, size_t len);
/**
* \brief GHASH implementation using multiplications (strict 32-bit).
*
* This implementation uses multiplications of 32-bit values, with a
* 32-bit result. It is usually somewhat slower than `br_ghash_ctmul()`,
* but it is expected to be faster on architectures for which the
* 32-bit multiplication opcode does not yield the upper 32 bits of the
* product. It is constant-time (if multiplications are constant-time).
*
* \param y the array to update.
* \param h the GHASH key.
* \param data the input data (may be `NULL` if `len` is zero).
* \param len the input data length (in bytes).
*/
void br_ghash_ctmul32(void *y, const void *h, const void *data, size_t len);
/**
* \brief GHASH implementation using multiplications (64-bit).
*

View File

@ -1,284 +0,0 @@
/*
* 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.
*/
#ifndef BR_BEARSSL_KDF_H__
#define BR_BEARSSL_KDF_H__
#include <stddef.h>
#include <stdint.h>
#include "bearssl_hash.h"
#include "bearssl_hmac.h"
#ifdef __cplusplus
extern "C" {
#endif
/** \file bearssl_kdf.h
*
* # Key Derivation Functions
*
* KDF are functions that takes a variable length input, and provide a
* variable length output, meant to be used to derive subkeys from a
* master key.
*
* ## HKDF
*
* HKDF is a KDF defined by [RFC 5869](https://tools.ietf.org/html/rfc5869).
* It is based on HMAC, itself using an underlying hash function. Any
* hash function can be used, as long as it is compatible with the rules
* for the HMAC implementation (i.e. output size is 64 bytes or less, hash
* internal state size is 64 bytes or less, and the internal block length is
* a power of 2 between 16 and 256 bytes). HKDF has two phases:
*
* - HKDF-Extract: the input data in ingested, along with a "salt" value.
*
* - HKDF-Expand: the output is produced, from the result of processing
* the input and salt, and using an extra non-secret parameter called
* "info".
*
* The "salt" and "info" strings are non-secret and can be empty. Their role
* is normally to bind the input and output, respectively, to conventional
* identifiers that qualifu them within the used protocol or application.
*
* The implementation defined in this file uses the following functions:
*
* - `br_hkdf_init()`: initialize an HKDF context, with a hash function,
* and the salt. This starts the HKDF-Extract process.
*
* - `br_hkdf_inject()`: inject more input bytes. This function may be
* called repeatedly if the input data is provided by chunks.
*
* - `br_hkdf_flip()`: end the HKDF-Extract process, and start the
* HKDF-Expand process.
*
* - `br_hkdf_produce()`: get the next bytes of output. This function
* may be called several times to obtain the full output by chunks.
* For correct HKDF processing, the same "info" string must be
* provided for each call.
*
* Note that the HKDF total output size (the number of bytes that
* HKDF-Expand is willing to produce) is limited: if the hash output size
* is _n_ bytes, then the maximum output size is _255*n_.
*
* ## SHAKE
*
* SHAKE is defined in
* [FIPS 202](https://csrc.nist.gov/publications/detail/fips/202/final)
* under two versions: SHAKE128 and SHAKE256, offering an alleged
* "security level" of 128 and 256 bits, respectively (SHAKE128 is
* about 20 to 25% faster than SHAKE256). SHAKE internally relies on
* the Keccak family of sponge functions, not on any externally provided
* hash function. Contrary to HKDF, SHAKE does not have a concept of
* either a "salt" or an "info" string. The API consists in four
* functions:
*
* - `br_shake_init()`: initialize a SHAKE context for a given
* security level.
*
* - `br_shake_inject()`: inject more input bytes. This function may be
* called repeatedly if the input data is provided by chunks.
*
* - `br_shake_flip()`: end the data injection process, and start the
* data production process.
*
* - `br_shake_produce()`: get the next bytes of output. This function
* may be called several times to obtain the full output by chunks.
*/
/**
* \brief HKDF context.
*
* The HKDF context is initialized with a hash function implementation
* and a salt value. Contents are opaque (callers should not access them
* directly). The caller is responsible for allocating the context where
* appropriate. Context initialisation and usage incurs no dynamic
* allocation, so there is no release function.
*/
typedef struct {
#ifndef BR_DOXYGEN_IGNORE
union {
br_hmac_context hmac_ctx;
br_hmac_key_context prk_ctx;
} u;
unsigned char buf[64];
size_t ptr;
size_t dig_len;
unsigned chunk_num;
#endif
} br_hkdf_context;
/**
* \brief HKDF context initialization.
*
* The underlying hash function and salt value are provided. Arbitrary
* salt lengths can be used.
*
* HKDF makes a difference between a salt of length zero, and an
* absent salt (the latter being equivalent to a salt consisting of
* bytes of value zero, of the same length as the hash function output).
* If `salt_len` is zero, then this function assumes that the salt is
* present but of length zero. To specify an _absent_ salt, use
* `BR_HKDF_NO_SALT` as `salt` parameter (`salt_len` is then ignored).
*
* \param hc HKDF context to initialise.
* \param digest_vtable pointer to the hash function implementation vtable.
* \param salt HKDF-Extract salt.
* \param salt_len HKDF-Extract salt length (in bytes).
*/
void br_hkdf_init(br_hkdf_context *hc, const br_hash_class *digest_vtable,
const void *salt, size_t salt_len);
/**
* \brief The special "absent salt" value for HKDF.
*/
#define BR_HKDF_NO_SALT (&br_hkdf_no_salt)
#ifndef BR_DOXYGEN_IGNORE
extern const unsigned char br_hkdf_no_salt;
#endif
/**
* \brief HKDF input injection (HKDF-Extract).
*
* This function injects some more input bytes ("key material") into
* HKDF. This function may be called several times, after `br_hkdf_init()`
* but before `br_hkdf_flip()`.
*
* \param hc HKDF context.
* \param ikm extra input bytes.
* \param ikm_len number of extra input bytes.
*/
void br_hkdf_inject(br_hkdf_context *hc, const void *ikm, size_t ikm_len);
/**
* \brief HKDF switch to the HKDF-Expand phase.
*
* This call terminates the HKDF-Extract process (input injection), and
* starts the HKDF-Expand process (output production).
*
* \param hc HKDF context.
*/
void br_hkdf_flip(br_hkdf_context *hc);
/**
* \brief HKDF output production (HKDF-Expand).
*
* Produce more output bytes from the current state. This function may be
* called several times, but only after `br_hkdf_flip()`.
*
* Returned value is the number of actually produced bytes. The total
* output length is limited to 255 times the output length of the
* underlying hash function.
*
* \param hc HKDF context.
* \param info application specific information string.
* \param info_len application specific information string length (in bytes).
* \param out destination buffer for the HKDF output.
* \param out_len the length of the requested output (in bytes).
* \return the produced output length (in bytes).
*/
size_t br_hkdf_produce(br_hkdf_context *hc,
const void *info, size_t info_len, void *out, size_t out_len);
/**
* \brief SHAKE context.
*
* The HKDF context is initialized with a "security level". The internal
* notion is called "capacity"; the capacity is twice the security level
* (for instance, SHAKE128 has capacity 256).
*
* The caller is responsible for allocating the context where
* appropriate. Context initialisation and usage incurs no dynamic
* allocation, so there is no release function.
*/
typedef struct {
#ifndef BR_DOXYGEN_IGNORE
unsigned char dbuf[200];
size_t dptr;
size_t rate;
uint64_t A[25];
#endif
} br_shake_context;
/**
* \brief SHAKE context initialization.
*
* The context is initialized for the provided "security level".
* Internally, this sets the "capacity" to twice the security level;
* thus, for SHAKE128, the `security_level` parameter should be 128,
* which corresponds to a 256-bit capacity.
*
* Allowed security levels are all multiples of 32, from 32 to 768,
* inclusive. Larger security levels imply lower performance; levels
* beyond 256 bits don't make much sense. Standard levels are 128
* and 256 bits (for SHAKE128 and SHAKE256, respectively).
*
* \param sc SHAKE context to initialise.
* \param security_level security level (in bits).
*/
void br_shake_init(br_shake_context *sc, int security_level);
/**
* \brief SHAKE input injection.
*
* This function injects some more input bytes ("key material") into
* SHAKE. This function may be called several times, after `br_shake_init()`
* but before `br_shake_flip()`.
*
* \param sc SHAKE context.
* \param data extra input bytes.
* \param len number of extra input bytes.
*/
void br_shake_inject(br_shake_context *sc, const void *data, size_t len);
/**
* \brief SHAKE switch to production phase.
*
* This call terminates the input injection process, and starts the
* output production process.
*
* \param sc SHAKE context.
*/
void br_shake_flip(br_shake_context *hc);
/**
* \brief SHAKE output production.
*
* Produce more output bytes from the current state. This function may be
* called several times, but only after `br_shake_flip()`.
*
* There is no practical limit to the number of bytes that may be produced.
*
* \param sc SHAKE context.
* \param out destination buffer for the SHAKE output.
* \param len the length of the requested output (in bytes).
*/
void br_shake_produce(br_shake_context *sc, void *out, size_t len);
#ifdef __cplusplus
}
#endif
#endif

View File

@ -1,294 +0,0 @@
/*
* 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.
*/
#ifndef BR_BEARSSL_PEM_H__
#define BR_BEARSSL_PEM_H__
#include <stddef.h>
#include <stdint.h>
#ifdef __cplusplus
extern "C" {
#endif
/** \file bearssl_pem.h
*
* # PEM Support
*
* PEM is a traditional encoding layer use to store binary objects (in
* particular X.509 certificates, and private keys) in text files. While
* the acronym comes from an old, defunct standard ("Privacy Enhanced
* Mail"), the format has been reused, with some variations, by many
* systems, and is a _de facto_ standard, even though it is not, actually,
* specified in all clarity anywhere.
*
* ## Format Details
*
* BearSSL contains a generic, streamed PEM decoder, which handles the
* following format:
*
* - The input source (a sequence of bytes) is assumed to be the
* encoding of a text file in an ASCII-compatible charset. This
* includes ISO-8859-1, Windows-1252, and UTF-8 encodings. Each
* line ends on a newline character (U+000A LINE FEED). The
* U+000D CARRIAGE RETURN characters are ignored, so the code
* accepts both Windows-style and Unix-style line endings.
*
* - Each object begins with a banner that occurs at the start of
* a line; the first banner characters are "`-----BEGIN `" (five
* dashes, the word "BEGIN", and a space). The banner matching is
* not case-sensitive.
*
* - The _object name_ consists in the characters that follow the
* banner start sequence, up to the end of the line, but without
* trailing dashes (in "normal" PEM, there are five trailing
* dashes, but this implementation is not picky about these dashes).
* The BearSSL decoder normalises the name characters to uppercase
* (for ASCII letters only) and accepts names up to 127 characters.
*
* - The object ends with a banner that again occurs at the start of
* a line, and starts with "`-----END `" (again case-insensitive).
*
* - Between that start and end banner, only Base64 data shall occur.
* Base64 converts each sequence of three bytes into four
* characters; the four characters are ASCII letters, digits, "`+`"
* or "`-`" signs, and one or two "`=`" signs may occur in the last
* quartet. Whitespace is ignored (whitespace is any ASCII character
* of code 32 or less, so control characters are whitespace) and
* lines may have arbitrary length; the only restriction is that the
* four characters of a quartet must appear on the same line (no
* line break inside a quartet).
*
* - A single file may contain more than one PEM object. Bytes that
* occur between objects are ignored.
*
*
* ## PEM Decoder API
*
* The PEM decoder offers a state-machine API. The caller allocates a
* decoder context, then injects source bytes. Source bytes are pushed
* with `br_pem_decoder_push()`. The decoder stops accepting bytes when
* it reaches an "event", which is either the start of an object, the
* end of an object, or a decoding error within an object.
*
* The `br_pem_decoder_event()` function is used to obtain the current
* event; it also clears it, thus allowing the decoder to accept more
* bytes. When a object start event is raised, the decoder context
* offers the found object name (normalised to ASCII uppercase).
*
* When an object is reached, the caller must set an appropriate callback
* function, which will receive (by chunks) the decoded object data.
*
* Since the decoder context makes no dynamic allocation, it requires
* no explicit deallocation.
*/
/**
* \brief PEM decoder context.
*
* Contents are opaque (they should not be accessed directly).
*/
typedef struct {
#ifndef BR_DOXYGEN_IGNORE
/* CPU for the T0 virtual machine. */
struct {
uint32_t *dp;
uint32_t *rp;
const unsigned char *ip;
} cpu;
uint32_t dp_stack[32];
uint32_t rp_stack[32];
int err;
const unsigned char *hbuf;
size_t hlen;
void (*dest)(void *dest_ctx, const void *src, size_t len);
void *dest_ctx;
unsigned char event;
char name[128];
unsigned char buf[255];
size_t ptr;
#endif
} br_pem_decoder_context;
/**
* \brief Initialise a PEM decoder structure.
*
* \param ctx decoder context to initialise.
*/
void br_pem_decoder_init(br_pem_decoder_context *ctx);
/**
* \brief Push some bytes into the decoder.
*
* Returned value is the number of bytes actually consumed; this may be
* less than the number of provided bytes if an event is raised. When an
* event is raised, it must be read (with `br_pem_decoder_event()`);
* until the event is read, this function will return 0.
*
* \param ctx decoder context.
* \param data new data bytes.
* \param len number of new data bytes.
* \return the number of bytes actually received (may be less than `len`).
*/
size_t br_pem_decoder_push(br_pem_decoder_context *ctx,
const void *data, size_t len);
/**
* \brief Set the receiver for decoded data.
*
* When an object is entered, the provided function (with opaque context
* pointer) will be called repeatedly with successive chunks of decoded
* data for that object. If `dest` is set to 0, then decoded data is
* simply ignored. The receiver can be set at any time, but, in practice,
* it should be called immediately after receiving a "start of object"
* event.
*
* \param ctx decoder context.
* \param dest callback for receiving decoded data.
* \param dest_ctx opaque context pointer for the `dest` callback.
*/
static inline void
br_pem_decoder_setdest(br_pem_decoder_context *ctx,
void (*dest)(void *dest_ctx, const void *src, size_t len),
void *dest_ctx)
{
ctx->dest = dest;
ctx->dest_ctx = dest_ctx;
}
/**
* \brief Get the last event.
*
* If an event was raised, then this function returns the event value, and
* also clears it, thereby allowing the decoder to proceed. If no event
* was raised since the last call to `br_pem_decoder_event()`, then this
* function returns 0.
*
* \param ctx decoder context.
* \return the raised event, or 0.
*/
int br_pem_decoder_event(br_pem_decoder_context *ctx);
/**
* \brief Event: start of object.
*
* This event is raised when the start of a new object has been detected.
* The object name (normalised to uppercase) can be accessed with
* `br_pem_decoder_name()`.
*/
#define BR_PEM_BEGIN_OBJ 1
/**
* \brief Event: end of object.
*
* This event is raised when the end of the current object is reached
* (normally, i.e. with no decoding error).
*/
#define BR_PEM_END_OBJ 2
/**
* \brief Event: decoding error.
*
* This event is raised when decoding fails within an object.
* This formally closes the current object and brings the decoder back
* to the "out of any object" state. The offending line in the source
* is consumed.
*/
#define BR_PEM_ERROR 3
/**
* \brief Get the name of the encountered object.
*
* The encountered object name is defined only when the "start of object"
* event is raised. That name is normalised to uppercase (for ASCII letters
* only) and does not include trailing dashes.
*
* \param ctx decoder context.
* \return the current object name.
*/
static inline const char *
br_pem_decoder_name(br_pem_decoder_context *ctx)
{
return ctx->name;
}
/**
* \brief Encode an object in PEM.
*
* This function encodes the provided binary object (`data`, of length `len`
* bytes) into PEM. The `banner` text will be included in the header and
* footer (e.g. use `"CERTIFICATE"` to get a `"BEGIN CERTIFICATE"` header).
*
* The length (in characters) of the PEM output is returned; that length
* does NOT include the terminating zero, that this function nevertheless
* adds. If using the returned value for allocation purposes, the allocated
* buffer size MUST be at least one byte larger than the returned size.
*
* If `dest` is `NULL`, then the encoding does not happen; however, the
* length of the encoded object is still computed and returned.
*
* The `data` pointer may be `NULL` only if `len` is zero (when encoding
* an object of length zero, which is not very useful), or when `dest`
* is `NULL` (in that case, source data bytes are ignored).
*
* Some `flags` can be specified to alter the encoding behaviour:
*
* - If `BR_PEM_LINE64` is set, then line-breaking will occur after
* every 64 characters of output, instead of the default of 76.
*
* - If `BR_PEM_CRLF` is set, then end-of-line sequence will use
* CR+LF instead of a single LF.
*
* The `data` and `dest` buffers may overlap, in which case the source
* binary data is destroyed in the process. Note that the PEM-encoded output
* is always larger than the source binary.
*
* \param dest the destination buffer (or `NULL`).
* \param data the source buffer (can be `NULL` in some cases).
* \param len the source length (in bytes).
* \param banner the PEM banner expression.
* \param flags the behavioural flags.
* \return the PEM object length (in characters), EXCLUDING the final zero.
*/
size_t br_pem_encode(void *dest, const void *data, size_t len,
const char *banner, unsigned flags);
/**
* \brief PEM encoding flag: split lines at 64 characters.
*/
#define BR_PEM_LINE64 0x0001
/**
* \brief PEM encoding flag: use CR+LF line endings.
*/
#define BR_PEM_CRLF 0x0002
#ifdef __cplusplus
}
#endif
#endif

File diff suppressed because it is too large Load Diff

View File

@ -989,186 +989,6 @@ br_x509_minimal_set_name_elements(br_x509_minimal_context *ctx,
ctx->num_name_elts = num_elts;
}
/**
* \brief X.509 decoder context.
*
* This structure is _not_ for X.509 validation, but for extracting
* names and public keys from encoded certificates. Intended usage is
* to use (self-signed) certificates as trust anchors.
*
* Contents are opaque and shall not be accessed directly.
*/
typedef struct {
#ifndef BR_DOXYGEN_IGNORE
/* Structure for returning the public key. */
br_x509_pkey pkey;
/* CPU for the T0 virtual machine. */
struct {
uint32_t *dp;
uint32_t *rp;
const unsigned char *ip;
} cpu;
uint32_t dp_stack[32];
uint32_t rp_stack[32];
int err;
/* The pad serves as destination for various operations. */
unsigned char pad[256];
/* Flag set when decoding succeeds. */
unsigned char decoded;
/* Validity dates. */
uint32_t notbefore_days, notbefore_seconds;
uint32_t notafter_days, notafter_seconds;
/* The "CA" flag. This is set to true if the certificate contains
a Basic Constraints extension that asserts CA status. */
unsigned char isCA;
/* DN processing: the subject DN is extracted and pushed to the
provided callback. */
unsigned char copy_dn;
void *append_dn_ctx;
void (*append_dn)(void *ctx, const void *buf, size_t len);
/* Certificate data chunk. */
const unsigned char *hbuf;
size_t hlen;
/* Buffer for decoded public key. */
unsigned char pkey_data[BR_X509_BUFSIZE_KEY];
/* Type of key and hash function used in the certificate signature. */
unsigned char signer_key_type;
unsigned char signer_hash_id;
#endif
} br_x509_decoder_context;
/**
* \brief Initialise an X.509 decoder context for processing a new
* certificate.
*
* The `append_dn()` callback (with opaque context `append_dn_ctx`)
* will be invoked to receive, chunk by chunk, the certificate's
* subject DN. If `append_dn` is `0` then the subject DN will be
* ignored.
*
* \param ctx X.509 decoder context to initialise.
* \param append_dn DN receiver callback (or `0`).
* \param append_dn_ctx context for the DN receiver callback.
*/
void br_x509_decoder_init(br_x509_decoder_context *ctx,
void (*append_dn)(void *ctx, const void *buf, size_t len),
void *append_dn_ctx);
/**
* \brief Push some certificate bytes into a decoder context.
*
* If `len` is non-zero, then that many bytes are pushed, from address
* `data`, into the provided decoder context.
*
* \param ctx X.509 decoder context.
* \param data certificate data chunk.
* \param len certificate data chunk length (in bytes).
*/
void br_x509_decoder_push(br_x509_decoder_context *ctx,
const void *data, size_t len);
/**
* \brief Obtain the decoded public key.
*
* Returned value is a pointer to a structure internal to the decoder
* context; releasing or reusing the decoder context invalidates that
* structure.
*
* If decoding was not finished, or failed, then `NULL` is returned.
*
* \param ctx X.509 decoder context.
* \return the public key, or `NULL` on unfinished/error.
*/
static inline br_x509_pkey *
br_x509_decoder_get_pkey(br_x509_decoder_context *ctx)
{
if (ctx->decoded && ctx->err == 0) {
return &ctx->pkey;
} else {
return NULL;
}
}
/**
* \brief Get decoder error status.
*
* If no error was reported yet but the certificate decoding is not
* finished, then the error code is `BR_ERR_X509_TRUNCATED`. If decoding
* was successful, then 0 is returned.
*
* \param ctx X.509 decoder context.
* \return 0 on successful decoding, or a non-zero error code.
*/
static inline int
br_x509_decoder_last_error(br_x509_decoder_context *ctx)
{
if (ctx->err != 0) {
return ctx->err;
}
if (!ctx->decoded) {
return BR_ERR_X509_TRUNCATED;
}
return 0;
}
/**
* \brief Get the "isCA" flag from an X.509 decoder context.
*
* This flag is set if the decoded certificate claims to be a CA through
* a Basic Constraints extension. This flag should not be read before
* decoding completed successfully.
*
* \param ctx X.509 decoder context.
* \return the "isCA" flag.
*/
static inline int
br_x509_decoder_isCA(br_x509_decoder_context *ctx)
{
return ctx->isCA;
}
/**
* \brief Get the issuing CA key type (type of algorithm used to sign the
* decoded certificate).
*
* This is `BR_KEYTYPE_RSA` or `BR_KEYTYPE_EC`. The value 0 is returned
* if the signature type was not recognised.
*
* \param ctx X.509 decoder context.
* \return the issuing CA key type.
*/
static inline int
br_x509_decoder_get_signer_key_type(br_x509_decoder_context *ctx)
{
return ctx->signer_key_type;
}
/**
* \brief Get the identifier for the hash function used to sign the decoded
* certificate.
*
* This is 0 if the hash function was not recognised.
*
* \param ctx X.509 decoder context.
* \return the signature hash function identifier.
*/
static inline int
br_x509_decoder_get_signer_hash_id(br_x509_decoder_context *ctx)
{
return ctx->signer_hash_id;
}
/**
* \brief Type for an X.509 certificate (DER-encoded).
*/
@ -1179,294 +999,6 @@ typedef struct {
size_t data_len;
} br_x509_certificate;
/**
* \brief Private key decoder context.
*
* The private key decoder recognises RSA and EC private keys, either in
* their raw, DER-encoded format, or wrapped in an unencrypted PKCS#8
* archive (again DER-encoded).
*
* Structure contents are opaque and shall not be accessed directly.
*/
typedef struct {
#ifndef BR_DOXYGEN_IGNORE
/* Structure for returning the private key. */
union {
br_rsa_private_key rsa;
br_ec_private_key ec;
} key;
/* CPU for the T0 virtual machine. */
struct {
uint32_t *dp;
uint32_t *rp;
const unsigned char *ip;
} cpu;
uint32_t dp_stack[32];
uint32_t rp_stack[32];
int err;
/* Private key data chunk. */
const unsigned char *hbuf;
size_t hlen;
/* The pad serves as destination for various operations. */
unsigned char pad[256];
/* Decoded key type; 0 until decoding is complete. */
unsigned char key_type;
/* Buffer for the private key elements. It shall be large enough
to accommodate all elements for a RSA-4096 private key (roughly
five 2048-bit integers, possibly a bit more). */
unsigned char key_data[3 * BR_X509_BUFSIZE_SIG];
#endif
} br_skey_decoder_context;
/**
* \brief Initialise a private key decoder context.
*
* \param ctx key decoder context to initialise.
*/
void br_skey_decoder_init(br_skey_decoder_context *ctx);
/**
* \brief Push some data bytes into a private key decoder context.
*
* If `len` is non-zero, then that many data bytes, starting at address
* `data`, are pushed into the decoder.
*
* \param ctx key decoder context.
* \param data private key data chunk.
* \param len private key data chunk length (in bytes).
*/
void br_skey_decoder_push(br_skey_decoder_context *ctx,
const void *data, size_t len);
/**
* \brief Get the decoding status for a private key.
*
* Decoding status is 0 on success, or a non-zero error code. If the
* decoding is unfinished when this function is called, then the
* status code `BR_ERR_X509_TRUNCATED` is returned.
*
* \param ctx key decoder context.
* \return 0 on successful decoding, or a non-zero error code.
*/
static inline int
br_skey_decoder_last_error(const br_skey_decoder_context *ctx)
{
if (ctx->err != 0) {
return ctx->err;
}
if (ctx->key_type == 0) {
return BR_ERR_X509_TRUNCATED;
}
return 0;
}
/**
* \brief Get the decoded private key type.
*
* Private key type is `BR_KEYTYPE_RSA` or `BR_KEYTYPE_EC`. If decoding is
* not finished or failed, then 0 is returned.
*
* \param ctx key decoder context.
* \return decoded private key type, or 0.
*/
static inline int
br_skey_decoder_key_type(const br_skey_decoder_context *ctx)
{
if (ctx->err == 0) {
return ctx->key_type;
} else {
return 0;
}
}
/**
* \brief Get the decoded RSA private key.
*
* This function returns `NULL` if the decoding failed, or is not
* finished, or the key is not RSA. The returned pointer references
* structures within the context that can become invalid if the context
* is reused or released.
*
* \param ctx key decoder context.
* \return decoded RSA private key, or `NULL`.
*/
static inline const br_rsa_private_key *
br_skey_decoder_get_rsa(const br_skey_decoder_context *ctx)
{
if (ctx->err == 0 && ctx->key_type == BR_KEYTYPE_RSA) {
return &ctx->key.rsa;
} else {
return NULL;
}
}
/**
* \brief Get the decoded EC private key.
*
* This function returns `NULL` if the decoding failed, or is not
* finished, or the key is not EC. The returned pointer references
* structures within the context that can become invalid if the context
* is reused or released.
*
* \param ctx key decoder context.
* \return decoded EC private key, or `NULL`.
*/
static inline const br_ec_private_key *
br_skey_decoder_get_ec(const br_skey_decoder_context *ctx)
{
if (ctx->err == 0 && ctx->key_type == BR_KEYTYPE_EC) {
return &ctx->key.ec;
} else {
return NULL;
}
}
/**
* \brief Encode an RSA private key (raw DER format).
*
* This function encodes the provided key into the "raw" format specified
* in PKCS#1 (RFC 8017, Appendix C, type `RSAPrivateKey`), with DER
* encoding rules.
*
* The key elements are:
*
* - `sk`: the private key (`p`, `q`, `dp`, `dq` and `iq`)
*
* - `pk`: the public key (`n` and `e`)
*
* - `d` (size: `dlen` bytes): the private exponent
*
* The public key elements, and the private exponent `d`, can be
* recomputed from the private key (see `br_rsa_compute_modulus()`,
* `br_rsa_compute_pubexp()` and `br_rsa_compute_privexp()`).
*
* If `dest` is not `NULL`, then the encoded key is written at that
* address, and the encoded length (in bytes) is returned. If `dest` is
* `NULL`, then nothing is written, but the encoded length is still
* computed and returned.
*
* \param dest the destination buffer (or `NULL`).
* \param sk the RSA private key.
* \param pk the RSA public key.
* \param d the RSA private exponent.
* \param dlen the RSA private exponent length (in bytes).
* \return the encoded key length (in bytes).
*/
size_t br_encode_rsa_raw_der(void *dest, const br_rsa_private_key *sk,
const br_rsa_public_key *pk, const void *d, size_t dlen);
/**
* \brief Encode an RSA private key (PKCS#8 DER format).
*
* This function encodes the provided key into the PKCS#8 format
* (RFC 5958, type `OneAsymmetricKey`). It wraps around the "raw DER"
* format for the RSA key, as implemented by `br_encode_rsa_raw_der()`.
*
* The key elements are:
*
* - `sk`: the private key (`p`, `q`, `dp`, `dq` and `iq`)
*
* - `pk`: the public key (`n` and `e`)
*
* - `d` (size: `dlen` bytes): the private exponent
*
* The public key elements, and the private exponent `d`, can be
* recomputed from the private key (see `br_rsa_compute_modulus()`,
* `br_rsa_compute_pubexp()` and `br_rsa_compute_privexp()`).
*
* If `dest` is not `NULL`, then the encoded key is written at that
* address, and the encoded length (in bytes) is returned. If `dest` is
* `NULL`, then nothing is written, but the encoded length is still
* computed and returned.
*
* \param dest the destination buffer (or `NULL`).
* \param sk the RSA private key.
* \param pk the RSA public key.
* \param d the RSA private exponent.
* \param dlen the RSA private exponent length (in bytes).
* \return the encoded key length (in bytes).
*/
size_t br_encode_rsa_pkcs8_der(void *dest, const br_rsa_private_key *sk,
const br_rsa_public_key *pk, const void *d, size_t dlen);
/**
* \brief Encode an EC private key (raw DER format).
*
* This function encodes the provided key into the "raw" format specified
* in RFC 5915 (type `ECPrivateKey`), with DER encoding rules.
*
* The private key is provided in `sk`, the public key being `pk`. If
* `pk` is `NULL`, then the encoded key will not include the public key
* in its `publicKey` field (which is nominally optional).
*
* If `dest` is not `NULL`, then the encoded key is written at that
* address, and the encoded length (in bytes) is returned. If `dest` is
* `NULL`, then nothing is written, but the encoded length is still
* computed and returned.
*
* If the key cannot be encoded (e.g. because there is no known OBJECT
* IDENTIFIER for the used curve), then 0 is returned.
*
* \param dest the destination buffer (or `NULL`).
* \param sk the EC private key.
* \param pk the EC public key (or `NULL`).
* \return the encoded key length (in bytes), or 0.
*/
size_t br_encode_ec_raw_der(void *dest,
const br_ec_private_key *sk, const br_ec_public_key *pk);
/**
* \brief Encode an EC private key (PKCS#8 DER format).
*
* This function encodes the provided key into the PKCS#8 format
* (RFC 5958, type `OneAsymmetricKey`). The curve is identified
* by an OID provided as parameters to the `privateKeyAlgorithm`
* field. The private key value (contents of the `privateKey` field)
* contains the DER encoding of the `ECPrivateKey` type defined in
* RFC 5915, without the `parameters` field (since they would be
* redundant with the information in `privateKeyAlgorithm`).
*
* The private key is provided in `sk`, the public key being `pk`. If
* `pk` is not `NULL`, then the encoded public key is included in the
* `publicKey` field of the private key value (but not in the `publicKey`
* field of the PKCS#8 `OneAsymmetricKey` wrapper).
*
* If `dest` is not `NULL`, then the encoded key is written at that
* address, and the encoded length (in bytes) is returned. If `dest` is
* `NULL`, then nothing is written, but the encoded length is still
* computed and returned.
*
* If the key cannot be encoded (e.g. because there is no known OBJECT
* IDENTIFIER for the used curve), then 0 is returned.
*
* \param dest the destination buffer (or `NULL`).
* \param sk the EC private key.
* \param pk the EC public key (or `NULL`).
* \return the encoded key length (in bytes), or 0.
*/
size_t br_encode_ec_pkcs8_der(void *dest,
const br_ec_private_key *sk, const br_ec_public_key *pk);
/**
* \brief PEM banner for RSA private key (raw).
*/
#define BR_ENCODE_PEM_RSA_RAW "RSA PRIVATE KEY"
/**
* \brief PEM banner for EC private key (raw).
*/
#define BR_ENCODE_PEM_EC_RAW "EC PRIVATE KEY"
/**
* \brief PEM banner for an RSA or EC private key in PKCS#8 format.
*/
#define BR_ENCODE_PEM_PKCS8 "PRIVATE KEY"
#ifdef __cplusplus
}
#endif

View File

@ -55,16 +55,6 @@
#define BR_64 1
*/
/*
* When BR_LOMUL is enabled, then multiplications of 32-bit values whose
* result are truncated to the low 32 bits are assumed to be
* substantially more efficient than 32-bit multiplications that yield
* 64-bit results. This is typically the case on low-end ARM Cortex M
* systems (M0, M0+, M1, and arguably M3 and M4 as well).
*
#define BR_LOMUL 1
*/
/*
* When BR_SLOW_MUL is enabled, multiplications are assumed to be
* substantially slow with regards to other integer operations, thus

View File

@ -1,411 +0,0 @@
/*
* 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 "inner.h"
/*
* During key schedule, we need to apply bit extraction PC-2 then permute
* things into our bitslice representation. PC-2 extracts 48 bits out
* of two 28-bit words (kl and kr), and we store these bits into two
* 32-bit words sk0 and sk1.
*
* -- bit 16+x of sk0 comes from bit QL0[x] of kl
* -- bit x of sk0 comes from bit QR0[x] of kr
* -- bit 16+x of sk1 comes from bit QL1[x] of kl
* -- bit x of sk1 comes from bit QR1[x] of kr
*/
static const unsigned char QL0[] = {
17, 4, 27, 23, 13, 22, 7, 18,
16, 24, 2, 20, 1, 8, 15, 26
};
static const unsigned char QR0[] = {
25, 19, 9, 1, 5, 11, 23, 8,
17, 0, 22, 3, 6, 20, 27, 24
};
static const unsigned char QL1[] = {
28, 28, 14, 11, 28, 28, 25, 0,
28, 28, 5, 9, 28, 28, 12, 21
};
static const unsigned char QR1[] = {
28, 28, 15, 4, 28, 28, 26, 16,
28, 28, 12, 7, 28, 28, 10, 14
};
/*
* 32-bit rotation. The C compiler is supposed to recognize it as a
* rotation and use the local architecture rotation opcode (if available).
*/
static inline uint32_t
rotl(uint32_t x, int n)
{
return (x << n) | (x >> (32 - n));
}
/*
* Compute key schedule for 8 key bytes (produces 32 subkey words).
*/
static void
keysched_unit(uint32_t *skey, const void *key)
{
int i;
br_des_keysched_unit(skey, key);
/*
* Apply PC-2 + bitslicing.
*/
for (i = 0; i < 16; i ++) {
uint32_t kl, kr, sk0, sk1;
int j;
kl = skey[(i << 1) + 0];
kr = skey[(i << 1) + 1];
sk0 = 0;
sk1 = 0;
for (j = 0; j < 16; j ++) {
sk0 <<= 1;
sk1 <<= 1;
sk0 |= ((kl >> QL0[j]) & (uint32_t)1) << 16;
sk0 |= (kr >> QR0[j]) & (uint32_t)1;
sk1 |= ((kl >> QL1[j]) & (uint32_t)1) << 16;
sk1 |= (kr >> QR1[j]) & (uint32_t)1;
}
skey[(i << 1) + 0] = sk0;
skey[(i << 1) + 1] = sk1;
}
#if 0
/*
* Speed-optimized version for PC-2 + bitslicing.
* (Unused. Kept for reference only.)
*/
sk0 = kl & (uint32_t)0x00100000;
sk0 |= (kl & (uint32_t)0x08008000) << 2;
sk0 |= (kl & (uint32_t)0x00400000) << 4;
sk0 |= (kl & (uint32_t)0x00800000) << 5;
sk0 |= (kl & (uint32_t)0x00040000) << 6;
sk0 |= (kl & (uint32_t)0x00010000) << 7;
sk0 |= (kl & (uint32_t)0x00000100) << 10;
sk0 |= (kl & (uint32_t)0x00022000) << 14;
sk0 |= (kl & (uint32_t)0x00000082) << 18;
sk0 |= (kl & (uint32_t)0x00000004) << 19;
sk0 |= (kl & (uint32_t)0x04000000) >> 10;
sk0 |= (kl & (uint32_t)0x00000010) << 26;
sk0 |= (kl & (uint32_t)0x01000000) >> 2;
sk0 |= kr & (uint32_t)0x00000100;
sk0 |= (kr & (uint32_t)0x00000008) << 1;
sk0 |= (kr & (uint32_t)0x00000200) << 4;
sk0 |= rotl(kr & (uint32_t)0x08000021, 6);
sk0 |= (kr & (uint32_t)0x01000000) >> 24;
sk0 |= (kr & (uint32_t)0x00000002) << 11;
sk0 |= (kr & (uint32_t)0x00100000) >> 18;
sk0 |= (kr & (uint32_t)0x00400000) >> 17;
sk0 |= (kr & (uint32_t)0x00800000) >> 14;
sk0 |= (kr & (uint32_t)0x02020000) >> 10;
sk0 |= (kr & (uint32_t)0x00080000) >> 5;
sk0 |= (kr & (uint32_t)0x00000040) >> 3;
sk0 |= (kr & (uint32_t)0x00000800) >> 1;
sk1 = kl & (uint32_t)0x02000000;
sk1 |= (kl & (uint32_t)0x00001000) << 5;
sk1 |= (kl & (uint32_t)0x00000200) << 11;
sk1 |= (kl & (uint32_t)0x00004000) << 15;
sk1 |= (kl & (uint32_t)0x00000020) << 16;
sk1 |= (kl & (uint32_t)0x00000800) << 17;
sk1 |= (kl & (uint32_t)0x00000001) << 24;
sk1 |= (kl & (uint32_t)0x00200000) >> 5;
sk1 |= (kr & (uint32_t)0x00000010) << 8;
sk1 |= (kr & (uint32_t)0x04000000) >> 17;
sk1 |= (kr & (uint32_t)0x00004000) >> 14;
sk1 |= (kr & (uint32_t)0x00000400) >> 9;
sk1 |= (kr & (uint32_t)0x00010000) >> 8;
sk1 |= (kr & (uint32_t)0x00001000) >> 7;
sk1 |= (kr & (uint32_t)0x00000080) >> 3;
sk1 |= (kr & (uint32_t)0x00008000) >> 2;
#endif
}
/* see inner.h */
unsigned
br_des_ct_keysched(uint32_t *skey, const void *key, size_t key_len)
{
switch (key_len) {
case 8:
keysched_unit(skey, key);
return 1;
case 16:
keysched_unit(skey, key);
keysched_unit(skey + 32, (const unsigned char *)key + 8);
br_des_rev_skey(skey + 32);
memcpy(skey + 64, skey, 32 * sizeof *skey);
return 3;
default:
keysched_unit(skey, key);
keysched_unit(skey + 32, (const unsigned char *)key + 8);
br_des_rev_skey(skey + 32);
keysched_unit(skey + 64, (const unsigned char *)key + 16);
return 3;
}
}
/*
* DES confusion function. This function performs expansion E (32 to
* 48 bits), XOR with subkey, S-boxes, and permutation P.
*/
static inline uint32_t
Fconf(uint32_t r0, const uint32_t *sk)
{
/*
* Each 6->4 S-box is virtually turned into four 6->1 boxes; we
* thus end up with 32 boxes that we call "T-boxes" here. We will
* evaluate them with bitslice code.
*
* Each T-box is a circuit of multiplexers (sort of) and thus
* takes 70 inputs: the 6 actual T-box inputs, and 64 constants
* that describe the T-box output for all combinations of the
* 6 inputs. With this model, all T-boxes are identical (with
* distinct inputs) and thus can be executed in parallel with
* bitslice code.
*
* T-boxes are numbered from 0 to 31, in least-to-most
* significant order. Thus, S-box S1 corresponds to T-boxes 31,
* 30, 29 and 28, in that order. T-box 'n' is computed with the
* bits at rank 'n' in the 32-bit words.
*
* Words x0 to x5 contain the T-box inputs 0 to 5.
*/
uint32_t x0, x1, x2, x3, x4, x5, z0;
uint32_t y0, y1, y2, y3, y4, y5, y6, y7, y8, y9;
uint32_t y10, y11, y12, y13, y14, y15, y16, y17, y18, y19;
uint32_t y20, y21, y22, y23, y24, y25, y26, y27, y28, y29;
uint32_t y30;
/*
* Spread input bits over the 6 input words x*.
*/
x1 = r0 & (uint32_t)0x11111111;
x2 = (r0 >> 1) & (uint32_t)0x11111111;
x3 = (r0 >> 2) & (uint32_t)0x11111111;
x4 = (r0 >> 3) & (uint32_t)0x11111111;
x1 = (x1 << 4) - x1;
x2 = (x2 << 4) - x2;
x3 = (x3 << 4) - x3;
x4 = (x4 << 4) - x4;
x0 = (x4 << 4) | (x4 >> 28);
x5 = (x1 >> 4) | (x1 << 28);
/*
* XOR with the subkey for this round.
*/
x0 ^= sk[0];
x1 ^= sk[1];
x2 ^= sk[2];
x3 ^= sk[3];
x4 ^= sk[4];
x5 ^= sk[5];
/*
* The T-boxes are done in parallel, since they all use a
* "tree of multiplexer". We use "fake multiplexers":
*
* y = a ^ (x & b)
*
* computes y as either 'a' (if x == 0) or 'a ^ b' (if x == 1).
*/
y0 = (uint32_t)0xEFA72C4D ^ (x0 & (uint32_t)0xEC7AC69C);
y1 = (uint32_t)0xAEAAEDFF ^ (x0 & (uint32_t)0x500FB821);
y2 = (uint32_t)0x37396665 ^ (x0 & (uint32_t)0x40EFA809);
y3 = (uint32_t)0x68D7B833 ^ (x0 & (uint32_t)0xA5EC0B28);
y4 = (uint32_t)0xC9C755BB ^ (x0 & (uint32_t)0x252CF820);
y5 = (uint32_t)0x73FC3606 ^ (x0 & (uint32_t)0x40205801);
y6 = (uint32_t)0xA2A0A918 ^ (x0 & (uint32_t)0xE220F929);
y7 = (uint32_t)0x8222BD90 ^ (x0 & (uint32_t)0x44A3F9E1);
y8 = (uint32_t)0xD6B6AC77 ^ (x0 & (uint32_t)0x794F104A);
y9 = (uint32_t)0x3069300C ^ (x0 & (uint32_t)0x026F320B);
y10 = (uint32_t)0x6CE0D5CC ^ (x0 & (uint32_t)0x7640B01A);
y11 = (uint32_t)0x59A9A22D ^ (x0 & (uint32_t)0x238F1572);
y12 = (uint32_t)0xAC6D0BD4 ^ (x0 & (uint32_t)0x7A63C083);
y13 = (uint32_t)0x21C83200 ^ (x0 & (uint32_t)0x11CCA000);
y14 = (uint32_t)0xA0E62188 ^ (x0 & (uint32_t)0x202F69AA);
/* y15 = (uint32_t)0x00000000 ^ (x0 & (uint32_t)0x00000000); */
y16 = (uint32_t)0xAF7D655A ^ (x0 & (uint32_t)0x51B33BE9);
y17 = (uint32_t)0xF0168AA3 ^ (x0 & (uint32_t)0x3B0FE8AE);
y18 = (uint32_t)0x90AA30C6 ^ (x0 & (uint32_t)0x90BF8816);
y19 = (uint32_t)0x5AB2750A ^ (x0 & (uint32_t)0x09E34F9B);
y20 = (uint32_t)0x5391BE65 ^ (x0 & (uint32_t)0x0103BE88);
y21 = (uint32_t)0x93372BAF ^ (x0 & (uint32_t)0x49AC8E25);
y22 = (uint32_t)0xF288210C ^ (x0 & (uint32_t)0x922C313D);
y23 = (uint32_t)0x920AF5C0 ^ (x0 & (uint32_t)0x70EF31B0);
y24 = (uint32_t)0x63D312C0 ^ (x0 & (uint32_t)0x6A707100);
y25 = (uint32_t)0x537B3006 ^ (x0 & (uint32_t)0xB97C9011);
y26 = (uint32_t)0xA2EFB0A5 ^ (x0 & (uint32_t)0xA320C959);
y27 = (uint32_t)0xBC8F96A5 ^ (x0 & (uint32_t)0x6EA0AB4A);
y28 = (uint32_t)0xFAD176A5 ^ (x0 & (uint32_t)0x6953DDF8);
y29 = (uint32_t)0x665A14A3 ^ (x0 & (uint32_t)0xF74F3E2B);
y30 = (uint32_t)0xF2EFF0CC ^ (x0 & (uint32_t)0xF0306CAD);
/* y31 = (uint32_t)0x00000000 ^ (x0 & (uint32_t)0x00000000); */
y0 = y0 ^ (x1 & y1);
y1 = y2 ^ (x1 & y3);
y2 = y4 ^ (x1 & y5);
y3 = y6 ^ (x1 & y7);
y4 = y8 ^ (x1 & y9);
y5 = y10 ^ (x1 & y11);
y6 = y12 ^ (x1 & y13);
y7 = y14; /* was: y14 ^ (x1 & y15) */
y8 = y16 ^ (x1 & y17);
y9 = y18 ^ (x1 & y19);
y10 = y20 ^ (x1 & y21);
y11 = y22 ^ (x1 & y23);
y12 = y24 ^ (x1 & y25);
y13 = y26 ^ (x1 & y27);
y14 = y28 ^ (x1 & y29);
y15 = y30; /* was: y30 ^ (x1 & y31) */
y0 = y0 ^ (x2 & y1);
y1 = y2 ^ (x2 & y3);
y2 = y4 ^ (x2 & y5);
y3 = y6 ^ (x2 & y7);
y4 = y8 ^ (x2 & y9);
y5 = y10 ^ (x2 & y11);
y6 = y12 ^ (x2 & y13);
y7 = y14 ^ (x2 & y15);
y0 = y0 ^ (x3 & y1);
y1 = y2 ^ (x3 & y3);
y2 = y4 ^ (x3 & y5);
y3 = y6 ^ (x3 & y7);
y0 = y0 ^ (x4 & y1);
y1 = y2 ^ (x4 & y3);
y0 = y0 ^ (x5 & y1);
/*
* The P permutation:
* -- Each bit move is converted into a mask + left rotation.
* -- Rotations that use the same movement are coalesced together.
* -- Left and right shifts are used as alternatives to a rotation
* where appropriate (this will help architectures that do not have
* a rotation opcode).
*/
z0 = (y0 & (uint32_t)0x00000004) << 3;
z0 |= (y0 & (uint32_t)0x00004000) << 4;
z0 |= rotl(y0 & 0x12020120, 5);
z0 |= (y0 & (uint32_t)0x00100000) << 6;
z0 |= (y0 & (uint32_t)0x00008000) << 9;
z0 |= (y0 & (uint32_t)0x04000000) >> 22;
z0 |= (y0 & (uint32_t)0x00000001) << 11;
z0 |= rotl(y0 & 0x20000200, 12);
z0 |= (y0 & (uint32_t)0x00200000) >> 19;
z0 |= (y0 & (uint32_t)0x00000040) << 14;
z0 |= (y0 & (uint32_t)0x00010000) << 15;
z0 |= (y0 & (uint32_t)0x00000002) << 16;
z0 |= rotl(y0 & 0x40801800, 17);
z0 |= (y0 & (uint32_t)0x00080000) >> 13;
z0 |= (y0 & (uint32_t)0x00000010) << 21;
z0 |= (y0 & (uint32_t)0x01000000) >> 10;
z0 |= rotl(y0 & 0x88000008, 24);
z0 |= (y0 & (uint32_t)0x00000480) >> 7;
z0 |= (y0 & (uint32_t)0x00442000) >> 6;
return z0;
}
/*
* Process one block through 16 successive rounds, omitting the swap
* in the final round.
*/
static void
process_block_unit(uint32_t *pl, uint32_t *pr, const uint32_t *sk_exp)
{
int i;
uint32_t l, r;
l = *pl;
r = *pr;
for (i = 0; i < 16; i ++) {
uint32_t t;
t = l ^ Fconf(r, sk_exp);
l = r;
r = t;
sk_exp += 6;
}
*pl = r;
*pr = l;
}
/* see inner.h */
void
br_des_ct_process_block(unsigned num_rounds,
const uint32_t *sk_exp, void *block)
{
unsigned char *buf;
uint32_t l, r;
buf = block;
l = br_dec32be(buf);
r = br_dec32be(buf + 4);
br_des_do_IP(&l, &r);
while (num_rounds -- > 0) {
process_block_unit(&l, &r, sk_exp);
sk_exp += 96;
}
br_des_do_invIP(&l, &r);
br_enc32be(buf, l);
br_enc32be(buf + 4, r);
}
/* see inner.h */
void
br_des_ct_skey_expand(uint32_t *sk_exp,
unsigned num_rounds, const uint32_t *skey)
{
num_rounds <<= 4;
while (num_rounds -- > 0) {
uint32_t v, w0, w1, w2, w3;
v = *skey ++;
w0 = v & 0x11111111;
w1 = (v >> 1) & 0x11111111;
w2 = (v >> 2) & 0x11111111;
w3 = (v >> 3) & 0x11111111;
*sk_exp ++ = (w0 << 4) - w0;
*sk_exp ++ = (w1 << 4) - w1;
*sk_exp ++ = (w2 << 4) - w2;
*sk_exp ++ = (w3 << 4) - w3;
v = *skey ++;
w0 = v & 0x11111111;
w1 = (v >> 1) & 0x11111111;
*sk_exp ++ = (w0 << 4) - w0;
*sk_exp ++ = (w1 << 4) - w1;
}
}

View File

@ -1,87 +0,0 @@
/*
* 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 "inner.h"
/* see bearssl_block.h */
void
br_des_ct_cbcdec_init(br_des_ct_cbcdec_keys *ctx,
const void *key, size_t len)
{
ctx->vtable = &br_des_ct_cbcdec_vtable;
ctx->num_rounds = br_des_ct_keysched(ctx->skey, key, len);
if (len == 8) {
br_des_rev_skey(ctx->skey);
} else {
int i;
for (i = 0; i < 48; i += 2) {
uint32_t t;
t = ctx->skey[i];
ctx->skey[i] = ctx->skey[94 - i];
ctx->skey[94 - i] = t;
t = ctx->skey[i + 1];
ctx->skey[i + 1] = ctx->skey[95 - i];
ctx->skey[95 - i] = t;
}
}
}
/* see bearssl_block.h */
void
br_des_ct_cbcdec_run(const br_des_ct_cbcdec_keys *ctx,
void *iv, void *data, size_t len)
{
unsigned char *buf, *ivbuf;
uint32_t sk_exp[288];
br_des_ct_skey_expand(sk_exp, ctx->num_rounds, ctx->skey);
ivbuf = iv;
buf = data;
while (len > 0) {
unsigned char tmp[8];
int i;
memcpy(tmp, buf, 8);
br_des_ct_process_block(ctx->num_rounds, sk_exp, buf);
for (i = 0; i < 8; i ++) {
buf[i] ^= ivbuf[i];
}
memcpy(ivbuf, tmp, 8);
buf += 8;
len -= 8;
}
}
/* see bearssl_block.h */
const br_block_cbcdec_class br_des_ct_cbcdec_vtable = {
sizeof(br_des_ct_cbcdec_keys),
8,
3,
(void (*)(const br_block_cbcdec_class **, const void *, size_t))
&br_des_ct_cbcdec_init,
(void (*)(const br_block_cbcdec_class *const *, void *, void *, size_t))
&br_des_ct_cbcdec_run
};

View File

@ -1,69 +0,0 @@
/*
* 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 "inner.h"
/* see bearssl_block.h */
void
br_des_ct_cbcenc_init(br_des_ct_cbcenc_keys *ctx,
const void *key, size_t len)
{
ctx->vtable = &br_des_ct_cbcenc_vtable;
ctx->num_rounds = br_des_ct_keysched(ctx->skey, key, len);
}
/* see bearssl_block.h */
void
br_des_ct_cbcenc_run(const br_des_ct_cbcenc_keys *ctx,
void *iv, void *data, size_t len)
{
unsigned char *buf, *ivbuf;
uint32_t sk_exp[288];
br_des_ct_skey_expand(sk_exp, ctx->num_rounds, ctx->skey);
ivbuf = iv;
buf = data;
while (len > 0) {
int i;
for (i = 0; i < 8; i ++) {
buf[i] ^= ivbuf[i];
}
br_des_ct_process_block(ctx->num_rounds, sk_exp, buf);
memcpy(ivbuf, buf, 8);
buf += 8;
len -= 8;
}
}
/* see bearssl_block.h */
const br_block_cbcenc_class br_des_ct_cbcenc_vtable = {
sizeof(br_des_ct_cbcenc_keys),
8,
3,
(void (*)(const br_block_cbcenc_class **, const void *, size_t))
&br_des_ct_cbcenc_init,
(void (*)(const br_block_cbcenc_class *const *, void *, void *, size_t))
&br_des_ct_cbcenc_run
};

View File

@ -1,166 +0,0 @@
/*
* 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 "inner.h"
/* see inner.h */
void
br_des_do_IP(uint32_t *xl, uint32_t *xr)
{
/*
* Permutation algorithm is initially from Richard Outerbridge;
* implementation here is adapted from Crypto++ "des.cpp" file
* (which is in public domain).
*/
uint32_t l, r, t;
l = *xl;
r = *xr;
t = ((l >> 4) ^ r) & (uint32_t)0x0F0F0F0F;
r ^= t;
l ^= t << 4;
t = ((l >> 16) ^ r) & (uint32_t)0x0000FFFF;
r ^= t;
l ^= t << 16;
t = ((r >> 2) ^ l) & (uint32_t)0x33333333;
l ^= t;
r ^= t << 2;
t = ((r >> 8) ^ l) & (uint32_t)0x00FF00FF;
l ^= t;
r ^= t << 8;
t = ((l >> 1) ^ r) & (uint32_t)0x55555555;
r ^= t;
l ^= t << 1;
*xl = l;
*xr = r;
}
/* see inner.h */
void
br_des_do_invIP(uint32_t *xl, uint32_t *xr)
{
/*
* See br_des_do_IP().
*/
uint32_t l, r, t;
l = *xl;
r = *xr;
t = ((l >> 1) ^ r) & 0x55555555;
r ^= t;
l ^= t << 1;
t = ((r >> 8) ^ l) & 0x00FF00FF;
l ^= t;
r ^= t << 8;
t = ((r >> 2) ^ l) & 0x33333333;
l ^= t;
r ^= t << 2;
t = ((l >> 16) ^ r) & 0x0000FFFF;
r ^= t;
l ^= t << 16;
t = ((l >> 4) ^ r) & 0x0F0F0F0F;
r ^= t;
l ^= t << 4;
*xl = l;
*xr = r;
}
/* see inner.h */
void
br_des_keysched_unit(uint32_t *skey, const void *key)
{
uint32_t xl, xr, kl, kr;
int i;
xl = br_dec32be(key);
xr = br_dec32be((const unsigned char *)key + 4);
/*
* Permutation PC-1 is quite similar to the IP permutation.
* Definition of IP (in FIPS 46-3 notations) is:
* 58 50 42 34 26 18 10 2
* 60 52 44 36 28 20 12 4
* 62 54 46 38 30 22 14 6
* 64 56 48 40 32 24 16 8
* 57 49 41 33 25 17 9 1
* 59 51 43 35 27 19 11 3
* 61 53 45 37 29 21 13 5
* 63 55 47 39 31 23 15 7
*
* Definition of PC-1 is:
* 57 49 41 33 25 17 9 1
* 58 50 42 34 26 18 10 2
* 59 51 43 35 27 19 11 3
* 60 52 44 36
* 63 55 47 39 31 23 15 7
* 62 54 46 38 30 22 14 6
* 61 53 45 37 29 21 13 5
* 28 20 12 4
*/
br_des_do_IP(&xl, &xr);
kl = ((xr & (uint32_t)0xFF000000) >> 4)
| ((xl & (uint32_t)0xFF000000) >> 12)
| ((xr & (uint32_t)0x00FF0000) >> 12)
| ((xl & (uint32_t)0x00FF0000) >> 20);
kr = ((xr & (uint32_t)0x000000FF) << 20)
| ((xl & (uint32_t)0x0000FF00) << 4)
| ((xr & (uint32_t)0x0000FF00) >> 4)
| ((xl & (uint32_t)0x000F0000) >> 16);
/*
* For each round, rotate the two 28-bit words kl and kr.
* The extraction of the 48-bit subkey (PC-2) is not done yet.
*/
for (i = 0; i < 16; i ++) {
if ((1 << i) & 0x8103) {
kl = (kl << 1) | (kl >> 27);
kr = (kr << 1) | (kr >> 27);
} else {
kl = (kl << 2) | (kl >> 26);
kr = (kr << 2) | (kr >> 26);
}
kl &= (uint32_t)0x0FFFFFFF;
kr &= (uint32_t)0x0FFFFFFF;
skey[(i << 1) + 0] = kl;
skey[(i << 1) + 1] = kr;
}
}
/* see inner.h */
void
br_des_rev_skey(uint32_t *skey)
{
int i;
for (i = 0; i < 16; i += 2) {
uint32_t t;
t = skey[i + 0];
skey[i + 0] = skey[30 - i];
skey[30 - i] = t;
t = skey[i + 1];
skey[i + 1] = skey[31 - i];
skey[31 - i] = t;
}
}

View File

@ -1,310 +0,0 @@
/*
* 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 "inner.h"
/*
* PC2left[x] tells where bit x goes when applying PC-2. 'x' is a bit
* position in the left rotated key word. Both position are in normal
* order (rightmost bit is 0).
*/
static const unsigned char PC2left[] = {
16, 3, 7, 24, 20, 11, 24,
13, 2, 10, 24, 22, 5, 15,
23, 1, 9, 21, 12, 24, 6,
4, 14, 18, 8, 17, 0, 19
};
/*
* Similar to PC2left[x], for the right rotated key word.
*/
static const unsigned char PC2right[] = {
8, 18, 24, 6, 22, 15, 3,
10, 12, 19, 5, 14, 11, 24,
4, 23, 16, 9, 24, 20, 2,
24, 7, 13, 0, 21, 17, 1
};
/*
* S-boxes and PC-1 merged.
*/
static const uint32_t S1[] = {
0x00808200, 0x00000000, 0x00008000, 0x00808202,
0x00808002, 0x00008202, 0x00000002, 0x00008000,
0x00000200, 0x00808200, 0x00808202, 0x00000200,
0x00800202, 0x00808002, 0x00800000, 0x00000002,
0x00000202, 0x00800200, 0x00800200, 0x00008200,
0x00008200, 0x00808000, 0x00808000, 0x00800202,
0x00008002, 0x00800002, 0x00800002, 0x00008002,
0x00000000, 0x00000202, 0x00008202, 0x00800000,
0x00008000, 0x00808202, 0x00000002, 0x00808000,
0x00808200, 0x00800000, 0x00800000, 0x00000200,
0x00808002, 0x00008000, 0x00008200, 0x00800002,
0x00000200, 0x00000002, 0x00800202, 0x00008202,
0x00808202, 0x00008002, 0x00808000, 0x00800202,
0x00800002, 0x00000202, 0x00008202, 0x00808200,
0x00000202, 0x00800200, 0x00800200, 0x00000000,
0x00008002, 0x00008200, 0x00000000, 0x00808002
};
static const uint32_t S2[] = {
0x40084010, 0x40004000, 0x00004000, 0x00084010,
0x00080000, 0x00000010, 0x40080010, 0x40004010,
0x40000010, 0x40084010, 0x40084000, 0x40000000,
0x40004000, 0x00080000, 0x00000010, 0x40080010,
0x00084000, 0x00080010, 0x40004010, 0x00000000,
0x40000000, 0x00004000, 0x00084010, 0x40080000,
0x00080010, 0x40000010, 0x00000000, 0x00084000,
0x00004010, 0x40084000, 0x40080000, 0x00004010,
0x00000000, 0x00084010, 0x40080010, 0x00080000,
0x40004010, 0x40080000, 0x40084000, 0x00004000,
0x40080000, 0x40004000, 0x00000010, 0x40084010,
0x00084010, 0x00000010, 0x00004000, 0x40000000,
0x00004010, 0x40084000, 0x00080000, 0x40000010,
0x00080010, 0x40004010, 0x40000010, 0x00080010,
0x00084000, 0x00000000, 0x40004000, 0x00004010,
0x40000000, 0x40080010, 0x40084010, 0x00084000
};
static const uint32_t S3[] = {
0x00000104, 0x04010100, 0x00000000, 0x04010004,
0x04000100, 0x00000000, 0x00010104, 0x04000100,
0x00010004, 0x04000004, 0x04000004, 0x00010000,
0x04010104, 0x00010004, 0x04010000, 0x00000104,
0x04000000, 0x00000004, 0x04010100, 0x00000100,
0x00010100, 0x04010000, 0x04010004, 0x00010104,
0x04000104, 0x00010100, 0x00010000, 0x04000104,
0x00000004, 0x04010104, 0x00000100, 0x04000000,
0x04010100, 0x04000000, 0x00010004, 0x00000104,
0x00010000, 0x04010100, 0x04000100, 0x00000000,
0x00000100, 0x00010004, 0x04010104, 0x04000100,
0x04000004, 0x00000100, 0x00000000, 0x04010004,
0x04000104, 0x00010000, 0x04000000, 0x04010104,
0x00000004, 0x00010104, 0x00010100, 0x04000004,
0x04010000, 0x04000104, 0x00000104, 0x04010000,
0x00010104, 0x00000004, 0x04010004, 0x00010100
};
static const uint32_t S4[] = {
0x80401000, 0x80001040, 0x80001040, 0x00000040,
0x00401040, 0x80400040, 0x80400000, 0x80001000,
0x00000000, 0x00401000, 0x00401000, 0x80401040,
0x80000040, 0x00000000, 0x00400040, 0x80400000,
0x80000000, 0x00001000, 0x00400000, 0x80401000,
0x00000040, 0x00400000, 0x80001000, 0x00001040,
0x80400040, 0x80000000, 0x00001040, 0x00400040,
0x00001000, 0x00401040, 0x80401040, 0x80000040,
0x00400040, 0x80400000, 0x00401000, 0x80401040,
0x80000040, 0x00000000, 0x00000000, 0x00401000,
0x00001040, 0x00400040, 0x80400040, 0x80000000,
0x80401000, 0x80001040, 0x80001040, 0x00000040,
0x80401040, 0x80000040, 0x80000000, 0x00001000,
0x80400000, 0x80001000, 0x00401040, 0x80400040,
0x80001000, 0x00001040, 0x00400000, 0x80401000,
0x00000040, 0x00400000, 0x00001000, 0x00401040
};
static const uint32_t S5[] = {
0x00000080, 0x01040080, 0x01040000, 0x21000080,
0x00040000, 0x00000080, 0x20000000, 0x01040000,
0x20040080, 0x00040000, 0x01000080, 0x20040080,
0x21000080, 0x21040000, 0x00040080, 0x20000000,
0x01000000, 0x20040000, 0x20040000, 0x00000000,
0x20000080, 0x21040080, 0x21040080, 0x01000080,
0x21040000, 0x20000080, 0x00000000, 0x21000000,
0x01040080, 0x01000000, 0x21000000, 0x00040080,
0x00040000, 0x21000080, 0x00000080, 0x01000000,
0x20000000, 0x01040000, 0x21000080, 0x20040080,
0x01000080, 0x20000000, 0x21040000, 0x01040080,
0x20040080, 0x00000080, 0x01000000, 0x21040000,
0x21040080, 0x00040080, 0x21000000, 0x21040080,
0x01040000, 0x00000000, 0x20040000, 0x21000000,
0x00040080, 0x01000080, 0x20000080, 0x00040000,
0x00000000, 0x20040000, 0x01040080, 0x20000080
};
static const uint32_t S6[] = {
0x10000008, 0x10200000, 0x00002000, 0x10202008,
0x10200000, 0x00000008, 0x10202008, 0x00200000,
0x10002000, 0x00202008, 0x00200000, 0x10000008,
0x00200008, 0x10002000, 0x10000000, 0x00002008,
0x00000000, 0x00200008, 0x10002008, 0x00002000,
0x00202000, 0x10002008, 0x00000008, 0x10200008,
0x10200008, 0x00000000, 0x00202008, 0x10202000,
0x00002008, 0x00202000, 0x10202000, 0x10000000,
0x10002000, 0x00000008, 0x10200008, 0x00202000,
0x10202008, 0x00200000, 0x00002008, 0x10000008,
0x00200000, 0x10002000, 0x10000000, 0x00002008,
0x10000008, 0x10202008, 0x00202000, 0x10200000,
0x00202008, 0x10202000, 0x00000000, 0x10200008,
0x00000008, 0x00002000, 0x10200000, 0x00202008,
0x00002000, 0x00200008, 0x10002008, 0x00000000,
0x10202000, 0x10000000, 0x00200008, 0x10002008
};
static const uint32_t S7[] = {
0x00100000, 0x02100001, 0x02000401, 0x00000000,
0x00000400, 0x02000401, 0x00100401, 0x02100400,
0x02100401, 0x00100000, 0x00000000, 0x02000001,
0x00000001, 0x02000000, 0x02100001, 0x00000401,
0x02000400, 0x00100401, 0x00100001, 0x02000400,
0x02000001, 0x02100000, 0x02100400, 0x00100001,
0x02100000, 0x00000400, 0x00000401, 0x02100401,
0x00100400, 0x00000001, 0x02000000, 0x00100400,
0x02000000, 0x00100400, 0x00100000, 0x02000401,
0x02000401, 0x02100001, 0x02100001, 0x00000001,
0x00100001, 0x02000000, 0x02000400, 0x00100000,
0x02100400, 0x00000401, 0x00100401, 0x02100400,
0x00000401, 0x02000001, 0x02100401, 0x02100000,
0x00100400, 0x00000000, 0x00000001, 0x02100401,
0x00000000, 0x00100401, 0x02100000, 0x00000400,
0x02000001, 0x02000400, 0x00000400, 0x00100001
};
static const uint32_t S8[] = {
0x08000820, 0x00000800, 0x00020000, 0x08020820,
0x08000000, 0x08000820, 0x00000020, 0x08000000,
0x00020020, 0x08020000, 0x08020820, 0x00020800,
0x08020800, 0x00020820, 0x00000800, 0x00000020,
0x08020000, 0x08000020, 0x08000800, 0x00000820,
0x00020800, 0x00020020, 0x08020020, 0x08020800,
0x00000820, 0x00000000, 0x00000000, 0x08020020,
0x08000020, 0x08000800, 0x00020820, 0x00020000,
0x00020820, 0x00020000, 0x08020800, 0x00000800,
0x00000020, 0x08020020, 0x00000800, 0x00020820,
0x08000800, 0x00000020, 0x08000020, 0x08020000,
0x08020020, 0x08000000, 0x00020000, 0x08000820,
0x00000000, 0x08020820, 0x00020020, 0x08000020,
0x08020000, 0x08000800, 0x08000820, 0x00000000,
0x08020820, 0x00020800, 0x00020800, 0x00000820,
0x00000820, 0x00020020, 0x08000000, 0x08020800
};
static inline uint32_t
Fconf(uint32_t r0, uint32_t skl, uint32_t skr)
{
uint32_t r1;
r1 = (r0 << 16) | (r0 >> 16);
return
S1[((r1 >> 11) ^ (skl >> 18)) & 0x3F]
| S2[((r0 >> 23) ^ (skl >> 12)) & 0x3F]
| S3[((r0 >> 19) ^ (skl >> 6)) & 0x3F]
| S4[((r0 >> 15) ^ (skl )) & 0x3F]
| S5[((r0 >> 11) ^ (skr >> 18)) & 0x3F]
| S6[((r0 >> 7) ^ (skr >> 12)) & 0x3F]
| S7[((r0 >> 3) ^ (skr >> 6)) & 0x3F]
| S8[((r1 >> 15) ^ (skr )) & 0x3F];
}
static void
process_block_unit(uint32_t *pl, uint32_t *pr, const uint32_t *skey)
{
int i;
uint32_t l, r;
l = *pl;
r = *pr;
for (i = 0; i < 16; i ++) {
uint32_t t;
t = l ^ Fconf(r, skey[(i << 1) + 0], skey[(i << 1) + 1]);
l = r;
r = t;
}
*pl = r;
*pr = l;
}
/* see inner.h */
void
br_des_tab_process_block(unsigned num_rounds, const uint32_t *skey, void *block)
{
unsigned char *buf;
uint32_t l, r;
buf = block;
l = br_dec32be(buf);
r = br_dec32be(buf + 4);
br_des_do_IP(&l, &r);
while (num_rounds -- > 0) {
process_block_unit(&l, &r, skey);
skey += 32;
}
br_des_do_invIP(&l, &r);
br_enc32be(buf, l);
br_enc32be(buf + 4, r);
}
static void
keysched_unit(uint32_t *skey, const void *key)
{
int i;
br_des_keysched_unit(skey, key);
/*
* Apply PC-2 to get the 48-bit subkeys.
*/
for (i = 0; i < 16; i ++) {
uint32_t xl, xr, ul, ur;
int j;
xl = skey[(i << 1) + 0];
xr = skey[(i << 1) + 1];
ul = 0;
ur = 0;
for (j = 0; j < 28; j ++) {
ul |= (xl & 1) << PC2left[j];
ur |= (xr & 1) << PC2right[j];
xl >>= 1;
xr >>= 1;
}
skey[(i << 1) + 0] = ul;
skey[(i << 1) + 1] = ur;
}
}
/* see inner.h */
unsigned
br_des_tab_keysched(uint32_t *skey, const void *key, size_t key_len)
{
switch (key_len) {
case 8:
keysched_unit(skey, key);
return 1;
case 16:
keysched_unit(skey, key);
keysched_unit(skey + 32, (const unsigned char *)key + 8);
br_des_rev_skey(skey + 32);
memcpy(skey + 64, skey, 32 * sizeof *skey);
return 3;
default:
keysched_unit(skey, key);
keysched_unit(skey + 32, (const unsigned char *)key + 8);
br_des_rev_skey(skey + 32);
keysched_unit(skey + 64, (const unsigned char *)key + 16);
return 3;
}
}

View File

@ -1,85 +0,0 @@
/*
* 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 "inner.h"
/* see bearssl_block.h */
void
br_des_tab_cbcdec_init(br_des_tab_cbcdec_keys *ctx,
const void *key, size_t len)
{
ctx->vtable = &br_des_tab_cbcdec_vtable;
ctx->num_rounds = br_des_tab_keysched(ctx->skey, key, len);
if (len == 8) {
br_des_rev_skey(ctx->skey);
} else {
int i;
for (i = 0; i < 48; i += 2) {
uint32_t t;
t = ctx->skey[i];
ctx->skey[i] = ctx->skey[94 - i];
ctx->skey[94 - i] = t;
t = ctx->skey[i + 1];
ctx->skey[i + 1] = ctx->skey[95 - i];
ctx->skey[95 - i] = t;
}
}
}
/* see bearssl_block.h */
void
br_des_tab_cbcdec_run(const br_des_tab_cbcdec_keys *ctx,
void *iv, void *data, size_t len)
{
unsigned char *buf, *ivbuf;
ivbuf = iv;
buf = data;
while (len > 0) {
unsigned char tmp[8];
int i;
memcpy(tmp, buf, 8);
br_des_tab_process_block(ctx->num_rounds, ctx->skey, buf);
for (i = 0; i < 8; i ++) {
buf[i] ^= ivbuf[i];
}
memcpy(ivbuf, tmp, 8);
buf += 8;
len -= 8;
}
}
/* see bearssl_block.h */
const br_block_cbcdec_class br_des_tab_cbcdec_vtable = {
sizeof(br_des_tab_cbcdec_keys),
8,
3,
(void (*)(const br_block_cbcdec_class **, const void *, size_t))
&br_des_tab_cbcdec_init,
(void (*)(const br_block_cbcdec_class *const *, void *, void *, size_t))
&br_des_tab_cbcdec_run
};

View File

@ -1,67 +0,0 @@
/*
* 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 "inner.h"
/* see bearssl_block.h */
void
br_des_tab_cbcenc_init(br_des_tab_cbcenc_keys *ctx,
const void *key, size_t len)
{
ctx->vtable = &br_des_tab_cbcenc_vtable;
ctx->num_rounds = br_des_tab_keysched(ctx->skey, key, len);
}
/* see bearssl_block.h */
void
br_des_tab_cbcenc_run(const br_des_tab_cbcenc_keys *ctx,
void *iv, void *data, size_t len)
{
unsigned char *buf, *ivbuf;
ivbuf = iv;
buf = data;
while (len > 0) {
int i;
for (i = 0; i < 8; i ++) {
buf[i] ^= ivbuf[i];
}
br_des_tab_process_block(ctx->num_rounds, ctx->skey, buf);
memcpy(ivbuf, buf, 8);
buf += 8;
len -= 8;
}
}
/* see bearssl_block.h */
const br_block_cbcenc_class br_des_tab_cbcenc_vtable = {
sizeof(br_des_tab_cbcenc_keys),
8,
3,
(void (*)(const br_block_cbcenc_class **, const void *, size_t))
&br_des_tab_cbcenc_init,
(void (*)(const br_block_cbcenc_class *const *, void *, void *, size_t))
&br_des_tab_cbcenc_run
};

View File

@ -1,121 +0,0 @@
/*
* Copyright (c) 2017 Thomas Pornin <pornin@bolet.org>
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#include "inner.h"
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 = {
(uint32_t)0x23800000,
&api_generator,
&api_order,
&api_xoff,
&api_mul,
&api_mulgen,
&api_muladd
};

View File

@ -1,398 +0,0 @@
/*
* Copyright (c) 2017 Thomas Pornin <pornin@bolet.org>
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#include "inner.h"
/*
* 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[] = {
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[] = {
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(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(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(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 = {
(uint32_t)0x20000000,
&api_generator,
&api_order,
&api_xoff,
&api_mul,
&api_mulgen,
&api_muladd
};

File diff suppressed because it is too large Load Diff

View File

@ -28,9 +28,5 @@
const br_ec_impl *
br_ec_get_default(void)
{
#if BR_LOMUL
return &br_ec_all_m15;
#else
return &br_ec_all_m31;
#endif
}

File diff suppressed because it is too large Load Diff

View File

@ -1,824 +0,0 @@
/*
* Copyright (c) 2017 Thomas Pornin <pornin@bolet.org>
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#include "inner.h"
/*
* 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[] = {
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[] = {
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[] = {
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[] = {
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[] = {
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[] = {
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[] = {
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[] = {
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[] = {
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[] = {
/*
* 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[] = {
/*
* 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[] = {
/* 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[] = {
/* 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));
/*
* Run formulas.
*/
for (u = 0;; u ++) {
unsigned op, d, a, b;
op = 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 = (cc->p[0] - (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 = (p[0] + 31) >> 4;
memset(x, 0, plen * sizeof *x);
x[0] = 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] = 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 = (*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 = (cc->p[0] - (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(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 = ((cc->p[0] + 31) >> 4) * sizeof(uint16_t);
memcpy(Q.c[0], cc->R2, zlen);
memcpy(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 = (cc->p[0] - (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);
if (Glen != cc->point_len) {
return 0;
}
r = point_decode(&P, G, Glen, cc);
point_mul(&P, x, xlen, cc);
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(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);
if (len != cc->point_len) {
return 0;
}
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 = {
(uint32_t)0x03800000,
&api_generator,
&api_order,
&api_xoff,
&api_mul,
&api_mulgen,
&api_muladd
};

View File

@ -28,9 +28,5 @@
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
}

View File

@ -28,9 +28,5 @@
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
}

View File

@ -28,9 +28,5 @@
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
}

View File

@ -28,9 +28,5 @@
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
}

View File

@ -1,47 +0,0 @@
/*
* Copyright (c) 2017 Thomas Pornin <pornin@bolet.org>
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#include "inner.h"
/* 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;
}

View File

@ -1,45 +0,0 @@
/*
* Copyright (c) 2017 Thomas Pornin <pornin@bolet.org>
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#include "inner.h"
#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;
}

View File

@ -1,174 +0,0 @@
/*
* Copyright (c) 2017 Thomas Pornin <pornin@bolet.org>
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#include "inner.h"
#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(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;
}

View File

@ -1,48 +0,0 @@
/*
* Copyright (c) 2017 Thomas Pornin <pornin@bolet.org>
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#include "inner.h"
#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);
}

View File

@ -1,166 +0,0 @@
/*
* Copyright (c) 2017 Thomas Pornin <pornin@bolet.org>
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#include "inner.h"
#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(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;
}

View File

@ -1,110 +0,0 @@
/*
* 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 "inner.h"
/* see bearssl_x509.h */
size_t
br_encode_ec_pkcs8_der(void *dest,
const br_ec_private_key *sk, const br_ec_public_key *pk)
{
/*
* ASN.1 format:
*
* OneAsymmetricKey ::= SEQUENCE {
* version Version,
* privateKeyAlgorithm PrivateKeyAlgorithmIdentifier,
* privateKey PrivateKey,
* attributes [0] Attributes OPTIONAL,
* ...,
* [[2: publicKey [1] PublicKey OPTIONAL ]],
* ...
* }
*
* We don't include attributes or public key (the public key
* is included in the private key value instead). The
* 'version' field is an INTEGER that we will set to 0
* (meaning 'v1', compatible with previous versions of PKCS#8).
* The 'privateKeyAlgorithm' structure is an AlgorithmIdentifier
* whose OID should be id-ecPublicKey, with, as parameters, the
* curve OID. The 'privateKey' is an OCTET STRING, whose value
* is the "raw DER" encoding of the key pair.
*/
/*
* OID id-ecPublicKey (1.2.840.10045.2.1), DER-encoded (with
* the tag).
*/
static const unsigned char OID_ECPUBKEY[] = {
0x06, 0x07, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x02, 0x01
};
size_t len_version, len_privateKeyAlgorithm, len_privateKeyValue;
size_t len_privateKey, len_seq;
const unsigned char *oid;
oid = br_get_curve_OID(sk->curve);
if (oid == NULL) {
return 0;
}
len_version = 3;
len_privateKeyAlgorithm = 2 + sizeof OID_ECPUBKEY + 2 + oid[0];
len_privateKeyValue = br_encode_ec_raw_der_inner(NULL, sk, pk, 0);
len_privateKey = 1 + len_of_len(len_privateKeyValue)
+ len_privateKeyValue;
len_seq = len_version + len_privateKeyAlgorithm + len_privateKey;
if (dest == NULL) {
return 1 + len_of_len(len_seq) + len_seq;
} else {
unsigned char *buf;
size_t lenlen;
buf = dest;
*buf ++ = 0x30; /* SEQUENCE tag */
lenlen = br_asn1_encode_length(buf, len_seq);
buf += lenlen;
/* version */
*buf ++ = 0x02;
*buf ++ = 0x01;
*buf ++ = 0x00;
/* privateKeyAlgorithm */
*buf ++ = 0x30;
*buf ++ = (sizeof OID_ECPUBKEY) + 2 + oid[0];
memcpy(buf, OID_ECPUBKEY, sizeof OID_ECPUBKEY);
buf += sizeof OID_ECPUBKEY;
*buf ++ = 0x06;
memcpy(buf, oid, 1 + oid[0]);
buf += 1 + oid[0];
/* privateKey */
*buf ++ = 0x04;
buf += br_asn1_encode_length(buf, len_privateKeyValue);
br_encode_ec_raw_der_inner(buf, sk, pk, 0);
return 1 + lenlen + len_seq;
}
}

View File

@ -1,161 +0,0 @@
/*
* 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 "inner.h"
/* see inner.h */
const unsigned char *
br_get_curve_OID(int curve)
{
static const unsigned char OID_secp256r1[] = {
0x08, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x03, 0x01, 0x07
};
static const unsigned char OID_secp384r1[] = {
0x05, 0x2b, 0x81, 0x04, 0x00, 0x22
};
static const unsigned char OID_secp521r1[] = {
0x05, 0x2b, 0x81, 0x04, 0x00, 0x23
};
switch (curve) {
case BR_EC_secp256r1: return OID_secp256r1;
case BR_EC_secp384r1: return OID_secp384r1;
case BR_EC_secp521r1: return OID_secp521r1;
default:
return NULL;
}
}
/* see inner.h */
size_t
br_encode_ec_raw_der_inner(void *dest,
const br_ec_private_key *sk, const br_ec_public_key *pk,
int include_curve_oid)
{
/*
* ASN.1 format:
*
* ECPrivateKey ::= SEQUENCE {
* version INTEGER { ecPrivkeyVer1(1) } (ecPrivkeyVer1),
* privateKey OCTET STRING,
* parameters [0] ECParameters {{ NamedCurve }} OPTIONAL,
* publicKey [1] BIT STRING OPTIONAL
* }
*
* The tages '[0]' and '[1]' are explicit. The 'ECParameters'
* is a CHOICE; in our case, it will always be an OBJECT IDENTIFIER
* that identifies the curve.
*
* The value of the 'privateKey' field is the raw unsigned big-endian
* encoding of the private key (integer modulo the curve subgroup
* order); there is no INTEGER tag, and the leading bit may be 1.
* Also, leading bytes of value 0x00 are _not_ removed.
*
* The 'publicKey' contents are the raw encoded public key point,
* normally uncompressed (leading byte of value 0x04, followed
* by the unsigned big-endian encodings of the X and Y coordinates,
* padded to the full field length if necessary).
*/
size_t len_version, len_privateKey, len_parameters, len_publicKey;
size_t len_publicKey_bits, len_seq;
const unsigned char *oid;
if (include_curve_oid) {
oid = br_get_curve_OID(sk->curve);
if (oid == NULL) {
return 0;
}
} else {
oid = NULL;
}
len_version = 3;
len_privateKey = 1 + len_of_len(sk->xlen) + sk->xlen;
if (include_curve_oid) {
len_parameters = 4 + oid[0];
} else {
len_parameters = 0;
}
if (pk == NULL) {
len_publicKey = 0;
len_publicKey_bits = 0;
} else {
len_publicKey_bits = 2 + len_of_len(pk->qlen) + pk->qlen;
len_publicKey = 1 + len_of_len(len_publicKey_bits)
+ len_publicKey_bits;
}
len_seq = len_version + len_privateKey + len_parameters + len_publicKey;
if (dest == NULL) {
return 1 + len_of_len(len_seq) + len_seq;
} else {
unsigned char *buf;
size_t lenlen;
buf = dest;
*buf ++ = 0x30; /* SEQUENCE tag */
lenlen = br_asn1_encode_length(buf, len_seq);
buf += lenlen;
/* version */
*buf ++ = 0x02;
*buf ++ = 0x01;
*buf ++ = 0x01;
/* privateKey */
*buf ++ = 0x04;
buf += br_asn1_encode_length(buf, sk->xlen);
memcpy(buf, sk->x, sk->xlen);
buf += sk->xlen;
/* parameters */
if (include_curve_oid) {
*buf ++ = 0xA0;
*buf ++ = oid[0] + 2;
*buf ++ = 0x06;
memcpy(buf, oid, oid[0] + 1);
buf += oid[0] + 1;
}
/* publicKey */
if (pk != NULL) {
*buf ++ = 0xA1;
buf += br_asn1_encode_length(buf, len_publicKey_bits);
*buf ++ = 0x03;
buf += br_asn1_encode_length(buf, pk->qlen + 1);
*buf ++ = 0x00;
memcpy(buf, pk->q, pk->qlen);
/* buf += pk->qlen; */
}
return 1 + lenlen + len_seq;
}
}
/* see bearssl_x509.h */
size_t
br_encode_ec_raw_der(void *dest,
const br_ec_private_key *sk, const br_ec_public_key *pk)
{
return br_encode_ec_raw_der_inner(dest, sk, pk, 1);
}

View File

@ -1,97 +0,0 @@
/*
* 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 "inner.h"
/* see bearssl_x509.h */
size_t
br_encode_rsa_pkcs8_der(void *dest, const br_rsa_private_key *sk,
const br_rsa_public_key *pk, const void *d, size_t dlen)
{
/*
* ASN.1 format:
*
* OneAsymmetricKey ::= SEQUENCE {
* version Version,
* privateKeyAlgorithm PrivateKeyAlgorithmIdentifier,
* privateKey PrivateKey,
* attributes [0] Attributes OPTIONAL,
* ...,
* [[2: publicKey [1] PublicKey OPTIONAL ]],
* ...
* }
*
* We don't include attributes or public key. The 'version' field
* is an INTEGER that we will set to 0 (meaning 'v1', compatible
* with previous versions of PKCS#8). The 'privateKeyAlgorithm'
* structure is an AlgorithmIdentifier whose OID should be
* rsaEncryption, with NULL parameters. The 'privateKey' is an
* OCTET STRING, whose value is the "raw DER" encoding of the
* key pair.
*
* Since the private key value comes last, this function really
* adds a header, which is mostly fixed (only some lengths have
* to be modified.
*/
/*
* Concatenation of:
* - DER encoding of an INTEGER of value 0 (the 'version' field)
* - DER encoding of a PrivateKeyAlgorithmIdentifier that uses
* the rsaEncryption OID, and NULL parameters
* - An OCTET STRING tag
*/
static const unsigned char PK8_HEAD[] = {
0x02, 0x01, 0x00,
0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86,
0xf7, 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00,
0x04
};
size_t len_raw, len_seq;
len_raw = br_encode_rsa_raw_der(NULL, sk, pk, d, dlen);
len_seq = (sizeof PK8_HEAD) + len_of_len(len_raw) + len_raw;
if (dest == NULL) {
return 1 + len_of_len(len_seq) + len_seq;
} else {
unsigned char *buf;
size_t lenlen;
buf = dest;
*buf ++ = 0x30; /* SEQUENCE tag */
lenlen = br_asn1_encode_length(buf, len_seq);
buf += lenlen;
/* version, privateKeyAlgorithm, privateKey tag */
memcpy(buf, PK8_HEAD, sizeof PK8_HEAD);
buf += sizeof PK8_HEAD;
/* privateKey */
buf += br_asn1_encode_length(buf, len_raw);
br_encode_rsa_raw_der(buf, sk, pk, d, dlen);
return 1 + lenlen + len_seq;
}
}

View File

@ -1,96 +0,0 @@
/*
* 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 "inner.h"
/* see bearssl_x509.h */
size_t
br_encode_rsa_raw_der(void *dest, const br_rsa_private_key *sk,
const br_rsa_public_key *pk, const void *d, size_t dlen)
{
/*
* ASN.1 format:
*
* RSAPrivateKey ::= SEQUENCE {
* version Version,
* modulus INTEGER, -- n
* publicExponent INTEGER, -- e
* privateExponent INTEGER, -- d
* prime1 INTEGER, -- p
* prime2 INTEGER, -- q
* exponent1 INTEGER, -- d mod (p-1)
* exponent2 INTEGER, -- d mod (q-1)
* coefficient INTEGER, -- (inverse of q) mod p
* otherPrimeInfos OtherPrimeInfos OPTIONAL
* }
*
* The 'version' field is an INTEGER of value 0 (meaning: there
* are exactly two prime factors), and 'otherPrimeInfos' will
* be absent (because there are exactly two prime factors).
*/
br_asn1_uint num[9];
size_t u, slen;
/*
* For all INTEGER values, get the pointer and length for the
* data bytes.
*/
num[0] = br_asn1_uint_prepare(NULL, 0);
num[1] = br_asn1_uint_prepare(pk->n, pk->nlen);
num[2] = br_asn1_uint_prepare(pk->e, pk->elen);
num[3] = br_asn1_uint_prepare(d, dlen);
num[4] = br_asn1_uint_prepare(sk->p, sk->plen);
num[5] = br_asn1_uint_prepare(sk->q, sk->qlen);
num[6] = br_asn1_uint_prepare(sk->dp, sk->dplen);
num[7] = br_asn1_uint_prepare(sk->dq, sk->dqlen);
num[8] = br_asn1_uint_prepare(sk->iq, sk->iqlen);
/*
* Get the length of the SEQUENCE contents.
*/
slen = 0;
for (u = 0; u < 9; u ++) {
uint32_t ilen;
ilen = num[u].asn1len;
slen += 1 + len_of_len(ilen) + ilen;
}
if (dest == NULL) {
return 1 + len_of_len(slen) + slen;
} else {
unsigned char *buf;
size_t lenlen;
buf = dest;
*buf ++ = 0x30; /* SEQUENCE tag */
lenlen = br_asn1_encode_length(buf, slen);
buf += lenlen;
for (u = 0; u < 9; u ++) {
buf += br_asn1_encode_uint(buf, num[u]);
}
return 1 + lenlen + slen;
}
}

View File

@ -1,251 +0,0 @@
/*
* 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 "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]);
}

View File

@ -1,107 +0,0 @@
/*
* 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 "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;
}

View File

@ -1,46 +0,0 @@
/*
* Copyright (c) 2017 Thomas Pornin <pornin@bolet.org>
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#include "inner.h"
/* 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 = b[u];
naw = aw + bw + cc;
cc = naw >> 15;
a[u] = MUX(ctl, naw & 0x7FFF, aw);
}
return cc;
}

View File

@ -1,44 +0,0 @@
/*
* Copyright (c) 2017 Thomas Pornin <pornin@bolet.org>
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#include "inner.h"
/* 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);
}

View File

@ -1,124 +0,0 @@
/*
* Copyright (c) 2017 Thomas Pornin <pornin@bolet.org>
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#include "inner.h"
/* 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 = (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 = 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, 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] = m[0];
return r & (uint32_t)1;
}

View File

@ -1,56 +0,0 @@
/*
* Copyright (c) 2017 Thomas Pornin <pornin@bolet.org>
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#include "inner.h"
/* 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 = 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);
}

View File

@ -1,100 +0,0 @@
/*
* Copyright (c) 2017 Thomas Pornin <pornin@bolet.org>
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#include "inner.h"
/* 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 = 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 = 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);
}
}

View File

@ -1,56 +0,0 @@
/*
* Copyright (c) 2017 Thomas Pornin <pornin@bolet.org>
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#include "inner.h"
/* 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 = (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)x[u ++] << acc_len;
}
acc_len += 15;
}
buf[len] = (unsigned char)acc;
acc >>= 8;
acc_len -= 8;
}
}

View File

@ -1,59 +0,0 @@
/*
* Copyright (c) 2017 Thomas Pornin <pornin@bolet.org>
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#include "inner.h"
/* see inner.h */
void
br_i15_from_monty(uint16_t *x, const uint16_t *m, uint16_t m0i)
{
size_t len, u, v;
len = (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, 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)));
}

View File

@ -1,39 +0,0 @@
/*
* Copyright (c) 2017 Thomas Pornin <pornin@bolet.org>
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#include "inner.h"
/* see inner.h */
uint32_t
br_i15_iszero(const uint16_t *x)
{
uint32_t z;
size_t u;
z = 0;
for (u = (x[0] + 15) >> 4; u > 0; u --) {
z |= x[u];
}
return ~(z | -z) >> 31;
}

View File

@ -1,465 +0,0 @@
/*
* 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 "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 = 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 = (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
+ m[k] * (uint32_t)fa + (uint32_t)cca;
zb = wa * (uint32_t)qa + wb * (uint32_t)qb
+ 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 = (m[0] + 15) >> 4;
a = t;
b = a + len;
u = x + 1;
v = b + len;
memcpy(a, y + 1, len * sizeof *y);
memcpy(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 = ((m[0] - (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);
}

View File

@ -1,50 +0,0 @@
/*
* Copyright (c) 2017 Thomas Pornin <pornin@bolet.org>
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#include "inner.h"
/* 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 = ((m[0] + 31) >> 4) * sizeof m[0];
memcpy(t1, x, mlen);
br_i15_to_monty(t1, m);
br_i15_zero(x, m[0]);
x[1] = 1;
for (k = 0; k < ((unsigned)elen << 3); k ++) {
uint32_t ctl;
ctl = (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);
}
}

View File

@ -1,160 +0,0 @@
/*
* Copyright (c) 2017 Thomas Pornin <pornin@bolet.org>
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#include "inner.h"
/* 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 = (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, m[0]);
x[(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) | *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, 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;
}

View File

@ -1,184 +0,0 @@
/*
* Copyright (c) 2017 Thomas Pornin <pornin@bolet.org>
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#include "inner.h"
/* 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 = (m[0] + 15) >> 4;
len4 = len & ~(size_t)3;
br_i15_zero(d, m[0]);
dh = 0;
for (u = 0; u < len; u ++) {
uint32_t f, xu, r, zh;
xu = x[u + 1];
f = MUL15((d[1] + MUL15(x[u + 1], 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;
for (v = 0; v < len4; v += 4) {
uint32_t z;
z = d[v + 1] + MUL15(xu, y[v + 1])
+ MUL15(f, m[v + 1]) + r;
r = z >> 15;
d[v + 0] = z & 0x7FFF;
z = d[v + 2] + MUL15(xu, y[v + 2])
+ MUL15(f, m[v + 2]) + r;
r = z >> 15;
d[v + 1] = z & 0x7FFF;
z = d[v + 3] + MUL15(xu, y[v + 3])
+ MUL15(f, m[v + 3]) + r;
r = z >> 15;
d[v + 2] = z & 0x7FFF;
z = d[v + 4] + MUL15(xu, y[v + 4])
+ MUL15(f, m[v + 4]) + r;
r = z >> 15;
d[v + 3] = z & 0x7FFF;
}
#endif
for (; v < len; v ++) {
uint32_t z;
z = d[v + 1] + MUL15(xu, y[v + 1])
+ MUL15(f, 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] = 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)));
}

View File

@ -1,61 +0,0 @@
/*
* Copyright (c) 2017 Thomas Pornin <pornin@bolet.org>
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#include "inner.h"
/* 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 = (a[0] + 15) >> 4;
blen = (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 = (a[0] & 15) + (b[0] & 15);
dh = (a[0] >> 4) + (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 = b[1 + u];
cc = 0;
for (v = 0; v < alen; v ++) {
uint32_t z;
z = (uint32_t)d[1 + u + v] + MUL15(f, a[1 + v]) + cc;
cc = z >> 15;
d[1 + u + v] = z & 0x7FFF;
}
d[1 + u + alen] = cc;
}
}

View File

@ -1,173 +0,0 @@
/*
* Copyright (c) 2017 Thomas Pornin <pornin@bolet.org>
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#include "inner.h"
/*
* 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 = m[0];
if (m_bitlen == 0) {
return;
}
if (m_bitlen <= 15) {
uint32_t rem;
divrem16(((uint32_t)x[1] << 15) | z, 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 = 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 = (m[mlen] << (15 - mblr)) | (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 = 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);
}

View File

@ -1,38 +0,0 @@
/*
* Copyright (c) 2017 Thomas Pornin <pornin@bolet.org>
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#include "inner.h"
/* 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;
}

View File

@ -1,66 +0,0 @@
/*
* Copyright (c) 2017 Thomas Pornin <pornin@bolet.org>
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#include "inner.h"
/* 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 = 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 = a[0];
alen = (a_bitlen + 15) >> 4;
if (a_bitlen < m_bitlen) {
memcpy(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(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, a[u], m);
}
}

View File

@ -1,47 +0,0 @@
/*
* Copyright (c) 2017 Thomas Pornin <pornin@bolet.org>
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#include "inner.h"
/* 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;
}

View File

@ -1,46 +0,0 @@
/*
* Copyright (c) 2017 Thomas Pornin <pornin@bolet.org>
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#include "inner.h"
/* 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 = b[u];
naw = aw - bw - cc;
cc = naw >> 31;
a[u] = MUX(ctl, naw & 0x7FFF, aw);
}
return cc;
}

View File

@ -1,36 +0,0 @@
/*
* Copyright (c) 2017 Thomas Pornin <pornin@bolet.org>
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#include "inner.h"
/* see inner.h */
void
br_i15_to_monty(uint16_t *x, const uint16_t *m)
{
unsigned k;
for (k = (m[0] + 15) >> 4; k > 0; k --) {
br_i15_muladd_small(x, 0, m);
}
}

View File

@ -1,51 +0,0 @@
/*
* 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 "inner.h"
/* see inner.h */
uint32_t
br_i32_add(uint32_t *a, const uint32_t *b, uint32_t ctl)
{
uint32_t cc;
size_t u, m;
cc = 0;
m = (a[0] + 63) >> 5;
for (u = 1; u < m; u ++) {
uint32_t aw, bw, naw;
aw = a[u];
bw = b[u];
naw = aw + bw + cc;
/*
* Carry is 1 if naw < aw. Carry is also 1 if naw == aw
* AND the carry was already 1.
*/
cc = (cc & EQ(naw, aw)) | LT(naw, aw);
a[u] = MUX(ctl, naw, aw);
}
return cc;
}

View File

@ -1,44 +0,0 @@
/*
* 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 "inner.h"
/* see inner.h */
uint32_t
br_i32_bit_length(uint32_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 << 5) + BIT_LENGTH(tw);
}

View File

@ -1,77 +0,0 @@
/*
* 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 "inner.h"
/* see inner.h */
uint32_t
br_i32_decode_mod(uint32_t *x, const void *src, size_t len, const uint32_t *m)
{
const unsigned char *buf;
uint32_t r;
size_t u, v, mlen;
buf = src;
/*
* First pass: determine whether the value fits. The 'r' value
* will contain the comparison result, as 0x00000000 (value is
* equal to the modulus), 0x00000001 (value is greater than the
* modulus), or 0xFFFFFFFF (value is lower than the modulus).
*/
mlen = (m[0] + 7) >> 3;
r = 0;
for (u = (mlen > len) ? mlen : len; u > 0; u --) {
uint32_t mb, xb;
v = u - 1;
if (v >= mlen) {
mb = 0;
} else {
mb = (m[1 + (v >> 2)] >> ((v & 3) << 3)) & 0xFF;
}
if (v >= len) {
xb = 0;
} else {
xb = buf[len - u];
}
r = MUX(EQ(r, 0), (uint32_t)CMP(xb, mb), r);
}
/*
* Only r == 0xFFFFFFFF is acceptable. We want to set r to 0xFF if
* the value fits, 0x00 otherwise.
*/
r >>= 24;
br_i32_zero(x, m[0]);
u = (mlen > len) ? len : mlen;
while (u > 0) {
uint32_t xb;
xb = buf[len - u] & r;
u --;
x[1 + (u >> 2)] |= xb << ((u & 3) << 3);
}
return r >> 7;
}

View File

@ -1,63 +0,0 @@
/*
* 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 "inner.h"
/* see inner.h */
void
br_i32_decode(uint32_t *x, const void *src, size_t len)
{
const unsigned char *buf;
size_t u, v;
buf = src;
u = len;
v = 1;
for (;;) {
if (u < 4) {
uint32_t w;
if (u < 2) {
if (u == 0) {
break;
} else {
w = buf[0];
}
} else {
if (u == 2) {
w = br_dec16be(buf);
} else {
w = ((uint32_t)buf[0] << 16)
| br_dec16be(buf + 1);
}
}
x[v ++] = w;
break;
} else {
u -= 4;
x[v ++] = br_dec32be(buf + u);
}
}
x[0] = br_i32_bit_length(x + 1, v - 1);
}

View File

@ -1,107 +0,0 @@
/*
* 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 "inner.h"
/* see inner.h */
void
br_i32_decode_reduce(uint32_t *x,
const void *src, size_t len, const uint32_t *m)
{
uint32_t m_bitlen;
size_t mblen, k, q;
const unsigned char *buf;
m_bitlen = m[0];
/*
* Special case for an invalid modulus.
*/
if (m_bitlen == 0) {
x[0] = 0;
return;
}
/*
* Clear the destination.
*/
br_i32_zero(x, m_bitlen);
/*
* First decode directly as many bytes as possible without
* reduction, taking care to leave a number of bytes which
* is a multiple of 4.
*/
mblen = (m_bitlen + 7) >> 3;
k = mblen - 1;
/*
* Up to k bytes can be safely decoded.
*/
if (k >= len) {
br_i32_decode(x, src, len);
x[0] = m_bitlen;
return;
}
/*
* We want to first inject some bytes with direct decoding,
* then extra bytes by whole 32-bit words. First compute
* the size that should be injected that way.
*/
buf = src;
q = (len - k + 3) & ~(size_t)3;
/*
* It may happen that this is more than what we already have
* (by at most 3 bytes). Such a case may happen only with
* a very short modulus. In that case, we must process the first
* bytes "manually".
*/
if (q > len) {
int i;
uint32_t w;
w = 0;
for (i = 0; i < 4; i ++) {
w <<= 8;
if (q <= len) {
w |= buf[len - q];
}
q --;
}
br_i32_muladd_small(x, w, m);
} else {
br_i32_decode(x, buf, len - q);
x[0] = m_bitlen;
}
/*
* At that point, we have exactly q bytes to inject, and q is
* a multiple of 4.
*/
for (k = len - q; k < len; k += 4) {
br_i32_muladd_small(x, br_dec32be(buf + k), m);
}
}

View File

@ -1,72 +0,0 @@
/*
* 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 "inner.h"
/* see inner.h */
void
br_i32_encode(void *dst, size_t len, const uint32_t *x)
{
unsigned char *buf;
size_t k;
buf = dst;
/*
* Compute the announced size of x in bytes; extra bytes are
* filled with zeros.
*/
k = (x[0] + 7) >> 3;
while (len > k) {
*buf ++ = 0;
len --;
}
/*
* Now we use k as index within x[]. That index starts at 1;
* we initialize it to the topmost complete word, and process
* any remaining incomplete word.
*/
k = (len + 3) >> 2;
switch (len & 3) {
case 3:
*buf ++ = x[k] >> 16;
/* fall through */
case 2:
*buf ++ = x[k] >> 8;
/* fall through */
case 1:
*buf ++ = x[k];
k --;
}
/*
* Encode all complete words.
*/
while (k > 0) {
br_enc32be(buf, x[k]);
k --;
buf += 4;
}
}

View File

@ -1,60 +0,0 @@
/*
* 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 "inner.h"
/* see inner.h */
void
br_i32_from_monty(uint32_t *x, const uint32_t *m, uint32_t m0i)
{
size_t len, u, v;
len = (m[0] + 31) >> 5;
for (u = 0; u < len; u ++) {
uint32_t f;
uint64_t cc;
f = x[1] * m0i;
cc = 0;
for (v = 0; v < len; v ++) {
uint64_t z;
z = (uint64_t)x[v + 1] + MUL(f, m[v + 1]) + cc;
cc = z >> 32;
if (v != 0) {
x[v] = (uint32_t)z;
}
}
x[len] = (uint32_t)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_i32_sub(x, m, NOT(br_i32_sub(x, m, 0)));
}

View File

@ -1,39 +0,0 @@
/*
* 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 "inner.h"
/* see inner.h */
uint32_t
br_i32_iszero(const uint32_t *x)
{
uint32_t z;
size_t u;
z = 0;
for (u = (x[0] + 31) >> 5; u > 0; u --) {
z |= x[u];
}
return ~(z | -z) >> 31;
}

View File

@ -1,65 +0,0 @@
/*
* 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 "inner.h"
/* see inner.h */
void
br_i32_modpow(uint32_t *x,
const unsigned char *e, size_t elen,
const uint32_t *m, uint32_t m0i, uint32_t *t1, uint32_t *t2)
{
size_t mlen;
uint32_t k;
/*
* 'mlen' is the length of m[] expressed in bytes (including
* the "bit length" first field).
*/
mlen = ((m[0] + 63) >> 5) * sizeof m[0];
/*
* Throughout the algorithm:
* -- t1[] is in Montgomery representation; it contains x, x^2,
* x^4, x^8...
* -- The result is accumulated, in normal representation, in
* the x[] array.
* -- t2[] is used as destination buffer for each multiplication.
*
* Note that there is no need to call br_i32_from_monty().
*/
memcpy(t1, x, mlen);
br_i32_to_monty(t1, m);
br_i32_zero(x, m[0]);
x[1] = 1;
for (k = 0; k < ((uint32_t)elen << 3); k ++) {
uint32_t ctl;
ctl = (e[elen - 1 - (k >> 3)] >> (k & 7)) & 1;
br_i32_montymul(t2, x, t1, m, m0i);
CCOPY(ctl, x, t2, mlen);
br_i32_montymul(t2, t1, t1, m, m0i);
memcpy(t1, t2, mlen);
}
}

View File

@ -1,69 +0,0 @@
/*
* 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 "inner.h"
/* see inner.h */
void
br_i32_montymul(uint32_t *d, const uint32_t *x, const uint32_t *y,
const uint32_t *m, uint32_t m0i)
{
size_t len, u, v;
uint64_t dh;
len = (m[0] + 31) >> 5;
br_i32_zero(d, m[0]);
dh = 0;
for (u = 0; u < len; u ++) {
uint32_t f, xu;
uint64_t r1, r2, zh;
xu = x[u + 1];
f = (d[1] + x[u + 1] * y[1]) * m0i;
r1 = 0;
r2 = 0;
for (v = 0; v < len; v ++) {
uint64_t z;
uint32_t t;
z = (uint64_t)d[v + 1] + MUL(xu, y[v + 1]) + r1;
r1 = z >> 32;
t = (uint32_t)z;
z = (uint64_t)t + MUL(f, m[v + 1]) + r2;
r2 = z >> 32;
if (v != 0) {
d[v] = (uint32_t)z;
}
}
zh = dh + r1 + r2;
d[len] = (uint32_t)zh;
dh = zh >> 32;
}
/*
* d[] may still be greater than m[] at that point; notably, the
* 'dh' word may be non-zero.
*/
br_i32_sub(d, m, NEQ(dh, 0) | NOT(br_i32_sub(d, m, 0)));
}

View File

@ -1,56 +0,0 @@
/*
* 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 "inner.h"
/* see inner.h */
void
br_i32_mulacc(uint32_t *d, const uint32_t *a, const uint32_t *b)
{
size_t alen, blen, u;
alen = (a[0] + 31) >> 5;
blen = (b[0] + 31) >> 5;
d[0] = a[0] + b[0];
for (u = 0; u < blen; u ++) {
uint32_t f;
size_t v;
#if BR_64
uint64_t cc;
#else
uint32_t cc;
#endif
f = b[1 + u];
cc = 0;
for (v = 0; v < alen; v ++) {
uint64_t z;
z = (uint64_t)d[1 + u + v] + MUL(f, a[1 + v]) + cc;
cc = z >> 32;
d[1 + u + v] = (uint32_t)z;
}
d[1 + u + alen] = (uint32_t)cc;
}
}

View File

@ -1,138 +0,0 @@
/*
* 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 "inner.h"
/* see inner.h */
void
br_i32_muladd_small(uint32_t *x, uint32_t z, const uint32_t *m)
{
uint32_t m_bitlen;
size_t u, mlen;
uint32_t a0, a1, b0, hi, g, q, tb;
uint32_t chf, clow, under, over;
uint64_t cc;
/*
* We can test on the modulus bit length since we accept to
* leak that length.
*/
m_bitlen = m[0];
if (m_bitlen == 0) {
return;
}
if (m_bitlen <= 32) {
x[1] = br_rem(x[1], z, m[1]);
return;
}
mlen = (m_bitlen + 31) >> 5;
/*
* Principle: we estimate the quotient (x*2^32+z)/m by
* doing a 64/32 division with the high words.
*
* Let:
* w = 2^32
* 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), we can estimate q by
* doing an Euclidean division on the top words:
* a0*w+a1 = b0*u + v (with 0 <= v < w)
* Then the following holds:
* 0 <= u <= w
* u-2 <= q <= u
*/
a0 = br_i32_word(x, m_bitlen - 32);
hi = x[mlen];
memmove(x + 2, x + 1, (mlen - 1) * sizeof *x);
x[1] = z;
a1 = br_i32_word(x, m_bitlen - 32);
b0 = br_i32_word(m, m_bitlen - 32);
/*
* We estimate a divisor q. If the quotient returned by br_div()
* is g:
* -- If a0 == b0 then g == 0; we want q = 0xFFFFFFFF.
* -- Otherwise:
* -- if g == 0 then we set q = 0;
* -- otherwise, we set q = g - 1.
* The properties described above then ensure that the true
* quotient is q-1, q or q+1.
*/
g = br_div(a0, a1, b0);
q = MUX(EQ(a0, b0), 0xFFFFFFFF, MUX(EQ(g, 0), 0, g - 1));
/*
* We subtract q*m from x (with the 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, zw, xw, nxw;
uint64_t zl;
mw = m[u];
zl = MUL(mw, q) + cc;
cc = (uint32_t)(zl >> 32);
zw = (uint32_t)zl;
xw = x[u];
nxw = xw - zw;
cc += (uint64_t)GT(nxw, xw);
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). In
* these cases we must subtract m once.
*
* Otherwise, we may have overestimated, which will show as
* cc > hi (thus a negative result). Correction is adding m once.
*/
chf = (uint32_t)(cc >> 32);
clow = (uint32_t)cc;
over = chf | GT(clow, hi);
under = ~over & (tb | (~chf & LT(clow, hi)));
br_i32_add(x, m, over);
br_i32_sub(x, m, under);
}

View File

@ -1,39 +0,0 @@
/*
* 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 "inner.h"
/* see inner.h */
uint32_t
br_i32_ninv32(uint32_t x)
{
uint32_t y;
y = 2 - x;
y *= 2 - y * x;
y *= 2 - y * x;
y *= 2 - y * x;
y *= 2 - y * x;
return MUX(x & 1, -y, 0);
}

View File

@ -1,66 +0,0 @@
/*
* 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 "inner.h"
/* see inner.h */
void
br_i32_reduce(uint32_t *x, const uint32_t *a, const uint32_t *m)
{
uint32_t m_bitlen, a_bitlen;
size_t mlen, alen, u;
m_bitlen = m[0];
mlen = (m_bitlen + 31) >> 5;
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 = a[0];
alen = (a_bitlen + 31) >> 5;
if (a_bitlen < m_bitlen) {
memcpy(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(x + 1, a + 2 + (alen - mlen), (mlen - 1) * sizeof *a);
x[mlen] = 0;
for (u = 1 + alen - mlen; u > 0; u --) {
br_i32_muladd_small(x, a[u], m);
}
}

View File

@ -1,51 +0,0 @@
/*
* 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 "inner.h"
/* see inner.h */
uint32_t
br_i32_sub(uint32_t *a, const uint32_t *b, uint32_t ctl)
{
uint32_t cc;
size_t u, m;
cc = 0;
m = (a[0] + 63) >> 5;
for (u = 1; u < m; u ++) {
uint32_t aw, bw, naw;
aw = a[u];
bw = b[u];
naw = aw - bw - cc;
/*
* Carry is 1 if naw > aw. Carry is 1 also if naw == aw
* AND the carry was already 1.
*/
cc = (cc & EQ(naw, aw)) | GT(naw, aw);
a[u] = MUX(ctl, naw, aw);
}
return cc;
}

View File

@ -1,36 +0,0 @@
/*
* 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 "inner.h"
/* see inner.h */
void
br_i32_to_monty(uint32_t *x, const uint32_t *m)
{
uint32_t k;
for (k = (m[0] + 31) >> 5; k > 0; k --) {
br_i32_muladd_small(x, 0, m);
}
}

View File

@ -125,15 +125,6 @@
#endif
#endif
/*
* Set BR_LOMUL on platforms where it makes sense.
*/
#ifndef BR_LOMUL
#if BR_ARMEL_CORTEXM_GCC
#define BR_LOMUL 1
#endif
#endif
/*
* Architecture detection.
*/

View File

@ -1,297 +0,0 @@
/*
* Copyright (c) 2017 Thomas Pornin <pornin@bolet.org>
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#include "inner.h"
/*
* Perform the inner processing of blocks for Poly1305.
*/
static void
poly1305_inner(uint32_t *a, const uint32_t *r, const void *data, size_t len)
{
/*
* Implementation notes: we split the 130-bit values into ten
* 13-bit words. This gives us some space for carries and allows
* using only 32x32->32 multiplications, which are way faster than
* 32x32->64 multiplications on the ARM Cortex-M0/M0+, and also
* help in making constant-time code on the Cortex-M3.
*
* Since we compute modulo 2^130-5, the "upper words" become
* low words with a factor of 5; that is, x*2^130 = x*5 mod p.
* This has already been integrated in the r[] array, which
* is extended to the 0..18 range.
*
* In each loop iteration, a[] and r[] words are 13-bit each,
* except a[1] which may use 14 bits.
*/
const unsigned char *buf;
buf = data;
while (len > 0) {
unsigned char tmp[16];
uint32_t b[10];
unsigned u, v;
uint32_t z, cc1, cc2;
/*
* If there is a partial block, right-pad it with zeros.
*/
if (len < 16) {
memset(tmp, 0, sizeof tmp);
memcpy(tmp, buf, len);
buf = tmp;
len = 16;
}
/*
* Decode next block and apply the "high bit"; that value
* is added to the accumulator.
*/
v = br_dec16le(buf);
a[0] += v & 0x01FFF;
v >>= 13;
v |= buf[2] << 3;
v |= buf[3] << 11;
a[1] += v & 0x01FFF;
v >>= 13;
v |= buf[4] << 6;
a[2] += v & 0x01FFF;
v >>= 13;
v |= buf[5] << 1;
v |= buf[6] << 9;
a[3] += v & 0x01FFF;
v >>= 13;
v |= buf[7] << 4;
v |= buf[8] << 12;
a[4] += v & 0x01FFF;
v >>= 13;
v |= buf[9] << 7;
a[5] += v & 0x01FFF;
v >>= 13;
v |= buf[10] << 2;
v |= buf[11] << 10;
a[6] += v & 0x01FFF;
v >>= 13;
v |= buf[12] << 5;
a[7] += v & 0x01FFF;
v = br_dec16le(buf + 13);
a[8] += v & 0x01FFF;
v >>= 13;
v |= buf[15] << 3;
a[9] += v | 0x00800;
/*
* At that point, all a[] values fit on 14 bits, while
* all r[] values fit on 13 bits. Thus products fit on
* 27 bits, and we can accumulate up to 31 of them in
* a 32-bit word and still have some room for carries.
*/
/*
* Now a[] contains words with values up to 14 bits each.
* We perform the multiplication with r[].
*
* The extended words of r[] may be larger than 13 bits
* (they are 5 times a 13-bit word) so the full summation
* may yield values up to 46 times a 27-bit word, which
* does not fit on a 32-bit word. To avoid that issue, we
* must split the loop below in two, with a carry
* propagation operation in the middle.
*/
cc1 = 0;
for (u = 0; u < 10; u ++) {
uint32_t s;
s = cc1
+ MUL15(a[0], r[u + 9 - 0])
+ MUL15(a[1], r[u + 9 - 1])
+ MUL15(a[2], r[u + 9 - 2])
+ MUL15(a[3], r[u + 9 - 3])
+ MUL15(a[4], r[u + 9 - 4]);
b[u] = s & 0x1FFF;
cc1 = s >> 13;
}
cc2 = 0;
for (u = 0; u < 10; u ++) {
uint32_t s;
s = b[u] + cc2
+ MUL15(a[5], r[u + 9 - 5])
+ MUL15(a[6], r[u + 9 - 6])
+ MUL15(a[7], r[u + 9 - 7])
+ MUL15(a[8], r[u + 9 - 8])
+ MUL15(a[9], r[u + 9 - 9]);
b[u] = s & 0x1FFF;
cc2 = s >> 13;
}
memcpy(a, b, sizeof b);
/*
* The two carries "loop back" with a factor of 5. We
* propagate them into a[0] and a[1].
*/
z = cc1 + cc2;
z += (z << 2) + a[0];
a[0] = z & 0x1FFF;
a[1] += z >> 13;
buf += 16;
len -= 16;
}
}
/* see bearssl_block.h */
void
br_poly1305_ctmul32_run(const void *key, const void *iv,
void *data, size_t len, const void *aad, size_t aad_len,
void *tag, br_chacha20_run ichacha, int encrypt)
{
unsigned char pkey[32], foot[16];
uint32_t z, r[19], acc[10], cc, ctl;
int i;
/*
* Compute the MAC key. The 'r' value is the first 16 bytes of
* pkey[].
*/
memset(pkey, 0, sizeof pkey);
ichacha(key, iv, 0, pkey, sizeof pkey);
/*
* If encrypting, ChaCha20 must run first, followed by Poly1305.
* When decrypting, the operations are reversed.
*/
if (encrypt) {
ichacha(key, iv, 1, data, len);
}
/*
* Run Poly1305. We must process the AAD, then ciphertext, then
* the footer (with the lengths). Note that the AAD and ciphertext
* are meant to be padded with zeros up to the next multiple of 16,
* and the length of the footer is 16 bytes as well.
*/
/*
* Decode the 'r' value into 13-bit words, with the "clamping"
* operation applied.
*/
z = br_dec32le(pkey) & 0x03FFFFFF;
r[9] = z & 0x1FFF;
r[10] = z >> 13;
z = (br_dec32le(pkey + 3) >> 2) & 0x03FFFF03;
r[11] = z & 0x1FFF;
r[12] = z >> 13;
z = (br_dec32le(pkey + 6) >> 4) & 0x03FFC0FF;
r[13] = z & 0x1FFF;
r[14] = z >> 13;
z = (br_dec32le(pkey + 9) >> 6) & 0x03F03FFF;
r[15] = z & 0x1FFF;
r[16] = z >> 13;
z = (br_dec32le(pkey + 12) >> 8) & 0x000FFFFF;
r[17] = z & 0x1FFF;
r[18] = z >> 13;
/*
* Extend r[] with the 5x factor pre-applied.
*/
for (i = 0; i < 9; i ++) {
r[i] = MUL15(5, r[i + 10]);
}
/*
* Accumulator is 0.
*/
memset(acc, 0, sizeof acc);
/*
* Process the additional authenticated data, ciphertext, and
* footer in due order.
*/
br_enc64le(foot, (uint64_t)aad_len);
br_enc64le(foot + 8, (uint64_t)len);
poly1305_inner(acc, r, aad, aad_len);
poly1305_inner(acc, r, data, len);
poly1305_inner(acc, r, foot, sizeof foot);
/*
* Finalise modular reduction. This is done with carry propagation
* and applying the '2^130 = -5 mod p' rule. Note that the output
* of poly1035_inner() is already mostly reduced, since only
* acc[1] may be (very slightly) above 2^13. A single loop back
* to acc[1] will be enough to make the value fit in 130 bits.
*/
cc = 0;
for (i = 1; i < 10; i ++) {
z = acc[i] + cc;
acc[i] = z & 0x1FFF;
cc = z >> 13;
}
z = acc[0] + cc + (cc << 2);
acc[0] = z & 0x1FFF;
acc[1] += z >> 13;
/*
* We may still have a value in the 2^130-5..2^130-1 range, in
* which case we must reduce it again. The code below selects,
* in constant-time, between 'acc' and 'acc-p',
*/
ctl = GT(acc[0], 0x1FFA);
for (i = 1; i < 10; i ++) {
ctl &= EQ(acc[i], 0x1FFF);
}
acc[0] = MUX(ctl, acc[0] - 0x1FFB, acc[0]);
for (i = 1; i < 10; i ++) {
acc[i] &= ~(-ctl);
}
/*
* Convert back the accumulator to 32-bit words, and add the
* 's' value (second half of pkey[]). That addition is done
* modulo 2^128.
*/
z = acc[0] + (acc[1] << 13) + br_dec16le(pkey + 16);
br_enc16le((unsigned char *)tag, z & 0xFFFF);
z = (z >> 16) + (acc[2] << 10) + br_dec16le(pkey + 18);
br_enc16le((unsigned char *)tag + 2, z & 0xFFFF);
z = (z >> 16) + (acc[3] << 7) + br_dec16le(pkey + 20);
br_enc16le((unsigned char *)tag + 4, z & 0xFFFF);
z = (z >> 16) + (acc[4] << 4) + br_dec16le(pkey + 22);
br_enc16le((unsigned char *)tag + 6, z & 0xFFFF);
z = (z >> 16) + (acc[5] << 1) + (acc[6] << 14) + br_dec16le(pkey + 24);
br_enc16le((unsigned char *)tag + 8, z & 0xFFFF);
z = (z >> 16) + (acc[7] << 11) + br_dec16le(pkey + 26);
br_enc16le((unsigned char *)tag + 10, z & 0xFFFF);
z = (z >> 16) + (acc[8] << 8) + br_dec16le(pkey + 28);
br_enc16le((unsigned char *)tag + 12, z & 0xFFFF);
z = (z >> 16) + (acc[9] << 5) + br_dec16le(pkey + 30);
br_enc16le((unsigned char *)tag + 14, z & 0xFFFF);
/*
* If decrypting, then ChaCha20 runs _after_ Poly1305.
*/
if (!encrypt) {
ichacha(key, iv, 1, data, len);
}
}

View File

@ -1,221 +0,0 @@
/*
* Copyright (c) 2017 Thomas Pornin <pornin@bolet.org>
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#include "inner.h"
/*
* This is a "reference" implementation of Poly1305 that uses the
* generic "i15" code for big integers. It is slow, but it handles all
* big-integer operations with generic code, thereby avoiding most
* tricky situations with carry propagation and modular reduction.
*/
/*
* Modulus: 2^130-5.
*/
static const uint16_t P1305[] = {
0x008A,
0x7FFB, 0x7FFF, 0x7FFF, 0x7FFF, 0x7FFF, 0x7FFF, 0x7FFF, 0x7FFF, 0x03FF
};
/*
* -p mod 2^15.
*/
#define P0I 0x4CCD
/*
* R^2 mod p, for conversion to Montgomery representation (R = 2^135,
* since we use 9 words of 15 bits each, and 15*9 = 135).
*/
static const uint16_t R2[] = {
0x008A,
0x6400, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000
};
/*
* Perform the inner processing of blocks for Poly1305. The "r" array
* is in Montgomery representation, while the "a" array is not.
*/
static void
poly1305_inner(uint16_t *a, const uint16_t *r, const void *data, size_t len)
{
const unsigned char *buf;
buf = data;
while (len > 0) {
unsigned char tmp[16], rev[16];
uint16_t b[10];
uint32_t ctl;
int i;
/*
* If there is a partial block, right-pad it with zeros.
*/
if (len < 16) {
memset(tmp, 0, sizeof tmp);
memcpy(tmp, buf, len);
buf = tmp;
len = 16;
}
/*
* Decode next block and apply the "high bit". Since
* decoding is little-endian, we must byte-swap the buffer.
*/
for (i = 0; i < 16; i ++) {
rev[i] = buf[15 - i];
}
br_i15_decode_mod(b, rev, sizeof rev, P1305);
b[9] |= 0x0100;
/*
* Add the accumulator to the decoded block (modular
* addition).
*/
ctl = br_i15_add(b, a, 1);
ctl |= NOT(br_i15_sub(b, P1305, 0));
br_i15_sub(b, P1305, ctl);
/*
* Multiply by r, result is the new accumulator value.
*/
br_i15_montymul(a, b, r, P1305, P0I);
buf += 16;
len -= 16;
}
}
/*
* Byteswap a 16-byte value.
*/
static void
byteswap16(unsigned char *buf)
{
int i;
for (i = 0; i < 8; i ++) {
unsigned x;
x = buf[i];
buf[i] = buf[15 - i];
buf[15 - i] = x;
}
}
/* see bearssl_block.h */
void
br_poly1305_i15_run(const void *key, const void *iv,
void *data, size_t len, const void *aad, size_t aad_len,
void *tag, br_chacha20_run ichacha, int encrypt)
{
unsigned char pkey[32], foot[16];
uint16_t t[10], r[10], acc[10];
/*
* Compute the MAC key. The 'r' value is the first 16 bytes of
* pkey[].
*/
memset(pkey, 0, sizeof pkey);
ichacha(key, iv, 0, pkey, sizeof pkey);
/*
* If encrypting, ChaCha20 must run first, followed by Poly1305.
* When decrypting, the operations are reversed.
*/
if (encrypt) {
ichacha(key, iv, 1, data, len);
}
/*
* Run Poly1305. We must process the AAD, then ciphertext, then
* the footer (with the lengths). Note that the AAD and ciphertext
* are meant to be padded with zeros up to the next multiple of 16,
* and the length of the footer is 16 bytes as well.
*/
/*
* Apply the "clamping" operation on the encoded 'r' value.
*/
pkey[ 3] &= 0x0F;
pkey[ 7] &= 0x0F;
pkey[11] &= 0x0F;
pkey[15] &= 0x0F;
pkey[ 4] &= 0xFC;
pkey[ 8] &= 0xFC;
pkey[12] &= 0xFC;
/*
* Decode the clamped 'r' value. Decoding should use little-endian
* so we must byteswap the value first.
*/
byteswap16(pkey);
br_i15_decode_mod(t, pkey, 16, P1305);
/*
* Convert 'r' to Montgomery representation.
*/
br_i15_montymul(r, t, R2, P1305, P0I);
/*
* Accumulator is 0.
*/
br_i15_zero(acc, 0x8A);
/*
* Process the additional authenticated data, ciphertext, and
* footer in due order.
*/
br_enc64le(foot, (uint64_t)aad_len);
br_enc64le(foot + 8, (uint64_t)len);
poly1305_inner(acc, r, aad, aad_len);
poly1305_inner(acc, r, data, len);
poly1305_inner(acc, r, foot, sizeof foot);
/*
* Decode the value 's'. Again, a byteswap is needed.
*/
byteswap16(pkey + 16);
br_i15_decode_mod(t, pkey + 16, 16, P1305);
/*
* Add the value 's' to the accumulator. That addition is done
* modulo 2^128, so we just ignore the carry.
*/
br_i15_add(acc, t, 1);
/*
* Encode the result (128 low bits) to the tag. Encoding should
* be little-endian.
*/
br_i15_encode(tag, 16, acc);
byteswap16(tag);
/*
* If decrypting, then ChaCha20 runs _after_ Poly1305.
*/
if (!encrypt) {
ichacha(key, iv, 1, data, len);
}
}

View File

@ -30,8 +30,6 @@ 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

View File

@ -28,9 +28,5 @@
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
}

View File

@ -30,8 +30,6 @@ 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

View File

@ -30,8 +30,6 @@ 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

View File

@ -30,8 +30,6 @@ 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

View File

@ -30,8 +30,6 @@ 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

View File

@ -30,8 +30,6 @@ 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

View File

@ -28,9 +28,5 @@
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
}

View File

@ -30,8 +30,6 @@ 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

View File

@ -30,8 +30,6 @@ 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

View File

@ -30,8 +30,6 @@ 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

View File

@ -28,9 +28,5 @@
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
}

View File

@ -1,583 +0,0 @@
/*
* 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 "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[] = {
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;
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;
}

Some files were not shown because too many files have changed in this diff Show More