import FIREFOX_52_6_0esr_RELEASE from mozilla-esr52 hg repo

This commit is contained in:
Roy Tam 2018-01-19 03:59:58 +08:00
commit dcd9973243
150858 changed files with 23884658 additions and 0 deletions

View file

@ -0,0 +1,764 @@
#! gmake
#
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
#######################################################################
# (1) Include initial platform-independent assignments (MANDATORY). #
#######################################################################
include manifest.mn
#######################################################################
# (2) Include "global" configuration information. (OPTIONAL) #
#######################################################################
include $(CORE_DEPTH)/coreconf/config.mk
#######################################################################
# (3) Include "component" configuration information. (OPTIONAL) #
#######################################################################
#######################################################################
# (4) Include "local" platform-dependent assignments (OPTIONAL). #
#######################################################################
include config.mk
# default for all platforms
# unset this on those that have multiple freebl libraries
FREEBL_BUILD_SINGLE_SHLIB = 1
ifdef USE_64
DEFINES += -DNSS_USE_64
endif
ifdef USE_ABI32_FPU
DEFINES += -DNSS_USE_ABI32_FPU
endif
ifeq ($(FREEBL_NO_DEPEND),1)
DEFINES += -DFREEBL_NO_DEPEND
STUBS_SRCS = stubs.c
endif
ifeq ($(FREEBL_LOWHASH),1)
DEFINES += -DFREEBL_LOWHASH
LOWHASH_SRCS = nsslowhash.c
LOWHASH_EXPORTS = nsslowhash.h
MAPFILE_SOURCE = freebl_hash_vector.def
NEED_STUB_BUILD = 1
else
MAPFILE_SOURCE = freebl.def
endif
ifdef USE_STUB_BUILD
CSRCS = lowhash_vector.c
SIMPLE_OBJS = $(CSRCS:.c=$(OBJ_SUFFIX))
OBJS = $(addprefix $(OBJDIR)/$(PROG_PREFIX), $(SIMPLE_OBJS))
ALL_TRASH := $(TARGETS) $(OBJS) $(OBJDIR) LOGS TAGS $(GARBAGE) \
$(NOSUCHFILE) so_locations
MAPFILE_SOURCE = freebl_hash.def
endif
# FREEBL_USE_PRELINK
#
# Most modern version of Linux support a speed optimization scheme where an
# application called prelink modifies programs and shared libraries to quickly
# load if they fit into an already designed address space. In short, prelink
# scans the list of programs and libraries on your system, assigns them a
# predefined space in the the address space, then provides the fixups to the
# library.
#
# The modification of the shared library is correctly detected by the freebl
# FIPS checksum scheme where we check a signed hash of the library against the
# library itself.
#
# The prelink command itself can reverse the process of modification and output
# the prestine shared library as it was before prelink made it's changes.
# This option tells Freebl could use prelink to output the original copy of
# the shared library before prelink modified it.
#
# FREEBL_PRELINK_COMMAND
#
# This is an optional environment variable which can override the default
# prelink command. It could be used on systems that did something similiar to
# prelink but used a different command and syntax. The only requirement is the
# program must take the library as the last argument, the program must output
# the original library to standard out, and the program does not need to take
# any quoted or imbedded spaces in its arguments (except the path to the
# library itself, which can have imbedded spaces or special characters).
#
ifdef FREEBL_USE_PRELINK
DEFINES += -DFREEBL_USE_PRELINK
ifdef LINUX
DEFINES += -D__GNU_SOURCE=1
endif
endif
ifdef NSS_NO_INIT_SUPPORT
DEFINES += -DNSS_NO_INIT_SUPPORT
endif
ifdef FREEBL_PRELINK_COMMAND
DEFINES +=-DFREEBL_PRELINK_COMMAND=\"$(FREEBL_PRELINK_COMMAND)\"
endif
# NSS_X86 means the target is a 32-bits x86 CPU architecture
# NSS_X64 means the target is a 64-bits 64 CPU architecture
# NSS_X86_OR_X64 means the target is either x86 or x64
ifeq (,$(filter-out i386 x386 x86 x86_64,$(CPU_ARCH)))
DEFINES += -DNSS_X86_OR_X64
ifneq (,$(USE_64)$(USE_X32))
DEFINES += -DNSS_X64
else
DEFINES += -DNSS_X86
endif
endif
ifeq ($(OS_TARGET),OSF1)
DEFINES += -DMP_ASSEMBLY_MULTIPLY -DMP_NO_MP_WORD
MPI_SRCS += mpvalpha.c
endif
ifeq (OS2,$(OS_TARGET))
ASFILES = mpi_x86_os2.s
DEFINES += -DMP_ASSEMBLY_MULTIPLY -DMP_ASSEMBLY_SQUARE
DEFINES += -DMP_ASSEMBLY_DIV_2DX1D
DEFINES += -DMP_USE_UINT_DIGIT -DMP_NO_MP_WORD
DEFINES += -DMP_IS_LITTLE_ENDIAN
endif
ifeq (,$(filter-out WINNT WIN95,$(OS_TARGET)))
ifndef USE_64
# 32-bit Windows
ifdef NS_USE_GCC
# Ideally, we want to use assembler
# ASFILES = mpi_x86.s
# DEFINES += -DMP_ASSEMBLY_MULTIPLY -DMP_ASSEMBLY_SQUARE \
# -DMP_ASSEMBLY_DIV_2DX1D
# but we haven't figured out how to make it work, so we are not
# using assembler right now.
ASFILES =
DEFINES += -DMP_NO_MP_WORD -DMP_USE_UINT_DIGIT
else
# MSVC
MPI_SRCS += mpi_x86_asm.c
DEFINES += -DMP_ASSEMBLY_MULTIPLY -DMP_ASSEMBLY_SQUARE
DEFINES += -DMP_ASSEMBLY_DIV_2DX1D -DMP_USE_UINT_DIGIT -DMP_NO_MP_WORD
ifdef BUILD_OPT
OPTIMIZER += -Ox # maximum optimization for freebl
endif
# The Intel AES assembly code requires Visual C++ 2010.
# if $(_MSC_VER) >= 1600 (Visual C++ 2010)
ifeq ($(firstword $(sort $(_MSC_VER) 1600)),1600)
DEFINES += -DUSE_HW_AES -DINTEL_GCM
ASFILES += intel-aes-x86-masm.asm intel-gcm-x86-masm.asm
EXTRA_SRCS += intel-gcm-wrap.c
ifeq ($(CLANG_CL),1)
INTEL_GCM_CLANG_CL = 1
endif
endif
endif
else
# -DMP_NO_MP_WORD
DEFINES += -DMP_IS_LITTLE_ENDIAN
ifdef NS_USE_GCC
# Ideally, we should use amd64 assembly code, but it's not yet mingw-w64
# compatible.
else
# MSVC
ifdef BUILD_OPT
OPTIMIZER += -Ox # maximum optimization for freebl
endif
ASFILES = arcfour-amd64-masm.asm mpi_amd64_masm.asm mp_comba_amd64_masm.asm
DEFINES += -DNSS_BEVAND_ARCFOUR -DMPI_AMD64 -DMP_ASSEMBLY_MULTIPLY
DEFINES += -DNSS_USE_COMBA
# The Intel AES assembly code requires Visual C++ 2010 (10.0). The _xgetbv
# compiler intrinsic function requires Visual C++ 2010 (10.0) SP1.
ifeq ($(_MSC_VER_GE_10SP1),1)
DEFINES += -DUSE_HW_AES -DINTEL_GCM
ASFILES += intel-aes-x64-masm.asm intel-gcm-x64-masm.asm
EXTRA_SRCS += intel-gcm-wrap.c
ifeq ($(CLANG_CL),1)
INTEL_GCM_CLANG_CL = 1
endif
endif
MPI_SRCS += mpi_amd64.c
endif
endif
endif
ifeq ($(OS_TARGET),IRIX)
ifeq ($(USE_N32),1)
ASFILES = mpi_mips.s
ifeq ($(NS_USE_GCC),1)
ASFLAGS = -Wp,-P -Wp,-traditional -O -mips3
else
ASFLAGS = -O -OPT:Olimit=4000 -dollar -fullwarn -xansi -n32 -mips3
endif
DEFINES += -DMP_ASSEMBLY_MULTIPLY -DMP_ASSEMBLY_SQUARE
DEFINES += -DMP_USE_UINT_DIGIT
endif
endif
ifeq ($(OS_TARGET),Darwin)
ifeq ($(CPU_ARCH),x86)
ASFILES = mpi_sse2.s
DEFINES += -DMP_USE_UINT_DIGIT
DEFINES += -DMP_ASSEMBLY_MULTIPLY -DMP_ASSEMBLY_SQUARE
DEFINES += -DMP_ASSEMBLY_DIV_2DX1D
endif
endif # Darwin
ifeq ($(OS_TARGET),Linux)
ifeq ($(CPU_ARCH),x86_64)
ASFILES = arcfour-amd64-gas.s mpi_amd64_gas.s
ASFLAGS += -fPIC -Wa,--noexecstack
DEFINES += -DNSS_BEVAND_ARCFOUR -DMPI_AMD64 -DMP_ASSEMBLY_MULTIPLY
DEFINES += -DNSS_USE_COMBA
DEFINES += -DMP_IS_LITTLE_ENDIAN
# DEFINES += -DMPI_AMD64_ADD
# comment the next four lines to turn off Intel HW acceleration.
DEFINES += -DUSE_HW_AES -DINTEL_GCM
ASFILES += intel-aes.s intel-gcm.s
EXTRA_SRCS += intel-gcm-wrap.c
INTEL_GCM = 1
MPI_SRCS += mpi_amd64.c mp_comba.c
endif
ifeq ($(CPU_ARCH),x86)
ASFILES = mpi_x86.s
DEFINES += -DMP_ASSEMBLY_MULTIPLY -DMP_ASSEMBLY_SQUARE
DEFINES += -DMP_ASSEMBLY_DIV_2DX1D -DMP_USE_UINT_DIGIT
DEFINES += -DMP_IS_LITTLE_ENDIAN
# The floating point ECC code doesn't work on Linux x86 (bug 311432).
#ECL_USE_FP = 1
endif
ifeq ($(CPU_ARCH),arm)
DEFINES += -DMP_ASSEMBLY_MULTIPLY -DMP_ASSEMBLY_SQUARE
DEFINES += -DMP_USE_UINT_DIGIT
DEFINES += -DSHA_NO_LONG_LONG # avoid 64-bit arithmetic in SHA512
MPI_SRCS += mpi_arm.c
endif
ifeq ($(CPU_ARCH),ppc)
ifdef USE_64
DEFINES += -DNSS_NO_INIT_SUPPORT
endif # USE_64
endif # ppc
endif # Linux
ifeq ($(OS_TARGET),AIX)
DEFINES += -DMP_USE_UINT_DIGIT
ifndef USE_64
DEFINES += -DMP_NO_DIV_WORD -DMP_NO_ADD_WORD -DMP_NO_SUB_WORD
endif
endif # AIX
ifeq ($(OS_TARGET), HP-UX)
ifneq ($(OS_TEST), ia64)
# PA-RISC
ASFILES += ret_cr16.s
ifndef USE_64
FREEBL_BUILD_SINGLE_SHLIB =
HAVE_ABI32_INT32 = 1
HAVE_ABI32_FPU = 1
endif
ifdef FREEBL_CHILD_BUILD
ifdef USE_ABI32_INT32
# build for DA1.1 (HP PA 1.1) 32-bit ABI build with 32-bit arithmetic
DEFINES += -DMP_USE_UINT_DIGIT -DMP_NO_MP_WORD
DEFINES += -DSHA_NO_LONG_LONG # avoid 64-bit arithmetic in SHA512
else
ifdef USE_64
# this builds for DA2.0W (HP PA 2.0 Wide), the LP64 ABI, using 64-bit digits
MPI_SRCS += mpi_hp.c
ASFILES += hpma512.s hppa20.s
DEFINES += -DMP_ASSEMBLY_MULTIPLY -DMP_ASSEMBLY_SQUARE
else
# this builds for DA2.0 (HP PA 2.0 Narrow) ABI32_FPU model
# (the 32-bit ABI with 64-bit registers) using 64-bit digits
MPI_SRCS += mpi_hp.c
ASFILES += hpma512.s hppa20.s
DEFINES += -DMP_ASSEMBLY_MULTIPLY -DMP_ASSEMBLY_SQUARE
ifndef NS_USE_GCC
ARCHFLAG = -Aa +e +DA2.0 +DS2.0
endif
endif
endif
endif
endif
endif
# The blapi functions are defined not only in the freebl shared
# libraries but also in the shared libraries linked with loader.c
# (libsoftokn3.so and libssl3.so). We need to use GNU ld's
# -Bsymbolic option or the equivalent option for other linkers
# to bind the blapi function references in FREEBLVector vector
# (ldvector.c) to the blapi functions defined in the freebl
# shared libraries.
ifeq (,$(filter-out BSD_OS FreeBSD Linux NetBSD OpenBSD, $(OS_TARGET)))
MKSHLIB += -Wl,-Bsymbolic
endif
ifeq ($(OS_TARGET),SunOS)
ifdef NS_USE_GCC
ifdef GCC_USE_GNU_LD
MKSHLIB += -Wl,-Bsymbolic,-z,now,-z,text
else
MKSHLIB += -Wl,-B,symbolic,-z,now,-z,text
endif # GCC_USE_GNU_LD
else
MKSHLIB += -B symbolic -z now -z text
endif # NS_USE_GCC
# Sun's WorkShop defines v8, v8plus and v9 architectures.
# gcc on Solaris defines v8 and v9 "cpus".
# gcc's v9 is equivalent to Workshop's v8plus.
# gcc's -m64 is equivalent to Workshop's v9
# We always use Sun's assembler, which uses Sun's naming convention.
ifeq ($(CPU_ARCH),sparc)
FREEBL_BUILD_SINGLE_SHLIB=
ifdef USE_64
HAVE_ABI64_INT = 1
HAVE_ABI64_FPU = 1
else
HAVE_ABI32_FPU = 1
HAVE_ABI32_INT64 = 1
endif
SYSV_SPARC = 1
SOLARIS_AS = /usr/ccs/bin/as
#### set arch, asm, c flags
ifdef NS_USE_GCC
ifdef USE_ABI32_INT64
ARCHFLAG=-mcpu=v9 -Wa,-xarch=v8plus
SOLARIS_AS_FLAGS = -xarch=v8plus -K PIC
endif
ifdef USE_ABI32_FPU
ARCHFLAG=-mcpu=v9 -Wa,-xarch=v8plusa
SOLARIS_AS_FLAGS = -xarch=v8plusa -K PIC
endif # USE_ABI32_FPU
ifdef USE_ABI64_INT
# this builds for Sparc v9a pure 64-bit architecture
ARCHFLAG += -mcpu=v9 -Wa,-xarch=v9
SOLARIS_AS_FLAGS = -xarch=v9 -K PIC
endif
ifdef USE_ABI64_FPU
# this builds for Sparc v9a pure 64-bit architecture
# It uses floating point, and 32-bit word size
ARCHFLAG += -mcpu=v9 -Wa,-xarch=v9a
SOLARIS_AS_FLAGS = -xarch=v9a -K PIC
endif
else # NS_USE_GCC
# FPU_TARGET_OPTIMIZER specifies the target processor and cache
# properties of the ABI32_FPU and ABI64_FPU architectures for use
# by the optimizer.
ifeq (,$(findstring Sun WorkShop 6,$(shell $(CC) -V 2>&1)))
# if the compiler is not Forte 6
FPU_TARGET_OPTIMIZER = -xcache=64/32/4:1024/64/4 -xchip=ultra3
else
# Forte 6 C compiler generates incorrect code for rijndael.c
# if -xchip=ultra3 is used (Bugzilla bug 333925). So we revert
# to what we used in NSS 3.10.
FPU_TARGET_OPTIMIZER = -xchip=ultra2
endif
ifdef USE_ABI32_INT64
# this builds for Sparc v8+a ABI32_FPU architecture, 64-bit registers,
# 32-bit ABI, it uses 64-bit words, integer arithmetic,
# no FPU (non-VIS cpus).
# These flags were suggested by the compiler group for building
# with SunStudio 10.
ifdef BUILD_OPT
SOL_CFLAGS += -xO4
endif
SOL_CFLAGS += -xtarget=generic
ARCHFLAG = -xarch=v8plus
SOLARIS_AS_FLAGS = -xarch=v8plus -K PIC
endif
ifdef USE_ABI32_FPU
# this builds for Sparc v8+a ABI32_FPU architecture, 64-bit registers,
# 32-bit ABI, it uses FPU code, and 32-bit word size.
# these flags were determined by running cc -### -fast and copying
# the generated flag settings
SOL_CFLAGS += -fsingle -xmemalign=8s
ifdef BUILD_OPT
SOL_CFLAGS += -D__MATHERR_ERRNO_DONTCARE -fsimple=1
SOL_CFLAGS += -xalias_level=basic -xbuiltin=%all
SOL_CFLAGS += $(FPU_TARGET_OPTIMIZER) -xdepend
SOL_CFLAGS += -xlibmil -xO5
endif
ARCHFLAG = -xarch=v8plusa
SOLARIS_AS_FLAGS = -xarch=v8plusa -K PIC
endif
ifdef USE_ABI64_INT
# this builds for Sparc v9a pure 64-bit architecture,
# no FPU (non-VIS cpus). For building with SunStudio 10.
ifdef BUILD_OPT
SOL_CFLAGS += -xO4
endif
SOL_CFLAGS += -xtarget=generic
ARCHFLAG = -xarch=v9
SOLARIS_AS_FLAGS = -xarch=v9 -K PIC
endif
ifdef USE_ABI64_FPU
# this builds for Sparc v9a pure 64-bit architecture
# It uses floating point, and 32-bit word size.
# See comment for USE_ABI32_FPU.
SOL_CFLAGS += -fsingle -xmemalign=8s
ifdef BUILD_OPT
SOL_CFLAGS += -D__MATHERR_ERRNO_DONTCARE -fsimple=1
SOL_CFLAGS += -xalias_level=basic -xbuiltin=%all
SOL_CFLAGS += $(FPU_TARGET_OPTIMIZER) -xdepend
SOL_CFLAGS += -xlibmil -xO5
endif
ARCHFLAG = -xarch=v9a
SOLARIS_AS_FLAGS = -xarch=v9a -K PIC
endif
endif # NS_USE_GCC
### set flags for both GCC and Sun cc
ifdef USE_ABI32_INT64
# this builds for Sparc v8+a ABI32_FPU architecture, 64-bit registers,
# 32-bit ABI, it uses 64-bit words, integer arithmetic, no FPU
# best times are with no MP_ flags specified
endif
ifdef USE_ABI32_FPU
# this builds for Sparc v8+a ABI32_FPU architecture, 64-bit registers,
# 32-bit ABI, it uses FPU code, and 32-bit word size
MPI_SRCS += mpi_sparc.c
ASFILES = mpv_sparcv8.s montmulfv8.s
DEFINES += -DMP_NO_MP_WORD -DMP_USE_UINT_DIGIT -DMP_ASSEMBLY_MULTIPLY
DEFINES += -DMP_USING_MONT_MULF -DMP_MONT_USE_MP_MUL
ECL_USE_FP = 1
endif
ifdef USE_ABI64_INT
# this builds for Sparc v9a pure 64-bit architecture
# best times are with no MP_ flags specified
endif
ifdef USE_ABI64_FPU
# this builds for Sparc v9a pure 64-bit architecture
# It uses floating point, and 32-bit word size
MPI_SRCS += mpi_sparc.c
ASFILES = mpv_sparcv9.s montmulfv9.s
DEFINES += -DMP_NO_MP_WORD -DMP_USE_UINT_DIGIT -DMP_ASSEMBLY_MULTIPLY
DEFINES += -DMP_USING_MONT_MULF -DMP_MONT_USE_MP_MUL
ECL_USE_FP = 1
endif
else
# Solaris for non-sparc family CPUs
ifdef NS_USE_GCC
LD = gcc
AS = gcc
ASFLAGS = -x assembler-with-cpp
endif
ifeq ($(USE_64),1)
# Solaris for AMD64
ifdef NS_USE_GCC
ASFILES = arcfour-amd64-gas.s mpi_amd64_gas.s
ASFLAGS += -march=opteron -m64 -fPIC
MPI_SRCS += mp_comba.c
# comment the next four lines to turn off Intel HW acceleration
ASFILES += intel-gcm.s
EXTRA_SRCS += intel-gcm-wrap.c
INTEL_GCM = 1
DEFINES += -DINTEL_GCM
else
ASFILES = arcfour-amd64-sun.s mpi_amd64_sun.s sha-fast-amd64-sun.s
ASFILES += mp_comba_amd64_sun.s mpcpucache_amd64.s
ASFLAGS += -xarch=generic64 -K PIC
SOL_CFLAGS += -xprefetch=no
SHA_SRCS =
MPCPU_SRCS =
# Intel acceleration for GCM does not build currently with Studio
endif
DEFINES += -DNSS_BEVAND_ARCFOUR -DMPI_AMD64 -DMP_ASSEMBLY_MULTIPLY
DEFINES += -DNSS_USE_COMBA -DMP_IS_LITTLE_ENDIAN
# comment the next two lines to turn off Intel HW acceleration
DEFINES += -DUSE_HW_AES
ASFILES += intel-aes.s
MPI_SRCS += mpi_amd64.c
else
# Solaris x86
DEFINES += -DMP_USE_UINT_DIGIT
DEFINES += -DMP_ASSEMBLY_MULTIPLY -DMP_ASSEMBLY_SQUARE
DEFINES += -DMP_ASSEMBLY_DIV_2DX1D
ASFILES = mpi_i86pc.s
ifndef NS_USE_GCC
MPCPU_SRCS =
ASFILES += mpcpucache_x86.s
endif
endif
endif # Solaris for non-sparc family CPUs
endif # target == SunOS
ifndef NSS_DISABLE_ECC
ifdef ECL_USE_FP
#enable floating point ECC code
DEFINES += -DECL_USE_FP
ECL_SRCS += ecp_fp160.c ecp_fp192.c ecp_fp224.c ecp_fp.c
ECL_HDRS += ecp_fp.h
endif
endif
# poly1305-donna-x64-sse2-incremental-source.c requires __int128 support
# in GCC 4.6.0.
ifdef USE_64
ifdef CC_IS_CLANG
HAVE_INT128_SUPPORT = 1
DEFINES += -DHAVE_INT128_SUPPORT
else ifeq (1,$(CC_IS_GCC))
ifneq (,$(filter 4.6 4.7 4.8 4.9,$(word 1,$(GCC_VERSION)).$(word 2,$(GCC_VERSION))))
HAVE_INT128_SUPPORT = 1
DEFINES += -DHAVE_INT128_SUPPORT
endif
ifeq (,$(filter 0 1 2 3 4,$(word 1,$(GCC_VERSION))))
HAVE_INT128_SUPPORT = 1
DEFINES += -DHAVE_INT128_SUPPORT
endif
endif
endif
ifndef NSS_DISABLE_CHACHAPOLY
ifeq ($(CPU_ARCH),x86_64)
ifdef HAVE_INT128_SUPPORT
EXTRA_SRCS += poly1305-donna-x64-sse2-incremental-source.c
else
EXTRA_SRCS += poly1305.c
endif
ifneq (1,$(CC_IS_GCC))
EXTRA_SRCS += chacha20.c
else
EXTRA_SRCS += chacha20_vec.c
endif
else
EXTRA_SRCS += poly1305.c
EXTRA_SRCS += chacha20.c
endif # x86_64
endif # NSS_DISABLE_CHACHAPOLY
ifeq (,$(filter-out i386 x386 x86 x86_64,$(CPU_ARCH)))
# All intel architectures get the 64 bit version
# With custom uint128 if necessary (faster than generic 32 bit version).
ECL_SRCS += curve25519_64.c
else
# All non intel architectures get the generic 32 bit implementation (slow!)
ECL_SRCS += curve25519_32.c
endif
ifndef HAVE_INT128_SUPPORT
ECL_SRCS += uint128.c
endif
#######################################################################
# (5) Execute "global" rules. (OPTIONAL) #
#######################################################################
include $(CORE_DEPTH)/coreconf/rules.mk
#######################################################################
# (6) Execute "component" rules. (OPTIONAL) #
#######################################################################
#######################################################################
# (7) Execute "local" rules. (OPTIONAL). #
#######################################################################
export:: private_export
rijndael_tables:
$(CC) -o $(OBJDIR)/make_rijndael_tab rijndael_tables.c \
$(DEFINES) $(INCLUDES) $(OBJDIR)/libfreebl.a
$(OBJDIR)/make_rijndael_tab
vpath %.h mpi ecl
vpath %.c mpi ecl
vpath %.S mpi ecl
vpath %.s mpi ecl
vpath %.asm mpi ecl
INCLUDES += -Impi -Iecl
DEFINES += -DMP_API_COMPATIBLE
MPI_USERS = dh.c pqg.c dsa.c rsa.c ec.c
MPI_OBJS = $(addprefix $(OBJDIR)/$(PROG_PREFIX), $(MPI_SRCS:.c=$(OBJ_SUFFIX)))
MPI_OBJS += $(addprefix $(OBJDIR)/$(PROG_PREFIX), $(MPI_USERS:.c=$(OBJ_SUFFIX)))
$(MPI_OBJS): $(MPI_HDRS)
ECL_USERS = ec.c
ECL_OBJS = $(addprefix $(OBJDIR)/$(PROG_PREFIX), $(ECL_SRCS:.c=$(OBJ_SUFFIX)) $(ECL_ASM_SRCS:$(ASM_SUFFIX)=$(OBJ_SUFFIX)))
ECL_OBJS += $(addprefix $(OBJDIR)/$(PROG_PREFIX), $(ECL_USERS:.c=$(OBJ_SUFFIX)))
$(ECL_OBJS): $(ECL_HDRS)
$(OBJDIR)/sysrand$(OBJ_SUFFIX): sysrand.c unix_rand.c win_rand.c os2_rand.c
$(OBJDIR)/$(PROG_PREFIX)mpprime$(OBJ_SUFFIX): primes.c
$(OBJDIR)/ldvector$(OBJ_SUFFIX) $(OBJDIR)/loader$(OBJ_SUFFIX) : loader.h
ifeq ($(SYSV_SPARC),1)
$(OBJDIR)/mpv_sparcv8.o $(OBJDIR)/mpv_sparcv8x.o $(OBJDIR)/montmulfv8.o : $(OBJDIR)/%.o : %.s
@$(MAKE_OBJDIR)
$(SOLARIS_AS) -o $@ $(SOLARIS_AS_FLAGS) $<
$(OBJDIR)/mpv_sparcv9.o $(OBJDIR)/montmulfv9.o : $(OBJDIR)/%.o : %.s
@$(MAKE_OBJDIR)
$(SOLARIS_AS) -o $@ $(SOLARIS_AS_FLAGS) $<
$(OBJDIR)/mpmontg.o: mpmontg.c montmulf.h
endif
ifndef FREEBL_CHILD_BUILD
# Parent build. This is where we decide which shared libraries to build
ifdef FREEBL_BUILD_SINGLE_SHLIB
################### Single shared lib stuff #########################
SINGLE_SHLIB_DIR = $(OBJDIR)/$(OS_TARGET)_SINGLE_SHLIB
ALL_TRASH += $(SINGLE_SHLIB_DIR)
$(SINGLE_SHLIB_DIR):
-mkdir -p $(SINGLE_SHLIB_DIR)
release_md libs:: $(SINGLE_SHLIB_DIR)
$(MAKE) FREEBL_CHILD_BUILD=1 \
OBJDIR=$(SINGLE_SHLIB_DIR) $@
######################## common stuff #########################
endif
ifdef NEED_STUB_BUILD
SINGLE_SHLIB_DIR = $(OBJDIR)/$(OS_TARGET)_SINGLE_SHLIB
ALL_TRASH += $(SINGLE_SHLIB_DIR)
$(SINGLE_SHLIB_DIR):
-mkdir $(SINGLE_SHLIB_DIR)
release_md libs:: $(SINGLE_SHLIB_DIR)
$(MAKE) FREEBL_CHILD_BUILD=1 USE_STUB_BUILD=1 \
OBJDIR=$(SINGLE_SHLIB_DIR) $@
endif
# multiple shared libraries
######################## ABI32_FPU stuff #########################
ifdef HAVE_ABI32_FPU
ABI32_FPU_DIR = $(OBJDIR)/$(OS_TARGET)_ABI32_FPU
ALL_TRASH += $(ABI32_FPU_DIR)
$(ABI32_FPU_DIR):
-mkdir $(ABI32_FPU_DIR)
release_md libs:: $(ABI32_FPU_DIR)
$(MAKE) FREEBL_CHILD_BUILD=1 USE_ABI32_FPU=1 \
OBJDIR=$(ABI32_FPU_DIR) $@
endif
######################## ABI32_INT32 stuff #########################
ifdef HAVE_ABI32_INT32
ABI32_INT32_DIR = $(OBJDIR)/$(OS_TARGET)_ABI32_INT32
ALL_TRASH += $(ABI32_INT32_DIR)
$(ABI32_INT32_DIR):
-mkdir $(ABI32_INT32_DIR)
release_md libs:: $(ABI32_INT32_DIR)
$(MAKE) FREEBL_CHILD_BUILD=1 USE_ABI32_INT32=1 \
OBJDIR=$(ABI32_INT32_DIR) $@
endif
######################## ABI32_INT64 stuff #########################
ifdef HAVE_ABI32_INT64
ABI32_INT64_DIR = $(OBJDIR)/$(OS_TARGET)_ABI32_INT64
ALL_TRASH += $(ABI32_INT64_DIR)
$(ABI32_INT64_DIR):
-mkdir $(ABI32_INT64_DIR)
release_md libs:: $(ABI32_INT64_DIR)
$(MAKE) FREEBL_CHILD_BUILD=1 USE_ABI32_INT64=1\
OBJDIR=$(ABI32_INT64_DIR) $@
endif
######################## END of 32-bit stuff #########################
# above is 32-bit builds, below is 64-bit builds
######################## ABI64_FPU stuff #########################
ifdef HAVE_ABI64_FPU
ABI64_FPU_DIR = $(OBJDIR)/$(OS_TARGET)_ABI64_FPU
ALL_TRASH += $(ABI64_FPU_DIR)
$(ABI64_FPU_DIR):
-mkdir $(ABI64_FPU_DIR)
release_md libs:: $(ABI64_FPU_DIR)
$(MAKE) FREEBL_CHILD_BUILD=1 USE_ABI64_FPU=1 \
OBJDIR=$(ABI64_FPU_DIR) $@
endif
######################## ABI64_INT stuff #########################
ifdef HAVE_ABI64_INT
ABI64_INT_DIR = $(OBJDIR)/$(OS_TARGET)_ABI64_INT
ALL_TRASH += $(ABI64_INT_DIR)
$(ABI64_INT_DIR):
-mkdir $(ABI64_INT_DIR)
release_md libs:: $(ABI64_INT_DIR)
$(MAKE) FREEBL_CHILD_BUILD=1 USE_ABI64_INT=1 \
OBJDIR=$(ABI64_INT_DIR) $@
endif
endif # FREEBL_CHILD_BUILD
# Bugzilla Bug 333917: the non-x86 code in desblapi.c seems to violate
# ANSI C's strict aliasing rules.
ifeq ($(OS_TARGET),Linux)
ifneq ($(CPU_ARCH),x86)
$(OBJDIR)/$(PROG_PREFIX)desblapi$(OBJ_SUFFIX): desblapi.c
@$(MAKE_OBJDIR)
ifdef NEED_ABSOLUTE_PATH
$(CC) -o $@ -c $(CFLAGS) -fno-strict-aliasing $(call core_abspath,$<)
else
$(CC) -o $@ -c $(CFLAGS) -fno-strict-aliasing $<
endif
endif
endif
ifdef INTEL_GCM
#
# GCM binary needs -mssse3
#
$(OBJDIR)/$(PROG_PREFIX)intel-gcm-wrap$(OBJ_SUFFIX): CFLAGS += -mssse3
# The integrated assembler in Clang 3.2 does not support % in the
# expression of a .set directive. intel-gcm.s uses .set to give
# symbolic names to registers, for example,
# .set Htbl, %rdi
# So we can't use Clang's integrated assembler with intel-gcm.s.
ifdef CC_IS_CLANG
$(OBJDIR)/$(PROG_PREFIX)intel-gcm$(OBJ_SUFFIX): CFLAGS += -no-integrated-as
endif
endif
ifdef INTEL_GCM_CLANG_CL
#
# clang-cl needs -mssse3
#
$(OBJDIR)/$(PROG_PREFIX)intel-gcm-wrap$(OBJ_SUFFIX): CFLAGS += -mssse3
endif

View file

@ -0,0 +1,389 @@
/*
* aeskeywrap.c - implement AES Key Wrap algorithm from RFC 3394
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifdef FREEBL_NO_DEPEND
#include "stubs.h"
#endif
#include "prcpucfg.h"
#if defined(IS_LITTLE_ENDIAN) || defined(SHA_NO_LONG_LONG)
#define BIG_ENDIAN_WITH_64_BIT_REGISTERS 0
#else
#define BIG_ENDIAN_WITH_64_BIT_REGISTERS 1
#endif
#include "prtypes.h" /* for PRUintXX */
#include "secport.h" /* for PORT_XXX */
#include "secerr.h"
#include "blapi.h" /* for AES_ functions */
#include "rijndael.h"
struct AESKeyWrapContextStr {
unsigned char iv[AES_KEY_WRAP_IV_BYTES];
AESContext aescx;
};
/******************************************/
/*
** AES key wrap algorithm, RFC 3394
*/
AESKeyWrapContext *
AESKeyWrap_AllocateContext(void)
{
AESKeyWrapContext *cx = PORT_New(AESKeyWrapContext);
return cx;
}
SECStatus
AESKeyWrap_InitContext(AESKeyWrapContext *cx,
const unsigned char *key,
unsigned int keylen,
const unsigned char *iv,
int x1,
unsigned int encrypt,
unsigned int x2)
{
SECStatus rv = SECFailure;
if (!cx) {
PORT_SetError(SEC_ERROR_INVALID_ARGS);
return SECFailure;
}
if (iv) {
memcpy(cx->iv, iv, sizeof cx->iv);
} else {
memset(cx->iv, 0xA6, sizeof cx->iv);
}
rv = AES_InitContext(&cx->aescx, key, keylen, NULL, NSS_AES, encrypt,
AES_BLOCK_SIZE);
return rv;
}
/*
** Create a new AES context suitable for AES encryption/decryption.
** "key" raw key data
** "keylen" the number of bytes of key data (16, 24, or 32)
*/
extern AESKeyWrapContext *
AESKeyWrap_CreateContext(const unsigned char *key, const unsigned char *iv,
int encrypt, unsigned int keylen)
{
SECStatus rv;
AESKeyWrapContext *cx = AESKeyWrap_AllocateContext();
if (!cx)
return NULL; /* error is already set */
rv = AESKeyWrap_InitContext(cx, key, keylen, iv, 0, encrypt, 0);
if (rv != SECSuccess) {
PORT_Free(cx);
cx = NULL; /* error should already be set */
}
return cx;
}
/*
** Destroy a AES KeyWrap context.
** "cx" the context
** "freeit" if PR_TRUE then free the object as well as its sub-objects
*/
extern void
AESKeyWrap_DestroyContext(AESKeyWrapContext *cx, PRBool freeit)
{
if (cx) {
AES_DestroyContext(&cx->aescx, PR_FALSE);
/* memset(cx, 0, sizeof *cx); */
if (freeit)
PORT_Free(cx);
}
}
#if !BIG_ENDIAN_WITH_64_BIT_REGISTERS
/* The AES Key Wrap algorithm has 64-bit values that are ALWAYS big-endian
** (Most significant byte first) in memory. The only ALU operations done
** on them are increment, decrement, and XOR. So, on little-endian CPUs,
** and on CPUs that lack 64-bit registers, these big-endian 64-bit operations
** are simulated in the following code. This is thought to be faster and
** simpler than trying to convert the data to little-endian and back.
*/
/* A and T point to two 64-bit values stored most signficant byte first
** (big endian). This function increments the 64-bit value T, and then
** XORs it with A, changing A.
*/
static void
increment_and_xor(unsigned char *A, unsigned char *T)
{
if (!++T[7])
if (!++T[6])
if (!++T[5])
if (!++T[4])
if (!++T[3])
if (!++T[2])
if (!++T[1])
++T[0];
A[0] ^= T[0];
A[1] ^= T[1];
A[2] ^= T[2];
A[3] ^= T[3];
A[4] ^= T[4];
A[5] ^= T[5];
A[6] ^= T[6];
A[7] ^= T[7];
}
/* A and T point to two 64-bit values stored most signficant byte first
** (big endian). This function XORs T with A, giving a new A, then
** decrements the 64-bit value T.
*/
static void
xor_and_decrement(PRUint64 *A, PRUint64 *T)
{
unsigned char *TP = (unsigned char *)T;
const PRUint64 mask = 0xFF;
*A = ((*A & mask << 56) ^ (*T & mask << 56)) |
((*A & mask << 48) ^ (*T & mask << 48)) |
((*A & mask << 40) ^ (*T & mask << 40)) |
((*A & mask << 32) ^ (*T & mask << 32)) |
((*A & mask << 24) ^ (*T & mask << 23)) |
((*A & mask << 16) ^ (*T & mask << 16)) |
((*A & mask << 8) ^ (*T & mask << 8)) |
((*A & mask) ^ (*T & mask));
if (!TP[7]--)
if (!TP[6]--)
if (!TP[5]--)
if (!TP[4]--)
if (!TP[3]--)
if (!TP[2]--)
if (!TP[1]--)
TP[0]--;
}
/* Given an unsigned long t (in host byte order), store this value as a
** 64-bit big-endian value (MSB first) in *pt.
*/
static void
set_t(unsigned char *pt, unsigned long t)
{
pt[7] = (unsigned char)t;
t >>= 8;
pt[6] = (unsigned char)t;
t >>= 8;
pt[5] = (unsigned char)t;
t >>= 8;
pt[4] = (unsigned char)t;
t >>= 8;
pt[3] = (unsigned char)t;
t >>= 8;
pt[2] = (unsigned char)t;
t >>= 8;
pt[1] = (unsigned char)t;
t >>= 8;
pt[0] = (unsigned char)t;
}
#endif
/*
** Perform AES key wrap.
** "cx" the context
** "output" the output buffer to store the encrypted data.
** "outputLen" how much data is stored in "output". Set by the routine
** after some data is stored in output.
** "maxOutputLen" the maximum amount of data that can ever be
** stored in "output"
** "input" the input data
** "inputLen" the amount of input data
*/
extern SECStatus
AESKeyWrap_Encrypt(AESKeyWrapContext *cx, unsigned char *output,
unsigned int *pOutputLen, unsigned int maxOutputLen,
const unsigned char *input, unsigned int inputLen)
{
PRUint64 *R = NULL;
unsigned int nBlocks;
unsigned int i, j;
unsigned int aesLen = AES_BLOCK_SIZE;
unsigned int outLen = inputLen + AES_KEY_WRAP_BLOCK_SIZE;
SECStatus s = SECFailure;
/* These PRUint64s are ALWAYS big endian, regardless of CPU orientation. */
PRUint64 t;
PRUint64 B[2];
#define A B[0]
/* Check args */
if (!inputLen || 0 != inputLen % AES_KEY_WRAP_BLOCK_SIZE) {
PORT_SetError(SEC_ERROR_INPUT_LEN);
return s;
}
#ifdef maybe
if (!output && pOutputLen) { /* caller is asking for output size */
*pOutputLen = outLen;
return SECSuccess;
}
#endif
if (maxOutputLen < outLen) {
PORT_SetError(SEC_ERROR_OUTPUT_LEN);
return s;
}
if (cx == NULL || output == NULL || input == NULL) {
PORT_SetError(SEC_ERROR_INVALID_ARGS);
return s;
}
nBlocks = inputLen / AES_KEY_WRAP_BLOCK_SIZE;
R = PORT_NewArray(PRUint64, nBlocks + 1);
if (!R)
return s; /* error is already set. */
/*
** 1) Initialize variables.
*/
memcpy(&A, cx->iv, AES_KEY_WRAP_IV_BYTES);
memcpy(&R[1], input, inputLen);
#if BIG_ENDIAN_WITH_64_BIT_REGISTERS
t = 0;
#else
memset(&t, 0, sizeof t);
#endif
/*
** 2) Calculate intermediate values.
*/
for (j = 0; j < 6; ++j) {
for (i = 1; i <= nBlocks; ++i) {
B[1] = R[i];
s = AES_Encrypt(&cx->aescx, (unsigned char *)B, &aesLen,
sizeof B, (unsigned char *)B, sizeof B);
if (s != SECSuccess)
break;
R[i] = B[1];
/* here, increment t and XOR A with t (in big endian order); */
#if BIG_ENDIAN_WITH_64_BIT_REGISTERS
A ^= ++t;
#else
increment_and_xor((unsigned char *)&A, (unsigned char *)&t);
#endif
}
}
/*
** 3) Output the results.
*/
if (s == SECSuccess) {
R[0] = A;
memcpy(output, &R[0], outLen);
if (pOutputLen)
*pOutputLen = outLen;
} else if (pOutputLen) {
*pOutputLen = 0;
}
PORT_ZFree(R, outLen);
return s;
}
#undef A
/*
** Perform AES key unwrap.
** "cx" the context
** "output" the output buffer to store the decrypted data.
** "outputLen" how much data is stored in "output". Set by the routine
** after some data is stored in output.
** "maxOutputLen" the maximum amount of data that can ever be
** stored in "output"
** "input" the input data
** "inputLen" the amount of input data
*/
extern SECStatus
AESKeyWrap_Decrypt(AESKeyWrapContext *cx, unsigned char *output,
unsigned int *pOutputLen, unsigned int maxOutputLen,
const unsigned char *input, unsigned int inputLen)
{
PRUint64 *R = NULL;
unsigned int nBlocks;
unsigned int i, j;
unsigned int aesLen = AES_BLOCK_SIZE;
unsigned int outLen;
SECStatus s = SECFailure;
/* These PRUint64s are ALWAYS big endian, regardless of CPU orientation. */
PRUint64 t;
PRUint64 B[2];
/* Check args */
if (inputLen < 3 * AES_KEY_WRAP_BLOCK_SIZE ||
0 != inputLen % AES_KEY_WRAP_BLOCK_SIZE) {
PORT_SetError(SEC_ERROR_INPUT_LEN);
return s;
}
outLen = inputLen - AES_KEY_WRAP_BLOCK_SIZE;
#ifdef maybe
if (!output && pOutputLen) { /* caller is asking for output size */
*pOutputLen = outLen;
return SECSuccess;
}
#endif
if (maxOutputLen < outLen) {
PORT_SetError(SEC_ERROR_OUTPUT_LEN);
return s;
}
if (cx == NULL || output == NULL || input == NULL) {
PORT_SetError(SEC_ERROR_INVALID_ARGS);
return s;
}
nBlocks = inputLen / AES_KEY_WRAP_BLOCK_SIZE;
R = PORT_NewArray(PRUint64, nBlocks);
if (!R)
return s; /* error is already set. */
nBlocks--;
/*
** 1) Initialize variables.
*/
memcpy(&R[0], input, inputLen);
B[0] = R[0];
#if BIG_ENDIAN_WITH_64_BIT_REGISTERS
t = 6UL * nBlocks;
#else
set_t((unsigned char *)&t, 6UL * nBlocks);
#endif
/*
** 2) Calculate intermediate values.
*/
for (j = 0; j < 6; ++j) {
for (i = nBlocks; i; --i) {
/* here, XOR A with t (in big endian order) and decrement t; */
#if BIG_ENDIAN_WITH_64_BIT_REGISTERS
B[0] ^= t--;
#else
xor_and_decrement(&B[0], &t);
#endif
B[1] = R[i];
s = AES_Decrypt(&cx->aescx, (unsigned char *)B, &aesLen,
sizeof B, (unsigned char *)B, sizeof B);
if (s != SECSuccess)
break;
R[i] = B[1];
}
}
/*
** 3) Output the results.
*/
if (s == SECSuccess) {
int bad = memcmp(&B[0], cx->iv, AES_KEY_WRAP_IV_BYTES);
if (!bad) {
memcpy(output, &R[1], outLen);
if (pOutputLen)
*pOutputLen = outLen;
} else {
s = SECFailure;
PORT_SetError(SEC_ERROR_BAD_DATA);
if (pOutputLen)
*pOutputLen = 0;
}
} else if (pOutputLen) {
*pOutputLen = 0;
}
PORT_ZFree(R, inputLen);
return s;
}
#undef A

View file

@ -0,0 +1,509 @@
/*
* alg2268.c - implementation of the algorithm in RFC 2268
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifdef FREEBL_NO_DEPEND
#include "stubs.h"
#endif
#include "blapi.h"
#include "blapii.h"
#include "secerr.h"
#ifdef XP_UNIX_XXX
#include <stddef.h> /* for ptrdiff_t */
#endif
/*
** RC2 symmetric block cypher
*/
typedef SECStatus(rc2Func)(RC2Context *cx, unsigned char *output,
const unsigned char *input, unsigned int inputLen);
/* forward declarations */
static rc2Func rc2_EncryptECB;
static rc2Func rc2_DecryptECB;
static rc2Func rc2_EncryptCBC;
static rc2Func rc2_DecryptCBC;
typedef union {
PRUint32 l[2];
PRUint16 s[4];
PRUint8 b[8];
} RC2Block;
struct RC2ContextStr {
union {
PRUint8 Kb[128];
PRUint16 Kw[64];
} u;
RC2Block iv;
rc2Func *enc;
rc2Func *dec;
};
#define B u.Kb
#define K u.Kw
#define BYTESWAP(x) ((x) << 8 | (x) >> 8)
#define SWAPK(i) cx->K[i] = (tmpS = cx->K[i], BYTESWAP(tmpS))
#define RC2_BLOCK_SIZE 8
#define LOAD_HARD(R) \
R[0] = (PRUint16)input[1] << 8 | input[0]; \
R[1] = (PRUint16)input[3] << 8 | input[2]; \
R[2] = (PRUint16)input[5] << 8 | input[4]; \
R[3] = (PRUint16)input[7] << 8 | input[6];
#define LOAD_EASY(R) \
R[0] = ((PRUint16 *)input)[0]; \
R[1] = ((PRUint16 *)input)[1]; \
R[2] = ((PRUint16 *)input)[2]; \
R[3] = ((PRUint16 *)input)[3];
#define STORE_HARD(R) \
output[0] = (PRUint8)(R[0]); \
output[1] = (PRUint8)(R[0] >> 8); \
output[2] = (PRUint8)(R[1]); \
output[3] = (PRUint8)(R[1] >> 8); \
output[4] = (PRUint8)(R[2]); \
output[5] = (PRUint8)(R[2] >> 8); \
output[6] = (PRUint8)(R[3]); \
output[7] = (PRUint8)(R[3] >> 8);
#define STORE_EASY(R) \
((PRUint16 *)output)[0] = R[0]; \
((PRUint16 *)output)[1] = R[1]; \
((PRUint16 *)output)[2] = R[2]; \
((PRUint16 *)output)[3] = R[3];
#if defined(NSS_X86_OR_X64)
#define LOAD(R) LOAD_EASY(R)
#define STORE(R) STORE_EASY(R)
#elif !defined(IS_LITTLE_ENDIAN)
#define LOAD(R) LOAD_HARD(R)
#define STORE(R) STORE_HARD(R)
#else
#define LOAD(R) \
if ((ptrdiff_t)input & 1) { \
LOAD_HARD(R) \
} else { \
LOAD_EASY(R) \
}
#define STORE(R) \
if ((ptrdiff_t)input & 1) { \
STORE_HARD(R) \
} else { \
STORE_EASY(R) \
}
#endif
static const PRUint8 S[256] = {
0331, 0170, 0371, 0304, 0031, 0335, 0265, 0355, 0050, 0351, 0375, 0171, 0112, 0240, 0330, 0235,
0306, 0176, 0067, 0203, 0053, 0166, 0123, 0216, 0142, 0114, 0144, 0210, 0104, 0213, 0373, 0242,
0027, 0232, 0131, 0365, 0207, 0263, 0117, 0023, 0141, 0105, 0155, 0215, 0011, 0201, 0175, 0062,
0275, 0217, 0100, 0353, 0206, 0267, 0173, 0013, 0360, 0225, 0041, 0042, 0134, 0153, 0116, 0202,
0124, 0326, 0145, 0223, 0316, 0140, 0262, 0034, 0163, 0126, 0300, 0024, 0247, 0214, 0361, 0334,
0022, 0165, 0312, 0037, 0073, 0276, 0344, 0321, 0102, 0075, 0324, 0060, 0243, 0074, 0266, 0046,
0157, 0277, 0016, 0332, 0106, 0151, 0007, 0127, 0047, 0362, 0035, 0233, 0274, 0224, 0103, 0003,
0370, 0021, 0307, 0366, 0220, 0357, 0076, 0347, 0006, 0303, 0325, 0057, 0310, 0146, 0036, 0327,
0010, 0350, 0352, 0336, 0200, 0122, 0356, 0367, 0204, 0252, 0162, 0254, 0065, 0115, 0152, 0052,
0226, 0032, 0322, 0161, 0132, 0025, 0111, 0164, 0113, 0237, 0320, 0136, 0004, 0030, 0244, 0354,
0302, 0340, 0101, 0156, 0017, 0121, 0313, 0314, 0044, 0221, 0257, 0120, 0241, 0364, 0160, 0071,
0231, 0174, 0072, 0205, 0043, 0270, 0264, 0172, 0374, 0002, 0066, 0133, 0045, 0125, 0227, 0061,
0055, 0135, 0372, 0230, 0343, 0212, 0222, 0256, 0005, 0337, 0051, 0020, 0147, 0154, 0272, 0311,
0323, 0000, 0346, 0317, 0341, 0236, 0250, 0054, 0143, 0026, 0001, 0077, 0130, 0342, 0211, 0251,
0015, 0070, 0064, 0033, 0253, 0063, 0377, 0260, 0273, 0110, 0014, 0137, 0271, 0261, 0315, 0056,
0305, 0363, 0333, 0107, 0345, 0245, 0234, 0167, 0012, 0246, 0040, 0150, 0376, 0177, 0301, 0255
};
RC2Context *
RC2_AllocateContext(void)
{
return PORT_ZNew(RC2Context);
}
SECStatus
RC2_InitContext(RC2Context *cx, const unsigned char *key, unsigned int len,
const unsigned char *input, int mode, unsigned int efLen8,
unsigned int unused)
{
PRUint8 *L, *L2;
int i;
#if !defined(IS_LITTLE_ENDIAN)
PRUint16 tmpS;
#endif
PRUint8 tmpB;
if (!key || !cx || !len || len > (sizeof cx->B) ||
efLen8 > (sizeof cx->B)) {
PORT_SetError(SEC_ERROR_INVALID_ARGS);
return SECFailure;
}
if (mode == NSS_RC2) {
/* groovy */
} else if (mode == NSS_RC2_CBC) {
if (!input) {
PORT_SetError(SEC_ERROR_INVALID_ARGS);
return SECFailure;
}
} else {
PORT_SetError(SEC_ERROR_INVALID_ARGS);
return SECFailure;
}
if (mode == NSS_RC2_CBC) {
cx->enc = &rc2_EncryptCBC;
cx->dec = &rc2_DecryptCBC;
LOAD(cx->iv.s);
} else {
cx->enc = &rc2_EncryptECB;
cx->dec = &rc2_DecryptECB;
}
/* Step 0. Copy key into table. */
memcpy(cx->B, key, len);
/* Step 1. Compute all values to the right of the key. */
L2 = cx->B;
L = L2 + len;
tmpB = L[-1];
for (i = (sizeof cx->B) - len; i > 0; --i) {
*L++ = tmpB = S[(PRUint8)(tmpB + *L2++)];
}
/* step 2. Adjust left most byte of effective key. */
i = (sizeof cx->B) - efLen8;
L = cx->B + i;
*L = tmpB = S[*L]; /* mask is always 0xff */
/* step 3. Recompute all values to the left of effective key. */
L2 = --L + efLen8;
while (L >= cx->B) {
*L-- = tmpB = S[tmpB ^ *L2--];
}
#if !defined(IS_LITTLE_ENDIAN)
for (i = 63; i >= 0; --i) {
SWAPK(i); /* candidate for unrolling */
}
#endif
return SECSuccess;
}
/*
** Create a new RC2 context suitable for RC2 encryption/decryption.
** "key" raw key data
** "len" the number of bytes of key data
** "iv" is the CBC initialization vector (if mode is NSS_RC2_CBC)
** "mode" one of NSS_RC2 or NSS_RC2_CBC
** "effectiveKeyLen" in bytes, not bits.
**
** When mode is set to NSS_RC2_CBC the RC2 cipher is run in "cipher block
** chaining" mode.
*/
RC2Context *
RC2_CreateContext(const unsigned char *key, unsigned int len,
const unsigned char *iv, int mode, unsigned efLen8)
{
RC2Context *cx = PORT_ZNew(RC2Context);
if (cx) {
SECStatus rv = RC2_InitContext(cx, key, len, iv, mode, efLen8, 0);
if (rv != SECSuccess) {
RC2_DestroyContext(cx, PR_TRUE);
cx = NULL;
}
}
return cx;
}
/*
** Destroy an RC2 encryption/decryption context.
** "cx" the context
** "freeit" if PR_TRUE then free the object as well as its sub-objects
*/
void
RC2_DestroyContext(RC2Context *cx, PRBool freeit)
{
if (cx) {
memset(cx, 0, sizeof *cx);
if (freeit) {
PORT_Free(cx);
}
}
}
#define ROL(x, k) (x << k | x >> (16 - k))
#define MIX(j) \
R0 = R0 + cx->K[4 * j + 0] + (R3 & R2) + (~R3 & R1); \
R0 = ROL(R0, 1); \
R1 = R1 + cx->K[4 * j + 1] + (R0 & R3) + (~R0 & R2); \
R1 = ROL(R1, 2); \
R2 = R2 + cx->K[4 * j + 2] + (R1 & R0) + (~R1 & R3); \
R2 = ROL(R2, 3); \
R3 = R3 + cx->K[4 * j + 3] + (R2 & R1) + (~R2 & R0); \
R3 = ROL(R3, 5)
#define MASH \
R0 = R0 + cx->K[R3 & 63]; \
R1 = R1 + cx->K[R0 & 63]; \
R2 = R2 + cx->K[R1 & 63]; \
R3 = R3 + cx->K[R2 & 63]
/* Encrypt one block */
static void
rc2_Encrypt1Block(RC2Context *cx, RC2Block *output, RC2Block *input)
{
register PRUint16 R0, R1, R2, R3;
/* step 1. Initialize input. */
R0 = input->s[0];
R1 = input->s[1];
R2 = input->s[2];
R3 = input->s[3];
/* step 2. Expand Key (already done, in context) */
/* step 3. j = 0 */
/* step 4. Perform 5 mixing rounds. */
MIX(0);
MIX(1);
MIX(2);
MIX(3);
MIX(4);
/* step 5. Perform 1 mashing round. */
MASH;
/* step 6. Perform 6 mixing rounds. */
MIX(5);
MIX(6);
MIX(7);
MIX(8);
MIX(9);
MIX(10);
/* step 7. Perform 1 mashing round. */
MASH;
/* step 8. Perform 5 mixing rounds. */
MIX(11);
MIX(12);
MIX(13);
MIX(14);
MIX(15);
/* output results */
output->s[0] = R0;
output->s[1] = R1;
output->s[2] = R2;
output->s[3] = R3;
}
#define ROR(x, k) (x >> k | x << (16 - k))
#define R_MIX(j) \
R3 = ROR(R3, 5); \
R3 = R3 - cx->K[4 * j + 3] - (R2 & R1) - (~R2 & R0); \
R2 = ROR(R2, 3); \
R2 = R2 - cx->K[4 * j + 2] - (R1 & R0) - (~R1 & R3); \
R1 = ROR(R1, 2); \
R1 = R1 - cx->K[4 * j + 1] - (R0 & R3) - (~R0 & R2); \
R0 = ROR(R0, 1); \
R0 = R0 - cx->K[4 * j + 0] - (R3 & R2) - (~R3 & R1)
#define R_MASH \
R3 = R3 - cx->K[R2 & 63]; \
R2 = R2 - cx->K[R1 & 63]; \
R1 = R1 - cx->K[R0 & 63]; \
R0 = R0 - cx->K[R3 & 63]
/* Encrypt one block */
static void
rc2_Decrypt1Block(RC2Context *cx, RC2Block *output, RC2Block *input)
{
register PRUint16 R0, R1, R2, R3;
/* step 1. Initialize input. */
R0 = input->s[0];
R1 = input->s[1];
R2 = input->s[2];
R3 = input->s[3];
/* step 2. Expand Key (already done, in context) */
/* step 3. j = 63 */
/* step 4. Perform 5 r_mixing rounds. */
R_MIX(15);
R_MIX(14);
R_MIX(13);
R_MIX(12);
R_MIX(11);
/* step 5. Perform 1 r_mashing round. */
R_MASH;
/* step 6. Perform 6 r_mixing rounds. */
R_MIX(10);
R_MIX(9);
R_MIX(8);
R_MIX(7);
R_MIX(6);
R_MIX(5);
/* step 7. Perform 1 r_mashing round. */
R_MASH;
/* step 8. Perform 5 r_mixing rounds. */
R_MIX(4);
R_MIX(3);
R_MIX(2);
R_MIX(1);
R_MIX(0);
/* output results */
output->s[0] = R0;
output->s[1] = R1;
output->s[2] = R2;
output->s[3] = R3;
}
static SECStatus NO_SANITIZE_ALIGNMENT
rc2_EncryptECB(RC2Context *cx, unsigned char *output,
const unsigned char *input, unsigned int inputLen)
{
RC2Block iBlock;
while (inputLen > 0) {
LOAD(iBlock.s)
rc2_Encrypt1Block(cx, &iBlock, &iBlock);
STORE(iBlock.s)
output += RC2_BLOCK_SIZE;
input += RC2_BLOCK_SIZE;
inputLen -= RC2_BLOCK_SIZE;
}
return SECSuccess;
}
static SECStatus NO_SANITIZE_ALIGNMENT
rc2_DecryptECB(RC2Context *cx, unsigned char *output,
const unsigned char *input, unsigned int inputLen)
{
RC2Block iBlock;
while (inputLen > 0) {
LOAD(iBlock.s)
rc2_Decrypt1Block(cx, &iBlock, &iBlock);
STORE(iBlock.s)
output += RC2_BLOCK_SIZE;
input += RC2_BLOCK_SIZE;
inputLen -= RC2_BLOCK_SIZE;
}
return SECSuccess;
}
static SECStatus NO_SANITIZE_ALIGNMENT
rc2_EncryptCBC(RC2Context *cx, unsigned char *output,
const unsigned char *input, unsigned int inputLen)
{
RC2Block iBlock;
while (inputLen > 0) {
LOAD(iBlock.s)
iBlock.l[0] ^= cx->iv.l[0];
iBlock.l[1] ^= cx->iv.l[1];
rc2_Encrypt1Block(cx, &iBlock, &iBlock);
cx->iv = iBlock;
STORE(iBlock.s)
output += RC2_BLOCK_SIZE;
input += RC2_BLOCK_SIZE;
inputLen -= RC2_BLOCK_SIZE;
}
return SECSuccess;
}
static SECStatus NO_SANITIZE_ALIGNMENT
rc2_DecryptCBC(RC2Context *cx, unsigned char *output,
const unsigned char *input, unsigned int inputLen)
{
RC2Block iBlock;
RC2Block oBlock;
while (inputLen > 0) {
LOAD(iBlock.s)
rc2_Decrypt1Block(cx, &oBlock, &iBlock);
oBlock.l[0] ^= cx->iv.l[0];
oBlock.l[1] ^= cx->iv.l[1];
cx->iv = iBlock;
STORE(oBlock.s)
output += RC2_BLOCK_SIZE;
input += RC2_BLOCK_SIZE;
inputLen -= RC2_BLOCK_SIZE;
}
return SECSuccess;
}
/*
** Perform RC2 encryption.
** "cx" the context
** "output" the output buffer to store the encrypted data.
** "outputLen" how much data is stored in "output". Set by the routine
** after some data is stored in output.
** "maxOutputLen" the maximum amount of data that can ever be
** stored in "output"
** "input" the input data
** "inputLen" the amount of input data
*/
SECStatus
RC2_Encrypt(RC2Context *cx, unsigned char *output,
unsigned int *outputLen, unsigned int maxOutputLen,
const unsigned char *input, unsigned int inputLen)
{
SECStatus rv = SECSuccess;
if (inputLen) {
if (inputLen % RC2_BLOCK_SIZE) {
PORT_SetError(SEC_ERROR_INPUT_LEN);
return SECFailure;
}
if (maxOutputLen < inputLen) {
PORT_SetError(SEC_ERROR_OUTPUT_LEN);
return SECFailure;
}
rv = (*cx->enc)(cx, output, input, inputLen);
}
if (rv == SECSuccess) {
*outputLen = inputLen;
}
return rv;
}
/*
** Perform RC2 decryption.
** "cx" the context
** "output" the output buffer to store the decrypted data.
** "outputLen" how much data is stored in "output". Set by the routine
** after some data is stored in output.
** "maxOutputLen" the maximum amount of data that can ever be
** stored in "output"
** "input" the input data
** "inputLen" the amount of input data
*/
SECStatus
RC2_Decrypt(RC2Context *cx, unsigned char *output,
unsigned int *outputLen, unsigned int maxOutputLen,
const unsigned char *input, unsigned int inputLen)
{
SECStatus rv = SECSuccess;
if (inputLen) {
if (inputLen % RC2_BLOCK_SIZE) {
PORT_SetError(SEC_ERROR_INPUT_LEN);
return SECFailure;
}
if (maxOutputLen < inputLen) {
PORT_SetError(SEC_ERROR_OUTPUT_LEN);
return SECFailure;
}
rv = (*cx->dec)(cx, output, input, inputLen);
}
if (rv == SECSuccess) {
*outputLen = inputLen;
}
return rv;
}

View file

@ -0,0 +1,165 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifdef FREEBL_NO_DEPEND
#include "stubs.h"
#endif
#include "secport.h"
#include "hasht.h"
#include "blapit.h"
#include "alghmac.h"
#include "secerr.h"
#define HMAC_PAD_SIZE HASH_BLOCK_LENGTH_MAX
struct HMACContextStr {
void *hash;
const SECHashObject *hashobj;
PRBool wasAllocated;
unsigned char ipad[HMAC_PAD_SIZE];
unsigned char opad[HMAC_PAD_SIZE];
};
void
HMAC_Destroy(HMACContext *cx, PRBool freeit)
{
if (cx == NULL)
return;
PORT_Assert(!freeit == !cx->wasAllocated);
if (cx->hash != NULL) {
cx->hashobj->destroy(cx->hash, PR_TRUE);
PORT_Memset(cx, 0, sizeof *cx);
}
if (freeit)
PORT_Free(cx);
}
SECStatus
HMAC_Init(HMACContext *cx, const SECHashObject *hash_obj,
const unsigned char *secret, unsigned int secret_len, PRBool isFIPS)
{
unsigned int i;
unsigned char hashed_secret[HASH_LENGTH_MAX];
/* required by FIPS 198 Section 3 */
if (isFIPS && secret_len < hash_obj->length / 2) {
PORT_SetError(SEC_ERROR_INVALID_ARGS);
return SECFailure;
}
if (cx == NULL) {
PORT_SetError(SEC_ERROR_INVALID_ARGS);
return SECFailure;
}
cx->wasAllocated = PR_FALSE;
cx->hashobj = hash_obj;
cx->hash = cx->hashobj->create();
if (cx->hash == NULL)
goto loser;
if (secret_len > cx->hashobj->blocklength) {
cx->hashobj->begin(cx->hash);
cx->hashobj->update(cx->hash, secret, secret_len);
PORT_Assert(cx->hashobj->length <= sizeof hashed_secret);
cx->hashobj->end(cx->hash, hashed_secret, &secret_len,
sizeof hashed_secret);
if (secret_len != cx->hashobj->length) {
PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
goto loser;
}
secret = (const unsigned char *)&hashed_secret[0];
}
PORT_Memset(cx->ipad, 0x36, cx->hashobj->blocklength);
PORT_Memset(cx->opad, 0x5c, cx->hashobj->blocklength);
/* fold secret into padding */
for (i = 0; i < secret_len; i++) {
cx->ipad[i] ^= secret[i];
cx->opad[i] ^= secret[i];
}
PORT_Memset(hashed_secret, 0, sizeof hashed_secret);
return SECSuccess;
loser:
PORT_Memset(hashed_secret, 0, sizeof hashed_secret);
if (cx->hash != NULL)
cx->hashobj->destroy(cx->hash, PR_TRUE);
return SECFailure;
}
HMACContext *
HMAC_Create(const SECHashObject *hash_obj, const unsigned char *secret,
unsigned int secret_len, PRBool isFIPS)
{
SECStatus rv;
HMACContext *cx = PORT_ZNew(HMACContext);
if (cx == NULL)
return NULL;
rv = HMAC_Init(cx, hash_obj, secret, secret_len, isFIPS);
cx->wasAllocated = PR_TRUE;
if (rv != SECSuccess) {
PORT_Free(cx); /* contains no secret info */
cx = NULL;
}
return cx;
}
void
HMAC_Begin(HMACContext *cx)
{
/* start inner hash */
cx->hashobj->begin(cx->hash);
cx->hashobj->update(cx->hash, cx->ipad, cx->hashobj->blocklength);
}
void
HMAC_Update(HMACContext *cx, const unsigned char *data, unsigned int data_len)
{
cx->hashobj->update(cx->hash, data, data_len);
}
SECStatus
HMAC_Finish(HMACContext *cx, unsigned char *result, unsigned int *result_len,
unsigned int max_result_len)
{
if (max_result_len < cx->hashobj->length) {
PORT_SetError(SEC_ERROR_INVALID_ARGS);
return SECFailure;
}
cx->hashobj->end(cx->hash, result, result_len, max_result_len);
if (*result_len != cx->hashobj->length)
return SECFailure;
cx->hashobj->begin(cx->hash);
cx->hashobj->update(cx->hash, cx->opad, cx->hashobj->blocklength);
cx->hashobj->update(cx->hash, result, *result_len);
cx->hashobj->end(cx->hash, result, result_len, max_result_len);
return SECSuccess;
}
HMACContext *
HMAC_Clone(HMACContext *cx)
{
HMACContext *newcx;
newcx = (HMACContext *)PORT_ZAlloc(sizeof(HMACContext));
if (newcx == NULL)
goto loser;
newcx->wasAllocated = PR_TRUE;
newcx->hashobj = cx->hashobj;
newcx->hash = cx->hashobj->clone(cx->hash);
if (newcx->hash == NULL)
goto loser;
PORT_Memcpy(newcx->ipad, cx->ipad, cx->hashobj->blocklength);
PORT_Memcpy(newcx->opad, cx->opad, cx->hashobj->blocklength);
return newcx;
loser:
HMAC_Destroy(newcx, PR_TRUE);
return NULL;
}

View file

@ -0,0 +1,64 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef _ALGHMAC_H_
#define _ALGHMAC_H_
typedef struct HMACContextStr HMACContext;
SEC_BEGIN_PROTOS
/* destroy HMAC context */
extern void
HMAC_Destroy(HMACContext *cx, PRBool freeit);
/* create HMAC context
* hash_obj hash object from SECRawHashObjects[]
* secret the secret with which the HMAC is performed.
* secret_len the length of the secret.
* isFIPS true if conforming to FIPS 198.
*
* NULL is returned if an error occurs.
*/
extern HMACContext *
HMAC_Create(const SECHashObject *hash_obj, const unsigned char *secret,
unsigned int secret_len, PRBool isFIPS);
/* like HMAC_Create, except caller allocates HMACContext. */
SECStatus
HMAC_Init(HMACContext *cx, const SECHashObject *hash_obj,
const unsigned char *secret, unsigned int secret_len, PRBool isFIPS);
/* reset HMAC for a fresh round */
extern void
HMAC_Begin(HMACContext *cx);
/* update HMAC
* cx HMAC Context
* data the data to perform HMAC on
* data_len the length of the data to process
*/
extern void
HMAC_Update(HMACContext *cx, const unsigned char *data, unsigned int data_len);
/* Finish HMAC -- place the results within result
* cx HMAC context
* result buffer for resulting hmac'd data
* result_len where the resultant hmac length is stored
* max_result_len maximum possible length that can be stored in result
*/
extern SECStatus
HMAC_Finish(HMACContext *cx, unsigned char *result, unsigned int *result_len,
unsigned int max_result_len);
/* clone a copy of the HMAC state. this is usefult when you would
* need to keep a running hmac but also need to extract portions
* partway through the process.
*/
extern HMACContext *
HMAC_Clone(HMACContext *cx);
SEC_END_PROTOS
#endif

View file

@ -0,0 +1,87 @@
/*
* arcfive.c - stubs for RC5 - NOT a working implementation!
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifdef FREEBL_NO_DEPEND
#include "stubs.h"
#endif
#include "blapi.h"
#include "prerror.h"
/******************************************/
/*
** RC5 symmetric block cypher -- 64-bit block size
*/
/*
** Create a new RC5 context suitable for RC5 encryption/decryption.
** "key" raw key data
** "len" the number of bytes of key data
** "iv" is the CBC initialization vector (if mode is NSS_RC5_CBC)
** "mode" one of NSS_RC5 or NSS_RC5_CBC
**
** When mode is set to NSS_RC5_CBC the RC5 cipher is run in "cipher block
** chaining" mode.
*/
RC5Context *
RC5_CreateContext(const SECItem *key, unsigned int rounds,
unsigned int wordSize, const unsigned char *iv, int mode)
{
PORT_SetError(PR_NOT_IMPLEMENTED_ERROR);
return NULL;
}
/*
** Destroy an RC5 encryption/decryption context.
** "cx" the context
** "freeit" if PR_TRUE then free the object as well as its sub-objects
*/
void
RC5_DestroyContext(RC5Context *cx, PRBool freeit)
{
PORT_SetError(PR_NOT_IMPLEMENTED_ERROR);
}
/*
** Perform RC5 encryption.
** "cx" the context
** "output" the output buffer to store the encrypted data.
** "outputLen" how much data is stored in "output". Set by the routine
** after some data is stored in output.
** "maxOutputLen" the maximum amount of data that can ever be
** stored in "output"
** "input" the input data
** "inputLen" the amount of input data
*/
SECStatus
RC5_Encrypt(RC5Context *cx, unsigned char *output, unsigned int *outputLen,
unsigned int maxOutputLen,
const unsigned char *input, unsigned int inputLen)
{
PORT_SetError(PR_NOT_IMPLEMENTED_ERROR);
return SECFailure;
}
/*
** Perform RC5 decryption.
** "cx" the context
** "output" the output buffer to store the decrypted data.
** "outputLen" how much data is stored in "output". Set by the routine
** after some data is stored in output.
** "maxOutputLen" the maximum amount of data that can ever be
** stored in "output"
** "input" the input data
** "inputLen" the amount of input data
*/
SECStatus
RC5_Decrypt(RC5Context *cx, unsigned char *output, unsigned int *outputLen,
unsigned int maxOutputLen,
const unsigned char *input, unsigned int inputLen)
{
PORT_SetError(PR_NOT_IMPLEMENTED_ERROR);
return SECFailure;
}

View file

@ -0,0 +1,88 @@
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
# ** ARCFOUR implementation optimized for AMD64.
# **
# ** The throughput achieved by this code is about 320 MBytes/sec, on
# ** a 1.8 GHz AMD Opteron (rev C0) processor.
.text
.align 16
.globl ARCFOUR
.type ARCFOUR,@function
ARCFOUR:
pushq %rbp
pushq %rbx
movq %rdi, %rbp # key = ARG(key)
movq %rsi, %rbx # rbx = ARG(len)
movq %rdx, %rsi # in = ARG(in)
movq %rcx, %rdi # out = ARG(out)
movq (%rbp), %rcx # x = key->x
movq 8(%rbp), %rdx # y = key->y
addq $16, %rbp # d = key->data
incq %rcx # x++
andq $255, %rcx # x &= 0xff
leaq -8(%rbx,%rsi), %rbx # rbx = in+len-8
movq %rbx, %r9 # tmp = in+len-8
movq 0(%rbp,%rcx,8), %rax # tx = d[x]
cmpq %rsi, %rbx # cmp in with in+len-8
jl .Lend # jump if (in+len-8 < in)
.Lstart:
addq $8, %rsi # increment in
addq $8, %rdi # increment out
# generate the next 8 bytes of the rc4 stream into %r8
movq $8, %r11 # byte counter
1: addb %al, %dl # y += tx
movl 0(%rbp,%rdx,8), %ebx # ty = d[y]
movl %ebx, 0(%rbp,%rcx,8) # d[x] = ty
addb %al, %bl # val = ty + tx
movl %eax, 0(%rbp,%rdx,8) # d[y] = tx
incb %cl # x++ (NEXT ROUND)
movl 0(%rbp,%rcx,8), %eax # tx = d[x] (NEXT ROUND)
movb 0(%rbp,%rbx,8), %r8b # val = d[val]
decb %r11b
rorq $8, %r8 # (ror does not change ZF)
jnz 1b
# xor 8 bytes
xorq -8(%rsi), %r8
cmpq %r9, %rsi # cmp in+len-8 with in
movq %r8, -8(%rdi)
jle .Lstart # jump if (in <= in+len-8)
.Lend:
addq $8, %r9 # tmp = in+len
# handle the last bytes, one by one
1: cmpq %rsi, %r9 # cmp in with in+len
jle .Lfinished # jump if (in+len <= in)
addb %al, %dl # y += tx
movl 0(%rbp,%rdx,8), %ebx # ty = d[y]
movl %ebx, 0(%rbp,%rcx,8) # d[x] = ty
addb %al, %bl # val = ty + tx
movl %eax, 0(%rbp,%rdx,8) # d[y] = tx
incb %cl # x++ (NEXT ROUND)
movl 0(%rbp,%rcx,8), %eax # tx = d[x] (NEXT ROUND)
movb 0(%rbp,%rbx,8), %r8b # val = d[val]
xorb (%rsi), %r8b # xor 1 byte
movb %r8b, (%rdi)
incq %rsi # in++
incq %rdi # out++
jmp 1b
.Lfinished:
decq %rcx # x--
movb %dl, -8(%rbp) # key->y = y
movb %cl, -16(%rbp) # key->x = x
popq %rbx
popq %rbp
ret
.L_ARCFOUR_end:
.size ARCFOUR,.L_ARCFOUR_end-ARCFOUR
# Magic indicating no need for an executable stack
.section .note.GNU-stack,"",@progbits
.previous

View file

@ -0,0 +1,107 @@
; This Source Code Form is subject to the terms of the Mozilla Public
; License, v. 2.0. If a copy of the MPL was not distributed with this
; file, You can obtain one at http://mozilla.org/MPL/2.0/.
; ** ARCFOUR implementation optimized for AMD64.
; **
; ** The throughput achieved by this code is about 320 MBytes/sec, on
; ** a 1.8 GHz AMD Opteron (rev C0) processor.
.CODE
; extern void ARCFOUR(RC4Context *cx, unsigned long long inputLen,
; const unsigned char *input, unsigned char *output);
ARCFOUR PROC
push rbp
push rbx
push rsi
push rdi
mov rbp, rcx ; key = ARG(key)
mov rbx, rdx ; rbx = ARG(len)
mov rsi, r8 ; in = ARG(in)
mov rdi, r9 ; out = ARG(out)
mov rcx, [rbp] ; x = key->x
mov rdx, [rbp+8] ; y = key->y
add rbp, 16 ; d = key->data
inc rcx ; x++
and rcx, 0ffh ; x &= 0xff
lea rbx, [rbx+rsi-8] ; rbx = in+len-8
mov r9, rbx ; tmp = in+len-8
mov rax, [rbp+rcx*8] ; tx = d[x]
cmp rbx, rsi ; cmp in with in+len-8
jl Lend ; jump if (in+len-8 < in)
Lstart:
add rsi, 8 ; increment in
add rdi, 8 ; increment out
;
; generate the next 8 bytes of the rc4 stream into r8
;
mov r11, 8 ; byte counter
@@:
add dl, al ; y += tx
mov ebx, [rbp+rdx*8] ; ty = d[y]
mov [rbp+rcx*8], ebx ; d[x] = ty
add bl, al ; val = ty + tx
mov [rbp+rdx*8], eax ; d[y] = tx
inc cl ; x++ (NEXT ROUND)
mov eax, [rbp+rcx*8] ; tx = d[x] (NEXT ROUND)
mov r8b, [rbp+rbx*8] ; val = d[val]
dec r11b
ror r8, 8 ; (ror does not change ZF)
jnz @b
;
; xor 8 bytes
;
xor r8, [rsi-8]
cmp rsi, r9 ; cmp in+len-8 with in
mov [rdi-8], r8
jle Lstart
Lend:
add r9, 8 ; tmp = in+len
;
; handle the last bytes, one by one
;
@@:
cmp r9, rsi ; cmp in with in+len
jle Lfinished ; jump if (in+len <= in)
add dl, al ; y += tx
mov ebx, [rbp+rdx*8] ; ty = d[y]
mov [rbp+rcx*8], ebx ; d[x] = ty
add bl, al ; val = ty + tx
mov [rbp+rdx*8], eax ; d[y] = tx
inc cl ; x++ (NEXT ROUND)
mov eax, [rbp+rcx*8] ; tx = d[x] (NEXT ROUND)
mov r8b, [rbp+rbx*8] ; val = d[val]
xor r8b, [rsi] ; xor 1 byte
mov [rdi], r8b
inc rsi ; in++
inc rdi
jmp @b
Lfinished:
dec rcx ; x--
mov [rbp-8], dl ; key->y = y
mov [rbp-16], cl ; key->x = x
pop rdi
pop rsi
pop rbx
pop rbp
ret
ARCFOUR ENDP
END

View file

@ -0,0 +1,84 @@
/ This Source Code Form is subject to the terms of the Mozilla Public
/ License, v. 2.0. If a copy of the MPL was not distributed with this
/ file, You can obtain one at http://mozilla.org/MPL/2.0/.
/ ** ARCFOUR implementation optimized for AMD64.
/ **
/ ** The throughput achieved by this code is about 320 MBytes/sec, on
/ ** a 1.8 GHz AMD Opteron (rev C0) processor.
.text
.align 16
.globl ARCFOUR
.type ARCFOUR,@function
ARCFOUR:
pushq %rbp
pushq %rbx
movq %rdi, %rbp / key = ARG(key)
movq %rsi, %rbx / rbx = ARG(len)
movq %rdx, %rsi / in = ARG(in)
movq %rcx, %rdi / out = ARG(out)
movq (%rbp), %rcx / x = key->x
movq 8(%rbp), %rdx / y = key->y
addq $16, %rbp / d = key->data
incq %rcx / x++
andq $255, %rcx / x &= 0xff
leaq -8(%rbx,%rsi), %rbx / rbx = in+len-8
movq %rbx, %r9 / tmp = in+len-8
movq 0(%rbp,%rcx,8), %rax / tx = d[x]
cmpq %rsi, %rbx / cmp in with in+len-8
jl .Lend / jump if (in+len-8 < in)
.Lstart:
addq $8, %rsi / increment in
addq $8, %rdi / increment out
/ generate the next 8 bytes of the rc4 stream into %r8
movq $8, %r11 / byte counter
1: addb %al, %dl / y += tx
movl 0(%rbp,%rdx,8), %ebx / ty = d[y]
movl %ebx, 0(%rbp,%rcx,8) / d[x] = ty
addb %al, %bl / val = ty + tx
movl %eax, 0(%rbp,%rdx,8) / d[y] = tx
incb %cl / x++ (NEXT ROUND)
movl 0(%rbp,%rcx,8), %eax / tx = d[x] (NEXT ROUND)
movb 0(%rbp,%rbx,8), %r8b / val = d[val]
decb %r11b
rorq $8, %r8 / (ror does not change ZF)
jnz 1b
/ xor 8 bytes
xorq -8(%rsi), %r8
cmpq %r9, %rsi / cmp in+len-8 with in
movq %r8, -8(%rdi)
jle .Lstart / jump if (in <= in+len-8)
.Lend:
addq $8, %r9 / tmp = in+len
/ handle the last bytes, one by one
1: cmpq %rsi, %r9 / cmp in with in+len
jle .Lfinished / jump if (in+len <= in)
addb %al, %dl / y += tx
movl 0(%rbp,%rdx,8), %ebx / ty = d[y]
movl %ebx, 0(%rbp,%rcx,8) / d[x] = ty
addb %al, %bl / val = ty + tx
movl %eax, 0(%rbp,%rdx,8) / d[y] = tx
incb %cl / x++ (NEXT ROUND)
movl 0(%rbp,%rcx,8), %eax / tx = d[x] (NEXT ROUND)
movb 0(%rbp,%rbx,8), %r8b / val = d[val]
xorb (%rsi), %r8b / xor 1 byte
movb %r8b, (%rdi)
incq %rsi / in++
incq %rdi / out++
jmp 1b
.Lfinished:
decq %rcx / x--
movb %dl, -8(%rbp) / key->y = y
movb %cl, -16(%rbp) / key->x = x
popq %rbx
popq %rbp
ret
.L_ARCFOUR_end:
.size ARCFOUR,.L_ARCFOUR_end-ARCFOUR

View file

@ -0,0 +1,594 @@
/* arcfour.c - the arc four algorithm.
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifdef FREEBL_NO_DEPEND
#include "stubs.h"
#endif
#include "prerr.h"
#include "secerr.h"
#include "prtypes.h"
#include "blapi.h"
/* Architecture-dependent defines */
#if defined(SOLARIS) || defined(HPUX) || defined(NSS_X86) || \
defined(_WIN64)
/* Convert the byte-stream to a word-stream */
#define CONVERT_TO_WORDS
#endif
#if defined(AIX) || defined(OSF1) || defined(NSS_BEVAND_ARCFOUR)
/* Treat array variables as words, not bytes, on CPUs that take
* much longer to write bytes than to write words, or when using
* assembler code that required it.
*/
#define USE_WORD
#endif
#if defined(IS_64) || defined(NSS_BEVAND_ARCFOUR)
typedef PRUint64 WORD;
#else
typedef PRUint32 WORD;
#endif
#define WORDSIZE sizeof(WORD)
#if defined(USE_WORD)
typedef WORD Stype;
#else
typedef PRUint8 Stype;
#endif
#define ARCFOUR_STATE_SIZE 256
#define MASK1BYTE (WORD)(0xff)
#define SWAP(a, b) \
tmp = a; \
a = b; \
b = tmp;
/*
* State information for stream cipher.
*/
struct RC4ContextStr {
#if defined(NSS_ARCFOUR_IJ_B4_S) || defined(NSS_BEVAND_ARCFOUR)
Stype i;
Stype j;
Stype S[ARCFOUR_STATE_SIZE];
#else
Stype S[ARCFOUR_STATE_SIZE];
Stype i;
Stype j;
#endif
};
/*
* array indices [0..255] to initialize cx->S array (faster than loop).
*/
static const Stype Kinit[256] = {
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27,
0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f,
0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f,
0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47,
0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f,
0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57,
0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f,
0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67,
0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f,
0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77,
0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f,
0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87,
0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f,
0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97,
0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f,
0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7,
0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf,
0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7,
0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf,
0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7,
0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf,
0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7,
0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf,
0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7,
0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef,
0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7,
0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff
};
RC4Context *
RC4_AllocateContext(void)
{
return PORT_ZNew(RC4Context);
}
SECStatus
RC4_InitContext(RC4Context *cx, const unsigned char *key, unsigned int len,
const unsigned char *unused1, int unused2,
unsigned int unused3, unsigned int unused4)
{
unsigned int i;
PRUint8 j, tmp;
PRUint8 K[256];
PRUint8 *L;
/* verify the key length. */
PORT_Assert(len > 0 && len < ARCFOUR_STATE_SIZE);
if (len == 0 || len >= ARCFOUR_STATE_SIZE) {
PORT_SetError(SEC_ERROR_BAD_KEY);
return SECFailure;
}
if (cx == NULL) {
PORT_SetError(SEC_ERROR_INVALID_ARGS);
return SECFailure;
}
/* Initialize the state using array indices. */
memcpy(cx->S, Kinit, sizeof cx->S);
/* Fill in K repeatedly with values from key. */
L = K;
for (i = sizeof K; i > len; i -= len) {
memcpy(L, key, len);
L += len;
}
memcpy(L, key, i);
/* Stir the state of the generator. At this point it is assumed
* that the key is the size of the state buffer. If this is not
* the case, the key bytes are repeated to fill the buffer.
*/
j = 0;
#define ARCFOUR_STATE_STIR(ii) \
j = j + cx->S[ii] + K[ii]; \
SWAP(cx->S[ii], cx->S[j]);
for (i = 0; i < ARCFOUR_STATE_SIZE; i++) {
ARCFOUR_STATE_STIR(i);
}
cx->i = 0;
cx->j = 0;
return SECSuccess;
}
/*
* Initialize a new generator.
*/
RC4Context *
RC4_CreateContext(const unsigned char *key, int len)
{
RC4Context *cx = RC4_AllocateContext();
if (cx) {
SECStatus rv = RC4_InitContext(cx, key, len, NULL, 0, 0, 0);
if (rv != SECSuccess) {
PORT_ZFree(cx, sizeof(*cx));
cx = NULL;
}
}
return cx;
}
void
RC4_DestroyContext(RC4Context *cx, PRBool freeit)
{
if (freeit)
PORT_ZFree(cx, sizeof(*cx));
}
#if defined(NSS_BEVAND_ARCFOUR)
extern void ARCFOUR(RC4Context *cx, WORD inputLen,
const unsigned char *input, unsigned char *output);
#else
/*
* Generate the next byte in the stream.
*/
#define ARCFOUR_NEXT_BYTE() \
tmpSi = cx->S[++tmpi]; \
tmpj += tmpSi; \
tmpSj = cx->S[tmpj]; \
cx->S[tmpi] = tmpSj; \
cx->S[tmpj] = tmpSi; \
t = tmpSi + tmpSj;
#ifdef CONVERT_TO_WORDS
/*
* Straight ARCFOUR op. No optimization.
*/
static SECStatus
rc4_no_opt(RC4Context *cx, unsigned char *output,
unsigned int *outputLen, unsigned int maxOutputLen,
const unsigned char *input, unsigned int inputLen)
{
PRUint8 t;
Stype tmpSi, tmpSj;
register PRUint8 tmpi = cx->i;
register PRUint8 tmpj = cx->j;
unsigned int index;
PORT_Assert(maxOutputLen >= inputLen);
if (maxOutputLen < inputLen) {
PORT_SetError(SEC_ERROR_OUTPUT_LEN);
return SECFailure;
}
for (index = 0; index < inputLen; index++) {
/* Generate next byte from stream. */
ARCFOUR_NEXT_BYTE();
/* output = next stream byte XOR next input byte */
output[index] = cx->S[t] ^ input[index];
}
*outputLen = inputLen;
cx->i = tmpi;
cx->j = tmpj;
return SECSuccess;
}
#else
/* !CONVERT_TO_WORDS */
/*
* Byte-at-a-time ARCFOUR, unrolling the loop into 8 pieces.
*/
static SECStatus
rc4_unrolled(RC4Context *cx, unsigned char *output,
unsigned int *outputLen, unsigned int maxOutputLen,
const unsigned char *input, unsigned int inputLen)
{
PRUint8 t;
Stype tmpSi, tmpSj;
register PRUint8 tmpi = cx->i;
register PRUint8 tmpj = cx->j;
int index;
PORT_Assert(maxOutputLen >= inputLen);
if (maxOutputLen < inputLen) {
PORT_SetError(SEC_ERROR_OUTPUT_LEN);
return SECFailure;
}
for (index = inputLen / 8; index-- > 0; input += 8, output += 8) {
ARCFOUR_NEXT_BYTE();
output[0] = cx->S[t] ^ input[0];
ARCFOUR_NEXT_BYTE();
output[1] = cx->S[t] ^ input[1];
ARCFOUR_NEXT_BYTE();
output[2] = cx->S[t] ^ input[2];
ARCFOUR_NEXT_BYTE();
output[3] = cx->S[t] ^ input[3];
ARCFOUR_NEXT_BYTE();
output[4] = cx->S[t] ^ input[4];
ARCFOUR_NEXT_BYTE();
output[5] = cx->S[t] ^ input[5];
ARCFOUR_NEXT_BYTE();
output[6] = cx->S[t] ^ input[6];
ARCFOUR_NEXT_BYTE();
output[7] = cx->S[t] ^ input[7];
}
index = inputLen % 8;
if (index) {
input += index;
output += index;
switch (index) {
case 7:
ARCFOUR_NEXT_BYTE();
output[-7] = cx->S[t] ^ input[-7]; /* FALLTHRU */
case 6:
ARCFOUR_NEXT_BYTE();
output[-6] = cx->S[t] ^ input[-6]; /* FALLTHRU */
case 5:
ARCFOUR_NEXT_BYTE();
output[-5] = cx->S[t] ^ input[-5]; /* FALLTHRU */
case 4:
ARCFOUR_NEXT_BYTE();
output[-4] = cx->S[t] ^ input[-4]; /* FALLTHRU */
case 3:
ARCFOUR_NEXT_BYTE();
output[-3] = cx->S[t] ^ input[-3]; /* FALLTHRU */
case 2:
ARCFOUR_NEXT_BYTE();
output[-2] = cx->S[t] ^ input[-2]; /* FALLTHRU */
case 1:
ARCFOUR_NEXT_BYTE();
output[-1] = cx->S[t] ^ input[-1]; /* FALLTHRU */
default:
/* FALLTHRU */
; /* hp-ux build breaks without this */
}
}
cx->i = tmpi;
cx->j = tmpj;
*outputLen = inputLen;
return SECSuccess;
}
#endif
#ifdef IS_LITTLE_ENDIAN
#define ARCFOUR_NEXT4BYTES_L(n) \
ARCFOUR_NEXT_BYTE(); \
streamWord |= (WORD)cx->S[t] << (n); \
ARCFOUR_NEXT_BYTE(); \
streamWord |= (WORD)cx->S[t] << (n + 8); \
ARCFOUR_NEXT_BYTE(); \
streamWord |= (WORD)cx->S[t] << (n + 16); \
ARCFOUR_NEXT_BYTE(); \
streamWord |= (WORD)cx->S[t] << (n + 24);
#else
#define ARCFOUR_NEXT4BYTES_B(n) \
ARCFOUR_NEXT_BYTE(); \
streamWord |= (WORD)cx->S[t] << (n + 24); \
ARCFOUR_NEXT_BYTE(); \
streamWord |= (WORD)cx->S[t] << (n + 16); \
ARCFOUR_NEXT_BYTE(); \
streamWord |= (WORD)cx->S[t] << (n + 8); \
ARCFOUR_NEXT_BYTE(); \
streamWord |= (WORD)cx->S[t] << (n);
#endif
#if (defined(IS_64) && !defined(__sparc)) || defined(NSS_USE_64)
/* 64-bit wordsize */
#ifdef IS_LITTLE_ENDIAN
#define ARCFOUR_NEXT_WORD() \
{ \
streamWord = 0; \
ARCFOUR_NEXT4BYTES_L(0); \
ARCFOUR_NEXT4BYTES_L(32); \
}
#else
#define ARCFOUR_NEXT_WORD() \
{ \
streamWord = 0; \
ARCFOUR_NEXT4BYTES_B(32); \
ARCFOUR_NEXT4BYTES_B(0); \
}
#endif
#else
/* 32-bit wordsize */
#ifdef IS_LITTLE_ENDIAN
#define ARCFOUR_NEXT_WORD() \
{ \
streamWord = 0; \
ARCFOUR_NEXT4BYTES_L(0); \
}
#else
#define ARCFOUR_NEXT_WORD() \
{ \
streamWord = 0; \
ARCFOUR_NEXT4BYTES_B(0); \
}
#endif
#endif
#ifdef IS_LITTLE_ENDIAN
#define RSH <<
#define LSH >>
#else
#define RSH >>
#define LSH <<
#endif
#ifdef IS_LITTLE_ENDIAN
#define LEFTMOST_BYTE_SHIFT 0
#define NEXT_BYTE_SHIFT(shift) shift + 8
#else
#define LEFTMOST_BYTE_SHIFT 8 * (WORDSIZE - 1)
#define NEXT_BYTE_SHIFT(shift) shift - 8
#endif
#ifdef CONVERT_TO_WORDS
static SECStatus
rc4_wordconv(RC4Context *cx, unsigned char *output,
unsigned int *outputLen, unsigned int maxOutputLen,
const unsigned char *input, unsigned int inputLen)
{
PR_STATIC_ASSERT(sizeof(PRUword) == sizeof(ptrdiff_t));
unsigned int inOffset = (PRUword)input % WORDSIZE;
unsigned int outOffset = (PRUword)output % WORDSIZE;
register WORD streamWord;
register const WORD *pInWord;
register WORD *pOutWord;
register WORD inWord, nextInWord;
PRUint8 t;
register Stype tmpSi, tmpSj;
register PRUint8 tmpi = cx->i;
register PRUint8 tmpj = cx->j;
unsigned int bufShift, invBufShift;
unsigned int i;
const unsigned char *finalIn;
unsigned char *finalOut;
PORT_Assert(maxOutputLen >= inputLen);
if (maxOutputLen < inputLen) {
PORT_SetError(SEC_ERROR_OUTPUT_LEN);
return SECFailure;
}
if (inputLen < 2 * WORDSIZE) {
/* Ignore word conversion, do byte-at-a-time */
return rc4_no_opt(cx, output, outputLen, maxOutputLen, input, inputLen);
}
*outputLen = inputLen;
pInWord = (const WORD *)(input - inOffset);
pOutWord = (WORD *)(output - outOffset);
if (inOffset <= outOffset) {
bufShift = 8 * (outOffset - inOffset);
invBufShift = 8 * WORDSIZE - bufShift;
} else {
invBufShift = 8 * (inOffset - outOffset);
bufShift = 8 * WORDSIZE - invBufShift;
}
/*****************************************************************/
/* Step 1: */
/* If the first output word is partial, consume the bytes in the */
/* first partial output word by loading one or two words of */
/* input and shifting them accordingly. Otherwise, just load */
/* in the first word of input. At the end of this block, at */
/* least one partial word of input should ALWAYS be loaded. */
/*****************************************************************/
if (outOffset) {
unsigned int byteCount = WORDSIZE - outOffset;
for (i = 0; i < byteCount; i++) {
ARCFOUR_NEXT_BYTE();
output[i] = cx->S[t] ^ input[i];
}
/* Consumed byteCount bytes of input */
inputLen -= byteCount;
pInWord++;
/* move to next word of output */
pOutWord++;
/* If buffers are relatively misaligned, shift the bytes in inWord
* to be aligned to the output buffer.
*/
if (inOffset < outOffset) {
/* The first input word (which may be partial) has more bytes
* than needed. Copy the remainder to inWord.
*/
unsigned int shift = LEFTMOST_BYTE_SHIFT;
inWord = 0;
for (i = 0; i < outOffset - inOffset; i++) {
inWord |= (WORD)input[byteCount + i] << shift;
shift = NEXT_BYTE_SHIFT(shift);
}
} else if (inOffset > outOffset) {
/* Consumed some bytes in the second input word. Copy the
* remainder to inWord.
*/
inWord = *pInWord++;
inWord = inWord LSH invBufShift;
} else {
inWord = 0;
}
} else {
/* output is word-aligned */
if (inOffset) {
/* Input is not word-aligned. The first word load of input
* will not produce a full word of input bytes, so one word
* must be pre-loaded. The main loop below will load in the
* next input word and shift some of its bytes into inWord
* in order to create a full input word. Note that the main
* loop must execute at least once because the input must
* be at least two words.
*/
unsigned int shift = LEFTMOST_BYTE_SHIFT;
inWord = 0;
for (i = 0; i < WORDSIZE - inOffset; i++) {
inWord |= (WORD)input[i] << shift;
shift = NEXT_BYTE_SHIFT(shift);
}
pInWord++;
} else {
/* Input is word-aligned. The first word load of input
* will produce a full word of input bytes, so nothing
* needs to be loaded here.
*/
inWord = 0;
}
}
/*****************************************************************/
/* Step 2: main loop */
/* At this point the output buffer is word-aligned. Any unused */
/* bytes from above will be in inWord (shifted correctly). If */
/* the input buffer is unaligned relative to the output buffer, */
/* shifting has to be done. */
/*****************************************************************/
if (bufShift) {
/* preloadedByteCount is the number of input bytes pre-loaded
* in inWord.
*/
unsigned int preloadedByteCount = bufShift / 8;
for (; inputLen >= preloadedByteCount + WORDSIZE;
inputLen -= WORDSIZE) {
nextInWord = *pInWord++;
inWord |= nextInWord RSH bufShift;
nextInWord = nextInWord LSH invBufShift;
ARCFOUR_NEXT_WORD();
*pOutWord++ = inWord ^ streamWord;
inWord = nextInWord;
}
if (inputLen == 0) {
/* Nothing left to do. */
cx->i = tmpi;
cx->j = tmpj;
return SECSuccess;
}
finalIn = (const unsigned char *)pInWord - preloadedByteCount;
} else {
for (; inputLen >= WORDSIZE; inputLen -= WORDSIZE) {
inWord = *pInWord++;
ARCFOUR_NEXT_WORD();
*pOutWord++ = inWord ^ streamWord;
}
if (inputLen == 0) {
/* Nothing left to do. */
cx->i = tmpi;
cx->j = tmpj;
return SECSuccess;
}
finalIn = (const unsigned char *)pInWord;
}
/*****************************************************************/
/* Step 3: */
/* Do the remaining partial word of input one byte at a time. */
/*****************************************************************/
finalOut = (unsigned char *)pOutWord;
for (i = 0; i < inputLen; i++) {
ARCFOUR_NEXT_BYTE();
finalOut[i] = cx->S[t] ^ finalIn[i];
}
cx->i = tmpi;
cx->j = tmpj;
return SECSuccess;
}
#endif
#endif /* NSS_BEVAND_ARCFOUR */
SECStatus
RC4_Encrypt(RC4Context *cx, unsigned char *output,
unsigned int *outputLen, unsigned int maxOutputLen,
const unsigned char *input, unsigned int inputLen)
{
PORT_Assert(maxOutputLen >= inputLen);
if (maxOutputLen < inputLen) {
PORT_SetError(SEC_ERROR_OUTPUT_LEN);
return SECFailure;
}
#if defined(NSS_BEVAND_ARCFOUR)
ARCFOUR(cx, inputLen, input, output);
*outputLen = inputLen;
return SECSuccess;
#elif defined(CONVERT_TO_WORDS)
/* Convert the byte-stream to a word-stream */
return rc4_wordconv(cx, output, outputLen, maxOutputLen, input, inputLen);
#else
/* Operate on bytes, but unroll the main loop */
return rc4_unrolled(cx, output, outputLen, maxOutputLen, input, inputLen);
#endif
}
SECStatus
RC4_Decrypt(RC4Context *cx, unsigned char *output,
unsigned int *outputLen, unsigned int maxOutputLen,
const unsigned char *input, unsigned int inputLen)
{
PORT_Assert(maxOutputLen >= inputLen);
if (maxOutputLen < inputLen) {
PORT_SetError(SEC_ERROR_OUTPUT_LEN);
return SECFailure;
}
/* decrypt and encrypt are same operation. */
#if defined(NSS_BEVAND_ARCFOUR)
ARCFOUR(cx, inputLen, input, output);
*outputLen = inputLen;
return SECSuccess;
#elif defined(CONVERT_TO_WORDS)
/* Convert the byte-stream to a word-stream */
return rc4_wordconv(cx, output, outputLen, maxOutputLen, input, inputLen);
#else
/* Operate on bytes, but unroll the main loop */
return rc4_unrolled(cx, output, outputLen, maxOutputLen, input, inputLen);
#endif
}
#undef CONVERT_TO_WORDS
#undef USE_WORD

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,61 @@
/*
* blapii.h - private data structures and prototypes for the freebl library
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef _BLAPII_H_
#define _BLAPII_H_
#include "blapit.h"
/* max block size of supported block ciphers */
#define MAX_BLOCK_SIZE 16
typedef SECStatus (*freeblCipherFunc)(void *cx, unsigned char *output,
unsigned int *outputLen, unsigned int maxOutputLen,
const unsigned char *input, unsigned int inputLen,
unsigned int blocksize);
typedef void (*freeblDestroyFunc)(void *cx, PRBool freeit);
SEC_BEGIN_PROTOS
SECStatus BL_FIPSEntryOK(PRBool freeblOnly);
PRBool BL_POSTRan(PRBool freeblOnly);
#if defined(XP_UNIX) && !defined(NO_FORK_CHECK)
extern PRBool bl_parentForkedAfterC_Initialize;
#define SKIP_AFTER_FORK(x) \
if (!bl_parentForkedAfterC_Initialize) \
x
#else
#define SKIP_AFTER_FORK(x) x
#endif
SEC_END_PROTOS
#if defined(NSS_X86_OR_X64)
#define HAVE_UNALIGNED_ACCESS 1
#endif
#if defined(__clang__)
#define HAVE_NO_SANITIZE_ATTR __has_attribute(no_sanitize)
#else
#define HAVE_NO_SANITIZE_ATTR 0
#endif
#if defined(HAVE_UNALIGNED_ACCESS) && HAVE_NO_SANITIZE_ATTR
#define NO_SANITIZE_ALIGNMENT __attribute__((no_sanitize("alignment")))
#else
#define NO_SANITIZE_ALIGNMENT
#endif
#undef HAVE_NO_SANITIZE_ATTR
#endif /* _BLAPII_H_ */

View file

@ -0,0 +1,414 @@
/*
* blapit.h - public data structures for the freebl library
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef _BLAPIT_H_
#define _BLAPIT_H_
#include "seccomon.h"
#include "prlink.h"
#include "plarena.h"
#include "ecl-exp.h"
/* RC2 operation modes */
#define NSS_RC2 0
#define NSS_RC2_CBC 1
/* RC5 operation modes */
#define NSS_RC5 0
#define NSS_RC5_CBC 1
/* DES operation modes */
#define NSS_DES 0
#define NSS_DES_CBC 1
#define NSS_DES_EDE3 2
#define NSS_DES_EDE3_CBC 3
#define DES_KEY_LENGTH 8 /* Bytes */
/* AES operation modes */
#define NSS_AES 0
#define NSS_AES_CBC 1
#define NSS_AES_CTS 2
#define NSS_AES_CTR 3
#define NSS_AES_GCM 4
/* Camellia operation modes */
#define NSS_CAMELLIA 0
#define NSS_CAMELLIA_CBC 1
/* SEED operation modes */
#define NSS_SEED 0
#define NSS_SEED_CBC 1
#define DSA1_SUBPRIME_LEN 20 /* Bytes */
#define DSA1_SIGNATURE_LEN (DSA1_SUBPRIME_LEN * 2) /* Bytes */
#define DSA_MAX_SUBPRIME_LEN 32 /* Bytes */
#define DSA_MAX_SIGNATURE_LEN (DSA_MAX_SUBPRIME_LEN * 2) /* Bytes */
/*
* Mark the old defines as deprecated. This will warn code that expected
* DSA1 only that they need to change if the are to support DSA2.
*/
#if defined(__GNUC__) && (__GNUC__ > 3)
/* make GCC warn when we use these #defines */
typedef int __BLAPI_DEPRECATED __attribute__((deprecated));
#define DSA_SUBPRIME_LEN ((__BLAPI_DEPRECATED)DSA1_SUBPRIME_LEN)
#define DSA_SIGNATURE_LEN ((__BLAPI_DEPRECATED)DSA1_SIGNATURE_LEN)
#define DSA_Q_BITS ((__BLAPI_DEPRECATED)(DSA1_SUBPRIME_LEN * 8))
#else
#ifdef _WIN32
/* This magic gets the windows compiler to give us a deprecation
* warning */
#pragma deprecated(DSA_SUBPRIME_LEN, DSA_SIGNATURE_LEN, DSA_QBITS)
#endif
#define DSA_SUBPRIME_LEN DSA1_SUBPRIME_LEN
#define DSA_SIGNATURE_LEN DSA1_SIGNATURE_LEN
#define DSA_Q_BITS (DSA1_SUBPRIME_LEN * 8)
#endif
/* XXX We shouldn't have to hard code this limit. For
* now, this is the quickest way to support ECDSA signature
* processing (ECDSA signature lengths depend on curve
* size). This limit is sufficient for curves upto
* 576 bits.
*/
#define MAX_ECKEY_LEN 72 /* Bytes */
#define EC_MAX_KEY_BITS 521 /* in bits */
#define EC_MIN_KEY_BITS 256 /* in bits */
/* EC point compression format */
#define EC_POINT_FORM_COMPRESSED_Y0 0x02
#define EC_POINT_FORM_COMPRESSED_Y1 0x03
#define EC_POINT_FORM_UNCOMPRESSED 0x04
#define EC_POINT_FORM_HYBRID_Y0 0x06
#define EC_POINT_FORM_HYBRID_Y1 0x07
/*
* Number of bytes each hash algorithm produces
*/
#define MD2_LENGTH 16 /* Bytes */
#define MD5_LENGTH 16 /* Bytes */
#define SHA1_LENGTH 20 /* Bytes */
#define SHA256_LENGTH 32 /* bytes */
#define SHA384_LENGTH 48 /* bytes */
#define SHA512_LENGTH 64 /* bytes */
#define HASH_LENGTH_MAX SHA512_LENGTH
/*
* Input block size for each hash algorithm.
*/
#define MD2_BLOCK_LENGTH 64 /* bytes */
#define MD5_BLOCK_LENGTH 64 /* bytes */
#define SHA1_BLOCK_LENGTH 64 /* bytes */
#define SHA224_BLOCK_LENGTH 64 /* bytes */
#define SHA256_BLOCK_LENGTH 64 /* bytes */
#define SHA384_BLOCK_LENGTH 128 /* bytes */
#define SHA512_BLOCK_LENGTH 128 /* bytes */
#define HASH_BLOCK_LENGTH_MAX SHA512_BLOCK_LENGTH
#define AES_KEY_WRAP_IV_BYTES 8
#define AES_KEY_WRAP_BLOCK_SIZE 8 /* bytes */
#define AES_BLOCK_SIZE 16 /* bytes */
#define AES_128_KEY_LENGTH 16 /* bytes */
#define AES_192_KEY_LENGTH 24 /* bytes */
#define AES_256_KEY_LENGTH 32 /* bytes */
#define CAMELLIA_BLOCK_SIZE 16 /* bytes */
#define SEED_BLOCK_SIZE 16 /* bytes */
#define SEED_KEY_LENGTH 16 /* bytes */
#define NSS_FREEBL_DEFAULT_CHUNKSIZE 2048
/*
* These values come from the initial key size limits from the PKCS #11
* module. They may be arbitrarily adjusted to any value freebl supports.
*/
#define RSA_MIN_MODULUS_BITS 128
#define RSA_MAX_MODULUS_BITS 16384
#define RSA_MAX_EXPONENT_BITS 64
#define DH_MIN_P_BITS 128
#define DH_MAX_P_BITS 16384
/*
* The FIPS 186-1 algorithm for generating primes P and Q allows only 9
* distinct values for the length of P, and only one value for the
* length of Q.
* The algorithm uses a variable j to indicate which of the 9 lengths
* of P is to be used.
* The following table relates j to the lengths of P and Q in bits.
*
* j bits in P bits in Q
* _ _________ _________
* 0 512 160
* 1 576 160
* 2 640 160
* 3 704 160
* 4 768 160
* 5 832 160
* 6 896 160
* 7 960 160
* 8 1024 160
*
* The FIPS-186-1 compliant PQG generator takes j as an input parameter.
*
* FIPS 186-3 algorithm specifies 4 distinct P and Q sizes:
*
* bits in P bits in Q
* _________ _________
* 1024 160
* 2048 224
* 2048 256
* 3072 256
*
* The FIPS-186-3 complaiant PQG generator (PQG V2) takes arbitrary p and q
* lengths as input and returns an error if they aren't in this list.
*/
#define DSA1_Q_BITS 160
#define DSA_MAX_P_BITS 3072
#define DSA_MIN_P_BITS 512
#define DSA_MAX_Q_BITS 256
#define DSA_MIN_Q_BITS 160
#if DSA_MAX_Q_BITS != DSA_MAX_SUBPRIME_LEN * 8
#error "Inconsistent declaration of DSA SUBPRIME/Q parameters in blapit.h"
#endif
/*
* function takes desired number of bits in P,
* returns index (0..8) or -1 if number of bits is invalid.
*/
#define PQG_PBITS_TO_INDEX(bits) \
(((bits) < 512 || (bits) > 1024 || (bits) % 64) ? -1 : (int)((bits)-512) / 64)
/*
* function takes index (0-8)
* returns number of bits in P for that index, or -1 if index is invalid.
*/
#define PQG_INDEX_TO_PBITS(j) (((unsigned)(j) > 8) ? -1 : (512 + 64 * (j)))
/***************************************************************************
** Opaque objects
*/
struct DESContextStr;
struct RC2ContextStr;
struct RC4ContextStr;
struct RC5ContextStr;
struct AESContextStr;
struct CamelliaContextStr;
struct MD2ContextStr;
struct MD5ContextStr;
struct SHA1ContextStr;
struct SHA256ContextStr;
struct SHA512ContextStr;
struct AESKeyWrapContextStr;
struct SEEDContextStr;
struct ChaCha20Poly1305ContextStr;
typedef struct DESContextStr DESContext;
typedef struct RC2ContextStr RC2Context;
typedef struct RC4ContextStr RC4Context;
typedef struct RC5ContextStr RC5Context;
typedef struct AESContextStr AESContext;
typedef struct CamelliaContextStr CamelliaContext;
typedef struct MD2ContextStr MD2Context;
typedef struct MD5ContextStr MD5Context;
typedef struct SHA1ContextStr SHA1Context;
typedef struct SHA256ContextStr SHA256Context;
/* SHA224Context is really a SHA256ContextStr. This is not a mistake. */
typedef struct SHA256ContextStr SHA224Context;
typedef struct SHA512ContextStr SHA512Context;
/* SHA384Context is really a SHA512ContextStr. This is not a mistake. */
typedef struct SHA512ContextStr SHA384Context;
typedef struct AESKeyWrapContextStr AESKeyWrapContext;
typedef struct SEEDContextStr SEEDContext;
typedef struct ChaCha20Poly1305ContextStr ChaCha20Poly1305Context;
/***************************************************************************
** RSA Public and Private Key structures
*/
/* member names from PKCS#1, section 7.1 */
struct RSAPublicKeyStr {
PLArenaPool *arena;
SECItem modulus;
SECItem publicExponent;
};
typedef struct RSAPublicKeyStr RSAPublicKey;
/* member names from PKCS#1, section 7.2 */
struct RSAPrivateKeyStr {
PLArenaPool *arena;
SECItem version;
SECItem modulus;
SECItem publicExponent;
SECItem privateExponent;
SECItem prime1;
SECItem prime2;
SECItem exponent1;
SECItem exponent2;
SECItem coefficient;
};
typedef struct RSAPrivateKeyStr RSAPrivateKey;
/***************************************************************************
** DSA Public and Private Key and related structures
*/
struct PQGParamsStr {
PLArenaPool *arena;
SECItem prime; /* p */
SECItem subPrime; /* q */
SECItem base; /* g */
/* XXX chrisk: this needs to be expanded to hold j and validationParms (RFC2459 7.3.2) */
};
typedef struct PQGParamsStr PQGParams;
struct PQGVerifyStr {
PLArenaPool *arena; /* includes this struct, seed, & h. */
unsigned int counter;
SECItem seed;
SECItem h;
};
typedef struct PQGVerifyStr PQGVerify;
struct DSAPublicKeyStr {
PQGParams params;
SECItem publicValue;
};
typedef struct DSAPublicKeyStr DSAPublicKey;
struct DSAPrivateKeyStr {
PQGParams params;
SECItem publicValue;
SECItem privateValue;
};
typedef struct DSAPrivateKeyStr DSAPrivateKey;
/***************************************************************************
** Diffie-Hellman Public and Private Key and related structures
** Structure member names suggested by PKCS#3.
*/
struct DHParamsStr {
PLArenaPool *arena;
SECItem prime; /* p */
SECItem base; /* g */
};
typedef struct DHParamsStr DHParams;
struct DHPublicKeyStr {
PLArenaPool *arena;
SECItem prime;
SECItem base;
SECItem publicValue;
};
typedef struct DHPublicKeyStr DHPublicKey;
struct DHPrivateKeyStr {
PLArenaPool *arena;
SECItem prime;
SECItem base;
SECItem publicValue;
SECItem privateValue;
};
typedef struct DHPrivateKeyStr DHPrivateKey;
/***************************************************************************
** Data structures used for elliptic curve parameters and
** public and private keys.
*/
/*
** The ECParams data structures can encode elliptic curve
** parameters for both GFp and GF2m curves.
*/
typedef enum { ec_params_explicit,
ec_params_named
} ECParamsType;
typedef enum { ec_field_GFp = 1,
ec_field_GF2m,
ec_field_plain
} ECFieldType;
struct ECFieldIDStr {
int size; /* field size in bits */
ECFieldType type;
union {
SECItem prime; /* prime p for (GFp) */
SECItem poly; /* irreducible binary polynomial for (GF2m) */
} u;
int k1; /* first coefficient of pentanomial or
* the only coefficient of trinomial
*/
int k2; /* two remaining coefficients of pentanomial */
int k3;
};
typedef struct ECFieldIDStr ECFieldID;
struct ECCurveStr {
SECItem a; /* contains octet stream encoding of
* field element (X9.62 section 4.3.3)
*/
SECItem b;
SECItem seed;
};
typedef struct ECCurveStr ECCurve;
struct ECParamsStr {
PLArenaPool *arena;
ECParamsType type;
ECFieldID fieldID;
ECCurve curve;
SECItem base;
SECItem order;
int cofactor;
SECItem DEREncoding;
ECCurveName name;
SECItem curveOID;
};
typedef struct ECParamsStr ECParams;
struct ECPublicKeyStr {
ECParams ecParams;
SECItem publicValue; /* elliptic curve point encoded as
* octet stream.
*/
};
typedef struct ECPublicKeyStr ECPublicKey;
struct ECPrivateKeyStr {
ECParams ecParams;
SECItem publicValue; /* encoded ec point */
SECItem privateValue; /* private big integer */
SECItem version; /* As per SEC 1, Appendix C, Section C.4 */
};
typedef struct ECPrivateKeyStr ECPrivateKey;
typedef void *(*BLapiAllocateFunc)(void);
typedef void (*BLapiDestroyContextFunc)(void *cx, PRBool freeit);
typedef SECStatus (*BLapiInitContextFunc)(void *cx,
const unsigned char *key,
unsigned int keylen,
const unsigned char *,
int,
unsigned int,
unsigned int);
typedef SECStatus (*BLapiEncrypt)(void *cx, unsigned char *output,
unsigned int *outputLen,
unsigned int maxOutputLen,
const unsigned char *input,
unsigned int inputLen);
#endif /* _BLAPIT_H_ */

View file

@ -0,0 +1,100 @@
/*
* blname.c - determine the freebl library name.
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#if defined(FREEBL_LOWHASH)
static const char* default_name =
SHLIB_PREFIX "freeblpriv" SHLIB_VERSION "." SHLIB_SUFFIX;
#else
static const char* default_name =
SHLIB_PREFIX "freebl" SHLIB_VERSION "." SHLIB_SUFFIX;
#endif
/* getLibName() returns the name of the library to load. */
#if defined(SOLARIS) && defined(__sparc)
#include <stddef.h>
#include <strings.h>
#include <sys/systeminfo.h>
#if defined(NSS_USE_64)
const static char fpu_hybrid_shared_lib[] = "libfreebl_64fpu_3.so";
const static char int_hybrid_shared_lib[] = "libfreebl_64int_3.so";
const static char non_hybrid_shared_lib[] = "libfreebl_64fpu_3.so";
const static char int_hybrid_isa[] = "sparcv9";
const static char fpu_hybrid_isa[] = "sparcv9+vis";
#else
const static char fpu_hybrid_shared_lib[] = "libfreebl_32fpu_3.so";
const static char int_hybrid_shared_lib[] = "libfreebl_32int64_3.so";
/* This was for SPARC V8, now obsolete. */
const static char* const non_hybrid_shared_lib = NULL;
const static char int_hybrid_isa[] = "sparcv8plus";
const static char fpu_hybrid_isa[] = "sparcv8plus+vis";
#endif
static const char*
getLibName(void)
{
char* found_int_hybrid;
char* found_fpu_hybrid;
long buflen;
char buf[256];
buflen = sysinfo(SI_ISALIST, buf, sizeof buf);
if (buflen <= 0)
return NULL;
/* sysinfo output is always supposed to be NUL terminated, but ... */
if (buflen < sizeof buf)
buf[buflen] = '\0';
else
buf[(sizeof buf) - 1] = '\0';
/* The ISA list is a space separated string of names of ISAs and
* ISA extensions, in order of decreasing performance.
* There are two different ISAs with which NSS's crypto code can be
* accelerated. If both are in the list, we take the first one.
* If one is in the list, we use it, and if neither then we use
* the base unaccelerated code.
*/
found_int_hybrid = strstr(buf, int_hybrid_isa);
found_fpu_hybrid = strstr(buf, fpu_hybrid_isa);
if (found_fpu_hybrid &&
(!found_int_hybrid ||
(found_int_hybrid - found_fpu_hybrid) >= 0)) {
return fpu_hybrid_shared_lib;
}
if (found_int_hybrid) {
return int_hybrid_shared_lib;
}
return non_hybrid_shared_lib;
}
#elif defined(HPUX) && !defined(NSS_USE_64) && !defined(__ia64)
#include <unistd.h>
/* This code tests to see if we're running on a PA2.x CPU.
** It returns true (1) if so, and false (0) otherwise.
*/
static const char*
getLibName(void)
{
long cpu = sysconf(_SC_CPU_VERSION);
return (cpu == CPU_PA_RISC2_0)
? "libfreebl_32fpu_3.sl"
: "libfreebl_32int_3.sl";
}
#else
/* default case, for platforms/ABIs that have only one freebl shared lib. */
static const char*
getLibName(void)
{
return default_name;
}
#endif

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,42 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef _CAMELLIA_H_
#define _CAMELLIA_H_ 1
#define CAMELLIA_BLOCK_SIZE 16 /* bytes */
#define CAMELLIA_MIN_KEYSIZE 16 /* bytes */
#define CAMELLIA_MAX_KEYSIZE 32 /* bytes */
#define CAMELLIA_MAX_EXPANDEDKEY (34 * 2) /* 32bit unit */
typedef PRUint32 KEY_TABLE_TYPE[CAMELLIA_MAX_EXPANDEDKEY];
typedef SECStatus CamelliaFunc(CamelliaContext *cx, unsigned char *output,
unsigned int *outputLen,
unsigned int maxOutputLen,
const unsigned char *input,
unsigned int inputLen);
typedef SECStatus CamelliaBlockFunc(const PRUint32 *subkey,
unsigned char *output,
const unsigned char *input);
/* CamelliaContextStr
*
* Values which maintain the state for Camellia encryption/decryption.
*
* keysize - the number of key bits
* worker - the encryption/decryption function to use with this context
* iv - initialization vector for CBC mode
* expandedKey - the round keys in 4-byte words
*/
struct CamelliaContextStr {
PRUint32 keysize; /* bytes */
CamelliaFunc *worker;
PRUint32 expandedKey[CAMELLIA_MAX_EXPANDEDKEY];
PRUint8 iv[CAMELLIA_BLOCK_SIZE];
};
#endif /* _CAMELLIA_H_ */

View file

@ -0,0 +1,119 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
/* Adopted from the public domain code in NaCl by djb. */
#include <string.h>
#include <stdio.h>
#include "prtypes.h"
#include "secport.h"
#include "chacha20.h"
#if defined(_MSC_VER)
#pragma intrinsic(_lrotl)
#define ROTL32(x, n) _lrotl(x, n)
#else
#define ROTL32(x, n) ((x << n) | (x >> ((8 * sizeof x) - n)))
#endif
#define ROTATE(v, c) ROTL32((v), (c))
#define U32TO8_LITTLE(p, v) \
{ \
(p)[0] = ((v)) & 0xff; \
(p)[1] = ((v) >> 8) & 0xff; \
(p)[2] = ((v) >> 16) & 0xff; \
(p)[3] = ((v) >> 24) & 0xff; \
}
#define U8TO32_LITTLE(p) \
(((PRUint32)((p)[0])) | ((PRUint32)((p)[1]) << 8) | \
((PRUint32)((p)[2]) << 16) | ((PRUint32)((p)[3]) << 24))
#define QUARTERROUND(x, a, b, c, d) \
x[a] = x[a] + x[b]; \
x[d] = ROTATE(x[d] ^ x[a], 16); \
x[c] = x[c] + x[d]; \
x[b] = ROTATE(x[b] ^ x[c], 12); \
x[a] = x[a] + x[b]; \
x[d] = ROTATE(x[d] ^ x[a], 8); \
x[c] = x[c] + x[d]; \
x[b] = ROTATE(x[b] ^ x[c], 7);
static void
ChaChaCore(unsigned char output[64], const PRUint32 input[16], int num_rounds)
{
PRUint32 x[16];
int i;
PORT_Memcpy(x, input, sizeof(PRUint32) * 16);
for (i = num_rounds; i > 0; i -= 2) {
QUARTERROUND(x, 0, 4, 8, 12)
QUARTERROUND(x, 1, 5, 9, 13)
QUARTERROUND(x, 2, 6, 10, 14)
QUARTERROUND(x, 3, 7, 11, 15)
QUARTERROUND(x, 0, 5, 10, 15)
QUARTERROUND(x, 1, 6, 11, 12)
QUARTERROUND(x, 2, 7, 8, 13)
QUARTERROUND(x, 3, 4, 9, 14)
}
for (i = 0; i < 16; ++i) {
x[i] = x[i] + input[i];
}
for (i = 0; i < 16; ++i) {
U32TO8_LITTLE(output + 4 * i, x[i]);
}
}
static const unsigned char sigma[16] = "expand 32-byte k";
void
ChaCha20XOR(unsigned char *out, const unsigned char *in, unsigned int inLen,
const unsigned char key[32], const unsigned char nonce[12],
uint32_t counter)
{
unsigned char block[64];
PRUint32 input[16];
unsigned int i;
input[4] = U8TO32_LITTLE(key + 0);
input[5] = U8TO32_LITTLE(key + 4);
input[6] = U8TO32_LITTLE(key + 8);
input[7] = U8TO32_LITTLE(key + 12);
input[8] = U8TO32_LITTLE(key + 16);
input[9] = U8TO32_LITTLE(key + 20);
input[10] = U8TO32_LITTLE(key + 24);
input[11] = U8TO32_LITTLE(key + 28);
input[0] = U8TO32_LITTLE(sigma + 0);
input[1] = U8TO32_LITTLE(sigma + 4);
input[2] = U8TO32_LITTLE(sigma + 8);
input[3] = U8TO32_LITTLE(sigma + 12);
input[12] = counter;
input[13] = U8TO32_LITTLE(nonce + 0);
input[14] = U8TO32_LITTLE(nonce + 4);
input[15] = U8TO32_LITTLE(nonce + 8);
while (inLen >= 64) {
ChaChaCore(block, input, 20);
for (i = 0; i < 64; i++) {
out[i] = in[i] ^ block[i];
}
input[12]++;
inLen -= 64;
in += 64;
out += 64;
}
if (inLen > 0) {
ChaChaCore(block, input, 20);
for (i = 0; i < inLen; i++) {
out[i] = in[i] ^ block[i];
}
}
}

View file

@ -0,0 +1,26 @@
/*
* chacha20.h - header file for ChaCha20 implementation.
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef FREEBL_CHACHA20_H_
#define FREEBL_CHACHA20_H_
#if defined(_MSC_VER) && _MSC_VER < 1600
#include "prtypes.h"
typedef PRUint32 uint32_t;
typedef PRUint64 uint64_t;
#else
#include <stdint.h>
#endif
/* ChaCha20XOR encrypts |inLen| bytes from |in| with the given key and
* nonce and writes the result to |out|, which may be equal to |in|. The
* initial block counter is specified by |counter|. */
extern void ChaCha20XOR(unsigned char *out, const unsigned char *in,
unsigned int inLen, const unsigned char key[32],
const unsigned char nonce[12], uint32_t counter);
#endif /* FREEBL_CHACHA20_H_ */

View file

@ -0,0 +1,327 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
/* This implementation is by Ted Krovetz and was submitted to SUPERCOP and
* marked as public domain. It was been altered to allow for non-aligned inputs
* and to allow the block counter to be passed in specifically. */
#include <string.h>
#include "chacha20.h"
#include "blapii.h"
#ifndef CHACHA_RNDS
#define CHACHA_RNDS 20 /* 8 (high speed), 20 (conservative), 12 (middle) */
#endif
/* Architecture-neutral way to specify 16-byte vector of ints */
typedef unsigned vec __attribute__((vector_size(16)));
/* This implementation is designed for Neon, SSE and AltiVec machines. The
* following specify how to do certain vector operations efficiently on
* each architecture, using intrinsics.
* This implementation supports parallel processing of multiple blocks,
* including potentially using general-purpose registers.
*/
#if __ARM_NEON__
#include <arm_neon.h>
#define GPR_TOO 1
#define VBPI 2
#define ONE (vec) vsetq_lane_u32(1, vdupq_n_u32(0), 0)
#define LOAD(m) (vec)(*((vec *)(m)))
#define STORE(m, r) (*((vec *)(m))) = (r)
#define ROTV1(x) (vec) vextq_u32((uint32x4_t)x, (uint32x4_t)x, 1)
#define ROTV2(x) (vec) vextq_u32((uint32x4_t)x, (uint32x4_t)x, 2)
#define ROTV3(x) (vec) vextq_u32((uint32x4_t)x, (uint32x4_t)x, 3)
#define ROTW16(x) (vec) vrev32q_u16((uint16x8_t)x)
#if __clang__
#define ROTW7(x) (x << ((vec){ 7, 7, 7, 7 })) ^ (x >> ((vec){ 25, 25, 25, 25 }))
#define ROTW8(x) (x << ((vec){ 8, 8, 8, 8 })) ^ (x >> ((vec){ 24, 24, 24, 24 }))
#define ROTW12(x) (x << ((vec){ 12, 12, 12, 12 })) ^ (x >> ((vec){ 20, 20, 20, 20 }))
#else
#define ROTW7(x) (vec) vsriq_n_u32(vshlq_n_u32((uint32x4_t)x, 7), (uint32x4_t)x, 25)
#define ROTW8(x) (vec) vsriq_n_u32(vshlq_n_u32((uint32x4_t)x, 8), (uint32x4_t)x, 24)
#define ROTW12(x) (vec) vsriq_n_u32(vshlq_n_u32((uint32x4_t)x, 12), (uint32x4_t)x, 20)
#endif
#elif __SSE2__
#include <emmintrin.h>
#define GPR_TOO 0
#if __clang__
#define VBPI 4
#else
#define VBPI 3
#endif
#define ONE (vec) _mm_set_epi32(0, 0, 0, 1)
#define LOAD(m) (vec) _mm_loadu_si128((__m128i *)(m))
#define STORE(m, r) _mm_storeu_si128((__m128i *)(m), (__m128i)(r))
#define ROTV1(x) (vec) _mm_shuffle_epi32((__m128i)x, _MM_SHUFFLE(0, 3, 2, 1))
#define ROTV2(x) (vec) _mm_shuffle_epi32((__m128i)x, _MM_SHUFFLE(1, 0, 3, 2))
#define ROTV3(x) (vec) _mm_shuffle_epi32((__m128i)x, _MM_SHUFFLE(2, 1, 0, 3))
#define ROTW7(x) (vec)(_mm_slli_epi32((__m128i)x, 7) ^ _mm_srli_epi32((__m128i)x, 25))
#define ROTW12(x) (vec)(_mm_slli_epi32((__m128i)x, 12) ^ _mm_srli_epi32((__m128i)x, 20))
#if __SSSE3__
#include <tmmintrin.h>
#define ROTW8(x) (vec) _mm_shuffle_epi8((__m128i)x, _mm_set_epi8(14, 13, 12, 15, 10, 9, 8, 11, 6, 5, 4, 7, 2, 1, 0, 3))
#define ROTW16(x) (vec) _mm_shuffle_epi8((__m128i)x, _mm_set_epi8(13, 12, 15, 14, 9, 8, 11, 10, 5, 4, 7, 6, 1, 0, 3, 2))
#else
#define ROTW8(x) (vec)(_mm_slli_epi32((__m128i)x, 8) ^ _mm_srli_epi32((__m128i)x, 24))
#define ROTW16(x) (vec)(_mm_slli_epi32((__m128i)x, 16) ^ _mm_srli_epi32((__m128i)x, 16))
#endif
#else
#error-- Implementation supports only machines with neon or SSE2
#endif
#ifndef REVV_BE
#define REVV_BE(x) (x)
#endif
#ifndef REVW_BE
#define REVW_BE(x) (x)
#endif
#define BPI (VBPI + GPR_TOO) /* Blocks computed per loop iteration */
#define DQROUND_VECTORS(a, b, c, d) \
a += b; \
d ^= a; \
d = ROTW16(d); \
c += d; \
b ^= c; \
b = ROTW12(b); \
a += b; \
d ^= a; \
d = ROTW8(d); \
c += d; \
b ^= c; \
b = ROTW7(b); \
b = ROTV1(b); \
c = ROTV2(c); \
d = ROTV3(d); \
a += b; \
d ^= a; \
d = ROTW16(d); \
c += d; \
b ^= c; \
b = ROTW12(b); \
a += b; \
d ^= a; \
d = ROTW8(d); \
c += d; \
b ^= c; \
b = ROTW7(b); \
b = ROTV3(b); \
c = ROTV2(c); \
d = ROTV1(d);
#define QROUND_WORDS(a, b, c, d) \
a = a + b; \
d ^= a; \
d = d << 16 | d >> 16; \
c = c + d; \
b ^= c; \
b = b << 12 | b >> 20; \
a = a + b; \
d ^= a; \
d = d << 8 | d >> 24; \
c = c + d; \
b ^= c; \
b = b << 7 | b >> 25;
#define WRITE_XOR(in, op, d, v0, v1, v2, v3) \
STORE(op + d + 0, LOAD(in + d + 0) ^ REVV_BE(v0)); \
STORE(op + d + 4, LOAD(in + d + 4) ^ REVV_BE(v1)); \
STORE(op + d + 8, LOAD(in + d + 8) ^ REVV_BE(v2)); \
STORE(op + d + 12, LOAD(in + d + 12) ^ REVV_BE(v3));
void NO_SANITIZE_ALIGNMENT
ChaCha20XOR(unsigned char *out, const unsigned char *in, unsigned int inlen,
const unsigned char key[32], const unsigned char nonce[12],
uint32_t counter)
{
unsigned iters, i, *op = (unsigned *)out, *ip = (unsigned *)in, *kp;
#if defined(__ARM_NEON__)
unsigned *np;
#endif
vec s0, s1, s2, s3;
#if !defined(__ARM_NEON__) && !defined(__SSE2__)
__attribute__((aligned(16))) unsigned key[8], nonce[4];
#endif
__attribute__((aligned(16))) unsigned chacha_const[] =
{ 0x61707865, 0x3320646E, 0x79622D32, 0x6B206574 };
#if defined(__ARM_NEON__) || defined(__SSE2__)
kp = (unsigned *)key;
#else
((vec *)key)[0] = REVV_BE(((vec *)key)[0]);
((vec *)key)[1] = REVV_BE(((vec *)key)[1]);
((unsigned *)nonce)[0] = REVW_BE(((unsigned *)nonce)[0]);
((unsigned *)nonce)[1] = REVW_BE(((unsigned *)nonce)[1]);
((unsigned *)nonce)[2] = REVW_BE(((unsigned *)nonce)[2]);
((unsigned *)nonce)[3] = REVW_BE(((unsigned *)nonce)[3]);
kp = (unsigned *)key;
np = (unsigned *)nonce;
#endif
#if defined(__ARM_NEON__)
np = (unsigned *)nonce;
#endif
s0 = LOAD(chacha_const);
s1 = LOAD(&((vec *)kp)[0]);
s2 = LOAD(&((vec *)kp)[1]);
s3 = (vec){
counter,
((uint32_t *)nonce)[0],
((uint32_t *)nonce)[1],
((uint32_t *)nonce)[2]
};
for (iters = 0; iters < inlen / (BPI * 64); iters++) {
#if GPR_TOO
register unsigned x0, x1, x2, x3, x4, x5, x6, x7, x8,
x9, x10, x11, x12, x13, x14, x15;
#endif
#if VBPI > 2
vec v8, v9, v10, v11;
#endif
#if VBPI > 3
vec v12, v13, v14, v15;
#endif
vec v0, v1, v2, v3, v4, v5, v6, v7;
v4 = v0 = s0;
v5 = v1 = s1;
v6 = v2 = s2;
v3 = s3;
v7 = v3 + ONE;
#if VBPI > 2
v8 = v4;
v9 = v5;
v10 = v6;
v11 = v7 + ONE;
#endif
#if VBPI > 3
v12 = v8;
v13 = v9;
v14 = v10;
v15 = v11 + ONE;
#endif
#if GPR_TOO
x0 = chacha_const[0];
x1 = chacha_const[1];
x2 = chacha_const[2];
x3 = chacha_const[3];
x4 = kp[0];
x5 = kp[1];
x6 = kp[2];
x7 = kp[3];
x8 = kp[4];
x9 = kp[5];
x10 = kp[6];
x11 = kp[7];
x12 = counter + BPI * iters + (BPI - 1);
x13 = np[0];
x14 = np[1];
x15 = np[2];
#endif
for (i = CHACHA_RNDS / 2; i; i--) {
DQROUND_VECTORS(v0, v1, v2, v3)
DQROUND_VECTORS(v4, v5, v6, v7)
#if VBPI > 2
DQROUND_VECTORS(v8, v9, v10, v11)
#endif
#if VBPI > 3
DQROUND_VECTORS(v12, v13, v14, v15)
#endif
#if GPR_TOO
QROUND_WORDS(x0, x4, x8, x12)
QROUND_WORDS(x1, x5, x9, x13)
QROUND_WORDS(x2, x6, x10, x14)
QROUND_WORDS(x3, x7, x11, x15)
QROUND_WORDS(x0, x5, x10, x15)
QROUND_WORDS(x1, x6, x11, x12)
QROUND_WORDS(x2, x7, x8, x13)
QROUND_WORDS(x3, x4, x9, x14)
#endif
}
WRITE_XOR(ip, op, 0, v0 + s0, v1 + s1, v2 + s2, v3 + s3)
s3 += ONE;
WRITE_XOR(ip, op, 16, v4 + s0, v5 + s1, v6 + s2, v7 + s3)
s3 += ONE;
#if VBPI > 2
WRITE_XOR(ip, op, 32, v8 + s0, v9 + s1, v10 + s2, v11 + s3)
s3 += ONE;
#endif
#if VBPI > 3
WRITE_XOR(ip, op, 48, v12 + s0, v13 + s1, v14 + s2, v15 + s3)
s3 += ONE;
#endif
ip += VBPI * 16;
op += VBPI * 16;
#if GPR_TOO
op[0] = REVW_BE(REVW_BE(ip[0]) ^ (x0 + chacha_const[0]));
op[1] = REVW_BE(REVW_BE(ip[1]) ^ (x1 + chacha_const[1]));
op[2] = REVW_BE(REVW_BE(ip[2]) ^ (x2 + chacha_const[2]));
op[3] = REVW_BE(REVW_BE(ip[3]) ^ (x3 + chacha_const[3]));
op[4] = REVW_BE(REVW_BE(ip[4]) ^ (x4 + kp[0]));
op[5] = REVW_BE(REVW_BE(ip[5]) ^ (x5 + kp[1]));
op[6] = REVW_BE(REVW_BE(ip[6]) ^ (x6 + kp[2]));
op[7] = REVW_BE(REVW_BE(ip[7]) ^ (x7 + kp[3]));
op[8] = REVW_BE(REVW_BE(ip[8]) ^ (x8 + kp[4]));
op[9] = REVW_BE(REVW_BE(ip[9]) ^ (x9 + kp[5]));
op[10] = REVW_BE(REVW_BE(ip[10]) ^ (x10 + kp[6]));
op[11] = REVW_BE(REVW_BE(ip[11]) ^ (x11 + kp[7]));
op[12] = REVW_BE(REVW_BE(ip[12]) ^ (x12 + counter + BPI * iters + (BPI - 1)));
op[13] = REVW_BE(REVW_BE(ip[13]) ^ (x13 + np[0]));
op[14] = REVW_BE(REVW_BE(ip[14]) ^ (x14 + np[1]));
op[15] = REVW_BE(REVW_BE(ip[15]) ^ (x15 + np[2]));
s3 += ONE;
ip += 16;
op += 16;
#endif
}
for (iters = inlen % (BPI * 64) / 64; iters != 0; iters--) {
vec v0 = s0, v1 = s1, v2 = s2, v3 = s3;
for (i = CHACHA_RNDS / 2; i; i--) {
DQROUND_VECTORS(v0, v1, v2, v3);
}
WRITE_XOR(ip, op, 0, v0 + s0, v1 + s1, v2 + s2, v3 + s3)
s3 += ONE;
ip += 16;
op += 16;
}
inlen = inlen % 64;
if (inlen) {
__attribute__((aligned(16))) vec buf[4];
vec v0, v1, v2, v3;
v0 = s0;
v1 = s1;
v2 = s2;
v3 = s3;
for (i = CHACHA_RNDS / 2; i; i--) {
DQROUND_VECTORS(v0, v1, v2, v3);
}
if (inlen >= 16) {
STORE(op + 0, LOAD(ip + 0) ^ REVV_BE(v0 + s0));
if (inlen >= 32) {
STORE(op + 4, LOAD(ip + 4) ^ REVV_BE(v1 + s1));
if (inlen >= 48) {
STORE(op + 8, LOAD(ip + 8) ^ REVV_BE(v2 + s2));
buf[3] = REVV_BE(v3 + s3);
} else {
buf[2] = REVV_BE(v2 + s2);
}
} else {
buf[1] = REVV_BE(v1 + s1);
}
} else {
buf[0] = REVV_BE(v0 + s0);
}
for (i = inlen & ~15; i < inlen; i++) {
((char *)op)[i] = ((char *)ip)[i] ^ ((char *)buf)[i];
}
}
}

View file

@ -0,0 +1,198 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifdef FREEBL_NO_DEPEND
#include "stubs.h"
#endif
#include <string.h>
#include <stdio.h>
#include "seccomon.h"
#include "secerr.h"
#include "blapit.h"
#ifndef NSS_DISABLE_CHACHAPOLY
#include "poly1305.h"
#include "chacha20.h"
#include "chacha20poly1305.h"
#endif
/* Poly1305Do writes the Poly1305 authenticator of the given additional data
* and ciphertext to |out|. */
#ifndef NSS_DISABLE_CHACHAPOLY
static void
Poly1305Do(unsigned char *out, const unsigned char *ad, unsigned int adLen,
const unsigned char *ciphertext, unsigned int ciphertextLen,
const unsigned char key[32])
{
poly1305_state state;
unsigned int j;
unsigned char lengthBytes[8];
static const unsigned char zeros[15];
unsigned int i;
Poly1305Init(&state, key);
Poly1305Update(&state, ad, adLen);
if (adLen % 16 > 0) {
Poly1305Update(&state, zeros, 16 - adLen % 16);
}
Poly1305Update(&state, ciphertext, ciphertextLen);
if (ciphertextLen % 16 > 0) {
Poly1305Update(&state, zeros, 16 - ciphertextLen % 16);
}
j = adLen;
for (i = 0; i < sizeof(lengthBytes); i++) {
lengthBytes[i] = j;
j >>= 8;
}
Poly1305Update(&state, lengthBytes, sizeof(lengthBytes));
j = ciphertextLen;
for (i = 0; i < sizeof(lengthBytes); i++) {
lengthBytes[i] = j;
j >>= 8;
}
Poly1305Update(&state, lengthBytes, sizeof(lengthBytes));
Poly1305Finish(&state, out);
}
#endif
SECStatus
ChaCha20Poly1305_InitContext(ChaCha20Poly1305Context *ctx,
const unsigned char *key, unsigned int keyLen,
unsigned int tagLen)
{
#ifdef NSS_DISABLE_CHACHAPOLY
return SECFailure;
#else
if (keyLen != 32) {
PORT_SetError(SEC_ERROR_BAD_KEY);
return SECFailure;
}
if (tagLen == 0 || tagLen > 16) {
PORT_SetError(SEC_ERROR_INPUT_LEN);
return SECFailure;
}
PORT_Memcpy(ctx->key, key, sizeof(ctx->key));
ctx->tagLen = tagLen;
return SECSuccess;
#endif
}
ChaCha20Poly1305Context *
ChaCha20Poly1305_CreateContext(const unsigned char *key, unsigned int keyLen,
unsigned int tagLen)
{
#ifdef NSS_DISABLE_CHACHAPOLY
return NULL;
#else
ChaCha20Poly1305Context *ctx;
ctx = PORT_New(ChaCha20Poly1305Context);
if (ctx == NULL) {
return NULL;
}
if (ChaCha20Poly1305_InitContext(ctx, key, keyLen, tagLen) != SECSuccess) {
PORT_Free(ctx);
ctx = NULL;
}
return ctx;
#endif
}
void
ChaCha20Poly1305_DestroyContext(ChaCha20Poly1305Context *ctx, PRBool freeit)
{
#ifndef NSS_DISABLE_CHACHAPOLY
PORT_Memset(ctx, 0, sizeof(*ctx));
if (freeit) {
PORT_Free(ctx);
}
#endif
}
SECStatus
ChaCha20Poly1305_Seal(const ChaCha20Poly1305Context *ctx, unsigned char *output,
unsigned int *outputLen, unsigned int maxOutputLen,
const unsigned char *input, unsigned int inputLen,
const unsigned char *nonce, unsigned int nonceLen,
const unsigned char *ad, unsigned int adLen)
{
#ifdef NSS_DISABLE_CHACHAPOLY
return SECFailure;
#else
unsigned char block[64];
unsigned char tag[16];
if (nonceLen != 12) {
PORT_SetError(SEC_ERROR_INPUT_LEN);
return SECFailure;
}
*outputLen = inputLen + ctx->tagLen;
if (maxOutputLen < *outputLen) {
PORT_SetError(SEC_ERROR_OUTPUT_LEN);
return SECFailure;
}
PORT_Memset(block, 0, sizeof(block));
// Generate a block of keystream. The first 32 bytes will be the poly1305
// key. The remainder of the block is discarded.
ChaCha20XOR(block, block, sizeof(block), ctx->key, nonce, 0);
ChaCha20XOR(output, input, inputLen, ctx->key, nonce, 1);
Poly1305Do(tag, ad, adLen, output, inputLen, block);
PORT_Memcpy(output + inputLen, tag, ctx->tagLen);
return SECSuccess;
#endif
}
SECStatus
ChaCha20Poly1305_Open(const ChaCha20Poly1305Context *ctx, unsigned char *output,
unsigned int *outputLen, unsigned int maxOutputLen,
const unsigned char *input, unsigned int inputLen,
const unsigned char *nonce, unsigned int nonceLen,
const unsigned char *ad, unsigned int adLen)
{
#ifdef NSS_DISABLE_CHACHAPOLY
return SECFailure;
#else
unsigned char block[64];
unsigned char tag[16];
unsigned int ciphertextLen;
if (nonceLen != 12) {
PORT_SetError(SEC_ERROR_INPUT_LEN);
return SECFailure;
}
if (inputLen < ctx->tagLen) {
PORT_SetError(SEC_ERROR_INPUT_LEN);
return SECFailure;
}
ciphertextLen = inputLen - ctx->tagLen;
*outputLen = ciphertextLen;
if (maxOutputLen < *outputLen) {
PORT_SetError(SEC_ERROR_OUTPUT_LEN);
return SECFailure;
}
PORT_Memset(block, 0, sizeof(block));
// Generate a block of keystream. The first 32 bytes will be the poly1305
// key. The remainder of the block is discarded.
ChaCha20XOR(block, block, sizeof(block), ctx->key, nonce, 0);
Poly1305Do(tag, ad, adLen, input, ciphertextLen, block);
if (NSS_SecureMemcmp(tag, &input[ciphertextLen], ctx->tagLen) != 0) {
PORT_SetError(SEC_ERROR_BAD_DATA);
return SECFailure;
}
ChaCha20XOR(output, input, ciphertextLen, ctx->key, nonce, 1);
return SECSuccess;
#endif
}

View file

@ -0,0 +1,15 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef _CHACHA20_POLY1305_H_
#define _CHACHA20_POLY1305_H_ 1
/* ChaCha20Poly1305ContextStr saves the key and tag length for a
* ChaCha20+Poly1305 AEAD operation. */
struct ChaCha20Poly1305ContextStr {
unsigned char key[32];
unsigned char tagLen;
};
#endif /* _CHACHA20_POLY1305_H_ */

View file

@ -0,0 +1,97 @@
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
# only do this in the outermost freebl build.
ifndef FREEBL_CHILD_BUILD
# We're going to change this build so that it builds libfreebl.a with
# just loader.c. Then we have to build this directory twice again to
# build the two DSOs.
# To build libfreebl.a with just loader.c, we must now override many
# of the make variables setup by the prior inclusion of CORECONF's config.mk
CSRCS = loader.c
SIMPLE_OBJS = $(CSRCS:.c=$(OBJ_SUFFIX))
OBJS = $(addprefix $(OBJDIR)/$(PROG_PREFIX), $(SIMPLE_OBJS))
ALL_TRASH := $(TARGETS) $(OBJS) $(OBJDIR) LOGS TAGS $(GARBAGE) \
$(NOSUCHFILE) so_locations
# this is not a recursive child make. We make a static lib. (archive)
# Override the values defined in coreconf's ruleset.mk.
#
# - (1) LIBRARY: a static (archival) library
# - (2) SHARED_LIBRARY: a shared (dynamic link) library
# - (3) IMPORT_LIBRARY: an import library, used only on Windows
# - (4) PROGRAM: an executable binary
#
# override these variables to prevent building a DSO/DLL.
TARGETS = $(LIBRARY)
SHARED_LIBRARY =
IMPORT_LIBRARY =
PROGRAM =
else
# This is a recursive child make. We build the shared lib.
TARGETS = $(SHARED_LIBRARY)
LIBRARY =
IMPORT_LIBRARY =
PROGRAM =
ifeq ($(OS_TARGET), SunOS)
OS_LIBS += -lkstat
endif
ifeq (,$(filter-out WIN%,$(OS_TARGET)))
# don't want the 32 in the shared library name
SHARED_LIBRARY = $(OBJDIR)/$(DLL_PREFIX)$(LIBRARY_NAME)$(LIBRARY_VERSION).$(DLL_SUFFIX)
RES = $(OBJDIR)/$(LIBRARY_NAME).res
RESNAME = freebl.rc
ifdef NS_USE_GCC
OS_LIBS += -ladvapi32
else
OS_LIBS += advapi32.lib
endif
ifdef NS_USE_GCC
EXTRA_SHARED_LIBS += \
-L$(DIST)/lib \
-L$(NSSUTIL_LIB_DIR) \
-lnssutil3 \
-L$(NSPR_LIB_DIR) \
-lnspr4 \
$(NULL)
else # ! NS_USE_GCC
EXTRA_SHARED_LIBS += \
$(DIST)/lib/nssutil3.lib \
$(NSPR_LIB_DIR)/$(NSPR31_LIB_PREFIX)nspr4.lib \
$(NULL)
endif # NS_USE_GCC
else
ifeq ($(FREEBL_NO_DEPEND),1)
#drop pthreads as well
OS_PTHREAD=
else
EXTRA_SHARED_LIBS += \
-L$(DIST)/lib \
-L$(NSSUTIL_LIB_DIR) \
-lnssutil3 \
-L$(NSPR_LIB_DIR) \
-lnspr4 \
$(NULL)
endif
endif
ifeq ($(OS_ARCH), Darwin)
EXTRA_SHARED_LIBS += -dylib_file @executable_path/libplc4.dylib:$(DIST)/lib/libplc4.dylib -dylib_file @executable_path/libplds4.dylib:$(DIST)/lib/libplds4.dylib
endif
endif

View file

@ -0,0 +1,246 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifdef FREEBL_NO_DEPEND
#include "stubs.h"
#endif
#include "prtypes.h"
#include "blapit.h"
#include "blapii.h"
#include "ctr.h"
#include "pkcs11t.h"
#include "secerr.h"
#ifdef USE_HW_AES
#include "intel-aes.h"
#include "rijndael.h"
#endif
SECStatus
CTR_InitContext(CTRContext *ctr, void *context, freeblCipherFunc cipher,
const unsigned char *param, unsigned int blocksize)
{
const CK_AES_CTR_PARAMS *ctrParams = (const CK_AES_CTR_PARAMS *)param;
if (ctrParams->ulCounterBits == 0 ||
ctrParams->ulCounterBits > blocksize * PR_BITS_PER_BYTE) {
PORT_SetError(SEC_ERROR_INVALID_ARGS);
return SECFailure;
}
/* Invariant: 0 < ctr->bufPtr <= blocksize */
ctr->checkWrap = PR_FALSE;
ctr->bufPtr = blocksize; /* no unused data in the buffer */
ctr->cipher = cipher;
ctr->context = context;
ctr->counterBits = ctrParams->ulCounterBits;
if (blocksize > sizeof(ctr->counter) ||
blocksize > sizeof(ctrParams->cb)) {
PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
return SECFailure;
}
PORT_Memcpy(ctr->counter, ctrParams->cb, blocksize);
if (ctr->counterBits < 64) {
PORT_Memcpy(ctr->counterFirst, ctr->counter, blocksize);
ctr->checkWrap = PR_TRUE;
}
return SECSuccess;
}
CTRContext *
CTR_CreateContext(void *context, freeblCipherFunc cipher,
const unsigned char *param, unsigned int blocksize)
{
CTRContext *ctr;
SECStatus rv;
/* first fill in the Counter context */
ctr = PORT_ZNew(CTRContext);
if (ctr == NULL) {
return NULL;
}
rv = CTR_InitContext(ctr, context, cipher, param, blocksize);
if (rv != SECSuccess) {
CTR_DestroyContext(ctr, PR_TRUE);
ctr = NULL;
}
return ctr;
}
void
CTR_DestroyContext(CTRContext *ctr, PRBool freeit)
{
PORT_Memset(ctr, 0, sizeof(CTRContext));
if (freeit) {
PORT_Free(ctr);
}
}
/*
* Used by counter mode. Increment the counter block. Not all bits in the
* counter block are part of the counter, counterBits tells how many bits
* are part of the counter. The counter block is blocksize long. It's a
* big endian value.
*
* XXX Does not handle counter rollover.
*/
static void
ctr_GetNextCtr(unsigned char *counter, unsigned int counterBits,
unsigned int blocksize)
{
unsigned char *counterPtr = counter + blocksize - 1;
unsigned char mask, count;
PORT_Assert(counterBits <= blocksize * PR_BITS_PER_BYTE);
while (counterBits >= PR_BITS_PER_BYTE) {
if (++(*(counterPtr--))) {
return;
}
counterBits -= PR_BITS_PER_BYTE;
}
if (counterBits == 0) {
return;
}
/* increment the final partial byte */
mask = (1 << counterBits) - 1;
count = ++(*counterPtr) & mask;
*counterPtr = ((*counterPtr) & ~mask) | count;
return;
}
static void
ctr_xor(unsigned char *target, const unsigned char *x,
const unsigned char *y, unsigned int count)
{
unsigned int i;
for (i = 0; i < count; i++) {
*target++ = *x++ ^ *y++;
}
}
SECStatus
CTR_Update(CTRContext *ctr, unsigned char *outbuf,
unsigned int *outlen, unsigned int maxout,
const unsigned char *inbuf, unsigned int inlen,
unsigned int blocksize)
{
unsigned int tmp;
SECStatus rv;
if (maxout < inlen) {
*outlen = inlen;
PORT_SetError(SEC_ERROR_OUTPUT_LEN);
return SECFailure;
}
*outlen = 0;
if (ctr->bufPtr != blocksize) {
unsigned int needed = PR_MIN(blocksize - ctr->bufPtr, inlen);
ctr_xor(outbuf, inbuf, ctr->buffer + ctr->bufPtr, needed);
ctr->bufPtr += needed;
outbuf += needed;
inbuf += needed;
*outlen += needed;
inlen -= needed;
if (inlen == 0) {
return SECSuccess;
}
PORT_Assert(ctr->bufPtr == blocksize);
}
while (inlen >= blocksize) {
rv = (*ctr->cipher)(ctr->context, ctr->buffer, &tmp, blocksize,
ctr->counter, blocksize, blocksize);
ctr_GetNextCtr(ctr->counter, ctr->counterBits, blocksize);
if (ctr->checkWrap) {
if (PORT_Memcmp(ctr->counter, ctr->counterFirst, blocksize) == 0) {
PORT_SetError(SEC_ERROR_INVALID_ARGS);
return SECFailure;
}
}
if (rv != SECSuccess) {
return SECFailure;
}
ctr_xor(outbuf, inbuf, ctr->buffer, blocksize);
outbuf += blocksize;
inbuf += blocksize;
*outlen += blocksize;
inlen -= blocksize;
}
if (inlen == 0) {
return SECSuccess;
}
rv = (*ctr->cipher)(ctr->context, ctr->buffer, &tmp, blocksize,
ctr->counter, blocksize, blocksize);
ctr_GetNextCtr(ctr->counter, ctr->counterBits, blocksize);
if (ctr->checkWrap) {
if (PORT_Memcmp(ctr->counter, ctr->counterFirst, blocksize) == 0) {
PORT_SetError(SEC_ERROR_INVALID_ARGS);
return SECFailure;
}
}
if (rv != SECSuccess) {
return SECFailure;
}
ctr_xor(outbuf, inbuf, ctr->buffer, inlen);
ctr->bufPtr = inlen;
*outlen += inlen;
return SECSuccess;
}
#if defined(USE_HW_AES) && defined(_MSC_VER)
SECStatus
CTR_Update_HW_AES(CTRContext *ctr, unsigned char *outbuf,
unsigned int *outlen, unsigned int maxout,
const unsigned char *inbuf, unsigned int inlen,
unsigned int blocksize)
{
unsigned int fullblocks;
unsigned int tmp;
SECStatus rv;
if (maxout < inlen) {
*outlen = inlen;
PORT_SetError(SEC_ERROR_OUTPUT_LEN);
return SECFailure;
}
*outlen = 0;
if (ctr->bufPtr != blocksize) {
unsigned int needed = PR_MIN(blocksize - ctr->bufPtr, inlen);
ctr_xor(outbuf, inbuf, ctr->buffer + ctr->bufPtr, needed);
ctr->bufPtr += needed;
outbuf += needed;
inbuf += needed;
*outlen += needed;
inlen -= needed;
if (inlen == 0) {
return SECSuccess;
}
PORT_Assert(ctr->bufPtr == blocksize);
}
intel_aes_ctr_worker(((AESContext *)(ctr->context))->Nr)(
ctr, outbuf, outlen, maxout, inbuf, inlen, blocksize);
/* XXX intel_aes_ctr_worker should set *outlen. */
PORT_Assert(*outlen == 0);
fullblocks = (inlen / blocksize) * blocksize;
*outlen += fullblocks;
outbuf += fullblocks;
inbuf += fullblocks;
inlen -= fullblocks;
if (inlen == 0) {
return SECSuccess;
}
rv = (*ctr->cipher)(ctr->context, ctr->buffer, &tmp, blocksize,
ctr->counter, blocksize, blocksize);
ctr_GetNextCtr(ctr->counter, ctr->counterBits, blocksize);
if (rv != SECSuccess) {
return SECFailure;
}
ctr_xor(outbuf, inbuf, ctr->buffer, inlen);
ctr->bufPtr = inlen;
*outlen += inlen;
return SECSuccess;
}
#endif

View file

@ -0,0 +1,53 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef CTR_H
#define CTR_H 1
#include "blapii.h"
/* This structure is defined in this header because both ctr.c and gcm.c
* need it. */
struct CTRContextStr {
freeblCipherFunc cipher;
void *context;
unsigned char counter[MAX_BLOCK_SIZE];
unsigned char buffer[MAX_BLOCK_SIZE];
unsigned char counterFirst[MAX_BLOCK_SIZE]; /* counter overlfow value */
PRBool checkWrap; /*check for counter overflow*/
unsigned long counterBits;
unsigned int bufPtr;
};
typedef struct CTRContextStr CTRContext;
SECStatus CTR_InitContext(CTRContext *ctr, void *context,
freeblCipherFunc cipher, const unsigned char *param,
unsigned int blocksize);
/*
* The context argument is the inner cipher context to use with cipher. The
* CTRContext does not own context. context needs to remain valid for as long
* as the CTRContext is valid.
*
* The cipher argument is a block cipher in the ECB encrypt mode.
*/
CTRContext *CTR_CreateContext(void *context, freeblCipherFunc cipher,
const unsigned char *param, unsigned int blocksize);
void CTR_DestroyContext(CTRContext *ctr, PRBool freeit);
SECStatus CTR_Update(CTRContext *ctr, unsigned char *outbuf,
unsigned int *outlen, unsigned int maxout,
const unsigned char *inbuf, unsigned int inlen,
unsigned int blocksize);
#ifdef USE_HW_AES
SECStatus CTR_Update_HW_AES(CTRContext *ctr, unsigned char *outbuf,
unsigned int *outlen, unsigned int maxout,
const unsigned char *inbuf, unsigned int inlen,
unsigned int blocksize);
#endif
#endif

View file

@ -0,0 +1,307 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifdef FREEBL_NO_DEPEND
#include "stubs.h"
#endif
#include "blapit.h"
#include "blapii.h"
#include "cts.h"
#include "secerr.h"
struct CTSContextStr {
freeblCipherFunc cipher;
void *context;
/* iv stores the last ciphertext block of the previous message.
* Only used by decrypt. */
unsigned char iv[MAX_BLOCK_SIZE];
};
CTSContext *
CTS_CreateContext(void *context, freeblCipherFunc cipher,
const unsigned char *iv, unsigned int blocksize)
{
CTSContext *cts;
if (blocksize > MAX_BLOCK_SIZE) {
PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
return NULL;
}
cts = PORT_ZNew(CTSContext);
if (cts == NULL) {
return NULL;
}
PORT_Memcpy(cts->iv, iv, blocksize);
cts->cipher = cipher;
cts->context = context;
return cts;
}
void
CTS_DestroyContext(CTSContext *cts, PRBool freeit)
{
if (freeit) {
PORT_Free(cts);
}
}
/*
* See addemdum to NIST SP 800-38A
* Generically handle cipher text stealing. Basically this is doing CBC
* operations except someone can pass us a partial block.
*
* Output Order:
* CS-1: C1||C2||C3..Cn-1(could be partial)||Cn (NIST)
* CS-2: pad == 0 C1||C2||C3...Cn-1(is full)||Cn (Schneier)
* CS-2: pad != 0 C1||C2||C3...Cn||Cn-1(is partial)(Schneier)
* CS-3: C1||C2||C3...Cn||Cn-1(could be partial) (Kerberos)
*
* The characteristics of these three options:
* - NIST & Schneier (CS-1 & CS-2) are identical to CBC if there are no
* partial blocks on input.
* - Scheier and Kerberos (CS-2 and CS-3) have no embedded partial blocks,
* which make decoding easier.
* - NIST & Kerberos (CS-1 and CS-3) have consistent block order independent
* of padding.
*
* PKCS #11 did not specify which version to implement, but points to the NIST
* spec, so this code implements CTS-CS-1 from NIST.
*
* To convert the returned buffer to:
* CS-2 (Schneier): do
* unsigned char tmp[MAX_BLOCK_SIZE];
* pad = *outlen % blocksize;
* if (pad) {
* memcpy(tmp, outbuf+*outlen-blocksize, blocksize);
* memcpy(outbuf+*outlen-pad,outbuf+*outlen-blocksize-pad, pad);
* memcpy(outbuf+*outlen-blocksize-pad, tmp, blocksize);
* }
* CS-3 (Kerberos): do
* unsigned char tmp[MAX_BLOCK_SIZE];
* pad = *outlen % blocksize;
* if (pad == 0) {
* pad = blocksize;
* }
* memcpy(tmp, outbuf+*outlen-blocksize, blocksize);
* memcpy(outbuf+*outlen-pad,outbuf+*outlen-blocksize-pad, pad);
* memcpy(outbuf+*outlen-blocksize-pad, tmp, blocksize);
*/
SECStatus
CTS_EncryptUpdate(CTSContext *cts, unsigned char *outbuf,
unsigned int *outlen, unsigned int maxout,
const unsigned char *inbuf, unsigned int inlen,
unsigned int blocksize)
{
unsigned char lastBlock[MAX_BLOCK_SIZE];
unsigned int tmp;
int fullblocks;
int written;
unsigned char *saveout = outbuf;
SECStatus rv;
if (inlen < blocksize) {
PORT_SetError(SEC_ERROR_INPUT_LEN);
return SECFailure;
}
if (maxout < inlen) {
*outlen = inlen;
PORT_SetError(SEC_ERROR_OUTPUT_LEN);
return SECFailure;
}
fullblocks = (inlen / blocksize) * blocksize;
rv = (*cts->cipher)(cts->context, outbuf, outlen, maxout, inbuf,
fullblocks, blocksize);
if (rv != SECSuccess) {
return SECFailure;
}
*outlen = fullblocks; /* AES low level doesn't set outlen */
inbuf += fullblocks;
inlen -= fullblocks;
if (inlen == 0) {
return SECSuccess;
}
written = *outlen - (blocksize - inlen);
outbuf += written;
maxout -= written;
/*
* here's the CTS magic, we pad our final block with zeros,
* then do a CBC encrypt. CBC will xor our plain text with
* the previous block (Cn-1), capturing part of that block (Cn-1**) as it
* xors with the zero pad. We then write this full block, overwritting
* (Cn-1**) in our buffer. This allows us to have input data == output
* data since Cn contains enough information to reconver Cn-1** when
* we decrypt (at the cost of some complexity as you can see in decrypt
* below */
PORT_Memcpy(lastBlock, inbuf, inlen);
PORT_Memset(lastBlock + inlen, 0, blocksize - inlen);
rv = (*cts->cipher)(cts->context, outbuf, &tmp, maxout, lastBlock,
blocksize, blocksize);
PORT_Memset(lastBlock, 0, blocksize);
if (rv == SECSuccess) {
*outlen = written + blocksize;
} else {
PORT_Memset(saveout, 0, written + blocksize);
}
return rv;
}
#define XOR_BLOCK(x, y, count) \
for (i = 0; i < count; i++) \
x[i] = x[i] ^ y[i]
/*
* See addemdum to NIST SP 800-38A
* Decrypt, Expect CS-1: input. See the comment on the encrypt side
* to understand what CS-2 and CS-3 mean.
*
* To convert the input buffer to CS-1 from ...
* CS-2 (Schneier): do
* unsigned char tmp[MAX_BLOCK_SIZE];
* pad = inlen % blocksize;
* if (pad) {
* memcpy(tmp, inbuf+inlen-blocksize-pad, blocksize);
* memcpy(inbuf+inlen-blocksize-pad,inbuf+inlen-pad, pad);
* memcpy(inbuf+inlen-blocksize, tmp, blocksize);
* }
* CS-3 (Kerberos): do
* unsigned char tmp[MAX_BLOCK_SIZE];
* pad = inlen % blocksize;
* if (pad == 0) {
* pad = blocksize;
* }
* memcpy(tmp, inbuf+inlen-blocksize-pad, blocksize);
* memcpy(inbuf+inlen-blocksize-pad,inbuf+inlen-pad, pad);
* memcpy(inbuf+inlen-blocksize, tmp, blocksize);
*/
SECStatus
CTS_DecryptUpdate(CTSContext *cts, unsigned char *outbuf,
unsigned int *outlen, unsigned int maxout,
const unsigned char *inbuf, unsigned int inlen,
unsigned int blocksize)
{
unsigned char *Pn;
unsigned char Cn_2[MAX_BLOCK_SIZE]; /* block Cn-2 */
unsigned char Cn_1[MAX_BLOCK_SIZE]; /* block Cn-1 */
unsigned char Cn[MAX_BLOCK_SIZE]; /* block Cn */
unsigned char lastBlock[MAX_BLOCK_SIZE];
const unsigned char *tmp;
unsigned char *saveout = outbuf;
unsigned int tmpLen;
unsigned int fullblocks, pad;
unsigned int i;
SECStatus rv;
if (inlen < blocksize) {
PORT_SetError(SEC_ERROR_INPUT_LEN);
return SECFailure;
}
if (maxout < inlen) {
*outlen = inlen;
PORT_SetError(SEC_ERROR_OUTPUT_LEN);
return SECFailure;
}
fullblocks = (inlen / blocksize) * blocksize;
/* even though we expect the input to be CS-1, CS-2 is easier to parse,
* so convert to CS-2 immediately. NOTE: this is the same code as in
* the comment for encrypt. NOTE2: since we can't modify inbuf unless
* inbuf and outbuf overlap, just copy inbuf to outbuf and modify it there
*/
pad = inlen - fullblocks;
if (pad != 0) {
if (inbuf != outbuf) {
memcpy(outbuf, inbuf, inlen);
/* keep the names so we logically know how we are using the
* buffers */
inbuf = outbuf;
}
memcpy(lastBlock, inbuf + inlen - blocksize, blocksize);
/* we know inbuf == outbuf now, inbuf is declared const and can't
* be the target, so use outbuf for the target here */
memcpy(outbuf + inlen - pad, inbuf + inlen - blocksize - pad, pad);
memcpy(outbuf + inlen - blocksize - pad, lastBlock, blocksize);
}
/* save the previous to last block so we can undo the misordered
* chaining */
tmp = (fullblocks < blocksize * 2) ? cts->iv : inbuf + fullblocks - blocksize * 2;
PORT_Memcpy(Cn_2, tmp, blocksize);
PORT_Memcpy(Cn, inbuf + fullblocks - blocksize, blocksize);
rv = (*cts->cipher)(cts->context, outbuf, outlen, maxout, inbuf,
fullblocks, blocksize);
if (rv != SECSuccess) {
return SECFailure;
}
*outlen = fullblocks; /* AES low level doesn't set outlen */
inbuf += fullblocks;
inlen -= fullblocks;
if (inlen == 0) {
return SECSuccess;
}
outbuf += fullblocks;
/* recover the stolen text */
PORT_Memset(lastBlock, 0, blocksize);
PORT_Memcpy(lastBlock, inbuf, inlen);
PORT_Memcpy(Cn_1, inbuf, inlen);
Pn = outbuf - blocksize;
/* inbuf points to Cn-1* in the input buffer */
/* NOTE: below there are 2 sections marked "make up for the out of order
* cbc decryption". You may ask, what is going on here.
* Short answer: CBC automatically xors the plain text with the previous
* encrypted block. We are decrypting the last 2 blocks out of order, so
* we have to 'back out' the decrypt xor and 'add back' the encrypt xor.
* Long answer: When we encrypted, we encrypted as follows:
* Pn-2, Pn-1, (Pn || 0), but on decryption we can't
* decrypt Cn-1 until we decrypt Cn because part of Cn-1 is stored in
* Cn (see below). So above we decrypted all the full blocks:
* Cn-2, Cn,
* to get:
* Pn-2, Pn, Except that Pn is not yet corect. On encrypt, we
* xor'd Pn || 0 with Cn-1, but on decrypt we xor'd it with Cn-2
* To recover Pn, we xor the block with Cn-1* || 0 (in last block) and
* Cn-2 to get Pn || Cn-1**. Pn can then be written to the output buffer
* and we can now reunite Cn-1. With the full Cn-1 we can decrypt it,
* but now decrypt is going to xor the decrypted data with Cn instead of
* Cn-2. xoring Cn and Cn-2 restores the original Pn-1 and we can now
* write that oout to the buffer */
/* make up for the out of order CBC decryption */
XOR_BLOCK(lastBlock, Cn_2, blocksize);
XOR_BLOCK(lastBlock, Pn, blocksize);
/* last buf now has Pn || Cn-1**, copy out Pn */
PORT_Memcpy(outbuf, lastBlock, inlen);
*outlen += inlen;
/* copy Cn-1* into last buf to recover Cn-1 */
PORT_Memcpy(lastBlock, Cn_1, inlen);
/* note: because Cn and Cn-1 were out of order, our pointer to Pn also
* points to where Pn-1 needs to reside. From here on out read Pn in
* the code as really Pn-1. */
rv = (*cts->cipher)(cts->context, Pn, &tmpLen, blocksize, lastBlock,
blocksize, blocksize);
if (rv != SECSuccess) {
PORT_Memset(lastBlock, 0, blocksize);
PORT_Memset(saveout, 0, *outlen);
return SECFailure;
}
/* make up for the out of order CBC decryption */
XOR_BLOCK(Pn, Cn_2, blocksize);
XOR_BLOCK(Pn, Cn, blocksize);
/* reset iv to Cn */
PORT_Memcpy(cts->iv, Cn, blocksize);
/* This makes Cn the last block for the next decrypt operation, which
* matches the encrypt. We don't care about the contexts of last block,
* only the side effect of setting the internal IV */
(void)(*cts->cipher)(cts->context, lastBlock, &tmpLen, blocksize, Cn,
blocksize, blocksize);
/* clear last block. At this point last block contains Pn xor Cn_1 xor
* Cn_2, both of with an attacker would know, so we need to clear this
* buffer out */
PORT_Memset(lastBlock, 0, blocksize);
/* Cn, Cn_1, and Cn_2 have encrypted data, so no need to clear them */
return SECSuccess;
}

View file

@ -0,0 +1,33 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef CTS_H
#define CTS_H 1
#include "blapii.h"
typedef struct CTSContextStr CTSContext;
/*
* The context argument is the inner cipher context to use with cipher. The
* CTSContext does not own context. context needs to remain valid for as long
* as the CTSContext is valid.
*
* The cipher argument is a block cipher in the CBC mode.
*/
CTSContext *CTS_CreateContext(void *context, freeblCipherFunc cipher,
const unsigned char *iv, unsigned int blocksize);
void CTS_DestroyContext(CTSContext *cts, PRBool freeit);
SECStatus CTS_EncryptUpdate(CTSContext *cts, unsigned char *outbuf,
unsigned int *outlen, unsigned int maxout,
const unsigned char *inbuf, unsigned int inlen,
unsigned int blocksize);
SECStatus CTS_DecryptUpdate(CTSContext *cts, unsigned char *outbuf,
unsigned int *outlen, unsigned int maxout,
const unsigned char *inbuf, unsigned int inlen,
unsigned int blocksize);
#endif

View file

@ -0,0 +1,676 @@
/*
* des.c
*
* core source file for DES-150 library
* Make key schedule from DES key.
* Encrypt/Decrypt one 8-byte block.
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "des.h"
#include "blapii.h"
#include <stddef.h> /* for ptrdiff_t */
/* #define USE_INDEXING 1 */
/*
* The tables below are the 8 sbox functions, with the 6-bit input permutation
* and the 32-bit output permutation pre-computed.
* They are shifted circularly to the left 3 bits, which removes 2 shifts
* and an or from each round by reducing the number of sboxes whose
* indices cross word broundaries from 2 to 1.
*/
static const HALF SP[8][64] = {
/* Box S1 */
{ 0x04041000, 0x00000000, 0x00040000, 0x04041010,
0x04040010, 0x00041010, 0x00000010, 0x00040000,
0x00001000, 0x04041000, 0x04041010, 0x00001000,
0x04001010, 0x04040010, 0x04000000, 0x00000010,
0x00001010, 0x04001000, 0x04001000, 0x00041000,
0x00041000, 0x04040000, 0x04040000, 0x04001010,
0x00040010, 0x04000010, 0x04000010, 0x00040010,
0x00000000, 0x00001010, 0x00041010, 0x04000000,
0x00040000, 0x04041010, 0x00000010, 0x04040000,
0x04041000, 0x04000000, 0x04000000, 0x00001000,
0x04040010, 0x00040000, 0x00041000, 0x04000010,
0x00001000, 0x00000010, 0x04001010, 0x00041010,
0x04041010, 0x00040010, 0x04040000, 0x04001010,
0x04000010, 0x00001010, 0x00041010, 0x04041000,
0x00001010, 0x04001000, 0x04001000, 0x00000000,
0x00040010, 0x00041000, 0x00000000, 0x04040010 },
/* Box S2 */
{ 0x00420082, 0x00020002, 0x00020000, 0x00420080,
0x00400000, 0x00000080, 0x00400082, 0x00020082,
0x00000082, 0x00420082, 0x00420002, 0x00000002,
0x00020002, 0x00400000, 0x00000080, 0x00400082,
0x00420000, 0x00400080, 0x00020082, 0x00000000,
0x00000002, 0x00020000, 0x00420080, 0x00400002,
0x00400080, 0x00000082, 0x00000000, 0x00420000,
0x00020080, 0x00420002, 0x00400002, 0x00020080,
0x00000000, 0x00420080, 0x00400082, 0x00400000,
0x00020082, 0x00400002, 0x00420002, 0x00020000,
0x00400002, 0x00020002, 0x00000080, 0x00420082,
0x00420080, 0x00000080, 0x00020000, 0x00000002,
0x00020080, 0x00420002, 0x00400000, 0x00000082,
0x00400080, 0x00020082, 0x00000082, 0x00400080,
0x00420000, 0x00000000, 0x00020002, 0x00020080,
0x00000002, 0x00400082, 0x00420082, 0x00420000 },
/* Box S3 */
{ 0x00000820, 0x20080800, 0x00000000, 0x20080020,
0x20000800, 0x00000000, 0x00080820, 0x20000800,
0x00080020, 0x20000020, 0x20000020, 0x00080000,
0x20080820, 0x00080020, 0x20080000, 0x00000820,
0x20000000, 0x00000020, 0x20080800, 0x00000800,
0x00080800, 0x20080000, 0x20080020, 0x00080820,
0x20000820, 0x00080800, 0x00080000, 0x20000820,
0x00000020, 0x20080820, 0x00000800, 0x20000000,
0x20080800, 0x20000000, 0x00080020, 0x00000820,
0x00080000, 0x20080800, 0x20000800, 0x00000000,
0x00000800, 0x00080020, 0x20080820, 0x20000800,
0x20000020, 0x00000800, 0x00000000, 0x20080020,
0x20000820, 0x00080000, 0x20000000, 0x20080820,
0x00000020, 0x00080820, 0x00080800, 0x20000020,
0x20080000, 0x20000820, 0x00000820, 0x20080000,
0x00080820, 0x00000020, 0x20080020, 0x00080800 },
/* Box S4 */
{ 0x02008004, 0x00008204, 0x00008204, 0x00000200,
0x02008200, 0x02000204, 0x02000004, 0x00008004,
0x00000000, 0x02008000, 0x02008000, 0x02008204,
0x00000204, 0x00000000, 0x02000200, 0x02000004,
0x00000004, 0x00008000, 0x02000000, 0x02008004,
0x00000200, 0x02000000, 0x00008004, 0x00008200,
0x02000204, 0x00000004, 0x00008200, 0x02000200,
0x00008000, 0x02008200, 0x02008204, 0x00000204,
0x02000200, 0x02000004, 0x02008000, 0x02008204,
0x00000204, 0x00000000, 0x00000000, 0x02008000,
0x00008200, 0x02000200, 0x02000204, 0x00000004,
0x02008004, 0x00008204, 0x00008204, 0x00000200,
0x02008204, 0x00000204, 0x00000004, 0x00008000,
0x02000004, 0x00008004, 0x02008200, 0x02000204,
0x00008004, 0x00008200, 0x02000000, 0x02008004,
0x00000200, 0x02000000, 0x00008000, 0x02008200 },
/* Box S5 */
{ 0x00000400, 0x08200400, 0x08200000, 0x08000401,
0x00200000, 0x00000400, 0x00000001, 0x08200000,
0x00200401, 0x00200000, 0x08000400, 0x00200401,
0x08000401, 0x08200001, 0x00200400, 0x00000001,
0x08000000, 0x00200001, 0x00200001, 0x00000000,
0x00000401, 0x08200401, 0x08200401, 0x08000400,
0x08200001, 0x00000401, 0x00000000, 0x08000001,
0x08200400, 0x08000000, 0x08000001, 0x00200400,
0x00200000, 0x08000401, 0x00000400, 0x08000000,
0x00000001, 0x08200000, 0x08000401, 0x00200401,
0x08000400, 0x00000001, 0x08200001, 0x08200400,
0x00200401, 0x00000400, 0x08000000, 0x08200001,
0x08200401, 0x00200400, 0x08000001, 0x08200401,
0x08200000, 0x00000000, 0x00200001, 0x08000001,
0x00200400, 0x08000400, 0x00000401, 0x00200000,
0x00000000, 0x00200001, 0x08200400, 0x00000401 },
/* Box S6 */
{ 0x80000040, 0x81000000, 0x00010000, 0x81010040,
0x81000000, 0x00000040, 0x81010040, 0x01000000,
0x80010000, 0x01010040, 0x01000000, 0x80000040,
0x01000040, 0x80010000, 0x80000000, 0x00010040,
0x00000000, 0x01000040, 0x80010040, 0x00010000,
0x01010000, 0x80010040, 0x00000040, 0x81000040,
0x81000040, 0x00000000, 0x01010040, 0x81010000,
0x00010040, 0x01010000, 0x81010000, 0x80000000,
0x80010000, 0x00000040, 0x81000040, 0x01010000,
0x81010040, 0x01000000, 0x00010040, 0x80000040,
0x01000000, 0x80010000, 0x80000000, 0x00010040,
0x80000040, 0x81010040, 0x01010000, 0x81000000,
0x01010040, 0x81010000, 0x00000000, 0x81000040,
0x00000040, 0x00010000, 0x81000000, 0x01010040,
0x00010000, 0x01000040, 0x80010040, 0x00000000,
0x81010000, 0x80000000, 0x01000040, 0x80010040 },
/* Box S7 */
{ 0x00800000, 0x10800008, 0x10002008, 0x00000000,
0x00002000, 0x10002008, 0x00802008, 0x10802000,
0x10802008, 0x00800000, 0x00000000, 0x10000008,
0x00000008, 0x10000000, 0x10800008, 0x00002008,
0x10002000, 0x00802008, 0x00800008, 0x10002000,
0x10000008, 0x10800000, 0x10802000, 0x00800008,
0x10800000, 0x00002000, 0x00002008, 0x10802008,
0x00802000, 0x00000008, 0x10000000, 0x00802000,
0x10000000, 0x00802000, 0x00800000, 0x10002008,
0x10002008, 0x10800008, 0x10800008, 0x00000008,
0x00800008, 0x10000000, 0x10002000, 0x00800000,
0x10802000, 0x00002008, 0x00802008, 0x10802000,
0x00002008, 0x10000008, 0x10802008, 0x10800000,
0x00802000, 0x00000000, 0x00000008, 0x10802008,
0x00000000, 0x00802008, 0x10800000, 0x00002000,
0x10000008, 0x10002000, 0x00002000, 0x00800008 },
/* Box S8 */
{ 0x40004100, 0x00004000, 0x00100000, 0x40104100,
0x40000000, 0x40004100, 0x00000100, 0x40000000,
0x00100100, 0x40100000, 0x40104100, 0x00104000,
0x40104000, 0x00104100, 0x00004000, 0x00000100,
0x40100000, 0x40000100, 0x40004000, 0x00004100,
0x00104000, 0x00100100, 0x40100100, 0x40104000,
0x00004100, 0x00000000, 0x00000000, 0x40100100,
0x40000100, 0x40004000, 0x00104100, 0x00100000,
0x00104100, 0x00100000, 0x40104000, 0x00004000,
0x00000100, 0x40100100, 0x00004000, 0x00104100,
0x40004000, 0x00000100, 0x40000100, 0x40100000,
0x40100100, 0x40000000, 0x00100000, 0x40004100,
0x00000000, 0x40104100, 0x00100100, 0x40000100,
0x40100000, 0x40004000, 0x40004100, 0x00000000,
0x40104100, 0x00104000, 0x00104000, 0x00004100,
0x00004100, 0x00100100, 0x40000000, 0x40104000 }
};
static const HALF PC2[8][64] = {
/* table 0 */
{ 0x00000000, 0x00001000, 0x04000000, 0x04001000,
0x00100000, 0x00101000, 0x04100000, 0x04101000,
0x00008000, 0x00009000, 0x04008000, 0x04009000,
0x00108000, 0x00109000, 0x04108000, 0x04109000,
0x00000004, 0x00001004, 0x04000004, 0x04001004,
0x00100004, 0x00101004, 0x04100004, 0x04101004,
0x00008004, 0x00009004, 0x04008004, 0x04009004,
0x00108004, 0x00109004, 0x04108004, 0x04109004,
0x08000000, 0x08001000, 0x0c000000, 0x0c001000,
0x08100000, 0x08101000, 0x0c100000, 0x0c101000,
0x08008000, 0x08009000, 0x0c008000, 0x0c009000,
0x08108000, 0x08109000, 0x0c108000, 0x0c109000,
0x08000004, 0x08001004, 0x0c000004, 0x0c001004,
0x08100004, 0x08101004, 0x0c100004, 0x0c101004,
0x08008004, 0x08009004, 0x0c008004, 0x0c009004,
0x08108004, 0x08109004, 0x0c108004, 0x0c109004 },
/* table 1 */
{ 0x00000000, 0x00002000, 0x80000000, 0x80002000,
0x00000008, 0x00002008, 0x80000008, 0x80002008,
0x00200000, 0x00202000, 0x80200000, 0x80202000,
0x00200008, 0x00202008, 0x80200008, 0x80202008,
0x20000000, 0x20002000, 0xa0000000, 0xa0002000,
0x20000008, 0x20002008, 0xa0000008, 0xa0002008,
0x20200000, 0x20202000, 0xa0200000, 0xa0202000,
0x20200008, 0x20202008, 0xa0200008, 0xa0202008,
0x00000400, 0x00002400, 0x80000400, 0x80002400,
0x00000408, 0x00002408, 0x80000408, 0x80002408,
0x00200400, 0x00202400, 0x80200400, 0x80202400,
0x00200408, 0x00202408, 0x80200408, 0x80202408,
0x20000400, 0x20002400, 0xa0000400, 0xa0002400,
0x20000408, 0x20002408, 0xa0000408, 0xa0002408,
0x20200400, 0x20202400, 0xa0200400, 0xa0202400,
0x20200408, 0x20202408, 0xa0200408, 0xa0202408 },
/* table 2 */
{ 0x00000000, 0x00004000, 0x00000020, 0x00004020,
0x00080000, 0x00084000, 0x00080020, 0x00084020,
0x00000800, 0x00004800, 0x00000820, 0x00004820,
0x00080800, 0x00084800, 0x00080820, 0x00084820,
0x00000010, 0x00004010, 0x00000030, 0x00004030,
0x00080010, 0x00084010, 0x00080030, 0x00084030,
0x00000810, 0x00004810, 0x00000830, 0x00004830,
0x00080810, 0x00084810, 0x00080830, 0x00084830,
0x00400000, 0x00404000, 0x00400020, 0x00404020,
0x00480000, 0x00484000, 0x00480020, 0x00484020,
0x00400800, 0x00404800, 0x00400820, 0x00404820,
0x00480800, 0x00484800, 0x00480820, 0x00484820,
0x00400010, 0x00404010, 0x00400030, 0x00404030,
0x00480010, 0x00484010, 0x00480030, 0x00484030,
0x00400810, 0x00404810, 0x00400830, 0x00404830,
0x00480810, 0x00484810, 0x00480830, 0x00484830 },
/* table 3 */
{ 0x00000000, 0x40000000, 0x00000080, 0x40000080,
0x00040000, 0x40040000, 0x00040080, 0x40040080,
0x00000040, 0x40000040, 0x000000c0, 0x400000c0,
0x00040040, 0x40040040, 0x000400c0, 0x400400c0,
0x10000000, 0x50000000, 0x10000080, 0x50000080,
0x10040000, 0x50040000, 0x10040080, 0x50040080,
0x10000040, 0x50000040, 0x100000c0, 0x500000c0,
0x10040040, 0x50040040, 0x100400c0, 0x500400c0,
0x00800000, 0x40800000, 0x00800080, 0x40800080,
0x00840000, 0x40840000, 0x00840080, 0x40840080,
0x00800040, 0x40800040, 0x008000c0, 0x408000c0,
0x00840040, 0x40840040, 0x008400c0, 0x408400c0,
0x10800000, 0x50800000, 0x10800080, 0x50800080,
0x10840000, 0x50840000, 0x10840080, 0x50840080,
0x10800040, 0x50800040, 0x108000c0, 0x508000c0,
0x10840040, 0x50840040, 0x108400c0, 0x508400c0 },
/* table 4 */
{ 0x00000000, 0x00000008, 0x08000000, 0x08000008,
0x00040000, 0x00040008, 0x08040000, 0x08040008,
0x00002000, 0x00002008, 0x08002000, 0x08002008,
0x00042000, 0x00042008, 0x08042000, 0x08042008,
0x80000000, 0x80000008, 0x88000000, 0x88000008,
0x80040000, 0x80040008, 0x88040000, 0x88040008,
0x80002000, 0x80002008, 0x88002000, 0x88002008,
0x80042000, 0x80042008, 0x88042000, 0x88042008,
0x00080000, 0x00080008, 0x08080000, 0x08080008,
0x000c0000, 0x000c0008, 0x080c0000, 0x080c0008,
0x00082000, 0x00082008, 0x08082000, 0x08082008,
0x000c2000, 0x000c2008, 0x080c2000, 0x080c2008,
0x80080000, 0x80080008, 0x88080000, 0x88080008,
0x800c0000, 0x800c0008, 0x880c0000, 0x880c0008,
0x80082000, 0x80082008, 0x88082000, 0x88082008,
0x800c2000, 0x800c2008, 0x880c2000, 0x880c2008 },
/* table 5 */
{ 0x00000000, 0x00400000, 0x00008000, 0x00408000,
0x40000000, 0x40400000, 0x40008000, 0x40408000,
0x00000020, 0x00400020, 0x00008020, 0x00408020,
0x40000020, 0x40400020, 0x40008020, 0x40408020,
0x00001000, 0x00401000, 0x00009000, 0x00409000,
0x40001000, 0x40401000, 0x40009000, 0x40409000,
0x00001020, 0x00401020, 0x00009020, 0x00409020,
0x40001020, 0x40401020, 0x40009020, 0x40409020,
0x00100000, 0x00500000, 0x00108000, 0x00508000,
0x40100000, 0x40500000, 0x40108000, 0x40508000,
0x00100020, 0x00500020, 0x00108020, 0x00508020,
0x40100020, 0x40500020, 0x40108020, 0x40508020,
0x00101000, 0x00501000, 0x00109000, 0x00509000,
0x40101000, 0x40501000, 0x40109000, 0x40509000,
0x00101020, 0x00501020, 0x00109020, 0x00509020,
0x40101020, 0x40501020, 0x40109020, 0x40509020 },
/* table 6 */
{ 0x00000000, 0x00000040, 0x04000000, 0x04000040,
0x00000800, 0x00000840, 0x04000800, 0x04000840,
0x00800000, 0x00800040, 0x04800000, 0x04800040,
0x00800800, 0x00800840, 0x04800800, 0x04800840,
0x10000000, 0x10000040, 0x14000000, 0x14000040,
0x10000800, 0x10000840, 0x14000800, 0x14000840,
0x10800000, 0x10800040, 0x14800000, 0x14800040,
0x10800800, 0x10800840, 0x14800800, 0x14800840,
0x00000080, 0x000000c0, 0x04000080, 0x040000c0,
0x00000880, 0x000008c0, 0x04000880, 0x040008c0,
0x00800080, 0x008000c0, 0x04800080, 0x048000c0,
0x00800880, 0x008008c0, 0x04800880, 0x048008c0,
0x10000080, 0x100000c0, 0x14000080, 0x140000c0,
0x10000880, 0x100008c0, 0x14000880, 0x140008c0,
0x10800080, 0x108000c0, 0x14800080, 0x148000c0,
0x10800880, 0x108008c0, 0x14800880, 0x148008c0 },
/* table 7 */
{ 0x00000000, 0x00000010, 0x00000400, 0x00000410,
0x00000004, 0x00000014, 0x00000404, 0x00000414,
0x00004000, 0x00004010, 0x00004400, 0x00004410,
0x00004004, 0x00004014, 0x00004404, 0x00004414,
0x20000000, 0x20000010, 0x20000400, 0x20000410,
0x20000004, 0x20000014, 0x20000404, 0x20000414,
0x20004000, 0x20004010, 0x20004400, 0x20004410,
0x20004004, 0x20004014, 0x20004404, 0x20004414,
0x00200000, 0x00200010, 0x00200400, 0x00200410,
0x00200004, 0x00200014, 0x00200404, 0x00200414,
0x00204000, 0x00204010, 0x00204400, 0x00204410,
0x00204004, 0x00204014, 0x00204404, 0x00204414,
0x20200000, 0x20200010, 0x20200400, 0x20200410,
0x20200004, 0x20200014, 0x20200404, 0x20200414,
0x20204000, 0x20204010, 0x20204400, 0x20204410,
0x20204004, 0x20204014, 0x20204404, 0x20204414 }
};
/*
* The PC-1 Permutation
* If we number the bits of the 8 bytes of key input like this (in octal):
* 00 01 02 03 04 05 06 07
* 10 11 12 13 14 15 16 17
* 20 21 22 23 24 25 26 27
* 30 31 32 33 34 35 36 37
* 40 41 42 43 44 45 46 47
* 50 51 52 53 54 55 56 57
* 60 61 62 63 64 65 66 67
* 70 71 72 73 74 75 76 77
* then after the PC-1 permutation,
* C0 is
* 70 60 50 40 30 20 10 00
* 71 61 51 41 31 21 11 01
* 72 62 52 42 32 22 12 02
* 73 63 53 43
* D0 is
* 76 66 56 46 36 26 16 06
* 75 65 55 45 35 25 15 05
* 74 64 54 44 34 24 14 04
* 33 23 13 03
* and these parity bits have been discarded:
* 77 67 57 47 37 27 17 07
*
* We achieve this by flipping the input matrix about the diagonal from 70-07,
* getting left =
* 77 67 57 47 37 27 17 07 (these are the parity bits)
* 76 66 56 46 36 26 16 06
* 75 65 55 45 35 25 15 05
* 74 64 54 44 34 24 14 04
* right =
* 73 63 53 43 33 23 13 03
* 72 62 52 42 32 22 12 02
* 71 61 51 41 31 21 11 01
* 70 60 50 40 30 20 10 00
* then byte swap right, ala htonl() on a little endian machine.
* right =
* 70 60 50 40 30 20 10 00
* 71 67 57 47 37 27 11 07
* 72 62 52 42 32 22 12 02
* 73 63 53 43 33 23 13 03
* then
* c0 = right >> 4;
* d0 = ((left & 0x00ffffff) << 4) | (right & 0xf);
*/
#define FLIP_RIGHT_DIAGONAL(word, temp) \
temp = (word ^ (word >> 18)) & 0x00003333; \
word ^= temp | (temp << 18); \
temp = (word ^ (word >> 9)) & 0x00550055; \
word ^= temp | (temp << 9);
#if defined(__GNUC__) && defined(NSS_X86_OR_X64)
#define BYTESWAP(word, temp) \
__asm("bswap %0" \
: "+r"(word));
#elif (_MSC_VER >= 1300) && defined(NSS_X86_OR_X64)
#include <stdlib.h>
#pragma intrinsic(_byteswap_ulong)
#define BYTESWAP(word, temp) \
word = _byteswap_ulong(word);
#elif defined(__GNUC__) && (defined(__thumb2__) || \
(!defined(__thumb__) && \
(defined(__ARM_ARCH_6__) || \
defined(__ARM_ARCH_6J__) || \
defined(__ARM_ARCH_6K__) || \
defined(__ARM_ARCH_6Z__) || \
defined(__ARM_ARCH_6ZK__) || \
defined(__ARM_ARCH_6T2__) || \
defined(__ARM_ARCH_7__) || \
defined(__ARM_ARCH_7A__) || \
defined(__ARM_ARCH_7R__))))
#define BYTESWAP(word, temp) \
__asm("rev %0, %0" \
: "+r"(word));
#else
#define BYTESWAP(word, temp) \
word = (word >> 16) | (word << 16); \
temp = 0x00ff00ff; \
word = ((word & temp) << 8) | ((word >> 8) & temp);
#endif
#define PC1(left, right, c0, d0, temp) \
right ^= temp = ((left >> 4) ^ right) & 0x0f0f0f0f; \
left ^= temp << 4; \
FLIP_RIGHT_DIAGONAL(left, temp); \
FLIP_RIGHT_DIAGONAL(right, temp); \
BYTESWAP(right, temp); \
c0 = right >> 4; \
d0 = ((left & 0x00ffffff) << 4) | (right & 0xf);
#define LEFT_SHIFT_1(reg) (((reg << 1) | (reg >> 27)) & 0x0FFFFFFF)
#define LEFT_SHIFT_2(reg) (((reg << 2) | (reg >> 26)) & 0x0FFFFFFF)
/*
* setup key schedules from key
*/
void
DES_MakeSchedule(HALF *ks, const BYTE *key, DESDirection direction)
{
register HALF left, right;
register HALF c0, d0;
register HALF temp;
int delta;
unsigned int ls;
#if defined(HAVE_UNALIGNED_ACCESS)
left = HALFPTR(key)[0];
right = HALFPTR(key)[1];
#if defined(IS_LITTLE_ENDIAN)
BYTESWAP(left, temp);
BYTESWAP(right, temp);
#endif
#else
if (((ptrdiff_t)key & 0x03) == 0) {
left = HALFPTR(key)[0];
right = HALFPTR(key)[1];
#if defined(IS_LITTLE_ENDIAN)
BYTESWAP(left, temp);
BYTESWAP(right, temp);
#endif
} else {
left = ((HALF)key[0] << 24) | ((HALF)key[1] << 16) |
((HALF)key[2] << 8) | key[3];
right = ((HALF)key[4] << 24) | ((HALF)key[5] << 16) |
((HALF)key[6] << 8) | key[7];
}
#endif
PC1(left, right, c0, d0, temp);
if (direction == DES_ENCRYPT) {
delta = 2 * (int)sizeof(HALF);
} else {
ks += 30;
delta = (-2) * (int)sizeof(HALF);
}
for (ls = 0x8103; ls; ls >>= 1) {
if (ls & 1) {
c0 = LEFT_SHIFT_1(c0);
d0 = LEFT_SHIFT_1(d0);
} else {
c0 = LEFT_SHIFT_2(c0);
d0 = LEFT_SHIFT_2(d0);
}
#ifdef USE_INDEXING
#define PC2LOOKUP(b, c) PC2[b][c]
left = PC2LOOKUP(0, ((c0 >> 22) & 0x3F));
left |= PC2LOOKUP(1, ((c0 >> 13) & 0x3F));
left |= PC2LOOKUP(2, ((c0 >> 4) & 0x38) | (c0 & 0x7));
left |= PC2LOOKUP(3, ((c0 >> 18) & 0xC) | ((c0 >> 11) & 0x3) | (c0 & 0x30));
right = PC2LOOKUP(4, ((d0 >> 22) & 0x3F));
right |= PC2LOOKUP(5, ((d0 >> 15) & 0x30) | ((d0 >> 14) & 0xf));
right |= PC2LOOKUP(6, ((d0 >> 7) & 0x3F));
right |= PC2LOOKUP(7, ((d0 >> 1) & 0x3C) | (d0 & 0x3));
#else
#define PC2LOOKUP(b, c) *(HALF *)((BYTE *)&PC2[b][0] + (c))
left = PC2LOOKUP(0, ((c0 >> 20) & 0xFC));
left |= PC2LOOKUP(1, ((c0 >> 11) & 0xFC));
left |= PC2LOOKUP(2, ((c0 >> 2) & 0xE0) | ((c0 << 2) & 0x1C));
left |= PC2LOOKUP(3, ((c0 >> 16) & 0x30) | ((c0 >> 9) & 0xC) | ((c0 << 2) & 0xC0));
right = PC2LOOKUP(4, ((d0 >> 20) & 0xFC));
right |= PC2LOOKUP(5, ((d0 >> 13) & 0xC0) | ((d0 >> 12) & 0x3C));
right |= PC2LOOKUP(6, ((d0 >> 5) & 0xFC));
right |= PC2LOOKUP(7, ((d0 << 1) & 0xF0) | ((d0 << 2) & 0x0C));
#endif
/* left contains key bits for S1 S3 S2 S4 */
/* right contains key bits for S6 S8 S5 S7 */
temp = (left << 16) /* S2 S4 XX XX */
| (right >> 16); /* XX XX S6 S8 */
ks[0] = temp;
temp = (left & 0xffff0000) /* S1 S3 XX XX */
| (right & 0x0000ffff); /* XX XX S5 S7 */
ks[1] = temp;
ks = (HALF *)((BYTE *)ks + delta);
}
}
/*
* The DES Initial Permutation
* if we number the bits of the 8 bytes of input like this (in octal):
* 00 01 02 03 04 05 06 07
* 10 11 12 13 14 15 16 17
* 20 21 22 23 24 25 26 27
* 30 31 32 33 34 35 36 37
* 40 41 42 43 44 45 46 47
* 50 51 52 53 54 55 56 57
* 60 61 62 63 64 65 66 67
* 70 71 72 73 74 75 76 77
* then after the initial permutation, they will be in this order.
* 71 61 51 41 31 21 11 01
* 73 63 53 43 33 23 13 03
* 75 65 55 45 35 25 15 05
* 77 67 57 47 37 27 17 07
* 70 60 50 40 30 20 10 00
* 72 62 52 42 32 22 12 02
* 74 64 54 44 34 24 14 04
* 76 66 56 46 36 26 16 06
*
* One way to do this is in two steps:
* 1. Flip this matrix about the diagonal from 70-07 as done for PC1.
* 2. Rearrange the bytes (rows in the matrix above) with the following code.
*
* #define swapHiLo(word, temp) \
* temp = (word ^ (word >> 24)) & 0x000000ff; \
* word ^= temp | (temp << 24);
*
* right ^= temp = ((left << 8) ^ right) & 0xff00ff00;
* left ^= temp >> 8;
* swapHiLo(left, temp);
* swapHiLo(right,temp);
*
* However, the two steps can be combined, so that the rows are rearranged
* while the matrix is being flipped, reducing the number of bit exchange
* operations from 8 ot 5.
*
* Initial Permutation */
#define IP(left, right, temp) \
right ^= temp = ((left >> 4) ^ right) & 0x0f0f0f0f; \
left ^= temp << 4; \
right ^= temp = ((left >> 16) ^ right) & 0x0000ffff; \
left ^= temp << 16; \
right ^= temp = ((left << 2) ^ right) & 0xcccccccc; \
left ^= temp >> 2; \
right ^= temp = ((left << 8) ^ right) & 0xff00ff00; \
left ^= temp >> 8; \
right ^= temp = ((left >> 1) ^ right) & 0x55555555; \
left ^= temp << 1;
/* The Final (Inverse Initial) permutation is done by reversing the
** steps of the Initital Permutation
*/
#define FP(left, right, temp) \
right ^= temp = ((left >> 1) ^ right) & 0x55555555; \
left ^= temp << 1; \
right ^= temp = ((left << 8) ^ right) & 0xff00ff00; \
left ^= temp >> 8; \
right ^= temp = ((left << 2) ^ right) & 0xcccccccc; \
left ^= temp >> 2; \
right ^= temp = ((left >> 16) ^ right) & 0x0000ffff; \
left ^= temp << 16; \
right ^= temp = ((left >> 4) ^ right) & 0x0f0f0f0f; \
left ^= temp << 4;
void NO_SANITIZE_ALIGNMENT
DES_Do1Block(HALF *ks, const BYTE *inbuf, BYTE *outbuf)
{
register HALF left, right;
register HALF temp;
#if defined(HAVE_UNALIGNED_ACCESS)
left = HALFPTR(inbuf)[0];
right = HALFPTR(inbuf)[1];
#if defined(IS_LITTLE_ENDIAN)
BYTESWAP(left, temp);
BYTESWAP(right, temp);
#endif
#else
if (((ptrdiff_t)inbuf & 0x03) == 0) {
left = HALFPTR(inbuf)[0];
right = HALFPTR(inbuf)[1];
#if defined(IS_LITTLE_ENDIAN)
BYTESWAP(left, temp);
BYTESWAP(right, temp);
#endif
} else {
left = ((HALF)inbuf[0] << 24) | ((HALF)inbuf[1] << 16) |
((HALF)inbuf[2] << 8) | inbuf[3];
right = ((HALF)inbuf[4] << 24) | ((HALF)inbuf[5] << 16) |
((HALF)inbuf[6] << 8) | inbuf[7];
}
#endif
IP(left, right, temp);
/* shift the values left circularly 3 bits. */
left = (left << 3) | (left >> 29);
right = (right << 3) | (right >> 29);
#ifdef USE_INDEXING
#define KSLOOKUP(s, b) SP[s][((temp >> (b + 2)) & 0x3f)]
#else
#define KSLOOKUP(s, b) *(HALF *)((BYTE *)&SP[s][0] + ((temp >> b) & 0xFC))
#endif
#define ROUND(out, in, r) \
temp = in ^ ks[2 * r]; \
out ^= KSLOOKUP(1, 24); \
out ^= KSLOOKUP(3, 16); \
out ^= KSLOOKUP(5, 8); \
out ^= KSLOOKUP(7, 0); \
temp = ((in >> 4) | (in << 28)) ^ ks[2 * r + 1]; \
out ^= KSLOOKUP(0, 24); \
out ^= KSLOOKUP(2, 16); \
out ^= KSLOOKUP(4, 8); \
out ^= KSLOOKUP(6, 0);
/* Do the 16 Feistel rounds */
ROUND(left, right, 0)
ROUND(right, left, 1)
ROUND(left, right, 2)
ROUND(right, left, 3)
ROUND(left, right, 4)
ROUND(right, left, 5)
ROUND(left, right, 6)
ROUND(right, left, 7)
ROUND(left, right, 8)
ROUND(right, left, 9)
ROUND(left, right, 10)
ROUND(right, left, 11)
ROUND(left, right, 12)
ROUND(right, left, 13)
ROUND(left, right, 14)
ROUND(right, left, 15)
/* now shift circularly right 3 bits to undo the shifting done
** above. switch left and right here.
*/
temp = (left >> 3) | (left << 29);
left = (right >> 3) | (right << 29);
right = temp;
FP(left, right, temp);
#if defined(HAVE_UNALIGNED_ACCESS)
#if defined(IS_LITTLE_ENDIAN)
BYTESWAP(left, temp);
BYTESWAP(right, temp);
#endif
HALFPTR(outbuf)
[0] = left;
HALFPTR(outbuf)
[1] = right;
#else
if (((ptrdiff_t)outbuf & 0x03) == 0) {
#if defined(IS_LITTLE_ENDIAN)
BYTESWAP(left, temp);
BYTESWAP(right, temp);
#endif
HALFPTR(outbuf)
[0] = left;
HALFPTR(outbuf)
[1] = right;
} else {
outbuf[0] = (BYTE)(left >> 24);
outbuf[1] = (BYTE)(left >> 16);
outbuf[2] = (BYTE)(left >> 8);
outbuf[3] = (BYTE)(left);
outbuf[4] = (BYTE)(right >> 24);
outbuf[5] = (BYTE)(right >> 16);
outbuf[6] = (BYTE)(right >> 8);
outbuf[7] = (BYTE)(right);
}
#endif
}
/* Ackowledgements:
** Two ideas used in this implementation were shown to me by Dennis Ferguson
** in 1990. He credits them to Richard Outerbridge and Dan Hoey. They were:
** 1. The method of computing the Initial and Final permutations.
** 2. Circularly rotating the SP tables and the initial values of left and
** right to reduce the number of shifts required during the 16 rounds.
*/

View file

@ -0,0 +1,43 @@
/*
* des.h
*
* header file for DES-150 library
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef _DES_H_
#define _DES_H_ 1
#include "blapi.h"
typedef unsigned char BYTE;
typedef unsigned int HALF;
#define HALFPTR(x) ((HALF *)(x))
#define SHORTPTR(x) ((unsigned short *)(x))
#define BYTEPTR(x) ((BYTE *)(x))
typedef enum {
DES_ENCRYPT = 0x5555,
DES_DECRYPT = 0xAAAA
} DESDirection;
typedef void DESFunc(struct DESContextStr *cx, BYTE *out, const BYTE *in,
unsigned int len);
struct DESContextStr {
/* key schedule, 16 internal keys, each with 8 6-bit parts */
HALF ks0[32];
HALF ks1[32];
HALF ks2[32];
HALF iv[2];
DESDirection direction;
DESFunc *worker;
};
void DES_MakeSchedule(HALF *ks, const BYTE *key, DESDirection direction);
void DES_Do1Block(HALF *ks, const BYTE *inbuf, BYTE *outbuf);
#endif

View file

@ -0,0 +1,256 @@
/*
* desblapi.c
*
* core source file for DES-150 library
* Implement DES Modes of Operation and Triple-DES.
* Adapt DES-150 to blapi API.
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifdef FREEBL_NO_DEPEND
#include "stubs.h"
#endif
#include "des.h"
#include "blapii.h"
#include <stddef.h>
#include "secerr.h"
#if defined(NSS_X86_OR_X64)
/* Intel X86 CPUs do unaligned loads and stores without complaint. */
#define COPY8B(to, from, ptr) \
HALFPTR(to) \
[0] = HALFPTR(from)[0]; \
HALFPTR(to) \
[1] = HALFPTR(from)[1];
#else
#define COPY8B(to, from, ptr) memcpy(to, from, 8)
#endif
#define COPY8BTOHALF(to, from) COPY8B(to, from, from)
#define COPY8BFROMHALF(to, from) COPY8B(to, from, to)
static void
DES_ECB(DESContext *cx, BYTE *out, const BYTE *in, unsigned int len)
{
while (len) {
DES_Do1Block(cx->ks0, in, out);
len -= 8;
in += 8;
out += 8;
}
}
static void
DES_EDE3_ECB(DESContext *cx, BYTE *out, const BYTE *in, unsigned int len)
{
while (len) {
DES_Do1Block(cx->ks0, in, out);
len -= 8;
in += 8;
DES_Do1Block(cx->ks1, out, out);
DES_Do1Block(cx->ks2, out, out);
out += 8;
}
}
static void NO_SANITIZE_ALIGNMENT
DES_CBCEn(DESContext *cx, BYTE *out, const BYTE *in, unsigned int len)
{
const BYTE *bufend = in + len;
HALF vec[2];
while (in != bufend) {
COPY8BTOHALF(vec, in);
in += 8;
vec[0] ^= cx->iv[0];
vec[1] ^= cx->iv[1];
DES_Do1Block(cx->ks0, (BYTE *)vec, (BYTE *)cx->iv);
COPY8BFROMHALF(out, cx->iv);
out += 8;
}
}
static void NO_SANITIZE_ALIGNMENT
DES_CBCDe(DESContext *cx, BYTE *out, const BYTE *in, unsigned int len)
{
const BYTE *bufend;
HALF oldciphertext[2];
HALF plaintext[2];
for (bufend = in + len; in != bufend;) {
oldciphertext[0] = cx->iv[0];
oldciphertext[1] = cx->iv[1];
COPY8BTOHALF(cx->iv, in);
in += 8;
DES_Do1Block(cx->ks0, (BYTE *)cx->iv, (BYTE *)plaintext);
plaintext[0] ^= oldciphertext[0];
plaintext[1] ^= oldciphertext[1];
COPY8BFROMHALF(out, plaintext);
out += 8;
}
}
static void NO_SANITIZE_ALIGNMENT
DES_EDE3CBCEn(DESContext *cx, BYTE *out, const BYTE *in, unsigned int len)
{
const BYTE *bufend = in + len;
HALF vec[2];
while (in != bufend) {
COPY8BTOHALF(vec, in);
in += 8;
vec[0] ^= cx->iv[0];
vec[1] ^= cx->iv[1];
DES_Do1Block(cx->ks0, (BYTE *)vec, (BYTE *)cx->iv);
DES_Do1Block(cx->ks1, (BYTE *)cx->iv, (BYTE *)cx->iv);
DES_Do1Block(cx->ks2, (BYTE *)cx->iv, (BYTE *)cx->iv);
COPY8BFROMHALF(out, cx->iv);
out += 8;
}
}
static void NO_SANITIZE_ALIGNMENT
DES_EDE3CBCDe(DESContext *cx, BYTE *out, const BYTE *in, unsigned int len)
{
const BYTE *bufend;
HALF oldciphertext[2];
HALF plaintext[2];
for (bufend = in + len; in != bufend;) {
oldciphertext[0] = cx->iv[0];
oldciphertext[1] = cx->iv[1];
COPY8BTOHALF(cx->iv, in);
in += 8;
DES_Do1Block(cx->ks0, (BYTE *)cx->iv, (BYTE *)plaintext);
DES_Do1Block(cx->ks1, (BYTE *)plaintext, (BYTE *)plaintext);
DES_Do1Block(cx->ks2, (BYTE *)plaintext, (BYTE *)plaintext);
plaintext[0] ^= oldciphertext[0];
plaintext[1] ^= oldciphertext[1];
COPY8BFROMHALF(out, plaintext);
out += 8;
}
}
DESContext *
DES_AllocateContext(void)
{
return PORT_ZNew(DESContext);
}
SECStatus
DES_InitContext(DESContext *cx, const unsigned char *key, unsigned int keylen,
const unsigned char *iv, int mode, unsigned int encrypt,
unsigned int unused)
{
DESDirection opposite;
if (!cx) {
PORT_SetError(SEC_ERROR_INVALID_ARGS);
return SECFailure;
}
cx->direction = encrypt ? DES_ENCRYPT : DES_DECRYPT;
opposite = encrypt ? DES_DECRYPT : DES_ENCRYPT;
switch (mode) {
case NSS_DES: /* DES ECB */
DES_MakeSchedule(cx->ks0, key, cx->direction);
cx->worker = &DES_ECB;
break;
case NSS_DES_EDE3: /* DES EDE ECB */
cx->worker = &DES_EDE3_ECB;
if (encrypt) {
DES_MakeSchedule(cx->ks0, key, cx->direction);
DES_MakeSchedule(cx->ks1, key + 8, opposite);
DES_MakeSchedule(cx->ks2, key + 16, cx->direction);
} else {
DES_MakeSchedule(cx->ks2, key, cx->direction);
DES_MakeSchedule(cx->ks1, key + 8, opposite);
DES_MakeSchedule(cx->ks0, key + 16, cx->direction);
}
break;
case NSS_DES_CBC: /* DES CBC */
COPY8BTOHALF(cx->iv, iv);
cx->worker = encrypt ? &DES_CBCEn : &DES_CBCDe;
DES_MakeSchedule(cx->ks0, key, cx->direction);
break;
case NSS_DES_EDE3_CBC: /* DES EDE CBC */
COPY8BTOHALF(cx->iv, iv);
if (encrypt) {
cx->worker = &DES_EDE3CBCEn;
DES_MakeSchedule(cx->ks0, key, cx->direction);
DES_MakeSchedule(cx->ks1, key + 8, opposite);
DES_MakeSchedule(cx->ks2, key + 16, cx->direction);
} else {
cx->worker = &DES_EDE3CBCDe;
DES_MakeSchedule(cx->ks2, key, cx->direction);
DES_MakeSchedule(cx->ks1, key + 8, opposite);
DES_MakeSchedule(cx->ks0, key + 16, cx->direction);
}
break;
default:
PORT_SetError(SEC_ERROR_INVALID_ARGS);
return SECFailure;
}
return SECSuccess;
}
DESContext *
DES_CreateContext(const BYTE *key, const BYTE *iv, int mode, PRBool encrypt)
{
DESContext *cx = PORT_ZNew(DESContext);
SECStatus rv = DES_InitContext(cx, key, 0, iv, mode, encrypt, 0);
if (rv != SECSuccess) {
PORT_ZFree(cx, sizeof *cx);
cx = NULL;
}
return cx;
}
void
DES_DestroyContext(DESContext *cx, PRBool freeit)
{
if (cx) {
memset(cx, 0, sizeof *cx);
if (freeit)
PORT_Free(cx);
}
}
SECStatus
DES_Encrypt(DESContext *cx, BYTE *out, unsigned int *outLen,
unsigned int maxOutLen, const BYTE *in, unsigned int inLen)
{
if ((inLen % 8) != 0 || maxOutLen < inLen || !cx ||
cx->direction != DES_ENCRYPT) {
PORT_SetError(SEC_ERROR_INVALID_ARGS);
return SECFailure;
}
cx->worker(cx, out, in, inLen);
if (outLen)
*outLen = inLen;
return SECSuccess;
}
SECStatus
DES_Decrypt(DESContext *cx, BYTE *out, unsigned int *outLen,
unsigned int maxOutLen, const BYTE *in, unsigned int inLen)
{
if ((inLen % 8) != 0 || maxOutLen < inLen || !cx ||
cx->direction != DES_DECRYPT) {
PORT_SetError(SEC_ERROR_INVALID_ARGS);
return SECFailure;
}
cx->worker(cx, out, in, inLen);
if (outLen)
*outLen = inLen;
return SECSuccess;
}

View file

@ -0,0 +1,67 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "blapi.h"
#include "blapit.h"
#include "chacha20.h"
#include "nssilock.h"
#include "seccomon.h"
#include "secerr.h"
static unsigned long globalNumCalls = 0;
SECStatus
prng_ResetForFuzzing(PZLock *rng_lock)
{
/* Check for a valid RNG lock. */
PORT_Assert(rng_lock != NULL);
if (rng_lock == NULL) {
PORT_SetError(SEC_ERROR_INVALID_ARGS);
return SECFailure;
}
/* --- LOCKED --- */
PZ_Lock(rng_lock);
globalNumCalls = 0;
PZ_Unlock(rng_lock);
/* --- UNLOCKED --- */
return SECSuccess;
}
SECStatus
prng_GenerateDeterministicRandomBytes(PZLock *rng_lock, void *dest, size_t len)
{
static const uint8_t key[32];
uint8_t nonce[12] = { 0 };
/* Check for a valid RNG lock. */
PORT_Assert(rng_lock != NULL);
if (rng_lock == NULL) {
PORT_SetError(SEC_ERROR_INVALID_ARGS);
return SECFailure;
}
/* --- LOCKED --- */
PZ_Lock(rng_lock);
memcpy(nonce, &globalNumCalls, sizeof(globalNumCalls));
globalNumCalls++;
ChaCha20Poly1305Context *cx =
ChaCha20Poly1305_CreateContext(key, sizeof(key), 16);
if (!cx) {
PORT_SetError(SEC_ERROR_NO_MEMORY);
PZ_Unlock(rng_lock);
return SECFailure;
}
memset(dest, 0, len);
ChaCha20XOR(dest, dest, len, key, nonce, 0);
ChaCha20Poly1305_DestroyContext(cx, PR_TRUE);
PZ_Unlock(rng_lock);
/* --- UNLOCKED --- */
return SECSuccess;
}

View file

@ -0,0 +1,12 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef __det_rng_h_
#define __det_rng_h_
SECStatus prng_ResetForFuzzing(PZLock *rng_lock);
SECStatus prng_GenerateDeterministicRandomBytes(PZLock *rng_lock, void *dest,
size_t len);
#endif /* __det_rng_h_ */

View file

@ -0,0 +1,452 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
/*
* Diffie-Hellman parameter generation, key generation, and secret derivation.
* KEA secret generation and verification.
*/
#ifdef FREEBL_NO_DEPEND
#include "stubs.h"
#endif
#include "prerr.h"
#include "secerr.h"
#include "blapi.h"
#include "secitem.h"
#include "mpi.h"
#include "mpprime.h"
#include "secmpi.h"
#define KEA_DERIVED_SECRET_LEN 128
/* Lengths are in bytes. */
static unsigned int
dh_GetSecretKeyLen(unsigned int primeLen)
{
/* Based on Table 2 in NIST SP 800-57. */
if (primeLen >= 1920) { /* 15360 bits */
return 64; /* 512 bits */
}
if (primeLen >= 960) { /* 7680 bits */
return 48; /* 384 bits */
}
if (primeLen >= 384) { /* 3072 bits */
return 32; /* 256 bits */
}
if (primeLen >= 256) { /* 2048 bits */
return 28; /* 224 bits */
}
return 20; /* 160 bits */
}
SECStatus
DH_GenParam(int primeLen, DHParams **params)
{
PLArenaPool *arena;
DHParams *dhparams;
unsigned char *pb = NULL;
unsigned char *ab = NULL;
unsigned long counter = 0;
mp_int p, q, a, h, psub1, test;
mp_err err = MP_OKAY;
SECStatus rv = SECSuccess;
if (!params || primeLen < 0) {
PORT_SetError(SEC_ERROR_INVALID_ARGS);
return SECFailure;
}
arena = PORT_NewArena(NSS_FREEBL_DEFAULT_CHUNKSIZE);
if (!arena) {
PORT_SetError(SEC_ERROR_NO_MEMORY);
return SECFailure;
}
dhparams = (DHParams *)PORT_ArenaZAlloc(arena, sizeof(DHParams));
if (!dhparams) {
PORT_SetError(SEC_ERROR_NO_MEMORY);
PORT_FreeArena(arena, PR_TRUE);
return SECFailure;
}
dhparams->arena = arena;
MP_DIGITS(&p) = 0;
MP_DIGITS(&q) = 0;
MP_DIGITS(&a) = 0;
MP_DIGITS(&h) = 0;
MP_DIGITS(&psub1) = 0;
MP_DIGITS(&test) = 0;
CHECK_MPI_OK(mp_init(&p));
CHECK_MPI_OK(mp_init(&q));
CHECK_MPI_OK(mp_init(&a));
CHECK_MPI_OK(mp_init(&h));
CHECK_MPI_OK(mp_init(&psub1));
CHECK_MPI_OK(mp_init(&test));
/* generate prime with MPI, uses Miller-Rabin to generate strong prime. */
pb = PORT_Alloc(primeLen);
CHECK_SEC_OK(RNG_GenerateGlobalRandomBytes(pb, primeLen));
pb[0] |= 0x80; /* set high-order bit */
pb[primeLen - 1] |= 0x01; /* set low-order bit */
CHECK_MPI_OK(mp_read_unsigned_octets(&p, pb, primeLen));
CHECK_MPI_OK(mpp_make_prime(&p, primeLen * 8, PR_TRUE, &counter));
/* construct Sophie-Germain prime q = (p-1)/2. */
CHECK_MPI_OK(mp_sub_d(&p, 1, &psub1));
CHECK_MPI_OK(mp_div_2(&psub1, &q));
/* construct a generator from the prime. */
ab = PORT_Alloc(primeLen);
/* generate a candidate number a in p's field */
CHECK_SEC_OK(RNG_GenerateGlobalRandomBytes(ab, primeLen));
CHECK_MPI_OK(mp_read_unsigned_octets(&a, ab, primeLen));
/* force a < p (note that quot(a/p) <= 1) */
if (mp_cmp(&a, &p) > 0)
CHECK_MPI_OK(mp_sub(&a, &p, &a));
do {
/* check that a is in the range [2..p-1] */
if (mp_cmp_d(&a, 2) < 0 || mp_cmp(&a, &psub1) >= 0) {
/* a is outside of the allowed range. Set a=3 and keep going. */
mp_set(&a, 3);
}
/* if a**q mod p != 1 then a is a generator */
CHECK_MPI_OK(mp_exptmod(&a, &q, &p, &test));
if (mp_cmp_d(&test, 1) != 0)
break;
/* increment the candidate and try again. */
CHECK_MPI_OK(mp_add_d(&a, 1, &a));
} while (PR_TRUE);
MPINT_TO_SECITEM(&p, &dhparams->prime, arena);
MPINT_TO_SECITEM(&a, &dhparams->base, arena);
*params = dhparams;
cleanup:
mp_clear(&p);
mp_clear(&q);
mp_clear(&a);
mp_clear(&h);
mp_clear(&psub1);
mp_clear(&test);
if (pb)
PORT_ZFree(pb, primeLen);
if (ab)
PORT_ZFree(ab, primeLen);
if (err) {
MP_TO_SEC_ERROR(err);
rv = SECFailure;
}
if (rv)
PORT_FreeArena(arena, PR_TRUE);
return rv;
}
SECStatus
DH_NewKey(DHParams *params, DHPrivateKey **privKey)
{
PLArenaPool *arena;
DHPrivateKey *key;
mp_int g, xa, p, Ya;
mp_err err = MP_OKAY;
SECStatus rv = SECSuccess;
if (!params || !privKey) {
PORT_SetError(SEC_ERROR_INVALID_ARGS);
return SECFailure;
}
arena = PORT_NewArena(NSS_FREEBL_DEFAULT_CHUNKSIZE);
if (!arena) {
PORT_SetError(SEC_ERROR_NO_MEMORY);
return SECFailure;
}
key = (DHPrivateKey *)PORT_ArenaZAlloc(arena, sizeof(DHPrivateKey));
if (!key) {
PORT_SetError(SEC_ERROR_NO_MEMORY);
PORT_FreeArena(arena, PR_TRUE);
return SECFailure;
}
key->arena = arena;
MP_DIGITS(&g) = 0;
MP_DIGITS(&xa) = 0;
MP_DIGITS(&p) = 0;
MP_DIGITS(&Ya) = 0;
CHECK_MPI_OK(mp_init(&g));
CHECK_MPI_OK(mp_init(&xa));
CHECK_MPI_OK(mp_init(&p));
CHECK_MPI_OK(mp_init(&Ya));
/* Set private key's p */
CHECK_SEC_OK(SECITEM_CopyItem(arena, &key->prime, &params->prime));
SECITEM_TO_MPINT(key->prime, &p);
/* Set private key's g */
CHECK_SEC_OK(SECITEM_CopyItem(arena, &key->base, &params->base));
SECITEM_TO_MPINT(key->base, &g);
/* Generate private key xa */
SECITEM_AllocItem(arena, &key->privateValue,
dh_GetSecretKeyLen(params->prime.len));
CHECK_SEC_OK(RNG_GenerateGlobalRandomBytes(key->privateValue.data,
key->privateValue.len));
SECITEM_TO_MPINT(key->privateValue, &xa);
/* xa < p */
CHECK_MPI_OK(mp_mod(&xa, &p, &xa));
/* Compute public key Ya = g ** xa mod p */
CHECK_MPI_OK(mp_exptmod(&g, &xa, &p, &Ya));
MPINT_TO_SECITEM(&Ya, &key->publicValue, key->arena);
*privKey = key;
cleanup:
mp_clear(&g);
mp_clear(&xa);
mp_clear(&p);
mp_clear(&Ya);
if (err) {
MP_TO_SEC_ERROR(err);
rv = SECFailure;
}
if (rv) {
*privKey = NULL;
PORT_FreeArena(arena, PR_TRUE);
}
return rv;
}
SECStatus
DH_Derive(SECItem *publicValue,
SECItem *prime,
SECItem *privateValue,
SECItem *derivedSecret,
unsigned int outBytes)
{
mp_int p, Xa, Yb, ZZ, psub1;
mp_err err = MP_OKAY;
unsigned int len = 0;
unsigned int nb;
unsigned char *secret = NULL;
if (!publicValue || !prime || !privateValue || !derivedSecret) {
PORT_SetError(SEC_ERROR_INVALID_ARGS);
return SECFailure;
}
memset(derivedSecret, 0, sizeof *derivedSecret);
MP_DIGITS(&p) = 0;
MP_DIGITS(&Xa) = 0;
MP_DIGITS(&Yb) = 0;
MP_DIGITS(&ZZ) = 0;
MP_DIGITS(&psub1) = 0;
CHECK_MPI_OK(mp_init(&p));
CHECK_MPI_OK(mp_init(&Xa));
CHECK_MPI_OK(mp_init(&Yb));
CHECK_MPI_OK(mp_init(&ZZ));
CHECK_MPI_OK(mp_init(&psub1));
SECITEM_TO_MPINT(*publicValue, &Yb);
SECITEM_TO_MPINT(*privateValue, &Xa);
SECITEM_TO_MPINT(*prime, &p);
CHECK_MPI_OK(mp_sub_d(&p, 1, &psub1));
/* We assume that the modulus, p, is a safe prime. That is, p = 2q+1 where
* q is also a prime. Thus the orders of the subgroups are factors of 2q:
* namely 1, 2, q and 2q.
*
* We check that the peer's public value isn't zero (which isn't in the
* group), one (subgroup of order one) or p-1 (subgroup of order 2). We
* also check that the public value is less than p, to avoid being fooled
* by values like p+1 or 2*p-1.
*
* Thus we must be operating in the subgroup of size q or 2q. */
if (mp_cmp_d(&Yb, 1) <= 0 ||
mp_cmp(&Yb, &psub1) >= 0) {
err = MP_BADARG;
goto cleanup;
}
/* ZZ = (Yb)**Xa mod p */
CHECK_MPI_OK(mp_exptmod(&Yb, &Xa, &p, &ZZ));
/* number of bytes in the derived secret */
len = mp_unsigned_octet_size(&ZZ);
if (len <= 0) {
err = MP_BADARG;
goto cleanup;
}
/*
* We check to make sure that ZZ is not equal to 1 or -1 mod p.
* This helps guard against small subgroup attacks, since an attacker
* using a subgroup of size N will produce 1 or -1 with probability 1/N.
* When the protocol is executed within a properly large subgroup, the
* probability of this result will be negligibly small. For example,
* with a strong prime of the form 2p+1, the probability will be 1/p.
*
* We return MP_BADARG because this is probably the result of a bad
* public value or a bad prime having been provided.
*/
if (mp_cmp_d(&ZZ, 1) == 0 ||
mp_cmp(&ZZ, &psub1) == 0) {
err = MP_BADARG;
goto cleanup;
}
/* allocate a buffer which can hold the entire derived secret. */
secret = PORT_Alloc(len);
if (secret == NULL) {
err = MP_MEM;
goto cleanup;
}
/* grab the derived secret */
err = mp_to_unsigned_octets(&ZZ, secret, len);
if (err >= 0)
err = MP_OKAY;
/*
** if outBytes is 0 take all of the bytes from the derived secret.
** if outBytes is not 0 take exactly outBytes from the derived secret, zero
** pad at the beginning if necessary, and truncate beginning bytes
** if necessary.
*/
if (outBytes > 0)
nb = outBytes;
else
nb = len;
if (SECITEM_AllocItem(NULL, derivedSecret, nb) == NULL) {
err = MP_MEM;
goto cleanup;
}
if (len < nb) {
unsigned int offset = nb - len;
memset(derivedSecret->data, 0, offset);
memcpy(derivedSecret->data + offset, secret, len);
} else {
memcpy(derivedSecret->data, secret + len - nb, nb);
}
cleanup:
mp_clear(&p);
mp_clear(&Xa);
mp_clear(&Yb);
mp_clear(&ZZ);
mp_clear(&psub1);
if (secret) {
/* free the buffer allocated for the full secret. */
PORT_ZFree(secret, len);
}
if (err) {
MP_TO_SEC_ERROR(err);
if (derivedSecret->data)
PORT_ZFree(derivedSecret->data, derivedSecret->len);
return SECFailure;
}
return SECSuccess;
}
SECStatus
KEA_Derive(SECItem *prime,
SECItem *public1,
SECItem *public2,
SECItem *private1,
SECItem *private2,
SECItem *derivedSecret)
{
mp_int p, Y, R, r, x, t, u, w;
mp_err err;
unsigned char *secret = NULL;
unsigned int len = 0, offset;
if (!prime || !public1 || !public2 || !private1 || !private2 ||
!derivedSecret) {
PORT_SetError(SEC_ERROR_INVALID_ARGS);
return SECFailure;
}
memset(derivedSecret, 0, sizeof *derivedSecret);
MP_DIGITS(&p) = 0;
MP_DIGITS(&Y) = 0;
MP_DIGITS(&R) = 0;
MP_DIGITS(&r) = 0;
MP_DIGITS(&x) = 0;
MP_DIGITS(&t) = 0;
MP_DIGITS(&u) = 0;
MP_DIGITS(&w) = 0;
CHECK_MPI_OK(mp_init(&p));
CHECK_MPI_OK(mp_init(&Y));
CHECK_MPI_OK(mp_init(&R));
CHECK_MPI_OK(mp_init(&r));
CHECK_MPI_OK(mp_init(&x));
CHECK_MPI_OK(mp_init(&t));
CHECK_MPI_OK(mp_init(&u));
CHECK_MPI_OK(mp_init(&w));
SECITEM_TO_MPINT(*prime, &p);
SECITEM_TO_MPINT(*public1, &Y);
SECITEM_TO_MPINT(*public2, &R);
SECITEM_TO_MPINT(*private1, &r);
SECITEM_TO_MPINT(*private2, &x);
/* t = DH(Y, r, p) = Y ** r mod p */
CHECK_MPI_OK(mp_exptmod(&Y, &r, &p, &t));
/* u = DH(R, x, p) = R ** x mod p */
CHECK_MPI_OK(mp_exptmod(&R, &x, &p, &u));
/* w = (t + u) mod p */
CHECK_MPI_OK(mp_addmod(&t, &u, &p, &w));
/* allocate a buffer for the full derived secret */
len = mp_unsigned_octet_size(&w);
secret = PORT_Alloc(len);
if (secret == NULL) {
err = MP_MEM;
goto cleanup;
}
/* grab the secret */
err = mp_to_unsigned_octets(&w, secret, len);
if (err > 0)
err = MP_OKAY;
/* allocate output buffer */
if (SECITEM_AllocItem(NULL, derivedSecret, KEA_DERIVED_SECRET_LEN) == NULL) {
err = MP_MEM;
goto cleanup;
}
memset(derivedSecret->data, 0, derivedSecret->len);
/* copy in the 128 lsb of the secret */
if (len >= KEA_DERIVED_SECRET_LEN) {
memcpy(derivedSecret->data, secret + (len - KEA_DERIVED_SECRET_LEN),
KEA_DERIVED_SECRET_LEN);
} else {
offset = KEA_DERIVED_SECRET_LEN - len;
memcpy(derivedSecret->data + offset, secret, len);
}
cleanup:
mp_clear(&p);
mp_clear(&Y);
mp_clear(&R);
mp_clear(&r);
mp_clear(&x);
mp_clear(&t);
mp_clear(&u);
mp_clear(&w);
if (secret)
PORT_ZFree(secret, len);
if (err) {
MP_TO_SEC_ERROR(err);
if (derivedSecret->data)
PORT_ZFree(derivedSecret->data, derivedSecret->len);
return SECFailure;
}
return SECSuccess;
}
PRBool
KEA_Verify(SECItem *Y, SECItem *prime, SECItem *subPrime)
{
mp_int p, q, y, r;
mp_err err;
int cmp = 1; /* default is false */
if (!Y || !prime || !subPrime) {
PORT_SetError(SEC_ERROR_INVALID_ARGS);
return SECFailure;
}
MP_DIGITS(&p) = 0;
MP_DIGITS(&q) = 0;
MP_DIGITS(&y) = 0;
MP_DIGITS(&r) = 0;
CHECK_MPI_OK(mp_init(&p));
CHECK_MPI_OK(mp_init(&q));
CHECK_MPI_OK(mp_init(&y));
CHECK_MPI_OK(mp_init(&r));
SECITEM_TO_MPINT(*prime, &p);
SECITEM_TO_MPINT(*subPrime, &q);
SECITEM_TO_MPINT(*Y, &y);
/* compute r = y**q mod p */
CHECK_MPI_OK(mp_exptmod(&y, &q, &p, &r));
/* compare to 1 */
cmp = mp_cmp_d(&r, 1);
cleanup:
mp_clear(&p);
mp_clear(&q);
mp_clear(&y);
mp_clear(&r);
if (err) {
MP_TO_SEC_ERROR(err);
return PR_FALSE;
}
return (cmp == 0) ? PR_TRUE : PR_FALSE;
}

View file

@ -0,0 +1,968 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifdef FREEBL_NO_DEPEND
#include "stubs.h"
#endif
#include "prerror.h"
#include "secerr.h"
#include "prtypes.h"
#include "prinit.h"
#include "blapi.h"
#include "blapii.h"
#include "nssilock.h"
#include "secitem.h"
#include "sha_fast.h"
#include "sha256.h"
#include "secrng.h" /* for RNG_SystemRNG() */
#include "secmpi.h"
#ifdef UNSAFE_FUZZER_MODE
#include "det_rng.h"
#endif
/* PRNG_SEEDLEN defined in NIST SP 800-90 section 10.1
* for SHA-1, SHA-224, and SHA-256 it's 440 bits.
* for SHA-384 and SHA-512 it's 888 bits */
#define PRNG_SEEDLEN (440 / PR_BITS_PER_BYTE)
#define PRNG_MAX_ADDITIONAL_BYTES PR_INT64(0x100000000)
/* 2^35 bits or 2^32 bytes */
#define PRNG_MAX_REQUEST_SIZE 0x10000 /* 2^19 bits or 2^16 bytes */
#define PRNG_ADDITONAL_DATA_CACHE_SIZE (8 * 1024) /* must be less than \
* PRNG_MAX_ADDITIONAL_BYTES \
*/
/* RESEED_COUNT is how many calls to the prng before we need to reseed
* under normal NIST rules, you must return an error. In the NSS case, we
* self-reseed with RNG_SystemRNG(). Count can be a large number. For code
* simplicity, we specify count with 2 components: RESEED_BYTE (which is
* the same as LOG256(RESEED_COUNT)) and RESEED_VALUE (which is the same as
* RESEED_COUNT / (256 ^ RESEED_BYTE)). Another way to look at this is
* RESEED_COUNT = RESEED_VALUE * (256 ^ RESEED_BYTE). For Hash based DRBG
* we use the maximum count value, 2^48, or RESEED_BYTE=6 and RESEED_VALUE=1
*/
#define RESEED_BYTE 6
#define RESEED_VALUE 1
#define PRNG_RESET_RESEED_COUNT(rng) \
PORT_Memset((rng)->reseed_counter, 0, sizeof(rng)->reseed_counter); \
(rng)->reseed_counter[RESEED_BYTE] = 1;
/*
* The actual values of this enum are specified in SP 800-90, 10.1.1.*
* The spec does not name the types, it only uses bare values
*/
typedef enum {
prngCGenerateType = 0, /* used when creating a new 'C' */
prngReseedType = 1, /* used in reseeding */
prngAdditionalDataType = 2, /* used in mixing additional data */
prngGenerateByteType = 3 /* used when mixing internal state while
* generating bytes */
} prngVTypes;
/*
* Global RNG context
*/
struct RNGContextStr {
PZLock *lock; /* Lock to serialize access to global rng */
/*
* NOTE, a number of steps in the drbg algorithm need to hash
* V_type || V. The code, therefore, depends on the V array following
* immediately after V_type to avoid extra copies. To accomplish this
* in a way that compiliers can't perturb, we declare V_type and V
* as a V_Data array and reference them by macros */
PRUint8 V_Data[PRNG_SEEDLEN + 1]; /* internal state variables */
#define V_type V_Data[0]
#define V(rng) (((rng)->V_Data) + 1)
#define VSize(rng) ((sizeof(rng)->V_Data) - 1)
PRUint8 C[PRNG_SEEDLEN]; /* internal state variables */
PRUint8 lastOutput[SHA256_LENGTH]; /* for continuous rng checking */
/* If we get calls for the PRNG to return less than the length of our
* hash, we extend the request for a full hash (since we'll be doing
* the full hash anyway). Future requests for random numbers are fulfilled
* from the remainder of the bytes we generated. Requests for bytes longer
* than the hash size are fulfilled directly from the HashGen function
* of the random number generator. */
PRUint8 reseed_counter[RESEED_BYTE + 1]; /* number of requests since the
* last reseed. Need only be
* big enough to hold the whole
* reseed count */
PRUint8 data[SHA256_LENGTH]; /* when we request less than a block
* save the rest of the rng output for
* another partial block */
PRUint8 dataAvail; /* # bytes of output available in our cache,
* [0...SHA256_LENGTH] */
/* store additional data that has been shovelled off to us by
* RNG_RandomUpdate. */
PRUint8 additionalDataCache[PRNG_ADDITONAL_DATA_CACHE_SIZE];
PRUint32 additionalAvail;
PRBool isValid; /* false if RNG reaches an invalid state */
PRBool isKatTest; /* true if running NIST PRNG KAT tests */
};
typedef struct RNGContextStr RNGContext;
static RNGContext *globalrng = NULL;
static RNGContext theGlobalRng;
/*
* The next several functions are derived from the NIST SP 800-90
* spec. In these functions, an attempt was made to use names consistent
* with the names in the spec, even if they differ from normal NSS usage.
*/
/*
* Hash Derive function defined in NISP SP 800-90 Section 10.4.1.
* This function is used in the Instantiate and Reseed functions.
*
* NOTE: requested_bytes cannot overlap with input_string_1 or input_string_2.
* input_string_1 and input_string_2 are logically concatentated.
* input_string_1 must be supplied.
* if input_string_2 is not supplied, NULL should be passed for this parameter.
*/
static SECStatus
prng_Hash_df(PRUint8 *requested_bytes, unsigned int no_of_bytes_to_return,
const PRUint8 *input_string_1, unsigned int input_string_1_len,
const PRUint8 *input_string_2, unsigned int input_string_2_len)
{
SHA256Context ctx;
PRUint32 tmp;
PRUint8 counter;
tmp = SHA_HTONL(no_of_bytes_to_return * 8);
for (counter = 1; no_of_bytes_to_return > 0; counter++) {
unsigned int hash_return_len;
SHA256_Begin(&ctx);
SHA256_Update(&ctx, &counter, 1);
SHA256_Update(&ctx, (unsigned char *)&tmp, sizeof tmp);
SHA256_Update(&ctx, input_string_1, input_string_1_len);
if (input_string_2) {
SHA256_Update(&ctx, input_string_2, input_string_2_len);
}
SHA256_End(&ctx, requested_bytes, &hash_return_len,
no_of_bytes_to_return);
requested_bytes += hash_return_len;
no_of_bytes_to_return -= hash_return_len;
}
return SECSuccess;
}
/*
* Hash_DRBG Instantiate NIST SP 800-90 10.1.1.2
*
* NOTE: bytes & len are entropy || nonce || personalization_string. In
* normal operation, NSS calculates them all together in a single call.
*/
static SECStatus
prng_instantiate(RNGContext *rng, const PRUint8 *bytes, unsigned int len)
{
if (!rng->isKatTest && len < PRNG_SEEDLEN) {
/* If the seedlen is too small, it's probably because we failed to get
* enough random data.
* This is stricter than NIST SP800-90A requires. Don't enforce it for
* tests. */
PORT_SetError(SEC_ERROR_NEED_RANDOM);
return SECFailure;
}
prng_Hash_df(V(rng), VSize(rng), bytes, len, NULL, 0);
rng->V_type = prngCGenerateType;
prng_Hash_df(rng->C, sizeof rng->C, rng->V_Data, sizeof rng->V_Data, NULL, 0);
PRNG_RESET_RESEED_COUNT(rng)
return SECSuccess;
}
/*
* Update the global random number generator with more seeding
* material. Use the Hash_DRBG reseed algorithm from NIST SP-800-90
* section 10.1.1.3
*
* If entropy is NULL, it is fetched from the noise generator.
*/
static SECStatus
prng_reseed(RNGContext *rng, const PRUint8 *entropy, unsigned int entropy_len,
const PRUint8 *additional_input, unsigned int additional_input_len)
{
PRUint8 noiseData[(sizeof rng->V_Data) + PRNG_SEEDLEN];
PRUint8 *noise = &noiseData[0];
/* if entropy wasn't supplied, fetch it. (normal operation case) */
if (entropy == NULL) {
entropy_len = (unsigned int)RNG_SystemRNG(
&noiseData[sizeof rng->V_Data], PRNG_SEEDLEN);
} else {
/* NOTE: this code is only available for testing, not to applications */
/* if entropy was too big for the stack variable, get it from malloc */
if (entropy_len > PRNG_SEEDLEN) {
noise = PORT_Alloc(entropy_len + (sizeof rng->V_Data));
if (noise == NULL) {
return SECFailure;
}
}
PORT_Memcpy(&noise[sizeof rng->V_Data], entropy, entropy_len);
}
if (entropy_len < 256 / PR_BITS_PER_BYTE) {
/* noise == &noiseData[0] at this point, so nothing to free */
PORT_SetError(SEC_ERROR_NEED_RANDOM);
return SECFailure;
}
rng->V_type = prngReseedType;
PORT_Memcpy(noise, rng->V_Data, sizeof rng->V_Data);
prng_Hash_df(V(rng), VSize(rng), noise, (sizeof rng->V_Data) + entropy_len,
additional_input, additional_input_len);
/* clear potential CSP */
PORT_Memset(noise, 0, (sizeof rng->V_Data) + entropy_len);
rng->V_type = prngCGenerateType;
prng_Hash_df(rng->C, sizeof rng->C, rng->V_Data, sizeof rng->V_Data, NULL, 0);
PRNG_RESET_RESEED_COUNT(rng)
if (noise != &noiseData[0]) {
PORT_Free(noise);
}
return SECSuccess;
}
/*
* SP 800-90 requires we rerun our health tests on reseed
*/
static SECStatus
prng_reseed_test(RNGContext *rng, const PRUint8 *entropy,
unsigned int entropy_len, const PRUint8 *additional_input,
unsigned int additional_input_len)
{
SECStatus rv;
/* do health checks in FIPS mode */
rv = PRNGTEST_RunHealthTests();
if (rv != SECSuccess) {
/* error set by PRNGTEST_RunHealTests() */
rng->isValid = PR_FALSE;
return SECFailure;
}
return prng_reseed(rng, entropy, entropy_len,
additional_input, additional_input_len);
}
/*
* build some fast inline functions for adding.
*/
#define PRNG_ADD_CARRY_ONLY(dest, start, carry) \
{ \
int k1; \
for (k1 = start; carry && k1 >= 0; k1--) { \
carry = !(++dest[k1]); \
} \
}
/*
* NOTE: dest must be an array for the following to work.
*/
#define PRNG_ADD_BITS(dest, dest_len, add, len, carry) \
carry = 0; \
PORT_Assert((dest_len) >= (len)); \
{ \
int k1, k2; \
for (k1 = dest_len - 1, k2 = len - 1; k2 >= 0; --k1, --k2) { \
carry += dest[k1] + add[k2]; \
dest[k1] = (PRUint8)carry; \
carry >>= 8; \
} \
}
#define PRNG_ADD_BITS_AND_CARRY(dest, dest_len, add, len, carry) \
PRNG_ADD_BITS(dest, dest_len, add, len, carry) \
PRNG_ADD_CARRY_ONLY(dest, dest_len - len - 1, carry)
/*
* This function expands the internal state of the prng to fulfill any number
* of bytes we need for this request. We only use this call if we need more
* than can be supplied by a single call to SHA256_HashBuf.
*
* This function is specified in NIST SP 800-90 section 10.1.1.4, Hashgen
*/
static void
prng_Hashgen(RNGContext *rng, PRUint8 *returned_bytes,
unsigned int no_of_returned_bytes)
{
PRUint8 data[VSize(rng)];
PRUint8 thisHash[SHA256_LENGTH];
PRUint8 *lastHash = rng->lastOutput;
PORT_Memcpy(data, V(rng), VSize(rng));
while (no_of_returned_bytes) {
SHA256Context ctx;
unsigned int len;
unsigned int carry;
SHA256_Begin(&ctx);
SHA256_Update(&ctx, data, sizeof data);
SHA256_End(&ctx, thisHash, &len, SHA256_LENGTH);
if (PORT_Memcmp(lastHash, thisHash, len) == 0) {
rng->isValid = PR_FALSE;
break;
}
if (no_of_returned_bytes < SHA256_LENGTH) {
len = no_of_returned_bytes;
}
PORT_Memcpy(returned_bytes, thisHash, len);
lastHash = returned_bytes;
returned_bytes += len;
no_of_returned_bytes -= len;
/* The carry parameter is a bool (increment or not).
* This increments data if no_of_returned_bytes is not zero */
carry = no_of_returned_bytes;
PRNG_ADD_CARRY_ONLY(data, (sizeof data) - 1, carry);
}
PORT_Memcpy(rng->lastOutput, thisHash, SHA256_LENGTH);
PORT_Memset(data, 0, sizeof data);
PORT_Memset(thisHash, 0, sizeof thisHash);
}
/*
* Generates new random bytes and advances the internal prng state.
* additional bytes are only used in algorithm testing.
*
* This function is specified in NIST SP 800-90 section 10.1.1.4
*/
static SECStatus
prng_generateNewBytes(RNGContext *rng,
PRUint8 *returned_bytes, unsigned int no_of_returned_bytes,
const PRUint8 *additional_input,
unsigned int additional_input_len)
{
PRUint8 H[SHA256_LENGTH]; /* both H and w since they
* aren't used concurrently */
unsigned int carry;
if (!rng->isValid) {
PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
return SECFailure;
}
/* This code only triggers during tests, normal
* prng operation does not use additional_input */
if (additional_input) {
SHA256Context ctx;
/* NIST SP 800-90 defines two temporaries in their calculations,
* w and H. These temporaries are the same lengths, and used
* at different times, so we use the following macro to collapse
* them to the same variable, but keeping their unique names for
* easy comparison to the spec */
#define w H
rng->V_type = prngAdditionalDataType;
SHA256_Begin(&ctx);
SHA256_Update(&ctx, rng->V_Data, sizeof rng->V_Data);
SHA256_Update(&ctx, additional_input, additional_input_len);
SHA256_End(&ctx, w, NULL, sizeof w);
PRNG_ADD_BITS_AND_CARRY(V(rng), VSize(rng), w, sizeof w, carry)
PORT_Memset(w, 0, sizeof w);
#undef w
}
if (no_of_returned_bytes == SHA256_LENGTH) {
/* short_cut to hashbuf and a couple of copies and clears */
SHA256_HashBuf(returned_bytes, V(rng), VSize(rng));
/* continuous rng check */
if (memcmp(rng->lastOutput, returned_bytes, SHA256_LENGTH) == 0) {
rng->isValid = PR_FALSE;
}
PORT_Memcpy(rng->lastOutput, returned_bytes, sizeof rng->lastOutput);
} else {
prng_Hashgen(rng, returned_bytes, no_of_returned_bytes);
}
/* advance our internal state... */
rng->V_type = prngGenerateByteType;
SHA256_HashBuf(H, rng->V_Data, sizeof rng->V_Data);
PRNG_ADD_BITS_AND_CARRY(V(rng), VSize(rng), H, sizeof H, carry)
PRNG_ADD_BITS(V(rng), VSize(rng), rng->C, sizeof rng->C, carry);
PRNG_ADD_BITS_AND_CARRY(V(rng), VSize(rng), rng->reseed_counter,
sizeof rng->reseed_counter, carry)
carry = 1;
PRNG_ADD_CARRY_ONLY(rng->reseed_counter, (sizeof rng->reseed_counter) - 1, carry);
/* if the prng failed, don't return any output, signal softoken */
if (!rng->isValid) {
PORT_Memset(returned_bytes, 0, no_of_returned_bytes);
PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
return SECFailure;
}
return SECSuccess;
}
/* Use NSPR to prevent RNG_RNGInit from being called from separate
* threads, creating a race condition.
*/
static const PRCallOnceType pristineCallOnce;
static PRCallOnceType coRNGInit;
static PRStatus
rng_init(void)
{
PRUint8 bytes[PRNG_SEEDLEN * 2]; /* entropy + nonce */
unsigned int numBytes;
SECStatus rv = SECSuccess;
if (globalrng == NULL) {
/* bytes needs to have enough space to hold
* a SHA256 hash value. Blow up at compile time if this isn't true */
PR_STATIC_ASSERT(sizeof(bytes) >= SHA256_LENGTH);
/* create a new global RNG context */
globalrng = &theGlobalRng;
PORT_Assert(NULL == globalrng->lock);
/* create a lock for it */
globalrng->lock = PZ_NewLock(nssILockOther);
if (globalrng->lock == NULL) {
globalrng = NULL;
PORT_SetError(PR_OUT_OF_MEMORY_ERROR);
return PR_FAILURE;
}
/* Try to get some seed data for the RNG */
numBytes = (unsigned int)RNG_SystemRNG(bytes, sizeof bytes);
PORT_Assert(numBytes == 0 || numBytes == sizeof bytes);
if (numBytes != 0) {
/* if this is our first call, instantiate, otherwise reseed
* prng_instantiate gets a new clean state, we want to mix
* any previous entropy we may have collected */
if (V(globalrng)[0] == 0) {
rv = prng_instantiate(globalrng, bytes, numBytes);
} else {
rv = prng_reseed_test(globalrng, bytes, numBytes, NULL, 0);
}
memset(bytes, 0, numBytes);
} else {
PZ_DestroyLock(globalrng->lock);
globalrng->lock = NULL;
globalrng = NULL;
return PR_FAILURE;
}
if (rv != SECSuccess) {
return PR_FAILURE;
}
/* the RNG is in a valid state */
globalrng->isValid = PR_TRUE;
globalrng->isKatTest = PR_FALSE;
/* fetch one random value so that we can populate rng->oldV for our
* continous random number test. */
prng_generateNewBytes(globalrng, bytes, SHA256_LENGTH, NULL, 0);
/* Fetch more entropy into the PRNG */
RNG_SystemInfoForRNG();
}
return PR_SUCCESS;
}
/*
* Clean up the global RNG context
*/
static void
prng_freeRNGContext(RNGContext *rng)
{
PRUint8 inputhash[VSize(rng) + (sizeof rng->C)];
/* destroy context lock */
SKIP_AFTER_FORK(PZ_DestroyLock(globalrng->lock));
/* zero global RNG context except for C & V to preserve entropy */
prng_Hash_df(inputhash, sizeof rng->C, rng->C, sizeof rng->C, NULL, 0);
prng_Hash_df(&inputhash[sizeof rng->C], VSize(rng), V(rng), VSize(rng),
NULL, 0);
memset(rng, 0, sizeof *rng);
memcpy(rng->C, inputhash, sizeof rng->C);
memcpy(V(rng), &inputhash[sizeof rng->C], VSize(rng));
memset(inputhash, 0, sizeof inputhash);
}
/*
* Public functions
*/
/*
* Initialize the global RNG context and give it some seed input taken
* from the system. This function is thread-safe and will only allow
* the global context to be initialized once. The seed input is likely
* small, so it is imperative that RNG_RandomUpdate() be called with
* additional seed data before the generator is used. A good way to
* provide the generator with additional entropy is to call
* RNG_SystemInfoForRNG(). Note that C_Initialize() does exactly that.
*/
SECStatus
RNG_RNGInit(void)
{
/* Allow only one call to initialize the context */
PR_CallOnce(&coRNGInit, rng_init);
/* Make sure there is a context */
return (globalrng != NULL) ? SECSuccess : SECFailure;
}
/*
** Update the global random number generator with more seeding
** material.
*/
SECStatus
RNG_RandomUpdate(const void *data, size_t bytes)
{
SECStatus rv;
/* Make sure our assumption that size_t is unsigned is true */
PR_STATIC_ASSERT(((size_t)-1) > (size_t)1);
#if defined(NS_PTR_GT_32) || (defined(NSS_USE_64) && !defined(NS_PTR_LE_32))
/*
* NIST 800-90 requires us to verify our inputs. This value can
* come from the application, so we need to make sure it's within the
* spec. The spec says it must be less than 2^32 bytes (2^35 bits).
* This can only happen if size_t is greater than 32 bits (i.e. on
* most 64 bit platforms). The 90% case (perhaps 100% case), size_t
* is less than or equal to 32 bits if the platform is not 64 bits, and
* greater than 32 bits if it is a 64 bit platform. The corner
* cases are handled with explicit defines NS_PTR_GT_32 and NS_PTR_LE_32.
*
* In general, neither NS_PTR_GT_32 nor NS_PTR_LE_32 will need to be
* defined. If you trip over the next two size ASSERTS at compile time,
* you will need to define them for your platform.
*
* if 'sizeof(size_t) > 4' is triggered it means that we were expecting
* sizeof(size_t) to be greater than 4, but it wasn't. Setting
* NS_PTR_LE_32 will correct that mistake.
*
* if 'sizeof(size_t) <= 4' is triggered, it means that we were expecting
* sizeof(size_t) to be less than or equal to 4, but it wasn't. Setting
* NS_PTR_GT_32 will correct that mistake.
*/
PR_STATIC_ASSERT(sizeof(size_t) > 4);
if (bytes > (size_t)PRNG_MAX_ADDITIONAL_BYTES) {
bytes = PRNG_MAX_ADDITIONAL_BYTES;
}
#else
PR_STATIC_ASSERT(sizeof(size_t) <= 4);
#endif
PZ_Lock(globalrng->lock);
/* if we're passed more than our additionalDataCache, simply
* call reseed with that data */
if (bytes > sizeof(globalrng->additionalDataCache)) {
rv = prng_reseed_test(globalrng, NULL, 0, data, (unsigned int)bytes);
/* if we aren't going to fill or overflow the buffer, just cache it */
} else if (bytes < ((sizeof globalrng->additionalDataCache) - globalrng->additionalAvail)) {
PORT_Memcpy(globalrng->additionalDataCache + globalrng->additionalAvail,
data, bytes);
globalrng->additionalAvail += (PRUint32)bytes;
rv = SECSuccess;
} else {
/* we are going to fill or overflow the buffer. In this case we will
* fill the entropy buffer, reseed with it, start a new buffer with the
* remainder. We know the remainder will fit in the buffer because
* we already handled the case where bytes > the size of the buffer.
*/
size_t bufRemain = (sizeof globalrng->additionalDataCache) - globalrng->additionalAvail;
/* fill the rest of the buffer */
if (bufRemain) {
PORT_Memcpy(globalrng->additionalDataCache + globalrng->additionalAvail,
data, bufRemain);
data = ((unsigned char *)data) + bufRemain;
bytes -= bufRemain;
}
/* reseed from buffer */
rv = prng_reseed_test(globalrng, NULL, 0,
globalrng->additionalDataCache,
sizeof globalrng->additionalDataCache);
/* copy the rest into the cache */
PORT_Memcpy(globalrng->additionalDataCache, data, bytes);
globalrng->additionalAvail = (PRUint32)bytes;
}
PZ_Unlock(globalrng->lock);
return rv;
}
/*
** Generate some random bytes, using the global random number generator
** object.
*/
static SECStatus
prng_GenerateGlobalRandomBytes(RNGContext *rng,
void *dest, size_t len)
{
SECStatus rv = SECSuccess;
PRUint8 *output = dest;
/* check for a valid global RNG context */
PORT_Assert(rng != NULL);
if (rng == NULL) {
PORT_SetError(SEC_ERROR_INVALID_ARGS);
return SECFailure;
}
/* FIPS limits the amount of entropy available in a single request */
if (len > PRNG_MAX_REQUEST_SIZE) {
PORT_SetError(SEC_ERROR_INVALID_ARGS);
return SECFailure;
}
/* --- LOCKED --- */
PZ_Lock(rng->lock);
/* Check the amount of seed data in the generator. If not enough,
* don't produce any data.
*/
if (rng->reseed_counter[0] >= RESEED_VALUE) {
rv = prng_reseed_test(rng, NULL, 0, NULL, 0);
PZ_Unlock(rng->lock);
if (rv != SECSuccess) {
return rv;
}
RNG_SystemInfoForRNG();
PZ_Lock(rng->lock);
}
/*
* see if we have enough bytes to fulfill the request.
*/
if (len <= rng->dataAvail) {
memcpy(output, rng->data + ((sizeof rng->data) - rng->dataAvail), len);
memset(rng->data + ((sizeof rng->data) - rng->dataAvail), 0, len);
rng->dataAvail -= len;
rv = SECSuccess;
/* if we are asking for a small number of bytes, cache the rest of
* the bytes */
} else if (len < sizeof rng->data) {
rv = prng_generateNewBytes(rng, rng->data, sizeof rng->data,
rng->additionalAvail ? rng->additionalDataCache : NULL,
rng->additionalAvail);
rng->additionalAvail = 0;
if (rv == SECSuccess) {
memcpy(output, rng->data, len);
memset(rng->data, 0, len);
rng->dataAvail = (sizeof rng->data) - len;
}
/* we are asking for lots of bytes, just ask the generator to pass them */
} else {
rv = prng_generateNewBytes(rng, output, len,
rng->additionalAvail ? rng->additionalDataCache : NULL,
rng->additionalAvail);
rng->additionalAvail = 0;
}
PZ_Unlock(rng->lock);
/* --- UNLOCKED --- */
return rv;
}
/*
** Generate some random bytes, using the global random number generator
** object.
*/
SECStatus
RNG_GenerateGlobalRandomBytes(void *dest, size_t len)
{
#ifdef UNSAFE_FUZZER_MODE
return prng_GenerateDeterministicRandomBytes(globalrng->lock, dest, len);
#else
return prng_GenerateGlobalRandomBytes(globalrng, dest, len);
#endif
}
SECStatus
RNG_ResetForFuzzing(void)
{
#ifdef UNSAFE_FUZZER_MODE
return prng_ResetForFuzzing(globalrng->lock);
#else
return SECFailure;
#endif
}
void
RNG_RNGShutdown(void)
{
/* check for a valid global RNG context */
PORT_Assert(globalrng != NULL);
if (globalrng == NULL) {
/* Should set a "not initialized" error code. */
PORT_SetError(SEC_ERROR_NO_MEMORY);
return;
}
/* clear */
prng_freeRNGContext(globalrng);
globalrng = NULL;
/* reset the callonce struct to allow a new call to RNG_RNGInit() */
coRNGInit = pristineCallOnce;
}
/*
* Test case interface. used by fips testing and power on self test
*/
/* make sure the test context is separate from the global context, This
* allows us to test the internal random number generator without losing
* entropy we may have previously collected. */
RNGContext testContext;
SECStatus
PRNGTEST_Instantiate_Kat(const PRUint8 *entropy, unsigned int entropy_len,
const PRUint8 *nonce, unsigned int nonce_len,
const PRUint8 *personal_string, unsigned int ps_len)
{
testContext.isKatTest = PR_TRUE;
return PRNGTEST_Instantiate(entropy, entropy_len,
nonce, nonce_len,
personal_string, ps_len);
}
/*
* Test vector API. Use NIST SP 800-90 general interface so one of the
* other NIST SP 800-90 algorithms may be used in the future.
*/
SECStatus
PRNGTEST_Instantiate(const PRUint8 *entropy, unsigned int entropy_len,
const PRUint8 *nonce, unsigned int nonce_len,
const PRUint8 *personal_string, unsigned int ps_len)
{
int bytes_len = entropy_len + nonce_len + ps_len;
PRUint8 *bytes = NULL;
SECStatus rv;
if (entropy_len < 256 / PR_BITS_PER_BYTE) {
PORT_SetError(SEC_ERROR_NEED_RANDOM);
return SECFailure;
}
bytes = PORT_Alloc(bytes_len);
if (bytes == NULL) {
PORT_SetError(SEC_ERROR_NO_MEMORY);
return SECFailure;
}
/* concatenate the various inputs, internally NSS only instantiates with
* a single long string */
PORT_Memcpy(bytes, entropy, entropy_len);
if (nonce) {
PORT_Memcpy(&bytes[entropy_len], nonce, nonce_len);
} else {
PORT_Assert(nonce_len == 0);
}
if (personal_string) {
PORT_Memcpy(&bytes[entropy_len + nonce_len], personal_string, ps_len);
} else {
PORT_Assert(ps_len == 0);
}
rv = prng_instantiate(&testContext, bytes, bytes_len);
PORT_ZFree(bytes, bytes_len);
if (rv == SECFailure) {
return SECFailure;
}
testContext.isValid = PR_TRUE;
return SECSuccess;
}
SECStatus
PRNGTEST_Reseed(const PRUint8 *entropy, unsigned int entropy_len,
const PRUint8 *additional, unsigned int additional_len)
{
if (!testContext.isValid) {
PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
return SECFailure;
}
/* This magic input tells us to set the reseed count to it's max count,
* so we can simulate PRNGTEST_Generate reaching max reseed count */
if ((entropy == NULL) && (entropy_len == 0) &&
(additional == NULL) && (additional_len == 0)) {
testContext.reseed_counter[0] = RESEED_VALUE;
return SECSuccess;
}
return prng_reseed(&testContext, entropy, entropy_len, additional,
additional_len);
}
SECStatus
PRNGTEST_Generate(PRUint8 *bytes, unsigned int bytes_len,
const PRUint8 *additional, unsigned int additional_len)
{
SECStatus rv;
if (!testContext.isValid) {
PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
return SECFailure;
}
/* replicate reseed test from prng_GenerateGlobalRandomBytes */
if (testContext.reseed_counter[0] >= RESEED_VALUE) {
rv = prng_reseed(&testContext, NULL, 0, NULL, 0);
if (rv != SECSuccess) {
return rv;
}
}
return prng_generateNewBytes(&testContext, bytes, bytes_len,
additional, additional_len);
}
SECStatus
PRNGTEST_Uninstantiate()
{
if (!testContext.isValid) {
PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
return SECFailure;
}
PORT_Memset(&testContext, 0, sizeof testContext);
return SECSuccess;
}
SECStatus
PRNGTEST_RunHealthTests()
{
static const PRUint8 entropy[] = {
0x8e, 0x9c, 0x0d, 0x25, 0x75, 0x22, 0x04, 0xf9,
0xc5, 0x79, 0x10, 0x8b, 0x23, 0x79, 0x37, 0x14,
0x9f, 0x2c, 0xc7, 0x0b, 0x39, 0xf8, 0xee, 0xef,
0x95, 0x0c, 0x97, 0x59, 0xfc, 0x0a, 0x85, 0x41,
0x76, 0x9d, 0x6d, 0x67, 0x00, 0x4e, 0x19, 0x12,
0x02, 0x16, 0x53, 0xea, 0xf2, 0x73, 0xd7, 0xd6,
0x7f, 0x7e, 0xc8, 0xae, 0x9c, 0x09, 0x99, 0x7d,
0xbb, 0x9e, 0x48, 0x7f, 0xbb, 0x96, 0x46, 0xb3,
0x03, 0x75, 0xf8, 0xc8, 0x69, 0x45, 0x3f, 0x97,
0x5e, 0x2e, 0x48, 0xe1, 0x5d, 0x58, 0x97, 0x4c
};
static const PRUint8 rng_known_result[] = {
0x16, 0xe1, 0x8c, 0x57, 0x21, 0xd8, 0xf1, 0x7e,
0x5a, 0xa0, 0x16, 0x0b, 0x7e, 0xa6, 0x25, 0xb4,
0x24, 0x19, 0xdb, 0x54, 0xfa, 0x35, 0x13, 0x66,
0xbb, 0xaa, 0x2a, 0x1b, 0x22, 0x33, 0x2e, 0x4a,
0x14, 0x07, 0x9d, 0x52, 0xfc, 0x73, 0x61, 0x48,
0xac, 0xc1, 0x22, 0xfc, 0xa4, 0xfc, 0xac, 0xa4,
0xdb, 0xda, 0x5b, 0x27, 0x33, 0xc4, 0xb3
};
static const PRUint8 reseed_entropy[] = {
0xc6, 0x0b, 0x0a, 0x30, 0x67, 0x07, 0xf4, 0xe2,
0x24, 0xa7, 0x51, 0x6f, 0x5f, 0x85, 0x3e, 0x5d,
0x67, 0x97, 0xb8, 0x3b, 0x30, 0x9c, 0x7a, 0xb1,
0x52, 0xc6, 0x1b, 0xc9, 0x46, 0xa8, 0x62, 0x79
};
static const PRUint8 additional_input[] = {
0x86, 0x82, 0x28, 0x98, 0xe7, 0xcb, 0x01, 0x14,
0xae, 0x87, 0x4b, 0x1d, 0x99, 0x1b, 0xc7, 0x41,
0x33, 0xff, 0x33, 0x66, 0x40, 0x95, 0x54, 0xc6,
0x67, 0x4d, 0x40, 0x2a, 0x1f, 0xf9, 0xeb, 0x65
};
static const PRUint8 rng_reseed_result[] = {
0x02, 0x0c, 0xc6, 0x17, 0x86, 0x49, 0xba, 0xc4,
0x7b, 0x71, 0x35, 0x05, 0xf0, 0xdb, 0x4a, 0xc2,
0x2c, 0x38, 0xc1, 0xa4, 0x42, 0xe5, 0x46, 0x4a,
0x7d, 0xf0, 0xbe, 0x47, 0x88, 0xb8, 0x0e, 0xc6,
0x25, 0x2b, 0x1d, 0x13, 0xef, 0xa6, 0x87, 0x96,
0xa3, 0x7d, 0x5b, 0x80, 0xc2, 0x38, 0x76, 0x61,
0xc7, 0x80, 0x5d, 0x0f, 0x05, 0x76, 0x85
};
static const PRUint8 rng_no_reseed_result[] = {
0xc4, 0x40, 0x41, 0x8c, 0xbf, 0x2f, 0x70, 0x23,
0x88, 0xf2, 0x7b, 0x30, 0xc3, 0xca, 0x1e, 0xf3,
0xef, 0x53, 0x81, 0x5d, 0x30, 0xed, 0x4c, 0xf1,
0xff, 0x89, 0xa5, 0xee, 0x92, 0xf8, 0xc0, 0x0f,
0x88, 0x53, 0xdf, 0xb6, 0x76, 0xf0, 0xaa, 0xd3,
0x2e, 0x1d, 0x64, 0x37, 0x3e, 0xe8, 0x4a, 0x02,
0xff, 0x0a, 0x7f, 0xe5, 0xe9, 0x2b, 0x6d
};
SECStatus rng_status = SECSuccess;
PR_STATIC_ASSERT(sizeof(rng_known_result) >= sizeof(rng_reseed_result));
PRUint8 result[sizeof(rng_known_result)];
/********************************************/
/* First test instantiate error path. */
/* In this case we supply enough entropy, */
/* but not enough seed. This will trigger */
/* the code that checks for a entropy */
/* source failure. */
/********************************************/
rng_status = PRNGTEST_Instantiate(entropy, 256 / PR_BITS_PER_BYTE,
NULL, 0, NULL, 0);
if (rng_status == SECSuccess) {
PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
return SECFailure;
}
if (PORT_GetError() != SEC_ERROR_NEED_RANDOM) {
PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
return SECFailure;
}
/* we failed with the proper error code, we can continue */
/********************************************/
/* Generate random bytes with a known seed. */
/********************************************/
rng_status = PRNGTEST_Instantiate(entropy, sizeof entropy,
NULL, 0, NULL, 0);
if (rng_status != SECSuccess) {
/* Error set by PRNGTEST_Instantiate */
return SECFailure;
}
rng_status = PRNGTEST_Generate(result, sizeof rng_known_result, NULL, 0);
if ((rng_status != SECSuccess) ||
(PORT_Memcmp(result, rng_known_result,
sizeof rng_known_result) != 0)) {
PRNGTEST_Uninstantiate();
PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
return SECFailure;
}
rng_status = PRNGTEST_Reseed(reseed_entropy, sizeof reseed_entropy,
additional_input, sizeof additional_input);
if (rng_status != SECSuccess) {
/* Error set by PRNG_Reseed */
PRNGTEST_Uninstantiate();
return SECFailure;
}
rng_status = PRNGTEST_Generate(result, sizeof rng_reseed_result, NULL, 0);
if ((rng_status != SECSuccess) ||
(PORT_Memcmp(result, rng_reseed_result,
sizeof rng_reseed_result) != 0)) {
PRNGTEST_Uninstantiate();
PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
return SECFailure;
}
/* This magic forces the reseed count to it's max count, so we can see if
* PRNGTEST_Generate will actually when it reaches it's count */
rng_status = PRNGTEST_Reseed(NULL, 0, NULL, 0);
if (rng_status != SECSuccess) {
PRNGTEST_Uninstantiate();
/* Error set by PRNG_Reseed */
return SECFailure;
}
/* This generate should now reseed */
rng_status = PRNGTEST_Generate(result, sizeof rng_reseed_result, NULL, 0);
if ((rng_status != SECSuccess) ||
/* NOTE we fail if the result is equal to the no_reseed_result.
* no_reseed_result is the value we would have gotten if we didn't
* do an automatic reseed in PRNGTEST_Generate */
(PORT_Memcmp(result, rng_no_reseed_result,
sizeof rng_no_reseed_result) == 0)) {
PRNGTEST_Uninstantiate();
PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
return SECFailure;
}
/* make sure reseed fails when we don't supply enough entropy */
rng_status = PRNGTEST_Reseed(reseed_entropy, 4, NULL, 0);
if (rng_status == SECSuccess) {
PRNGTEST_Uninstantiate();
PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
return SECFailure;
}
if (PORT_GetError() != SEC_ERROR_NEED_RANDOM) {
PRNGTEST_Uninstantiate();
PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
return SECFailure;
}
rng_status = PRNGTEST_Uninstantiate();
if (rng_status != SECSuccess) {
/* Error set by PRNG_Uninstantiate */
return rng_status;
}
/* make sure uninstantiate fails if the contest is not initiated (also tests
* if the context was cleared in the previous Uninstantiate) */
rng_status = PRNGTEST_Uninstantiate();
if (rng_status == SECSuccess) {
PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
return SECFailure;
}
if (PORT_GetError() != SEC_ERROR_LIBRARY_FAILURE) {
return rng_status;
}
return SECSuccess;
}

View file

@ -0,0 +1,647 @@
/*
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifdef FREEBL_NO_DEPEND
#include "stubs.h"
#endif
#include "prerror.h"
#include "secerr.h"
#include "prtypes.h"
#include "prinit.h"
#include "blapi.h"
#include "nssilock.h"
#include "secitem.h"
#include "blapi.h"
#include "mpi.h"
#include "secmpi.h"
#include "pqg.h"
/* XXX to be replaced by define in blapit.h */
#define NSS_FREEBL_DSA_DEFAULT_CHUNKSIZE 2048
/*
* FIPS 186-2 requires result from random output to be reduced mod q when
* generating random numbers for DSA.
*
* Input: w, 2*qLen bytes
* q, qLen bytes
* Output: xj, qLen bytes
*/
static SECStatus
fips186Change_ReduceModQForDSA(const PRUint8 *w, const PRUint8 *q,
unsigned int qLen, PRUint8 *xj)
{
mp_int W, Q, Xj;
mp_err err;
SECStatus rv = SECSuccess;
/* Initialize MPI integers. */
MP_DIGITS(&W) = 0;
MP_DIGITS(&Q) = 0;
MP_DIGITS(&Xj) = 0;
CHECK_MPI_OK(mp_init(&W));
CHECK_MPI_OK(mp_init(&Q));
CHECK_MPI_OK(mp_init(&Xj));
/*
* Convert input arguments into MPI integers.
*/
CHECK_MPI_OK(mp_read_unsigned_octets(&W, w, 2 * qLen));
CHECK_MPI_OK(mp_read_unsigned_octets(&Q, q, qLen));
/*
* Algorithm 1 of FIPS 186-2 Change Notice 1, Step 3.3
*
* xj = (w0 || w1) mod q
*/
CHECK_MPI_OK(mp_mod(&W, &Q, &Xj));
CHECK_MPI_OK(mp_to_fixlen_octets(&Xj, xj, qLen));
cleanup:
mp_clear(&W);
mp_clear(&Q);
mp_clear(&Xj);
if (err) {
MP_TO_SEC_ERROR(err);
rv = SECFailure;
}
return rv;
}
/*
* FIPS 186-2 requires result from random output to be reduced mod q when
* generating random numbers for DSA.
*/
SECStatus
FIPS186Change_ReduceModQForDSA(const unsigned char *w,
const unsigned char *q,
unsigned char *xj)
{
return fips186Change_ReduceModQForDSA(w, q, DSA1_SUBPRIME_LEN, xj);
}
/*
* The core of Algorithm 1 of FIPS 186-2 Change Notice 1.
*
* We no longer support FIPS 186-2 RNG. This function was exported
* for power-up self tests and FIPS tests. Keep this stub, which fails,
* to prevent crashes, but also to signal to test code that FIPS 186-2
* RNG is no longer supported.
*/
SECStatus
FIPS186Change_GenerateX(PRUint8 *XKEY, const PRUint8 *XSEEDj,
PRUint8 *x_j)
{
PORT_SetError(PR_NOT_IMPLEMENTED_ERROR);
return SECFailure;
}
/*
* Specialized RNG for DSA
*
* As per Algorithm 1 of FIPS 186-2 Change Notice 1, in step 3.3 the value
* Xj should be reduced mod q, a 160-bit prime number. Since this parameter
* is only meaningful in the context of DSA, the above RNG functions
* were implemented without it. They are re-implemented below for use
* with DSA.
*/
/*
** Generate some random bytes, using the global random number generator
** object. In DSA mode, so there is a q.
*/
static SECStatus
dsa_GenerateGlobalRandomBytes(const SECItem *qItem, PRUint8 *dest,
unsigned int *destLen, unsigned int maxDestLen)
{
SECStatus rv;
SECItem w;
const PRUint8 *q = qItem->data;
unsigned int qLen = qItem->len;
if (*q == 0) {
++q;
--qLen;
}
if (maxDestLen < qLen) {
/* This condition can occur when DSA_SignDigest is passed a group
with a subprime that is larger than DSA_MAX_SUBPRIME_LEN. */
PORT_SetError(SEC_ERROR_INVALID_ARGS);
return SECFailure;
}
w.data = NULL; /* otherwise SECITEM_AllocItem asserts */
if (!SECITEM_AllocItem(NULL, &w, 2 * qLen)) {
return SECFailure;
}
*destLen = qLen;
rv = RNG_GenerateGlobalRandomBytes(w.data, w.len);
if (rv == SECSuccess) {
rv = fips186Change_ReduceModQForDSA(w.data, q, qLen, dest);
}
SECITEM_FreeItem(&w, PR_FALSE);
return rv;
}
static void
translate_mpi_error(mp_err err)
{
MP_TO_SEC_ERROR(err);
}
static SECStatus
dsa_NewKeyExtended(const PQGParams *params, const SECItem *seed,
DSAPrivateKey **privKey)
{
mp_int p, g;
mp_int x, y;
mp_err err;
PLArenaPool *arena;
DSAPrivateKey *key;
/* Check args. */
if (!params || !privKey || !seed || !seed->data) {
PORT_SetError(SEC_ERROR_INVALID_ARGS);
return SECFailure;
}
/* Initialize an arena for the DSA key. */
arena = PORT_NewArena(NSS_FREEBL_DSA_DEFAULT_CHUNKSIZE);
if (!arena) {
PORT_SetError(SEC_ERROR_NO_MEMORY);
return SECFailure;
}
key = (DSAPrivateKey *)PORT_ArenaZAlloc(arena, sizeof(DSAPrivateKey));
if (!key) {
PORT_SetError(SEC_ERROR_NO_MEMORY);
PORT_FreeArena(arena, PR_TRUE);
return SECFailure;
}
key->params.arena = arena;
/* Initialize MPI integers. */
MP_DIGITS(&p) = 0;
MP_DIGITS(&g) = 0;
MP_DIGITS(&x) = 0;
MP_DIGITS(&y) = 0;
CHECK_MPI_OK(mp_init(&p));
CHECK_MPI_OK(mp_init(&g));
CHECK_MPI_OK(mp_init(&x));
CHECK_MPI_OK(mp_init(&y));
/* Copy over the PQG params */
CHECK_MPI_OK(SECITEM_CopyItem(arena, &key->params.prime,
&params->prime));
CHECK_MPI_OK(SECITEM_CopyItem(arena, &key->params.subPrime,
&params->subPrime));
CHECK_MPI_OK(SECITEM_CopyItem(arena, &key->params.base, &params->base));
/* Convert stored p, g, and received x into MPI integers. */
SECITEM_TO_MPINT(params->prime, &p);
SECITEM_TO_MPINT(params->base, &g);
OCTETS_TO_MPINT(seed->data, &x, seed->len);
/* Store x in private key */
SECITEM_AllocItem(arena, &key->privateValue, seed->len);
PORT_Memcpy(key->privateValue.data, seed->data, seed->len);
/* Compute public key y = g**x mod p */
CHECK_MPI_OK(mp_exptmod(&g, &x, &p, &y));
/* Store y in public key */
MPINT_TO_SECITEM(&y, &key->publicValue, arena);
*privKey = key;
key = NULL;
cleanup:
mp_clear(&p);
mp_clear(&g);
mp_clear(&x);
mp_clear(&y);
if (key)
PORT_FreeArena(key->params.arena, PR_TRUE);
if (err) {
translate_mpi_error(err);
return SECFailure;
}
return SECSuccess;
}
SECStatus
DSA_NewRandom(PLArenaPool *arena, const SECItem *q, SECItem *seed)
{
int retries = 10;
unsigned int i;
PRBool good;
if (q == NULL || q->data == NULL || q->len == 0 ||
(q->data[0] == 0 && q->len == 1)) {
PORT_SetError(SEC_ERROR_INVALID_ARGS);
return SECFailure;
}
if (!SECITEM_AllocItem(arena, seed, q->len)) {
return SECFailure;
}
do {
/* Generate seed bytes for x according to FIPS 186-1 appendix 3 */
if (dsa_GenerateGlobalRandomBytes(q, seed->data, &seed->len,
seed->len)) {
goto loser;
}
/* Disallow values of 0 and 1 for x. */
good = PR_FALSE;
for (i = 0; i < seed->len - 1; i++) {
if (seed->data[i] != 0) {
good = PR_TRUE;
break;
}
}
if (!good && seed->data[i] > 1) {
good = PR_TRUE;
}
} while (!good && --retries > 0);
if (!good) {
PORT_SetError(SEC_ERROR_NEED_RANDOM);
loser:
if (arena != NULL) {
SECITEM_FreeItem(seed, PR_FALSE);
}
return SECFailure;
}
return SECSuccess;
}
/*
** Generate and return a new DSA public and private key pair,
** both of which are encoded into a single DSAPrivateKey struct.
** "params" is a pointer to the PQG parameters for the domain
** Uses a random seed.
*/
SECStatus
DSA_NewKey(const PQGParams *params, DSAPrivateKey **privKey)
{
SECItem seed;
SECStatus rv;
rv = PQG_Check(params);
if (rv != SECSuccess) {
return rv;
}
seed.data = NULL;
rv = DSA_NewRandom(NULL, &params->subPrime, &seed);
if (rv == SECSuccess) {
if (seed.len != PQG_GetLength(&params->subPrime)) {
PORT_SetError(SEC_ERROR_INVALID_ARGS);
rv = SECFailure;
} else {
rv = dsa_NewKeyExtended(params, &seed, privKey);
}
}
SECITEM_FreeItem(&seed, PR_FALSE);
return rv;
}
/* For FIPS compliance testing. Seed must be exactly the size of subPrime */
SECStatus
DSA_NewKeyFromSeed(const PQGParams *params,
const unsigned char *seed,
DSAPrivateKey **privKey)
{
SECItem seedItem;
seedItem.data = (unsigned char *)seed;
seedItem.len = PQG_GetLength(&params->subPrime);
return dsa_NewKeyExtended(params, &seedItem, privKey);
}
static SECStatus
dsa_SignDigest(DSAPrivateKey *key, SECItem *signature, const SECItem *digest,
const unsigned char *kb)
{
mp_int p, q, g; /* PQG parameters */
mp_int x, k; /* private key & pseudo-random integer */
mp_int r, s; /* tuple (r, s) is signature) */
mp_int t; /* holding tmp values */
mp_err err = MP_OKAY;
SECStatus rv = SECSuccess;
unsigned int dsa_subprime_len, dsa_signature_len, offset;
SECItem localDigest;
unsigned char localDigestData[DSA_MAX_SUBPRIME_LEN];
SECItem t2 = { siBuffer, NULL, 0 };
/* FIPS-compliance dictates that digest is a SHA hash. */
/* Check args. */
if (!key || !signature || !digest) {
PORT_SetError(SEC_ERROR_INVALID_ARGS);
return SECFailure;
}
dsa_subprime_len = PQG_GetLength(&key->params.subPrime);
dsa_signature_len = dsa_subprime_len * 2;
if ((signature->len < dsa_signature_len) ||
(digest->len > HASH_LENGTH_MAX) ||
(digest->len < SHA1_LENGTH)) {
PORT_SetError(SEC_ERROR_INVALID_ARGS);
return SECFailure;
}
/* DSA accepts digests not equal to dsa_subprime_len, if the
* digests are greater, then they are truncated to the size of
* dsa_subprime_len, using the left most bits. If they are less
* then they are padded on the left.*/
PORT_Memset(localDigestData, 0, dsa_subprime_len);
offset = (digest->len < dsa_subprime_len) ? (dsa_subprime_len - digest->len) : 0;
PORT_Memcpy(localDigestData + offset, digest->data,
dsa_subprime_len - offset);
localDigest.data = localDigestData;
localDigest.len = dsa_subprime_len;
/* Initialize MPI integers. */
MP_DIGITS(&p) = 0;
MP_DIGITS(&q) = 0;
MP_DIGITS(&g) = 0;
MP_DIGITS(&x) = 0;
MP_DIGITS(&k) = 0;
MP_DIGITS(&r) = 0;
MP_DIGITS(&s) = 0;
MP_DIGITS(&t) = 0;
CHECK_MPI_OK(mp_init(&p));
CHECK_MPI_OK(mp_init(&q));
CHECK_MPI_OK(mp_init(&g));
CHECK_MPI_OK(mp_init(&x));
CHECK_MPI_OK(mp_init(&k));
CHECK_MPI_OK(mp_init(&r));
CHECK_MPI_OK(mp_init(&s));
CHECK_MPI_OK(mp_init(&t));
/*
** Convert stored PQG and private key into MPI integers.
*/
SECITEM_TO_MPINT(key->params.prime, &p);
SECITEM_TO_MPINT(key->params.subPrime, &q);
SECITEM_TO_MPINT(key->params.base, &g);
SECITEM_TO_MPINT(key->privateValue, &x);
OCTETS_TO_MPINT(kb, &k, dsa_subprime_len);
/*
** FIPS 186-1, Section 5, Step 1
**
** r = (g**k mod p) mod q
*/
CHECK_MPI_OK(mp_exptmod(&g, &k, &p, &r)); /* r = g**k mod p */
CHECK_MPI_OK(mp_mod(&r, &q, &r)); /* r = r mod q */
/*
** FIPS 186-1, Section 5, Step 2
**
** s = (k**-1 * (HASH(M) + x*r)) mod q
*/
if (DSA_NewRandom(NULL, &key->params.subPrime, &t2) != SECSuccess) {
PORT_SetError(SEC_ERROR_NEED_RANDOM);
rv = SECFailure;
goto cleanup;
}
SECITEM_TO_MPINT(t2, &t); /* t <-$ Zq */
CHECK_MPI_OK(mp_mulmod(&k, &t, &q, &k)); /* k = k * t mod q */
CHECK_MPI_OK(mp_invmod(&k, &q, &k)); /* k = k**-1 mod q */
CHECK_MPI_OK(mp_mulmod(&k, &t, &q, &k)); /* k = k * t mod q */
SECITEM_TO_MPINT(localDigest, &s); /* s = HASH(M) */
CHECK_MPI_OK(mp_mulmod(&x, &r, &q, &x)); /* x = x * r mod q */
CHECK_MPI_OK(mp_addmod(&s, &x, &q, &s)); /* s = s + x mod q */
CHECK_MPI_OK(mp_mulmod(&s, &k, &q, &s)); /* s = s * k mod q */
/*
** verify r != 0 and s != 0
** mentioned as optional in FIPS 186-1.
*/
if (mp_cmp_z(&r) == 0 || mp_cmp_z(&s) == 0) {
PORT_SetError(SEC_ERROR_NEED_RANDOM);
rv = SECFailure;
goto cleanup;
}
/*
** Step 4
**
** Signature is tuple (r, s)
*/
err = mp_to_fixlen_octets(&r, signature->data, dsa_subprime_len);
if (err < 0)
goto cleanup;
err = mp_to_fixlen_octets(&s, signature->data + dsa_subprime_len,
dsa_subprime_len);
if (err < 0)
goto cleanup;
err = MP_OKAY;
signature->len = dsa_signature_len;
cleanup:
PORT_Memset(localDigestData, 0, DSA_MAX_SUBPRIME_LEN);
mp_clear(&p);
mp_clear(&q);
mp_clear(&g);
mp_clear(&x);
mp_clear(&k);
mp_clear(&r);
mp_clear(&s);
mp_clear(&t);
SECITEM_FreeItem(&t2, PR_FALSE);
if (err) {
translate_mpi_error(err);
rv = SECFailure;
}
return rv;
}
/* signature is caller-supplied buffer of at least 40 bytes.
** On input, signature->len == size of buffer to hold signature.
** digest->len == size of digest.
** On output, signature->len == size of signature in buffer.
** Uses a random seed.
*/
SECStatus
DSA_SignDigest(DSAPrivateKey *key, SECItem *signature, const SECItem *digest)
{
SECStatus rv;
int retries = 10;
unsigned char kSeed[DSA_MAX_SUBPRIME_LEN];
unsigned int kSeedLen = 0;
unsigned int i;
unsigned int dsa_subprime_len = PQG_GetLength(&key->params.subPrime);
PRBool good;
PORT_SetError(0);
do {
rv = dsa_GenerateGlobalRandomBytes(&key->params.subPrime,
kSeed, &kSeedLen, sizeof kSeed);
if (rv != SECSuccess)
break;
if (kSeedLen != dsa_subprime_len) {
PORT_SetError(SEC_ERROR_INVALID_ARGS);
rv = SECFailure;
break;
}
/* Disallow a value of 0 for k. */
good = PR_FALSE;
for (i = 0; i < kSeedLen; i++) {
if (kSeed[i] != 0) {
good = PR_TRUE;
break;
}
}
if (!good) {
PORT_SetError(SEC_ERROR_NEED_RANDOM);
rv = SECFailure;
continue;
}
rv = dsa_SignDigest(key, signature, digest, kSeed);
} while (rv != SECSuccess && PORT_GetError() == SEC_ERROR_NEED_RANDOM &&
--retries > 0);
return rv;
}
/* For FIPS compliance testing. Seed must be exactly 20 bytes. */
SECStatus
DSA_SignDigestWithSeed(DSAPrivateKey *key,
SECItem *signature,
const SECItem *digest,
const unsigned char *seed)
{
SECStatus rv;
rv = dsa_SignDigest(key, signature, digest, seed);
return rv;
}
/* signature is caller-supplied buffer of at least 20 bytes.
** On input, signature->len == size of buffer to hold signature.
** digest->len == size of digest.
*/
SECStatus
DSA_VerifyDigest(DSAPublicKey *key, const SECItem *signature,
const SECItem *digest)
{
/* FIPS-compliance dictates that digest is a SHA hash. */
mp_int p, q, g; /* PQG parameters */
mp_int r_, s_; /* tuple (r', s') is received signature) */
mp_int u1, u2, v, w; /* intermediate values used in verification */
mp_int y; /* public key */
mp_err err;
unsigned int dsa_subprime_len, dsa_signature_len, offset;
SECItem localDigest;
unsigned char localDigestData[DSA_MAX_SUBPRIME_LEN];
SECStatus verified = SECFailure;
/* Check args. */
if (!key || !signature || !digest) {
PORT_SetError(SEC_ERROR_INVALID_ARGS);
return SECFailure;
}
dsa_subprime_len = PQG_GetLength(&key->params.subPrime);
dsa_signature_len = dsa_subprime_len * 2;
if ((signature->len != dsa_signature_len) ||
(digest->len > HASH_LENGTH_MAX) ||
(digest->len < SHA1_LENGTH)) {
PORT_SetError(SEC_ERROR_INVALID_ARGS);
return SECFailure;
}
/* DSA accepts digests not equal to dsa_subprime_len, if the
* digests are greater, than they are truncated to the size of
* dsa_subprime_len, using the left most bits. If they are less
* then they are padded on the left.*/
PORT_Memset(localDigestData, 0, dsa_subprime_len);
offset = (digest->len < dsa_subprime_len) ? (dsa_subprime_len - digest->len) : 0;
PORT_Memcpy(localDigestData + offset, digest->data,
dsa_subprime_len - offset);
localDigest.data = localDigestData;
localDigest.len = dsa_subprime_len;
/* Initialize MPI integers. */
MP_DIGITS(&p) = 0;
MP_DIGITS(&q) = 0;
MP_DIGITS(&g) = 0;
MP_DIGITS(&y) = 0;
MP_DIGITS(&r_) = 0;
MP_DIGITS(&s_) = 0;
MP_DIGITS(&u1) = 0;
MP_DIGITS(&u2) = 0;
MP_DIGITS(&v) = 0;
MP_DIGITS(&w) = 0;
CHECK_MPI_OK(mp_init(&p));
CHECK_MPI_OK(mp_init(&q));
CHECK_MPI_OK(mp_init(&g));
CHECK_MPI_OK(mp_init(&y));
CHECK_MPI_OK(mp_init(&r_));
CHECK_MPI_OK(mp_init(&s_));
CHECK_MPI_OK(mp_init(&u1));
CHECK_MPI_OK(mp_init(&u2));
CHECK_MPI_OK(mp_init(&v));
CHECK_MPI_OK(mp_init(&w));
/*
** Convert stored PQG and public key into MPI integers.
*/
SECITEM_TO_MPINT(key->params.prime, &p);
SECITEM_TO_MPINT(key->params.subPrime, &q);
SECITEM_TO_MPINT(key->params.base, &g);
SECITEM_TO_MPINT(key->publicValue, &y);
/*
** Convert received signature (r', s') into MPI integers.
*/
OCTETS_TO_MPINT(signature->data, &r_, dsa_subprime_len);
OCTETS_TO_MPINT(signature->data + dsa_subprime_len, &s_, dsa_subprime_len);
/*
** Verify that 0 < r' < q and 0 < s' < q
*/
if (mp_cmp_z(&r_) <= 0 || mp_cmp_z(&s_) <= 0 ||
mp_cmp(&r_, &q) >= 0 || mp_cmp(&s_, &q) >= 0) {
/* err is zero here. */
PORT_SetError(SEC_ERROR_BAD_SIGNATURE);
goto cleanup; /* will return verified == SECFailure */
}
/*
** FIPS 186-1, Section 6, Step 1
**
** w = (s')**-1 mod q
*/
CHECK_MPI_OK(mp_invmod(&s_, &q, &w)); /* w = (s')**-1 mod q */
/*
** FIPS 186-1, Section 6, Step 2
**
** u1 = ((Hash(M')) * w) mod q
*/
SECITEM_TO_MPINT(localDigest, &u1); /* u1 = HASH(M') */
CHECK_MPI_OK(mp_mulmod(&u1, &w, &q, &u1)); /* u1 = u1 * w mod q */
/*
** FIPS 186-1, Section 6, Step 3
**
** u2 = ((r') * w) mod q
*/
CHECK_MPI_OK(mp_mulmod(&r_, &w, &q, &u2));
/*
** FIPS 186-1, Section 6, Step 4
**
** v = ((g**u1 * y**u2) mod p) mod q
*/
CHECK_MPI_OK(mp_exptmod(&g, &u1, &p, &g)); /* g = g**u1 mod p */
CHECK_MPI_OK(mp_exptmod(&y, &u2, &p, &y)); /* y = y**u2 mod p */
CHECK_MPI_OK(mp_mulmod(&g, &y, &p, &v)); /* v = g * y mod p */
CHECK_MPI_OK(mp_mod(&v, &q, &v)); /* v = v mod q */
/*
** Verification: v == r'
*/
if (mp_cmp(&v, &r_)) {
PORT_SetError(SEC_ERROR_BAD_SIGNATURE);
verified = SECFailure; /* Signature failed to verify. */
} else {
verified = SECSuccess; /* Signature verified. */
}
cleanup:
mp_clear(&p);
mp_clear(&q);
mp_clear(&g);
mp_clear(&y);
mp_clear(&r_);
mp_clear(&s_);
mp_clear(&u1);
mp_clear(&u2);
mp_clear(&v);
mp_clear(&w);
if (err) {
translate_mpi_error(err);
}
return verified;
}

1159
security/nss/lib/freebl/ec.c Normal file

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,21 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef __ec_h_
#define __ec_h_
#define EC_DEBUG 0
#define ANSI_X962_CURVE_OID_TOTAL_LEN 10
#define SECG_CURVE_OID_TOTAL_LEN 7
#define PKIX_NEWCURVES_OID_TOTAL_LEN 11
struct ECMethodStr {
ECCurveName name;
SECStatus (*mul)(SECItem *result, SECItem *scalar, SECItem *point);
SECStatus (*validate)(const SECItem *point);
};
typedef struct ECMethodStr ECMethod;
#endif /* __ec_h_ */

View file

@ -0,0 +1,311 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef NSS_DISABLE_ECC
#ifdef FREEBL_NO_DEPEND
#include "stubs.h"
#endif
#include "blapi.h"
#include "secoid.h"
#include "secitem.h"
#include "secerr.h"
#include "ec.h"
#include "ecl-curve.h"
#define CHECK_OK(func) \
if (func == NULL) \
goto cleanup
#define CHECK_SEC_OK(func) \
if (SECSuccess != (rv = func)) \
goto cleanup
/*
* Initializes a SECItem from a hexadecimal string
*
* Warning: This function ignores leading 00's, so any leading 00's
* in the hexadecimal string must be optional.
*/
static SECItem *
hexString2SECItem(PLArenaPool *arena, SECItem *item, const char *str)
{
int i = 0;
int byteval = 0;
int tmp = PORT_Strlen(str);
PORT_Assert(arena);
PORT_Assert(item);
if ((tmp % 2) != 0)
return NULL;
/* skip leading 00's unless the hex string is "00" */
while ((tmp > 2) && (str[0] == '0') && (str[1] == '0')) {
str += 2;
tmp -= 2;
}
item->data = (unsigned char *)PORT_ArenaAlloc(arena, tmp / 2);
if (item->data == NULL)
return NULL;
item->len = tmp / 2;
while (str[i]) {
if ((str[i] >= '0') && (str[i] <= '9'))
tmp = str[i] - '0';
else if ((str[i] >= 'a') && (str[i] <= 'f'))
tmp = str[i] - 'a' + 10;
else if ((str[i] >= 'A') && (str[i] <= 'F'))
tmp = str[i] - 'A' + 10;
else
return NULL;
byteval = byteval * 16 + tmp;
if ((i % 2) != 0) {
item->data[i / 2] = byteval;
byteval = 0;
}
i++;
}
return item;
}
/* Copy all of the fields from srcParams into dstParams
*/
SECStatus
EC_CopyParams(PLArenaPool *arena, ECParams *dstParams,
const ECParams *srcParams)
{
SECStatus rv = SECFailure;
dstParams->arena = arena;
dstParams->type = srcParams->type;
dstParams->fieldID.size = srcParams->fieldID.size;
dstParams->fieldID.type = srcParams->fieldID.type;
if (srcParams->fieldID.type == ec_field_GFp ||
srcParams->fieldID.type == ec_field_plain) {
CHECK_SEC_OK(SECITEM_CopyItem(arena, &dstParams->fieldID.u.prime,
&srcParams->fieldID.u.prime));
} else {
CHECK_SEC_OK(SECITEM_CopyItem(arena, &dstParams->fieldID.u.poly,
&srcParams->fieldID.u.poly));
}
dstParams->fieldID.k1 = srcParams->fieldID.k1;
dstParams->fieldID.k2 = srcParams->fieldID.k2;
dstParams->fieldID.k3 = srcParams->fieldID.k3;
CHECK_SEC_OK(SECITEM_CopyItem(arena, &dstParams->curve.a,
&srcParams->curve.a));
CHECK_SEC_OK(SECITEM_CopyItem(arena, &dstParams->curve.b,
&srcParams->curve.b));
CHECK_SEC_OK(SECITEM_CopyItem(arena, &dstParams->curve.seed,
&srcParams->curve.seed));
CHECK_SEC_OK(SECITEM_CopyItem(arena, &dstParams->base,
&srcParams->base));
CHECK_SEC_OK(SECITEM_CopyItem(arena, &dstParams->order,
&srcParams->order));
CHECK_SEC_OK(SECITEM_CopyItem(arena, &dstParams->DEREncoding,
&srcParams->DEREncoding));
dstParams->name = srcParams->name;
CHECK_SEC_OK(SECITEM_CopyItem(arena, &dstParams->curveOID,
&srcParams->curveOID));
dstParams->cofactor = srcParams->cofactor;
return SECSuccess;
cleanup:
return SECFailure;
}
static SECStatus
gf_populate_params(ECCurveName name, ECFieldType field_type, ECParams *params)
{
SECStatus rv = SECFailure;
const ECCurveParams *curveParams;
/* 2 ['0'+'4'] + MAX_ECKEY_LEN * 2 [x,y] * 2 [hex string] + 1 ['\0'] */
char genenc[3 + 2 * 2 * MAX_ECKEY_LEN];
if ((name < ECCurve_noName) || (name > ECCurve_pastLastCurve))
goto cleanup;
params->name = name;
curveParams = ecCurve_map[params->name];
CHECK_OK(curveParams);
params->fieldID.size = curveParams->size;
params->fieldID.type = field_type;
if (field_type == ec_field_GFp ||
field_type == ec_field_plain) {
CHECK_OK(hexString2SECItem(params->arena, &params->fieldID.u.prime,
curveParams->irr));
} else {
CHECK_OK(hexString2SECItem(params->arena, &params->fieldID.u.poly,
curveParams->irr));
}
CHECK_OK(hexString2SECItem(params->arena, &params->curve.a,
curveParams->curvea));
CHECK_OK(hexString2SECItem(params->arena, &params->curve.b,
curveParams->curveb));
genenc[0] = '0';
genenc[1] = '4';
genenc[2] = '\0';
strcat(genenc, curveParams->genx);
strcat(genenc, curveParams->geny);
CHECK_OK(hexString2SECItem(params->arena, &params->base, genenc));
CHECK_OK(hexString2SECItem(params->arena, &params->order,
curveParams->order));
params->cofactor = curveParams->cofactor;
rv = SECSuccess;
cleanup:
return rv;
}
SECStatus
EC_FillParams(PLArenaPool *arena, const SECItem *encodedParams,
ECParams *params)
{
SECStatus rv = SECFailure;
SECOidTag tag;
SECItem oid = { siBuffer, NULL, 0 };
#if EC_DEBUG
int i;
printf("Encoded params in EC_DecodeParams: ");
for (i = 0; i < encodedParams->len; i++) {
printf("%02x:", encodedParams->data[i]);
}
printf("\n");
#endif
if ((encodedParams->len != ANSI_X962_CURVE_OID_TOTAL_LEN) &&
(encodedParams->len != SECG_CURVE_OID_TOTAL_LEN) &&
(encodedParams->len != PKIX_NEWCURVES_OID_TOTAL_LEN)) {
PORT_SetError(SEC_ERROR_UNSUPPORTED_ELLIPTIC_CURVE);
return SECFailure;
};
oid.len = encodedParams->len - 2;
oid.data = encodedParams->data + 2;
if ((encodedParams->data[0] != SEC_ASN1_OBJECT_ID) ||
((tag = SECOID_FindOIDTag(&oid)) == SEC_OID_UNKNOWN)) {
PORT_SetError(SEC_ERROR_UNSUPPORTED_ELLIPTIC_CURVE);
return SECFailure;
}
params->arena = arena;
params->cofactor = 0;
params->type = ec_params_named;
params->name = ECCurve_noName;
/* Fill out curveOID */
params->curveOID.len = oid.len;
params->curveOID.data = (unsigned char *)PORT_ArenaAlloc(arena, oid.len);
if (params->curveOID.data == NULL)
goto cleanup;
memcpy(params->curveOID.data, oid.data, oid.len);
#if EC_DEBUG
printf("Curve: %s\n", SECOID_FindOIDTagDescription(tag));
#endif
switch (tag) {
case SEC_OID_ANSIX962_EC_PRIME256V1:
/* Populate params for prime256v1 aka secp256r1
* (the NIST P-256 curve)
*/
CHECK_SEC_OK(gf_populate_params(ECCurve_X9_62_PRIME_256V1, ec_field_GFp,
params));
break;
case SEC_OID_SECG_EC_SECP384R1:
/* Populate params for secp384r1
* (the NIST P-384 curve)
*/
CHECK_SEC_OK(gf_populate_params(ECCurve_SECG_PRIME_384R1, ec_field_GFp,
params));
break;
case SEC_OID_SECG_EC_SECP521R1:
/* Populate params for secp521r1
* (the NIST P-521 curve)
*/
CHECK_SEC_OK(gf_populate_params(ECCurve_SECG_PRIME_521R1, ec_field_GFp,
params));
break;
case SEC_OID_CURVE25519:
/* Populate params for Curve25519 */
CHECK_SEC_OK(gf_populate_params(ECCurve25519, ec_field_plain, params));
break;
default:
break;
};
cleanup:
if (!params->cofactor) {
PORT_SetError(SEC_ERROR_UNSUPPORTED_ELLIPTIC_CURVE);
#if EC_DEBUG
printf("Unrecognized curve, returning NULL params\n");
#endif
}
return rv;
}
SECStatus
EC_DecodeParams(const SECItem *encodedParams, ECParams **ecparams)
{
PLArenaPool *arena;
ECParams *params;
SECStatus rv = SECFailure;
/* Initialize an arena for the ECParams structure */
if (!(arena = PORT_NewArena(NSS_FREEBL_DEFAULT_CHUNKSIZE)))
return SECFailure;
params = (ECParams *)PORT_ArenaZAlloc(arena, sizeof(ECParams));
if (!params) {
PORT_FreeArena(arena, PR_TRUE);
return SECFailure;
}
/* Copy the encoded params */
SECITEM_AllocItem(arena, &(params->DEREncoding),
encodedParams->len);
memcpy(params->DEREncoding.data, encodedParams->data, encodedParams->len);
/* Fill out the rest of the ECParams structure based on
* the encoded params
*/
rv = EC_FillParams(arena, encodedParams, params);
if (rv == SECFailure) {
PORT_FreeArena(arena, PR_TRUE);
return SECFailure;
} else {
*ecparams = params;
;
return SECSuccess;
}
}
int
EC_GetPointSize(const ECParams *params)
{
ECCurveName name = params->name;
const ECCurveParams *curveParams;
if ((name < ECCurve_noName) || (name > ECCurve_pastLastCurve) ||
((curveParams = ecCurve_map[name]) == NULL)) {
/* unknown curve, calculate point size from params. assume standard curves with 2 points
* and a point compression indicator byte */
int sizeInBytes = (params->fieldID.size + 7) / 8;
return sizeInBytes * 2 + 1;
}
return curveParams->pointSize;
}
#endif /* NSS_DISABLE_ECC */

View file

@ -0,0 +1,267 @@
This Source Code Form is subject to the terms of the Mozilla Public
License, v. 2.0. If a copy of the MPL was not distributed with this
file, You can obtain one at http://mozilla.org/MPL/2.0/.
The ECL exposes routines for constructing and converting curve
parameters for internal use.
HEADER FILES
============
ecl-exp.h - Exports data structures and curve names. For use by code
that does not have access to mp_ints.
ecl-curve.h - Provides hex encodings (in the form of ECCurveParams
structs) of standardizes elliptic curve domain parameters and mappings
from ECCurveName to ECCurveParams. For use by code that does not have
access to mp_ints.
ecl.h - Interface to constructors for curve parameters and group object,
and point multiplication operations. Used by higher level algorithms
(like ECDH and ECDSA) to actually perform elliptic curve cryptography.
ecl-priv.h - Data structures and functions for internal use within the
library.
ecp.h - Internal header file that contains all functions for point
arithmetic over prime fields.
DATA STRUCTURES AND TYPES
=========================
ECCurveName (from ecl-exp.h) - Opaque name for standardized elliptic
curve domain parameters.
ECCurveParams (from ecl-exp.h) - Provides hexadecimal encoding
of elliptic curve domain parameters. Can be generated by a user
and passed to ECGroup_fromHex or can be generated from a name by
EC_GetNamedCurveParams. ecl-curve.h contains ECCurveParams structs for
the standardized curves defined by ECCurveName.
ECGroup (from ecl.h and ecl-priv.h) - Opaque data structure that
represents a group of elliptic curve points for a particular set of
elliptic curve domain parameters. Contains all domain parameters (curve
a and b, field, base point) as well as pointers to the functions that
should be used for point arithmetic and the underlying field GFMethod.
Generated by either ECGroup_fromHex or ECGroup_fromName.
GFMethod (from ecl-priv.h) - Represents a field underlying a set of
elliptic curve domain parameters. Contains the irreducible that defines
the field (either the prime or the binary polynomial) as well as
pointers to the functions that should be used for field arithmetic.
ARITHMETIC FUNCTIONS
====================
Higher-level algorithms (like ECDH and ECDSA) should call ECPoint_mul
or ECPoints_mul (from ecl.h) to do point arithmetic. These functions
will choose which underlying algorithms to use, based on the ECGroup
structure.
Point Multiplication
--------------------
ecl_mult.c provides the ECPoints_mul and ECPoint_mul wrappers.
It also provides two implementations for the pts_mul operation -
ec_pts_mul_basic (which computes kP, lQ, and then adds kP + lQ) and
ec_pts_mul_simul_w2 (which does a simultaneous point multiplication
using a table with window size 2*2).
ec_naf.c provides an implementation of an algorithm to calculate a
non-adjacent form of a scalar, minimizing the number of point
additions that need to be done in a point multiplication.
Point Arithmetic over Prime Fields
----------------------------------
ecp_aff.c provides point arithmetic using affine coordinates.
ecp_jac.c provides point arithmetic using Jacobian projective
coordinates and mixed Jacobian-affine coordinates. (Jacobian projective
coordinates represent a point (x, y) as (X, Y, Z), where x=X/Z^2,
y=Y/Z^3).
ecp_jm.c provides point arithmetic using Modified Jacobian
coordinates and mixed Modified_Jacobian-affine coordinates.
(Modified Jacobian coordinates represent a point (x, y)
as (X, Y, Z, a*Z^4), where x=X/Z^2, y=Y/Z^3, and a is
the linear coefficient in the curve defining equation).
ecp_192.c and ecp_224.c provide optimized field arithmetic.
Point Arithmetic over Binary Polynomial Fields
----------------------------------------------
ec2_aff.c provides point arithmetic using affine coordinates.
ec2_proj.c provides point arithmetic using projective coordinates.
(Projective coordinates represent a point (x, y) as (X, Y, Z), where
x=X/Z, y=Y/Z^2).
ec2_mont.c provides point multiplication using Montgomery projective
coordinates.
ec2_163.c, ec2_193.c, and ec2_233.c provide optimized field arithmetic.
Field Arithmetic
----------------
ecl_gf.c provides constructors for field objects (GFMethod) with the
functions GFMethod_cons*. It also provides wrappers around the basic
field operations.
Prime Field Arithmetic
----------------------
The mpi library provides the basic prime field arithmetic.
ecp_mont.c provides wrappers around the Montgomery multiplication
functions from the mpi library and adds encoding and decoding functions.
It also provides the function to construct a GFMethod object using
Montgomery multiplication.
ecp_192.c and ecp_224.c provide optimized modular reduction for the
fields defined by nistp192 and nistp224 primes.
ecl_gf.c provides wrappers around the basic field operations.
Binary Polynomial Field Arithmetic
----------------------------------
../mpi/mp_gf2m.c provides basic binary polynomial field arithmetic,
including addition, multiplication, squaring, mod, and division, as well
as conversion ob polynomial representations between bitstring and int[].
ec2_163.c, ec2_193.c, and ec2_233.c provide optimized field mod, mul,
and sqr operations.
ecl_gf.c provides wrappers around the basic field operations.
Field Encoding
--------------
By default, field elements are encoded in their basic form. It is
possible to use an alternative encoding, however. For example, it is
possible to Montgomery representation of prime field elements and
take advantage of the fast modular multiplication that Montgomery
representation provides. The process of converting from basic form to
Montgomery representation is called field encoding, and the opposite
process would be field decoding. All internal point operations assume
that the operands are field encoded as appropriate. By rewiring the
underlying field arithmetic to perform operations on these encoded
values, the same overlying point arithmetic operations can be used
regardless of field representation.
ALGORITHM WIRING
================
The EC library allows point and field arithmetic algorithms to be
substituted ("wired-in") on a fine-grained basis. This allows for
generic algorithms and algorithms that are optimized for a particular
curve, field, or architecture, to coexist and to be automatically
selected at runtime.
Wiring Mechanism
----------------
The ECGroup and GFMethod structure contain pointers to the point and
field arithmetic functions, respectively, that are to be used in
operations.
The selection of algorithms to use is handled in the function
ecgroup_fromNameAndHex in ecl.c.
Default Wiring
--------------
Curves over prime fields by default use montgomery field arithmetic,
point multiplication using 5-bit window non-adjacent-form with
Modified Jacobian coordinates, and 2*2-bit simultaneous point
multiplication using Jacobian coordinates.
(Wiring in function ECGroup_consGFp_mont in ecl.c.)
Curves over prime fields that have optimized modular reduction (i.e.,
secp160r1, nistp192, and nistp224) do not use Montgomery field
arithmetic. Instead, they use basic field arithmetic with their
optimized reduction (as in ecp_192.c and ecp_224.c). They
use the same point multiplication and simultaneous point multiplication
algorithms as other curves over prime fields.
Curves over binary polynomial fields by default use generic field
arithmetic with montgomery point multiplication and basic kP + lQ
computation (multiply, multiply, and add). (Wiring in function
ECGroup_cons_GF2m in ecl.c.)
Curves over binary polynomial fields that have optimized field
arithmetic (i.e., any 163-, 193, or 233-bit field) use their optimized
field arithmetic. They use the same point multiplication and
simultaneous point multiplication algorithms as other curves over binary
fields.
Example
-------
We provide an example for plugging in an optimized implementation for
the Koblitz curve nistk163.
Suppose the file ec2_k163.c contains the optimized implementation. In
particular it contains a point multiplication function:
mp_err ec_GF2m_nistk163_pt_mul(const mp_int *n, const mp_int *px,
const mp_int *py, mp_int *rx, mp_int *ry, const ECGroup *group);
Since only a pt_mul function is provided, the generic pt_add function
will be used.
There are two options for handling the optimized field arithmetic used
by the ..._pt_mul function. Say the optimized field arithmetic includes
the following functions:
mp_err ec_GF2m_nistk163_add(const mp_int *a, const mp_int *b,
mp_int *r, const GFMethod *meth);
mp_err ec_GF2m_nistk163_mul(const mp_int *a, const mp_int *b,
mp_int *r, const GFMethod *meth);
mp_err ec_GF2m_nistk163_sqr(const mp_int *a, const mp_int *b,
mp_int *r, const GFMethod *meth);
mp_err ec_GF2m_nistk163_div(const mp_int *a, const mp_int *b,
mp_int *r, const GFMethod *meth);
First, the optimized field arithmetic could simply be called directly
by the ..._pt_mul function. This would be accomplished by changing
the ecgroup_fromNameAndHex function in ecl.c to include the following
statements:
if (name == ECCurve_NIST_K163) {
group = ECGroup_consGF2m(&irr, NULL, &curvea, &curveb, &genx,
&geny, &order, params->cofactor);
if (group == NULL) { res = MP_UNDEF; goto CLEANUP; }
MP_CHECKOK( ec_group_set_nistk163(group) );
}
and including in ec2_k163.c the following function:
mp_err ec_group_set_nistk163(ECGroup *group) {
group->point_mul = &ec_GF2m_nistk163_pt_mul;
return MP_OKAY;
}
As a result, ec_GF2m_pt_add and similar functions would use the
basic binary polynomial field arithmetic ec_GF2m_add, ec_GF2m_mul,
ec_GF2m_sqr, and ec_GF2m_div.
Alternatively, the optimized field arithmetic could be wired into the
group's GFMethod. This would be accomplished by putting the following
function in ec2_k163.c:
mp_err ec_group_set_nistk163(ECGroup *group) {
group->meth->field_add = &ec_GF2m_nistk163_add;
group->meth->field_mul = &ec_GF2m_nistk163_mul;
group->meth->field_sqr = &ec_GF2m_nistk163_sqr;
group->meth->field_div = &ec_GF2m_nistk163_div;
group->point_mul = &ec_GF2m_nistk163_pt_mul;
return MP_OKAY;
}
For an example of functions that use special field encodings, take a
look at ecp_mont.c.

View file

@ -0,0 +1,390 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
/*
* Derived from public domain code by Matthew Dempsky and D. J. Bernstein.
*/
#include "ecl-priv.h"
#include "mpi.h"
#include <stdint.h>
#include <stdio.h>
typedef uint32_t elem[32];
/*
* Add two field elements.
* out = a + b
*/
static void
add(elem out, const elem a, const elem b)
{
uint32_t j;
uint32_t u = 0;
for (j = 0; j < 31; ++j) {
u += a[j] + b[j];
out[j] = u & 0xFF;
u >>= 8;
}
u += a[31] + b[31];
out[31] = u;
}
/*
* Subtract two field elements.
* out = a - b
*/
static void
sub(elem out, const elem a, const elem b)
{
uint32_t j;
uint32_t u;
u = 218;
for (j = 0; j < 31; ++j) {
u += a[j] + 0xFF00 - b[j];
out[j] = u & 0xFF;
u >>= 8;
}
u += a[31] - b[31];
out[31] = u;
}
/*
* "Squeeze" an element after multiplication (and square).
*/
static void
squeeze(elem a)
{
uint32_t j;
uint32_t u;
u = 0;
for (j = 0; j < 31; ++j) {
u += a[j];
a[j] = u & 0xFF;
u >>= 8;
}
u += a[31];
a[31] = u & 0x7F;
u = 19 * (u >> 7);
for (j = 0; j < 31; ++j) {
u += a[j];
a[j] = u & 0xFF;
u >>= 8;
}
a[31] += u;
}
static const elem minusp = { 19, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 128 };
/*
* Reduce point a by 2^255-19
*/
static void
reduce(elem a)
{
elem aorig;
uint32_t j;
uint32_t negative;
for (j = 0; j < 32; ++j) {
aorig[j] = a[j];
}
add(a, a, minusp);
negative = 1 + ~((a[31] >> 7) & 1);
for (j = 0; j < 32; ++j) {
a[j] ^= negative & (aorig[j] ^ a[j]);
}
}
/*
* Multiplication and squeeze
* out = a * b
*/
static void
mult(elem out, const elem a, const elem b)
{
uint32_t i;
uint32_t j;
uint32_t u;
for (i = 0; i < 32; ++i) {
u = 0;
for (j = 0; j <= i; ++j) {
u += a[j] * b[i - j];
}
for (j = i + 1; j < 32; ++j) {
u += 38 * a[j] * b[i + 32 - j];
}
out[i] = u;
}
squeeze(out);
}
/*
* Multiplication
* out = 121665 * a
*/
static void
mult121665(elem out, const elem a)
{
uint32_t j;
uint32_t u;
u = 0;
for (j = 0; j < 31; ++j) {
u += 121665 * a[j];
out[j] = u & 0xFF;
u >>= 8;
}
u += 121665 * a[31];
out[31] = u & 0x7F;
u = 19 * (u >> 7);
for (j = 0; j < 31; ++j) {
u += out[j];
out[j] = u & 0xFF;
u >>= 8;
}
u += out[j];
out[j] = u;
}
/*
* Square a and squeeze the result.
* out = a * a
*/
static void
square(elem out, const elem a)
{
uint32_t i;
uint32_t j;
uint32_t u;
for (i = 0; i < 32; ++i) {
u = 0;
for (j = 0; j < i - j; ++j) {
u += a[j] * a[i - j];
}
for (j = i + 1; j < i + 32 - j; ++j) {
u += 38 * a[j] * a[i + 32 - j];
}
u *= 2;
if ((i & 1) == 0) {
u += a[i / 2] * a[i / 2];
u += 38 * a[i / 2 + 16] * a[i / 2 + 16];
}
out[i] = u;
}
squeeze(out);
}
/*
* Constant time swap between r and s depending on b
*/
static void
cswap(uint32_t p[64], uint32_t q[64], uint32_t b)
{
uint32_t j;
uint32_t swap = 1 + ~b;
for (j = 0; j < 64; ++j) {
const uint32_t t = swap & (p[j] ^ q[j]);
p[j] ^= t;
q[j] ^= t;
}
}
/*
* Montgomery ladder
*/
static void
monty(elem x_2_out, elem z_2_out,
const elem point, const elem scalar)
{
uint32_t x_3[64] = { 0 };
uint32_t x_2[64] = { 0 };
uint32_t a0[64];
uint32_t a1[64];
uint32_t b0[64];
uint32_t b1[64];
uint32_t c1[64];
uint32_t r[32];
uint32_t s[32];
uint32_t t[32];
uint32_t u[32];
uint32_t swap = 0;
uint32_t k_t = 0;
int j;
for (j = 0; j < 32; ++j) {
x_3[j] = point[j];
}
x_3[32] = 1;
x_2[0] = 1;
for (j = 254; j >= 0; --j) {
k_t = (scalar[j >> 3] >> (j & 7)) & 1;
swap ^= k_t;
cswap(x_2, x_3, swap);
swap = k_t;
add(a0, x_2, x_2 + 32);
sub(a0 + 32, x_2, x_2 + 32);
add(a1, x_3, x_3 + 32);
sub(a1 + 32, x_3, x_3 + 32);
square(b0, a0);
square(b0 + 32, a0 + 32);
mult(b1, a1, a0 + 32);
mult(b1 + 32, a1 + 32, a0);
add(c1, b1, b1 + 32);
sub(c1 + 32, b1, b1 + 32);
square(r, c1 + 32);
sub(s, b0, b0 + 32);
mult121665(t, s);
add(u, t, b0);
mult(x_2, b0, b0 + 32);
mult(x_2 + 32, s, u);
square(x_3, c1);
mult(x_3 + 32, r, point);
}
cswap(x_2, x_3, swap);
for (j = 0; j < 32; ++j) {
x_2_out[j] = x_2[j];
}
for (j = 0; j < 32; ++j) {
z_2_out[j] = x_2[j + 32];
}
}
static void
recip(elem out, const elem z)
{
elem z2;
elem z9;
elem z11;
elem z2_5_0;
elem z2_10_0;
elem z2_20_0;
elem z2_50_0;
elem z2_100_0;
elem t0;
elem t1;
int i;
/* 2 */ square(z2, z);
/* 4 */ square(t1, z2);
/* 8 */ square(t0, t1);
/* 9 */ mult(z9, t0, z);
/* 11 */ mult(z11, z9, z2);
/* 22 */ square(t0, z11);
/* 2^5 - 2^0 = 31 */ mult(z2_5_0, t0, z9);
/* 2^6 - 2^1 */ square(t0, z2_5_0);
/* 2^7 - 2^2 */ square(t1, t0);
/* 2^8 - 2^3 */ square(t0, t1);
/* 2^9 - 2^4 */ square(t1, t0);
/* 2^10 - 2^5 */ square(t0, t1);
/* 2^10 - 2^0 */ mult(z2_10_0, t0, z2_5_0);
/* 2^11 - 2^1 */ square(t0, z2_10_0);
/* 2^12 - 2^2 */ square(t1, t0);
/* 2^20 - 2^10 */
for (i = 2; i < 10; i += 2) {
square(t0, t1);
square(t1, t0);
}
/* 2^20 - 2^0 */ mult(z2_20_0, t1, z2_10_0);
/* 2^21 - 2^1 */ square(t0, z2_20_0);
/* 2^22 - 2^2 */ square(t1, t0);
/* 2^40 - 2^20 */
for (i = 2; i < 20; i += 2) {
square(t0, t1);
square(t1, t0);
}
/* 2^40 - 2^0 */ mult(t0, t1, z2_20_0);
/* 2^41 - 2^1 */ square(t1, t0);
/* 2^42 - 2^2 */ square(t0, t1);
/* 2^50 - 2^10 */
for (i = 2; i < 10; i += 2) {
square(t1, t0);
square(t0, t1);
}
/* 2^50 - 2^0 */ mult(z2_50_0, t0, z2_10_0);
/* 2^51 - 2^1 */ square(t0, z2_50_0);
/* 2^52 - 2^2 */ square(t1, t0);
/* 2^100 - 2^50 */
for (i = 2; i < 50; i += 2) {
square(t0, t1);
square(t1, t0);
}
/* 2^100 - 2^0 */ mult(z2_100_0, t1, z2_50_0);
/* 2^101 - 2^1 */ square(t1, z2_100_0);
/* 2^102 - 2^2 */ square(t0, t1);
/* 2^200 - 2^100 */
for (i = 2; i < 100; i += 2) {
square(t1, t0);
square(t0, t1);
}
/* 2^200 - 2^0 */ mult(t1, t0, z2_100_0);
/* 2^201 - 2^1 */ square(t0, t1);
/* 2^202 - 2^2 */ square(t1, t0);
/* 2^250 - 2^50 */
for (i = 2; i < 50; i += 2) {
square(t0, t1);
square(t1, t0);
}
/* 2^250 - 2^0 */ mult(t0, t1, z2_50_0);
/* 2^251 - 2^1 */ square(t1, t0);
/* 2^252 - 2^2 */ square(t0, t1);
/* 2^253 - 2^3 */ square(t1, t0);
/* 2^254 - 2^4 */ square(t0, t1);
/* 2^255 - 2^5 */ square(t1, t0);
/* 2^255 - 21 */ mult(out, t1, z11);
}
/*
* Computes q = Curve25519(p, s)
*/
SECStatus
ec_Curve25519_mul(PRUint8 *q, const PRUint8 *s, const PRUint8 *p)
{
elem point = { 0 };
elem x_2 = { 0 };
elem z_2 = { 0 };
elem X = { 0 };
elem scalar = { 0 };
uint32_t i;
/* read and mask scalar */
for (i = 0; i < 32; ++i) {
scalar[i] = s[i];
}
scalar[0] &= 0xF8;
scalar[31] &= 0x7F;
scalar[31] |= 64;
/* read and mask point */
for (i = 0; i < 32; ++i) {
point[i] = p[i];
}
point[31] &= 0x7F;
monty(x_2, z_2, point, scalar);
recip(z_2, z_2);
mult(X, x_2, z_2);
reduce(X);
for (i = 0; i < 32; ++i) {
q[i] = X[i];
}
return 0;
}

View file

@ -0,0 +1,514 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
/*
* Derived from public domain C code by Adan Langley and Daniel J. Bernstein
*/
#include "uint128.h"
#include "ecl-priv.h"
#include "mpi.h"
#include <stdint.h>
#include <stdio.h>
#include <string.h>
typedef uint8_t u8;
typedef uint64_t felem;
/* Sum two numbers: output += in */
static void
fsum(felem *output, const felem *in)
{
unsigned i;
for (i = 0; i < 5; ++i) {
output[i] += in[i];
}
}
/* Find the difference of two numbers: output = in - output
* (note the order of the arguments!)
*/
static void
fdifference_backwards(felem *ioutput, const felem *iin)
{
static const int64_t twotothe51 = ((int64_t)1l << 51);
const int64_t *in = (const int64_t *)iin;
int64_t *out = (int64_t *)ioutput;
out[0] = in[0] - out[0];
out[1] = in[1] - out[1];
out[2] = in[2] - out[2];
out[3] = in[3] - out[3];
out[4] = in[4] - out[4];
// An arithmetic shift right of 63 places turns a positive number to 0 and a
// negative number to all 1's. This gives us a bitmask that lets us avoid
// side-channel prone branches.
int64_t t;
#define NEGCHAIN(a, b) \
t = out[a] >> 63; \
out[a] += twotothe51 & t; \
out[b] -= 1 & t;
#define NEGCHAIN19(a, b) \
t = out[a] >> 63; \
out[a] += twotothe51 & t; \
out[b] -= 19 & t;
NEGCHAIN(0, 1);
NEGCHAIN(1, 2);
NEGCHAIN(2, 3);
NEGCHAIN(3, 4);
NEGCHAIN19(4, 0);
NEGCHAIN(0, 1);
NEGCHAIN(1, 2);
NEGCHAIN(2, 3);
NEGCHAIN(3, 4);
}
/* Multiply a number by a scalar: output = in * scalar */
static void
fscalar_product(felem *output, const felem *in,
const felem scalar)
{
uint128_t tmp, tmp2;
tmp = mul6464(in[0], scalar);
output[0] = mask51(tmp);
tmp2 = mul6464(in[1], scalar);
tmp = add128(tmp2, rshift128(tmp, 51));
output[1] = mask51(tmp);
tmp2 = mul6464(in[2], scalar);
tmp = add128(tmp2, rshift128(tmp, 51));
output[2] = mask51(tmp);
tmp2 = mul6464(in[3], scalar);
tmp = add128(tmp2, rshift128(tmp, 51));
output[3] = mask51(tmp);
tmp2 = mul6464(in[4], scalar);
tmp = add128(tmp2, rshift128(tmp, 51));
output[4] = mask51(tmp);
output[0] += mask_lower(rshift128(tmp, 51)) * 19;
}
/* Multiply two numbers: output = in2 * in
*
* output must be distinct to both inputs. The inputs are reduced coefficient
* form, the output is not.
*/
static void
fmul(felem *output, const felem *in2, const felem *in)
{
uint128_t t0, t1, t2, t3, t4, t5, t6, t7, t8;
t0 = mul6464(in[0], in2[0]);
t1 = add128(mul6464(in[1], in2[0]), mul6464(in[0], in2[1]));
t2 = add128(add128(mul6464(in[0], in2[2]),
mul6464(in[2], in2[0])),
mul6464(in[1], in2[1]));
t3 = add128(add128(add128(mul6464(in[0], in2[3]),
mul6464(in[3], in2[0])),
mul6464(in[1], in2[2])),
mul6464(in[2], in2[1]));
t4 = add128(add128(add128(add128(mul6464(in[0], in2[4]),
mul6464(in[4], in2[0])),
mul6464(in[3], in2[1])),
mul6464(in[1], in2[3])),
mul6464(in[2], in2[2]));
t5 = add128(add128(add128(mul6464(in[4], in2[1]),
mul6464(in[1], in2[4])),
mul6464(in[2], in2[3])),
mul6464(in[3], in2[2]));
t6 = add128(add128(mul6464(in[4], in2[2]),
mul6464(in[2], in2[4])),
mul6464(in[3], in2[3]));
t7 = add128(mul6464(in[3], in2[4]), mul6464(in[4], in2[3]));
t8 = mul6464(in[4], in2[4]);
t0 = add128(t0, mul12819(t5));
t1 = add128(t1, mul12819(t6));
t2 = add128(t2, mul12819(t7));
t3 = add128(t3, mul12819(t8));
t1 = add128(t1, rshift128(t0, 51));
t0 = mask51full(t0);
t2 = add128(t2, rshift128(t1, 51));
t1 = mask51full(t1);
t3 = add128(t3, rshift128(t2, 51));
t4 = add128(t4, rshift128(t3, 51));
t0 = add128(t0, mul12819(rshift128(t4, 51)));
t1 = add128(t1, rshift128(t0, 51));
t2 = mask51full(t2);
t2 = add128(t2, rshift128(t1, 51));
output[0] = mask51(t0);
output[1] = mask51(t1);
output[2] = mask_lower(t2);
output[3] = mask51(t3);
output[4] = mask51(t4);
}
static void
fsquare(felem *output, const felem *in)
{
uint128_t t0, t1, t2, t3, t4, t5, t6, t7, t8;
t0 = mul6464(in[0], in[0]);
t1 = lshift128(mul6464(in[0], in[1]), 1);
t2 = add128(lshift128(mul6464(in[0], in[2]), 1),
mul6464(in[1], in[1]));
t3 = add128(lshift128(mul6464(in[0], in[3]), 1),
lshift128(mul6464(in[1], in[2]), 1));
t4 = add128(add128(lshift128(mul6464(in[0], in[4]), 1),
lshift128(mul6464(in[3], in[1]), 1)),
mul6464(in[2], in[2]));
t5 = add128(lshift128(mul6464(in[4], in[1]), 1),
lshift128(mul6464(in[2], in[3]), 1));
t6 = add128(lshift128(mul6464(in[4], in[2]), 1),
mul6464(in[3], in[3]));
t7 = lshift128(mul6464(in[3], in[4]), 1);
t8 = mul6464(in[4], in[4]);
t0 = add128(t0, mul12819(t5));
t1 = add128(t1, mul12819(t6));
t2 = add128(t2, mul12819(t7));
t3 = add128(t3, mul12819(t8));
t1 = add128(t1, rshift128(t0, 51));
t0 = mask51full(t0);
t2 = add128(t2, rshift128(t1, 51));
t1 = mask51full(t1);
t3 = add128(t3, rshift128(t2, 51));
t4 = add128(t4, rshift128(t3, 51));
t0 = add128(t0, mul12819(rshift128(t4, 51)));
t1 = add128(t1, rshift128(t0, 51));
output[0] = mask51(t0);
output[1] = mask_lower(t1);
output[2] = mask51(t2);
output[3] = mask51(t3);
output[4] = mask51(t4);
}
/* Take a 32-byte number and expand it into polynomial form */
static void NO_SANITIZE_ALIGNMENT
fexpand(felem *output, const u8 *in)
{
output[0] = *((const uint64_t *)(in)) & MASK51;
output[1] = (*((const uint64_t *)(in + 6)) >> 3) & MASK51;
output[2] = (*((const uint64_t *)(in + 12)) >> 6) & MASK51;
output[3] = (*((const uint64_t *)(in + 19)) >> 1) & MASK51;
output[4] = (*((const uint64_t *)(in + 25)) >> 4) & MASK51;
}
/* Take a fully reduced polynomial form number and contract it into a
* 32-byte array
*/
static void
fcontract(u8 *output, const felem *input)
{
uint128_t t0 = init128x(input[0]);
uint128_t t1 = init128x(input[1]);
uint128_t t2 = init128x(input[2]);
uint128_t t3 = init128x(input[3]);
uint128_t t4 = init128x(input[4]);
uint128_t tmp = init128x(19);
t1 = add128(t1, rshift128(t0, 51));
t0 = mask51full(t0);
t2 = add128(t2, rshift128(t1, 51));
t1 = mask51full(t1);
t3 = add128(t3, rshift128(t2, 51));
t2 = mask51full(t2);
t4 = add128(t4, rshift128(t3, 51));
t3 = mask51full(t3);
t0 = add128(t0, mul12819(rshift128(t4, 51)));
t4 = mask51full(t4);
t1 = add128(t1, rshift128(t0, 51));
t0 = mask51full(t0);
t2 = add128(t2, rshift128(t1, 51));
t1 = mask51full(t1);
t3 = add128(t3, rshift128(t2, 51));
t2 = mask51full(t2);
t4 = add128(t4, rshift128(t3, 51));
t3 = mask51full(t3);
t0 = add128(t0, mul12819(rshift128(t4, 51)));
t4 = mask51full(t4);
/* now t is between 0 and 2^255-1, properly carried. */
/* case 1: between 0 and 2^255-20. case 2: between 2^255-19 and 2^255-1. */
t0 = add128(t0, tmp);
t1 = add128(t1, rshift128(t0, 51));
t0 = mask51full(t0);
t2 = add128(t2, rshift128(t1, 51));
t1 = mask51full(t1);
t3 = add128(t3, rshift128(t2, 51));
t2 = mask51full(t2);
t4 = add128(t4, rshift128(t3, 51));
t3 = mask51full(t3);
t0 = add128(t0, mul12819(rshift128(t4, 51)));
t4 = mask51full(t4);
/* now between 19 and 2^255-1 in both cases, and offset by 19. */
t0 = add128(t0, init128x(0x8000000000000 - 19));
tmp = init128x(0x8000000000000 - 1);
t1 = add128(t1, tmp);
t2 = add128(t2, tmp);
t3 = add128(t3, tmp);
t4 = add128(t4, tmp);
/* now between 2^255 and 2^256-20, and offset by 2^255. */
t1 = add128(t1, rshift128(t0, 51));
t0 = mask51full(t0);
t2 = add128(t2, rshift128(t1, 51));
t1 = mask51full(t1);
t3 = add128(t3, rshift128(t2, 51));
t2 = mask51full(t2);
t4 = add128(t4, rshift128(t3, 51));
t3 = mask51full(t3);
t4 = mask51full(t4);
*((uint64_t *)(output)) = mask_lower(t0) | mask_lower(t1) << 51;
*((uint64_t *)(output + 8)) = (mask_lower(t1) >> 13) | (mask_lower(t2) << 38);
*((uint64_t *)(output + 16)) = (mask_lower(t2) >> 26) | (mask_lower(t3) << 25);
*((uint64_t *)(output + 24)) = (mask_lower(t3) >> 39) | (mask_lower(t4) << 12);
}
/* Input: Q, Q', Q-Q'
* Output: 2Q, Q+Q'
*
* x2 z3: long form
* x3 z3: long form
* x z: short form, destroyed
* xprime zprime: short form, destroyed
* qmqp: short form, preserved
*/
static void
fmonty(felem *x2, felem *z2, /* output 2Q */
felem *x3, felem *z3, /* output Q + Q' */
felem *x, felem *z, /* input Q */
felem *xprime, felem *zprime, /* input Q' */
const felem *qmqp /* input Q - Q' */)
{
felem origx[5], origxprime[5], zzz[5], xx[5], zz[5], xxprime[5], zzprime[5],
zzzprime[5];
memcpy(origx, x, 5 * sizeof(felem));
fsum(x, z);
fdifference_backwards(z, origx); // does x - z
memcpy(origxprime, xprime, sizeof(felem) * 5);
fsum(xprime, zprime);
fdifference_backwards(zprime, origxprime);
fmul(xxprime, xprime, z);
fmul(zzprime, x, zprime);
memcpy(origxprime, xxprime, sizeof(felem) * 5);
fsum(xxprime, zzprime);
fdifference_backwards(zzprime, origxprime);
fsquare(x3, xxprime);
fsquare(zzzprime, zzprime);
fmul(z3, zzzprime, qmqp);
fsquare(xx, x);
fsquare(zz, z);
fmul(x2, xx, zz);
fdifference_backwards(zz, xx); // does zz = xx - zz
fscalar_product(zzz, zz, 121665);
fsum(zzz, xx);
fmul(z2, zz, zzz);
}
// -----------------------------------------------------------------------------
// Maybe swap the contents of two felem arrays (@a and @b), each @len elements
// long. Perform the swap iff @swap is non-zero.
//
// This function performs the swap without leaking any side-channel
// information.
// -----------------------------------------------------------------------------
static void
swap_conditional(felem *a, felem *b, unsigned len, felem iswap)
{
unsigned i;
const felem swap = 1 + ~iswap;
for (i = 0; i < len; ++i) {
const felem x = swap & (a[i] ^ b[i]);
a[i] ^= x;
b[i] ^= x;
}
}
/* Calculates nQ where Q is the x-coordinate of a point on the curve
*
* resultx/resultz: the x coordinate of the resulting curve point (short form)
* n: a 32-byte number
* q: a point of the curve (short form)
*/
static void
cmult(felem *resultx, felem *resultz, const u8 *n, const felem *q)
{
felem a[5] = { 0 }, b[5] = { 1 }, c[5] = { 1 }, d[5] = { 0 };
felem *nqpqx = a, *nqpqz = b, *nqx = c, *nqz = d, *t;
felem e[5] = { 0 }, f[5] = { 1 }, g[5] = { 0 }, h[5] = { 1 };
felem *nqpqx2 = e, *nqpqz2 = f, *nqx2 = g, *nqz2 = h;
unsigned i, j;
memcpy(nqpqx, q, sizeof(felem) * 5);
for (i = 0; i < 32; ++i) {
u8 byte = n[31 - i];
for (j = 0; j < 8; ++j) {
const felem bit = byte >> 7;
swap_conditional(nqx, nqpqx, 5, bit);
swap_conditional(nqz, nqpqz, 5, bit);
fmonty(nqx2, nqz2, nqpqx2, nqpqz2, nqx, nqz, nqpqx, nqpqz, q);
swap_conditional(nqx2, nqpqx2, 5, bit);
swap_conditional(nqz2, nqpqz2, 5, bit);
t = nqx;
nqx = nqx2;
nqx2 = t;
t = nqz;
nqz = nqz2;
nqz2 = t;
t = nqpqx;
nqpqx = nqpqx2;
nqpqx2 = t;
t = nqpqz;
nqpqz = nqpqz2;
nqpqz2 = t;
byte <<= 1;
}
}
memcpy(resultx, nqx, sizeof(felem) * 5);
memcpy(resultz, nqz, sizeof(felem) * 5);
}
// -----------------------------------------------------------------------------
// Shamelessly copied from djb's code
// -----------------------------------------------------------------------------
static void
crecip(felem *out, const felem *z)
{
felem z2[5];
felem z9[5];
felem z11[5];
felem z2_5_0[5];
felem z2_10_0[5];
felem z2_20_0[5];
felem z2_50_0[5];
felem z2_100_0[5];
felem t0[5];
felem t1[5];
int i;
/* 2 */ fsquare(z2, z);
/* 4 */ fsquare(t1, z2);
/* 8 */ fsquare(t0, t1);
/* 9 */ fmul(z9, t0, z);
/* 11 */ fmul(z11, z9, z2);
/* 22 */ fsquare(t0, z11);
/* 2^5 - 2^0 = 31 */ fmul(z2_5_0, t0, z9);
/* 2^6 - 2^1 */ fsquare(t0, z2_5_0);
/* 2^7 - 2^2 */ fsquare(t1, t0);
/* 2^8 - 2^3 */ fsquare(t0, t1);
/* 2^9 - 2^4 */ fsquare(t1, t0);
/* 2^10 - 2^5 */ fsquare(t0, t1);
/* 2^10 - 2^0 */ fmul(z2_10_0, t0, z2_5_0);
/* 2^11 - 2^1 */ fsquare(t0, z2_10_0);
/* 2^12 - 2^2 */ fsquare(t1, t0);
/* 2^20 - 2^10 */ for (i = 2; i < 10; i += 2) {
fsquare(t0, t1);
fsquare(t1, t0);
}
/* 2^20 - 2^0 */ fmul(z2_20_0, t1, z2_10_0);
/* 2^21 - 2^1 */ fsquare(t0, z2_20_0);
/* 2^22 - 2^2 */ fsquare(t1, t0);
/* 2^40 - 2^20 */ for (i = 2; i < 20; i += 2) {
fsquare(t0, t1);
fsquare(t1, t0);
}
/* 2^40 - 2^0 */ fmul(t0, t1, z2_20_0);
/* 2^41 - 2^1 */ fsquare(t1, t0);
/* 2^42 - 2^2 */ fsquare(t0, t1);
/* 2^50 - 2^10 */ for (i = 2; i < 10; i += 2) {
fsquare(t1, t0);
fsquare(t0, t1);
}
/* 2^50 - 2^0 */ fmul(z2_50_0, t0, z2_10_0);
/* 2^51 - 2^1 */ fsquare(t0, z2_50_0);
/* 2^52 - 2^2 */ fsquare(t1, t0);
/* 2^100 - 2^50 */ for (i = 2; i < 50; i += 2) {
fsquare(t0, t1);
fsquare(t1, t0);
}
/* 2^100 - 2^0 */ fmul(z2_100_0, t1, z2_50_0);
/* 2^101 - 2^1 */ fsquare(t1, z2_100_0);
/* 2^102 - 2^2 */ fsquare(t0, t1);
/* 2^200 - 2^100 */ for (i = 2; i < 100; i += 2) {
fsquare(t1, t0);
fsquare(t0, t1);
}
/* 2^200 - 2^0 */ fmul(t1, t0, z2_100_0);
/* 2^201 - 2^1 */ fsquare(t0, t1);
/* 2^202 - 2^2 */ fsquare(t1, t0);
/* 2^250 - 2^50 */ for (i = 2; i < 50; i += 2) {
fsquare(t0, t1);
fsquare(t1, t0);
}
/* 2^250 - 2^0 */ fmul(t0, t1, z2_50_0);
/* 2^251 - 2^1 */ fsquare(t1, t0);
/* 2^252 - 2^2 */ fsquare(t0, t1);
/* 2^253 - 2^3 */ fsquare(t1, t0);
/* 2^254 - 2^4 */ fsquare(t0, t1);
/* 2^255 - 2^5 */ fsquare(t1, t0);
/* 2^255 - 21 */ fmul(out, t1, z11);
}
SECStatus
ec_Curve25519_mul(uint8_t *mypublic, const uint8_t *secret,
const uint8_t *basepoint)
{
felem bp[5], x[5], z[5], zmone[5];
uint8_t e[32];
int i;
for (i = 0; i < 32; ++i) {
e[i] = secret[i];
}
e[0] &= 248;
e[31] &= 127;
e[31] |= 64;
fexpand(bp, basepoint);
cmult(x, z, e, bp);
crecip(zmone, z);
fmul(z, x, zmone);
fcontract(mypublic, z);
return 0;
}

View file

@ -0,0 +1,68 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "ecl-priv.h"
/* Returns 2^e as an integer. This is meant to be used for small powers of
* two. */
int
ec_twoTo(int e)
{
int a = 1;
int i;
for (i = 0; i < e; i++) {
a *= 2;
}
return a;
}
/* Computes the windowed non-adjacent-form (NAF) of a scalar. Out should
* be an array of signed char's to output to, bitsize should be the number
* of bits of out, in is the original scalar, and w is the window size.
* NAF is discussed in the paper: D. Hankerson, J. Hernandez and A.
* Menezes, "Software implementation of elliptic curve cryptography over
* binary fields", Proc. CHES 2000. */
mp_err
ec_compute_wNAF(signed char *out, int bitsize, const mp_int *in, int w)
{
mp_int k;
mp_err res = MP_OKAY;
int i, twowm1, mask;
twowm1 = ec_twoTo(w - 1);
mask = 2 * twowm1 - 1;
MP_DIGITS(&k) = 0;
MP_CHECKOK(mp_init_copy(&k, in));
i = 0;
/* Compute wNAF form */
while (mp_cmp_z(&k) > 0) {
if (mp_isodd(&k)) {
out[i] = MP_DIGIT(&k, 0) & mask;
if (out[i] >= twowm1)
out[i] -= 2 * twowm1;
/* Subtract off out[i]. Note mp_sub_d only works with
* unsigned digits */
if (out[i] >= 0) {
MP_CHECKOK(mp_sub_d(&k, out[i], &k));
} else {
MP_CHECKOK(mp_add_d(&k, -(out[i]), &k));
}
} else {
out[i] = 0;
}
MP_CHECKOK(mp_div_2(&k, &k));
i++;
}
/* Zero out the remaining elements of the out array. */
for (; i < bitsize + 1; i++) {
out[i] = 0;
}
CLEANUP:
mp_clear(&k);
return res;
}

View file

@ -0,0 +1,123 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "ecl-exp.h"
#include <stdlib.h>
#ifndef __ecl_curve_h_
#define __ecl_curve_h_
/* copied from certt.h */
#define KU_DIGITAL_SIGNATURE (0x80) /* bit 0 */
#define KU_KEY_AGREEMENT (0x08) /* bit 4 */
static const ECCurveParams ecCurve_NIST_P256 = {
"NIST-P256", ECField_GFp, 256,
"FFFFFFFF00000001000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFF",
"FFFFFFFF00000001000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFC",
"5AC635D8AA3A93E7B3EBBD55769886BC651D06B0CC53B0F63BCE3C3E27D2604B",
"6B17D1F2E12C4247F8BCE6E563A440F277037D812DEB33A0F4A13945D898C296",
"4FE342E2FE1A7F9B8EE7EB4A7C0F9E162BCE33576B315ECECBB6406837BF51F5",
"FFFFFFFF00000000FFFFFFFFFFFFFFFFBCE6FAADA7179E84F3B9CAC2FC632551",
1, 128, 65, KU_DIGITAL_SIGNATURE | KU_KEY_AGREEMENT
};
static const ECCurveParams ecCurve_NIST_P384 = {
"NIST-P384", ECField_GFp, 384,
"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFFFF0000000000000000FFFFFFFF",
"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFFFF0000000000000000FFFFFFFC",
"B3312FA7E23EE7E4988E056BE3F82D19181D9C6EFE8141120314088F5013875AC656398D8A2ED19D2A85C8EDD3EC2AEF",
"AA87CA22BE8B05378EB1C71EF320AD746E1D3B628BA79B9859F741E082542A385502F25DBF55296C3A545E3872760AB7",
"3617DE4A96262C6F5D9E98BF9292DC29F8F41DBD289A147CE9DA3113B5F0B8C00A60B1CE1D7E819D7A431D7C90EA0E5F",
"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFC7634D81F4372DDF581A0DB248B0A77AECEC196ACCC52973",
1, 192, 97, KU_DIGITAL_SIGNATURE | KU_KEY_AGREEMENT
};
static const ECCurveParams ecCurve_NIST_P521 = {
"NIST-P521", ECField_GFp, 521,
"01FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF",
"01FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFC",
"0051953EB9618E1C9A1F929A21A0B68540EEA2DA725B99B315F3B8B489918EF109E156193951EC7E937B1652C0BD3BB1BF073573DF883D2C34F1EF451FD46B503F00",
"00C6858E06B70404E9CD9E3ECB662395B4429C648139053FB521F828AF606B4D3DBAA14B5E77EFE75928FE1DC127A2FFA8DE3348B3C1856A429BF97E7E31C2E5BD66",
"011839296A789A3BC0045C8A5FB42C7D1BD998F54449579B446817AFBD17273E662C97EE72995EF42640C550B9013FAD0761353C7086A272C24088BE94769FD16650",
"01FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFA51868783BF2F966B7FCC0148F709A5D03BB5C9B8899C47AEBB6FB71E91386409",
1, 256, 133, KU_DIGITAL_SIGNATURE | KU_KEY_AGREEMENT
};
static const ECCurveParams ecCurve25519 = {
"Curve25519", ECField_GFp, 255,
"7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffed",
"076D06",
"00",
"0900000000000000000000000000000000000000000000000000000000000000",
"20AE19A1B8A086B4E01EDD2C7748D14C923D4D7E6D7C61B229E9C5A27ECED3D9",
"1000000000000000000000000000000014def9dea2f79cd65812631a5cf5d3ed",
8, 128, 32, KU_KEY_AGREEMENT
};
/* mapping between ECCurveName enum and pointers to ECCurveParams */
static const ECCurveParams *ecCurve_map[] = {
NULL, /* ECCurve_noName */
NULL, /* ECCurve_NIST_P192 */
NULL, /* ECCurve_NIST_P224 */
&ecCurve_NIST_P256, /* ECCurve_NIST_P256 */
&ecCurve_NIST_P384, /* ECCurve_NIST_P384 */
&ecCurve_NIST_P521, /* ECCurve_NIST_P521 */
NULL, /* ECCurve_NIST_K163 */
NULL, /* ECCurve_NIST_B163 */
NULL, /* ECCurve_NIST_K233 */
NULL, /* ECCurve_NIST_B233 */
NULL, /* ECCurve_NIST_K283 */
NULL, /* ECCurve_NIST_B283 */
NULL, /* ECCurve_NIST_K409 */
NULL, /* ECCurve_NIST_B409 */
NULL, /* ECCurve_NIST_K571 */
NULL, /* ECCurve_NIST_B571 */
NULL, /* ECCurve_X9_62_PRIME_192V2 */
NULL, /* ECCurve_X9_62_PRIME_192V3 */
NULL, /* ECCurve_X9_62_PRIME_239V1 */
NULL, /* ECCurve_X9_62_PRIME_239V2 */
NULL, /* ECCurve_X9_62_PRIME_239V3 */
NULL, /* ECCurve_X9_62_CHAR2_PNB163V1 */
NULL, /* ECCurve_X9_62_CHAR2_PNB163V2 */
NULL, /* ECCurve_X9_62_CHAR2_PNB163V3 */
NULL, /* ECCurve_X9_62_CHAR2_PNB176V1 */
NULL, /* ECCurve_X9_62_CHAR2_TNB191V1 */
NULL, /* ECCurve_X9_62_CHAR2_TNB191V2 */
NULL, /* ECCurve_X9_62_CHAR2_TNB191V3 */
NULL, /* ECCurve_X9_62_CHAR2_PNB208W1 */
NULL, /* ECCurve_X9_62_CHAR2_TNB239V1 */
NULL, /* ECCurve_X9_62_CHAR2_TNB239V2 */
NULL, /* ECCurve_X9_62_CHAR2_TNB239V3 */
NULL, /* ECCurve_X9_62_CHAR2_PNB272W1 */
NULL, /* ECCurve_X9_62_CHAR2_PNB304W1 */
NULL, /* ECCurve_X9_62_CHAR2_TNB359V1 */
NULL, /* ECCurve_X9_62_CHAR2_PNB368W1 */
NULL, /* ECCurve_X9_62_CHAR2_TNB431R1 */
NULL, /* ECCurve_SECG_PRIME_112R1 */
NULL, /* ECCurve_SECG_PRIME_112R2 */
NULL, /* ECCurve_SECG_PRIME_128R1 */
NULL, /* ECCurve_SECG_PRIME_128R2 */
NULL, /* ECCurve_SECG_PRIME_160K1 */
NULL, /* ECCurve_SECG_PRIME_160R1 */
NULL, /* ECCurve_SECG_PRIME_160R2 */
NULL, /* ECCurve_SECG_PRIME_192K1 */
NULL, /* ECCurve_SECG_PRIME_224K1 */
NULL, /* ECCurve_SECG_PRIME_256K1 */
NULL, /* ECCurve_SECG_CHAR2_113R1 */
NULL, /* ECCurve_SECG_CHAR2_113R2 */
NULL, /* ECCurve_SECG_CHAR2_131R1 */
NULL, /* ECCurve_SECG_CHAR2_131R2 */
NULL, /* ECCurve_SECG_CHAR2_163R1 */
NULL, /* ECCurve_SECG_CHAR2_193R1 */
NULL, /* ECCurve_SECG_CHAR2_193R2 */
NULL, /* ECCurve_SECG_CHAR2_239K1 */
NULL, /* ECCurve_WTLS_1 */
NULL, /* ECCurve_WTLS_8 */
NULL, /* ECCurve_WTLS_9 */
&ecCurve25519, /* ECCurve25519 */
NULL /* ECCurve_pastLastCurve */
};
#endif

View file

@ -0,0 +1,167 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef __ecl_exp_h_
#define __ecl_exp_h_
/* Curve field type */
typedef enum {
ECField_GFp,
ECField_GF2m
} ECField;
/* Hexadecimal encoding of curve parameters */
struct ECCurveParamsStr {
char *text;
ECField field;
unsigned int size;
char *irr;
char *curvea;
char *curveb;
char *genx;
char *geny;
char *order;
int cofactor;
int security;
int pointSize;
unsigned int usage;
};
typedef struct ECCurveParamsStr ECCurveParams;
/* Named curve parameters */
typedef enum {
ECCurve_noName = 0,
/* NIST prime curves */
ECCurve_NIST_P192, /* not supported */
ECCurve_NIST_P224, /* not supported */
ECCurve_NIST_P256,
ECCurve_NIST_P384,
ECCurve_NIST_P521,
/* NIST binary curves */
ECCurve_NIST_K163, /* not supported */
ECCurve_NIST_B163, /* not supported */
ECCurve_NIST_K233, /* not supported */
ECCurve_NIST_B233, /* not supported */
ECCurve_NIST_K283, /* not supported */
ECCurve_NIST_B283, /* not supported */
ECCurve_NIST_K409, /* not supported */
ECCurve_NIST_B409, /* not supported */
ECCurve_NIST_K571, /* not supported */
ECCurve_NIST_B571, /* not supported */
/* ANSI X9.62 prime curves */
/* ECCurve_X9_62_PRIME_192V1 == ECCurve_NIST_P192 */
ECCurve_X9_62_PRIME_192V2, /* not supported */
ECCurve_X9_62_PRIME_192V3, /* not supported */
ECCurve_X9_62_PRIME_239V1, /* not supported */
ECCurve_X9_62_PRIME_239V2, /* not supported */
ECCurve_X9_62_PRIME_239V3, /* not supported */
/* ECCurve_X9_62_PRIME_256V1 == ECCurve_NIST_P256 */
/* ANSI X9.62 binary curves */
ECCurve_X9_62_CHAR2_PNB163V1, /* not supported */
ECCurve_X9_62_CHAR2_PNB163V2, /* not supported */
ECCurve_X9_62_CHAR2_PNB163V3, /* not supported */
ECCurve_X9_62_CHAR2_PNB176V1, /* not supported */
ECCurve_X9_62_CHAR2_TNB191V1, /* not supported */
ECCurve_X9_62_CHAR2_TNB191V2, /* not supported */
ECCurve_X9_62_CHAR2_TNB191V3, /* not supported */
ECCurve_X9_62_CHAR2_PNB208W1, /* not supported */
ECCurve_X9_62_CHAR2_TNB239V1, /* not supported */
ECCurve_X9_62_CHAR2_TNB239V2, /* not supported */
ECCurve_X9_62_CHAR2_TNB239V3, /* not supported */
ECCurve_X9_62_CHAR2_PNB272W1, /* not supported */
ECCurve_X9_62_CHAR2_PNB304W1, /* not supported */
ECCurve_X9_62_CHAR2_TNB359V1, /* not supported */
ECCurve_X9_62_CHAR2_PNB368W1, /* not supported */
ECCurve_X9_62_CHAR2_TNB431R1, /* not supported */
/* SEC2 prime curves */
ECCurve_SECG_PRIME_112R1, /* not supported */
ECCurve_SECG_PRIME_112R2, /* not supported */
ECCurve_SECG_PRIME_128R1, /* not supported */
ECCurve_SECG_PRIME_128R2, /* not supported */
ECCurve_SECG_PRIME_160K1, /* not supported */
ECCurve_SECG_PRIME_160R1, /* not supported */
ECCurve_SECG_PRIME_160R2, /* not supported */
ECCurve_SECG_PRIME_192K1, /* not supported */
/* ECCurve_SECG_PRIME_192R1 == ECCurve_NIST_P192 */
ECCurve_SECG_PRIME_224K1, /* not supported */
/* ECCurve_SECG_PRIME_224R1 == ECCurve_NIST_P224 */
ECCurve_SECG_PRIME_256K1, /* not supported */
/* ECCurve_SECG_PRIME_256R1 == ECCurve_NIST_P256 */
/* ECCurve_SECG_PRIME_384R1 == ECCurve_NIST_P384 */
/* ECCurve_SECG_PRIME_521R1 == ECCurve_NIST_P521 */
/* SEC2 binary curves */
ECCurve_SECG_CHAR2_113R1, /* not supported */
ECCurve_SECG_CHAR2_113R2, /* not supported */
ECCurve_SECG_CHAR2_131R1, /* not supported */
ECCurve_SECG_CHAR2_131R2, /* not supported */
/* ECCurve_SECG_CHAR2_163K1 == ECCurve_NIST_K163 */
ECCurve_SECG_CHAR2_163R1, /* not supported */
/* ECCurve_SECG_CHAR2_163R2 == ECCurve_NIST_B163 */
ECCurve_SECG_CHAR2_193R1, /* not supported */
ECCurve_SECG_CHAR2_193R2, /* not supported */
/* ECCurve_SECG_CHAR2_233K1 == ECCurve_NIST_K233 */
/* ECCurve_SECG_CHAR2_233R1 == ECCurve_NIST_B233 */
ECCurve_SECG_CHAR2_239K1, /* not supported */
/* ECCurve_SECG_CHAR2_283K1 == ECCurve_NIST_K283 */
/* ECCurve_SECG_CHAR2_283R1 == ECCurve_NIST_B283 */
/* ECCurve_SECG_CHAR2_409K1 == ECCurve_NIST_K409 */
/* ECCurve_SECG_CHAR2_409R1 == ECCurve_NIST_B409 */
/* ECCurve_SECG_CHAR2_571K1 == ECCurve_NIST_K571 */
/* ECCurve_SECG_CHAR2_571R1 == ECCurve_NIST_B571 */
/* WTLS curves */
ECCurve_WTLS_1, /* not supported */
/* there is no WTLS 2 curve */
/* ECCurve_WTLS_3 == ECCurve_NIST_K163 */
/* ECCurve_WTLS_4 == ECCurve_SECG_CHAR2_113R1 */
/* ECCurve_WTLS_5 == ECCurve_X9_62_CHAR2_PNB163V1 */
/* ECCurve_WTLS_6 == ECCurve_SECG_PRIME_112R1 */
/* ECCurve_WTLS_7 == ECCurve_SECG_PRIME_160R1 */
ECCurve_WTLS_8, /* not supported */
ECCurve_WTLS_9, /* not supported */
/* ECCurve_WTLS_10 == ECCurve_NIST_K233 */
/* ECCurve_WTLS_11 == ECCurve_NIST_B233 */
/* ECCurve_WTLS_12 == ECCurve_NIST_P224 */
ECCurve25519,
ECCurve_pastLastCurve
} ECCurveName;
/* Aliased named curves */
#define ECCurve_X9_62_PRIME_192V1 ECCurve_NIST_P192 /* not supported */
#define ECCurve_X9_62_PRIME_256V1 ECCurve_NIST_P256
#define ECCurve_SECG_PRIME_192R1 ECCurve_NIST_P192 /* not supported */
#define ECCurve_SECG_PRIME_224R1 ECCurve_NIST_P224 /* not supported */
#define ECCurve_SECG_PRIME_256R1 ECCurve_NIST_P256
#define ECCurve_SECG_PRIME_384R1 ECCurve_NIST_P384
#define ECCurve_SECG_PRIME_521R1 ECCurve_NIST_P521
#define ECCurve_SECG_CHAR2_163K1 ECCurve_NIST_K163 /* not supported */
#define ECCurve_SECG_CHAR2_163R2 ECCurve_NIST_B163 /* not supported */
#define ECCurve_SECG_CHAR2_233K1 ECCurve_NIST_K233 /* not supported */
#define ECCurve_SECG_CHAR2_233R1 ECCurve_NIST_B233 /* not supported */
#define ECCurve_SECG_CHAR2_283K1 ECCurve_NIST_K283 /* not supported */
#define ECCurve_SECG_CHAR2_283R1 ECCurve_NIST_B283 /* not supported */
#define ECCurve_SECG_CHAR2_409K1 ECCurve_NIST_K409 /* not supported */
#define ECCurve_SECG_CHAR2_409R1 ECCurve_NIST_B409 /* not supported */
#define ECCurve_SECG_CHAR2_571K1 ECCurve_NIST_K571 /* not supported */
#define ECCurve_SECG_CHAR2_571R1 ECCurve_NIST_B571 /* not supported */
#define ECCurve_WTLS_3 ECCurve_NIST_K163 /* not supported */
#define ECCurve_WTLS_4 ECCurve_SECG_CHAR2_113R1 /* not supported */
#define ECCurve_WTLS_5 ECCurve_X9_62_CHAR2_PNB163V1 /* not supported */
#define ECCurve_WTLS_6 ECCurve_SECG_PRIME_112R1 /* not supported */
#define ECCurve_WTLS_7 ECCurve_SECG_PRIME_160R1 /* not supported */
#define ECCurve_WTLS_10 ECCurve_NIST_K233 /* not supported */
#define ECCurve_WTLS_11 ECCurve_NIST_B233 /* not supported */
#define ECCurve_WTLS_12 ECCurve_NIST_P224 /* not supported */
#endif /* __ecl_exp_h_ */

View file

@ -0,0 +1,257 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef __ecl_priv_h_
#define __ecl_priv_h_
#include "ecl.h"
#include "mpi.h"
#include "mplogic.h"
#include "../blapii.h"
/* MAX_FIELD_SIZE_DIGITS is the maximum size of field element supported */
/* the following needs to go away... */
#if defined(MP_USE_LONG_LONG_DIGIT) || defined(MP_USE_LONG_DIGIT)
#define ECL_SIXTY_FOUR_BIT
#else
#define ECL_THIRTY_TWO_BIT
#endif
#define ECL_CURVE_DIGITS(curve_size_in_bits) \
(((curve_size_in_bits) + (sizeof(mp_digit) * 8 - 1)) / (sizeof(mp_digit) * 8))
#define ECL_BITS (sizeof(mp_digit) * 8)
#define ECL_MAX_FIELD_SIZE_DIGITS (80 / sizeof(mp_digit))
/* Gets the i'th bit in the binary representation of a. If i >= length(a),
* then return 0. (The above behaviour differs from mpl_get_bit, which
* causes an error if i >= length(a).) */
#define MP_GET_BIT(a, i) \
((i) >= mpl_significant_bits((a))) ? 0 : mpl_get_bit((a), (i))
#if !defined(MP_NO_MP_WORD) && !defined(MP_NO_ADD_WORD)
#define MP_ADD_CARRY(a1, a2, s, carry) \
{ \
mp_word w; \
w = ((mp_word)carry) + (a1) + (a2); \
s = ACCUM(w); \
carry = CARRYOUT(w); \
}
#define MP_SUB_BORROW(a1, a2, s, borrow) \
{ \
mp_word w; \
w = ((mp_word)(a1)) - (a2)-borrow; \
s = ACCUM(w); \
borrow = (w >> MP_DIGIT_BIT) & 1; \
}
#else
/* NOTE,
* carry and borrow are both read and written.
* a1 or a2 and s could be the same variable.
* don't trash those outputs until their respective inputs have
* been read. */
#define MP_ADD_CARRY(a1, a2, s, carry) \
{ \
mp_digit tmp, sum; \
tmp = (a1); \
sum = tmp + (a2); \
tmp = (sum < tmp); /* detect overflow */ \
s = sum += carry; \
carry = tmp + (sum < carry); \
}
#define MP_SUB_BORROW(a1, a2, s, borrow) \
{ \
mp_digit tmp; \
tmp = (a1); \
s = tmp - (a2); \
tmp = (s > tmp); /* detect borrow */ \
if (borrow && !s--) \
tmp++; \
borrow = tmp; \
}
#endif
struct GFMethodStr;
typedef struct GFMethodStr GFMethod;
struct GFMethodStr {
/* Indicates whether the structure was constructed from dynamic memory
* or statically created. */
int constructed;
/* Irreducible that defines the field. For prime fields, this is the
* prime p. For binary polynomial fields, this is the bitstring
* representation of the irreducible polynomial. */
mp_int irr;
/* For prime fields, the value irr_arr[0] is the number of bits in the
* field. For binary polynomial fields, the irreducible polynomial
* f(t) is represented as an array of unsigned int[], where f(t) is
* of the form: f(t) = t^p[0] + t^p[1] + ... + t^p[4] where m = p[0]
* > p[1] > ... > p[4] = 0. */
unsigned int irr_arr[5];
/* Field arithmetic methods. All methods (except field_enc and
* field_dec) are assumed to take field-encoded parameters and return
* field-encoded values. All methods (except field_enc and field_dec)
* are required to be implemented. */
mp_err (*field_add)(const mp_int *a, const mp_int *b, mp_int *r,
const GFMethod *meth);
mp_err (*field_neg)(const mp_int *a, mp_int *r, const GFMethod *meth);
mp_err (*field_sub)(const mp_int *a, const mp_int *b, mp_int *r,
const GFMethod *meth);
mp_err (*field_mod)(const mp_int *a, mp_int *r, const GFMethod *meth);
mp_err (*field_mul)(const mp_int *a, const mp_int *b, mp_int *r,
const GFMethod *meth);
mp_err (*field_sqr)(const mp_int *a, mp_int *r, const GFMethod *meth);
mp_err (*field_div)(const mp_int *a, const mp_int *b, mp_int *r,
const GFMethod *meth);
mp_err (*field_enc)(const mp_int *a, mp_int *r, const GFMethod *meth);
mp_err (*field_dec)(const mp_int *a, mp_int *r, const GFMethod *meth);
/* Extra storage for implementation-specific data. Any memory
* allocated to these extra fields will be cleared by extra_free. */
void *extra1;
void *extra2;
void (*extra_free)(GFMethod *meth);
};
/* Construct generic GFMethods. */
GFMethod *GFMethod_consGFp(const mp_int *irr);
GFMethod *GFMethod_consGFp_mont(const mp_int *irr);
/* Free the memory allocated (if any) to a GFMethod object. */
void GFMethod_free(GFMethod *meth);
struct ECGroupStr {
/* Indicates whether the structure was constructed from dynamic memory
* or statically created. */
int constructed;
/* Field definition and arithmetic. */
GFMethod *meth;
/* Textual representation of curve name, if any. */
char *text;
/* Curve parameters, field-encoded. */
mp_int curvea, curveb;
/* x and y coordinates of the base point, field-encoded. */
mp_int genx, geny;
/* Order and cofactor of the base point. */
mp_int order;
int cofactor;
/* Point arithmetic methods. All methods are assumed to take
* field-encoded parameters and return field-encoded values. All
* methods (except base_point_mul and points_mul) are required to be
* implemented. */
mp_err (*point_add)(const mp_int *px, const mp_int *py,
const mp_int *qx, const mp_int *qy, mp_int *rx,
mp_int *ry, const ECGroup *group);
mp_err (*point_sub)(const mp_int *px, const mp_int *py,
const mp_int *qx, const mp_int *qy, mp_int *rx,
mp_int *ry, const ECGroup *group);
mp_err (*point_dbl)(const mp_int *px, const mp_int *py, mp_int *rx,
mp_int *ry, const ECGroup *group);
mp_err (*point_mul)(const mp_int *n, const mp_int *px,
const mp_int *py, mp_int *rx, mp_int *ry,
const ECGroup *group);
mp_err (*base_point_mul)(const mp_int *n, mp_int *rx, mp_int *ry,
const ECGroup *group);
mp_err (*points_mul)(const mp_int *k1, const mp_int *k2,
const mp_int *px, const mp_int *py, mp_int *rx,
mp_int *ry, const ECGroup *group);
mp_err (*validate_point)(const mp_int *px, const mp_int *py, const ECGroup *group);
/* Extra storage for implementation-specific data. Any memory
* allocated to these extra fields will be cleared by extra_free. */
void *extra1;
void *extra2;
void (*extra_free)(ECGroup *group);
};
/* Wrapper functions for generic prime field arithmetic. */
mp_err ec_GFp_add(const mp_int *a, const mp_int *b, mp_int *r,
const GFMethod *meth);
mp_err ec_GFp_neg(const mp_int *a, mp_int *r, const GFMethod *meth);
mp_err ec_GFp_sub(const mp_int *a, const mp_int *b, mp_int *r,
const GFMethod *meth);
/* fixed length in-line adds. Count is in words */
mp_err ec_GFp_add_3(const mp_int *a, const mp_int *b, mp_int *r,
const GFMethod *meth);
mp_err ec_GFp_add_4(const mp_int *a, const mp_int *b, mp_int *r,
const GFMethod *meth);
mp_err ec_GFp_add_5(const mp_int *a, const mp_int *b, mp_int *r,
const GFMethod *meth);
mp_err ec_GFp_add_6(const mp_int *a, const mp_int *b, mp_int *r,
const GFMethod *meth);
mp_err ec_GFp_sub_3(const mp_int *a, const mp_int *b, mp_int *r,
const GFMethod *meth);
mp_err ec_GFp_sub_4(const mp_int *a, const mp_int *b, mp_int *r,
const GFMethod *meth);
mp_err ec_GFp_sub_5(const mp_int *a, const mp_int *b, mp_int *r,
const GFMethod *meth);
mp_err ec_GFp_sub_6(const mp_int *a, const mp_int *b, mp_int *r,
const GFMethod *meth);
mp_err ec_GFp_mod(const mp_int *a, mp_int *r, const GFMethod *meth);
mp_err ec_GFp_mul(const mp_int *a, const mp_int *b, mp_int *r,
const GFMethod *meth);
mp_err ec_GFp_sqr(const mp_int *a, mp_int *r, const GFMethod *meth);
mp_err ec_GFp_div(const mp_int *a, const mp_int *b, mp_int *r,
const GFMethod *meth);
/* Wrapper functions for generic binary polynomial field arithmetic. */
mp_err ec_GF2m_add(const mp_int *a, const mp_int *b, mp_int *r,
const GFMethod *meth);
mp_err ec_GF2m_neg(const mp_int *a, mp_int *r, const GFMethod *meth);
mp_err ec_GF2m_mod(const mp_int *a, mp_int *r, const GFMethod *meth);
mp_err ec_GF2m_mul(const mp_int *a, const mp_int *b, mp_int *r,
const GFMethod *meth);
mp_err ec_GF2m_sqr(const mp_int *a, mp_int *r, const GFMethod *meth);
mp_err ec_GF2m_div(const mp_int *a, const mp_int *b, mp_int *r,
const GFMethod *meth);
/* Montgomery prime field arithmetic. */
mp_err ec_GFp_mul_mont(const mp_int *a, const mp_int *b, mp_int *r,
const GFMethod *meth);
mp_err ec_GFp_sqr_mont(const mp_int *a, mp_int *r, const GFMethod *meth);
mp_err ec_GFp_div_mont(const mp_int *a, const mp_int *b, mp_int *r,
const GFMethod *meth);
mp_err ec_GFp_enc_mont(const mp_int *a, mp_int *r, const GFMethod *meth);
mp_err ec_GFp_dec_mont(const mp_int *a, mp_int *r, const GFMethod *meth);
void ec_GFp_extra_free_mont(GFMethod *meth);
/* point multiplication */
mp_err ec_pts_mul_basic(const mp_int *k1, const mp_int *k2,
const mp_int *px, const mp_int *py, mp_int *rx,
mp_int *ry, const ECGroup *group);
mp_err ec_pts_mul_simul_w2(const mp_int *k1, const mp_int *k2,
const mp_int *px, const mp_int *py, mp_int *rx,
mp_int *ry, const ECGroup *group);
/* Computes the windowed non-adjacent-form (NAF) of a scalar. Out should
* be an array of signed char's to output to, bitsize should be the number
* of bits of out, in is the original scalar, and w is the window size.
* NAF is discussed in the paper: D. Hankerson, J. Hernandez and A.
* Menezes, "Software implementation of elliptic curve cryptography over
* binary fields", Proc. CHES 2000. */
mp_err ec_compute_wNAF(signed char *out, int bitsize, const mp_int *in,
int w);
/* Optimized field arithmetic */
mp_err ec_group_set_gfp192(ECGroup *group, ECCurveName);
mp_err ec_group_set_gfp224(ECGroup *group, ECCurveName);
mp_err ec_group_set_gfp256(ECGroup *group, ECCurveName);
mp_err ec_group_set_gfp384(ECGroup *group, ECCurveName);
mp_err ec_group_set_gfp521(ECGroup *group, ECCurveName);
mp_err ec_group_set_gf2m163(ECGroup *group, ECCurveName name);
mp_err ec_group_set_gf2m193(ECGroup *group, ECCurveName name);
mp_err ec_group_set_gf2m233(ECGroup *group, ECCurveName name);
/* Optimized point multiplication */
mp_err ec_group_set_gfp256_32(ECGroup *group, ECCurveName name);
/* Optimized floating-point arithmetic */
#ifdef ECL_USE_FP
mp_err ec_group_set_secp160r1_fp(ECGroup *group);
mp_err ec_group_set_nistp192_fp(ECGroup *group);
mp_err ec_group_set_nistp224_fp(ECGroup *group);
#endif
SECStatus ec_Curve25519_mul(PRUint8 *q, const PRUint8 *s, const PRUint8 *p);
#endif /* __ecl_priv_h_ */

View file

@ -0,0 +1,301 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "mpi.h"
#include "mplogic.h"
#include "ecl.h"
#include "ecl-priv.h"
#include "ecp.h"
#include <stdlib.h>
#include <string.h>
/* Allocate memory for a new ECGroup object. */
ECGroup *
ECGroup_new()
{
mp_err res = MP_OKAY;
ECGroup *group;
group = (ECGroup *)malloc(sizeof(ECGroup));
if (group == NULL)
return NULL;
group->constructed = MP_YES;
group->meth = NULL;
group->text = NULL;
MP_DIGITS(&group->curvea) = 0;
MP_DIGITS(&group->curveb) = 0;
MP_DIGITS(&group->genx) = 0;
MP_DIGITS(&group->geny) = 0;
MP_DIGITS(&group->order) = 0;
group->base_point_mul = NULL;
group->points_mul = NULL;
group->validate_point = NULL;
group->extra1 = NULL;
group->extra2 = NULL;
group->extra_free = NULL;
MP_CHECKOK(mp_init(&group->curvea));
MP_CHECKOK(mp_init(&group->curveb));
MP_CHECKOK(mp_init(&group->genx));
MP_CHECKOK(mp_init(&group->geny));
MP_CHECKOK(mp_init(&group->order));
CLEANUP:
if (res != MP_OKAY) {
ECGroup_free(group);
return NULL;
}
return group;
}
/* Construct a generic ECGroup for elliptic curves over prime fields. */
ECGroup *
ECGroup_consGFp(const mp_int *irr, const mp_int *curvea,
const mp_int *curveb, const mp_int *genx,
const mp_int *geny, const mp_int *order, int cofactor)
{
mp_err res = MP_OKAY;
ECGroup *group = NULL;
group = ECGroup_new();
if (group == NULL)
return NULL;
group->meth = GFMethod_consGFp(irr);
if (group->meth == NULL) {
res = MP_MEM;
goto CLEANUP;
}
MP_CHECKOK(mp_copy(curvea, &group->curvea));
MP_CHECKOK(mp_copy(curveb, &group->curveb));
MP_CHECKOK(mp_copy(genx, &group->genx));
MP_CHECKOK(mp_copy(geny, &group->geny));
MP_CHECKOK(mp_copy(order, &group->order));
group->cofactor = cofactor;
group->point_add = &ec_GFp_pt_add_aff;
group->point_sub = &ec_GFp_pt_sub_aff;
group->point_dbl = &ec_GFp_pt_dbl_aff;
group->point_mul = &ec_GFp_pt_mul_jm_wNAF;
group->base_point_mul = NULL;
group->points_mul = &ec_GFp_pts_mul_jac;
group->validate_point = &ec_GFp_validate_point;
CLEANUP:
if (res != MP_OKAY) {
ECGroup_free(group);
return NULL;
}
return group;
}
/* Construct a generic ECGroup for elliptic curves over prime fields with
* field arithmetic implemented in Montgomery coordinates. */
ECGroup *
ECGroup_consGFp_mont(const mp_int *irr, const mp_int *curvea,
const mp_int *curveb, const mp_int *genx,
const mp_int *geny, const mp_int *order, int cofactor)
{
mp_err res = MP_OKAY;
ECGroup *group = NULL;
group = ECGroup_new();
if (group == NULL)
return NULL;
group->meth = GFMethod_consGFp_mont(irr);
if (group->meth == NULL) {
res = MP_MEM;
goto CLEANUP;
}
MP_CHECKOK(group->meth->field_enc(curvea, &group->curvea, group->meth));
MP_CHECKOK(group->meth->field_enc(curveb, &group->curveb, group->meth));
MP_CHECKOK(group->meth->field_enc(genx, &group->genx, group->meth));
MP_CHECKOK(group->meth->field_enc(geny, &group->geny, group->meth));
MP_CHECKOK(mp_copy(order, &group->order));
group->cofactor = cofactor;
group->point_add = &ec_GFp_pt_add_aff;
group->point_sub = &ec_GFp_pt_sub_aff;
group->point_dbl = &ec_GFp_pt_dbl_aff;
group->point_mul = &ec_GFp_pt_mul_jm_wNAF;
group->base_point_mul = NULL;
group->points_mul = &ec_GFp_pts_mul_jac;
group->validate_point = &ec_GFp_validate_point;
CLEANUP:
if (res != MP_OKAY) {
ECGroup_free(group);
return NULL;
}
return group;
}
/* Construct ECGroup from hex parameters and name, if any. Called by
* ECGroup_fromHex and ECGroup_fromName. */
ECGroup *
ecgroup_fromNameAndHex(const ECCurveName name,
const ECCurveParams *params)
{
mp_int irr, curvea, curveb, genx, geny, order;
int bits;
ECGroup *group = NULL;
mp_err res = MP_OKAY;
/* initialize values */
MP_DIGITS(&irr) = 0;
MP_DIGITS(&curvea) = 0;
MP_DIGITS(&curveb) = 0;
MP_DIGITS(&genx) = 0;
MP_DIGITS(&geny) = 0;
MP_DIGITS(&order) = 0;
MP_CHECKOK(mp_init(&irr));
MP_CHECKOK(mp_init(&curvea));
MP_CHECKOK(mp_init(&curveb));
MP_CHECKOK(mp_init(&genx));
MP_CHECKOK(mp_init(&geny));
MP_CHECKOK(mp_init(&order));
MP_CHECKOK(mp_read_radix(&irr, params->irr, 16));
MP_CHECKOK(mp_read_radix(&curvea, params->curvea, 16));
MP_CHECKOK(mp_read_radix(&curveb, params->curveb, 16));
MP_CHECKOK(mp_read_radix(&genx, params->genx, 16));
MP_CHECKOK(mp_read_radix(&geny, params->geny, 16));
MP_CHECKOK(mp_read_radix(&order, params->order, 16));
/* determine number of bits */
bits = mpl_significant_bits(&irr) - 1;
if (bits < MP_OKAY) {
res = bits;
goto CLEANUP;
}
/* determine which optimizations (if any) to use */
if (params->field == ECField_GFp) {
switch (name) {
case ECCurve_SECG_PRIME_256R1:
group =
ECGroup_consGFp(&irr, &curvea, &curveb, &genx, &geny,
&order, params->cofactor);
if (group == NULL) {
res = MP_UNDEF;
goto CLEANUP;
}
MP_CHECKOK(ec_group_set_gfp256(group, name));
MP_CHECKOK(ec_group_set_gfp256_32(group, name));
break;
case ECCurve_SECG_PRIME_521R1:
group =
ECGroup_consGFp(&irr, &curvea, &curveb, &genx, &geny,
&order, params->cofactor);
if (group == NULL) {
res = MP_UNDEF;
goto CLEANUP;
}
MP_CHECKOK(ec_group_set_gfp521(group, name));
break;
default:
/* use generic arithmetic */
group =
ECGroup_consGFp_mont(&irr, &curvea, &curveb, &genx, &geny,
&order, params->cofactor);
if (group == NULL) {
res = MP_UNDEF;
goto CLEANUP;
}
}
} else {
res = MP_UNDEF;
goto CLEANUP;
}
/* set name, if any */
if ((group != NULL) && (params->text != NULL)) {
group->text = strdup(params->text);
if (group->text == NULL) {
res = MP_MEM;
}
}
CLEANUP:
mp_clear(&irr);
mp_clear(&curvea);
mp_clear(&curveb);
mp_clear(&genx);
mp_clear(&geny);
mp_clear(&order);
if (res != MP_OKAY) {
ECGroup_free(group);
return NULL;
}
return group;
}
/* Construct ECGroup from hexadecimal representations of parameters. */
ECGroup *
ECGroup_fromHex(const ECCurveParams *params)
{
return ecgroup_fromNameAndHex(ECCurve_noName, params);
}
/* Construct ECGroup from named parameters. */
ECGroup *
ECGroup_fromName(const ECCurveName name)
{
ECGroup *group = NULL;
ECCurveParams *params = NULL;
mp_err res = MP_OKAY;
params = EC_GetNamedCurveParams(name);
if (params == NULL) {
res = MP_UNDEF;
goto CLEANUP;
}
/* construct actual group */
group = ecgroup_fromNameAndHex(name, params);
if (group == NULL) {
res = MP_UNDEF;
goto CLEANUP;
}
CLEANUP:
EC_FreeCurveParams(params);
if (res != MP_OKAY) {
ECGroup_free(group);
return NULL;
}
return group;
}
/* Validates an EC public key as described in Section 5.2.2 of X9.62. */
mp_err
ECPoint_validate(const ECGroup *group, const mp_int *px, const mp_int *py)
{
/* 1: Verify that publicValue is not the point at infinity */
/* 2: Verify that the coordinates of publicValue are elements
* of the field.
*/
/* 3: Verify that publicValue is on the curve. */
/* 4: Verify that the order of the curve times the publicValue
* is the point at infinity.
*/
return group->validate_point(px, py, group);
}
/* Free the memory allocated (if any) to an ECGroup object. */
void
ECGroup_free(ECGroup *group)
{
if (group == NULL)
return;
GFMethod_free(group->meth);
if (group->constructed == MP_NO)
return;
mp_clear(&group->curvea);
mp_clear(&group->curveb);
mp_clear(&group->genx);
mp_clear(&group->geny);
mp_clear(&group->order);
if (group->text != NULL)
free(group->text);
if (group->extra_free != NULL)
group->extra_free(group);
free(group);
}

View file

@ -0,0 +1,60 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
/* Although this is not an exported header file, code which uses elliptic
* curve point operations will need to include it. */
#ifndef __ecl_h_
#define __ecl_h_
#include "blapi.h"
#include "ecl-exp.h"
#include "mpi.h"
struct ECGroupStr;
typedef struct ECGroupStr ECGroup;
/* Construct ECGroup from hexadecimal representations of parameters. */
ECGroup *ECGroup_fromHex(const ECCurveParams *params);
/* Construct ECGroup from named parameters. */
ECGroup *ECGroup_fromName(const ECCurveName name);
/* Free an allocated ECGroup. */
void ECGroup_free(ECGroup *group);
/* Construct ECCurveParams from an ECCurveName */
ECCurveParams *EC_GetNamedCurveParams(const ECCurveName name);
/* Duplicates an ECCurveParams */
ECCurveParams *ECCurveParams_dup(const ECCurveParams *params);
/* Free an allocated ECCurveParams */
void EC_FreeCurveParams(ECCurveParams *params);
/* Elliptic curve scalar-point multiplication. Computes Q(x, y) = k * P(x,
* y). If x, y = NULL, then P is assumed to be the generator (base point)
* of the group of points on the elliptic curve. Input and output values
* are assumed to be NOT field-encoded. */
mp_err ECPoint_mul(const ECGroup *group, const mp_int *k, const mp_int *px,
const mp_int *py, mp_int *qx, mp_int *qy);
/* Elliptic curve scalar-point multiplication. Computes Q(x, y) = k1 * G +
* k2 * P(x, y), where G is the generator (base point) of the group of
* points on the elliptic curve. Input and output values are assumed to
* be NOT field-encoded. */
mp_err ECPoints_mul(const ECGroup *group, const mp_int *k1,
const mp_int *k2, const mp_int *px, const mp_int *py,
mp_int *qx, mp_int *qy);
/* Validates an EC public key as described in Section 5.2.2 of X9.62.
* Returns MP_YES if the public key is valid, MP_NO if the public key
* is invalid, or an error code if the validation could not be
* performed. */
mp_err ECPoint_validate(const ECGroup *group, const mp_int *px, const mp_int *py);
SECStatus ec_Curve25519_pt_mul(SECItem *X, SECItem *k, SECItem *P);
SECStatus ec_Curve25519_pt_validate(const SECItem *px);
#endif /* __ecl_h_ */

View file

@ -0,0 +1,93 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "ecl.h"
#include "ecl-curve.h"
#include "ecl-priv.h"
#include <stdlib.h>
#include <string.h>
#define CHECK(func) \
if ((func) == NULL) { \
res = 0; \
goto CLEANUP; \
}
/* Duplicates an ECCurveParams */
ECCurveParams *
ECCurveParams_dup(const ECCurveParams *params)
{
int res = 1;
ECCurveParams *ret = NULL;
CHECK(ret = (ECCurveParams *)calloc(1, sizeof(ECCurveParams)));
if (params->text != NULL) {
CHECK(ret->text = strdup(params->text));
}
ret->field = params->field;
ret->size = params->size;
if (params->irr != NULL) {
CHECK(ret->irr = strdup(params->irr));
}
if (params->curvea != NULL) {
CHECK(ret->curvea = strdup(params->curvea));
}
if (params->curveb != NULL) {
CHECK(ret->curveb = strdup(params->curveb));
}
if (params->genx != NULL) {
CHECK(ret->genx = strdup(params->genx));
}
if (params->geny != NULL) {
CHECK(ret->geny = strdup(params->geny));
}
if (params->order != NULL) {
CHECK(ret->order = strdup(params->order));
}
ret->cofactor = params->cofactor;
CLEANUP:
if (res != 1) {
EC_FreeCurveParams(ret);
return NULL;
}
return ret;
}
#undef CHECK
/* Construct ECCurveParams from an ECCurveName */
ECCurveParams *
EC_GetNamedCurveParams(const ECCurveName name)
{
if ((name <= ECCurve_noName) || (ECCurve_pastLastCurve <= name) ||
(ecCurve_map[name] == NULL)) {
return NULL;
} else {
return ECCurveParams_dup(ecCurve_map[name]);
}
}
/* Free the memory allocated (if any) to an ECCurveParams object. */
void
EC_FreeCurveParams(ECCurveParams *params)
{
if (params == NULL)
return;
if (params->text != NULL)
free(params->text);
if (params->irr != NULL)
free(params->irr);
if (params->curvea != NULL)
free(params->curvea);
if (params->curveb != NULL)
free(params->curveb);
if (params->genx != NULL)
free(params->genx);
if (params->geny != NULL)
free(params->geny);
if (params->order != NULL)
free(params->order);
free(params);
}

View file

@ -0,0 +1,958 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "mpi.h"
#include "mp_gf2m.h"
#include "ecl-priv.h"
#include "mpi-priv.h"
#include <stdlib.h>
/* Allocate memory for a new GFMethod object. */
GFMethod *
GFMethod_new()
{
mp_err res = MP_OKAY;
GFMethod *meth;
meth = (GFMethod *)malloc(sizeof(GFMethod));
if (meth == NULL)
return NULL;
meth->constructed = MP_YES;
MP_DIGITS(&meth->irr) = 0;
meth->extra_free = NULL;
MP_CHECKOK(mp_init(&meth->irr));
CLEANUP:
if (res != MP_OKAY) {
GFMethod_free(meth);
return NULL;
}
return meth;
}
/* Construct a generic GFMethod for arithmetic over prime fields with
* irreducible irr. */
GFMethod *
GFMethod_consGFp(const mp_int *irr)
{
mp_err res = MP_OKAY;
GFMethod *meth = NULL;
meth = GFMethod_new();
if (meth == NULL)
return NULL;
MP_CHECKOK(mp_copy(irr, &meth->irr));
meth->irr_arr[0] = mpl_significant_bits(irr);
meth->irr_arr[1] = meth->irr_arr[2] = meth->irr_arr[3] =
meth->irr_arr[4] = 0;
switch (MP_USED(&meth->irr)) {
/* maybe we need 1 and 2 words here as well?*/
case 3:
meth->field_add = &ec_GFp_add_3;
meth->field_sub = &ec_GFp_sub_3;
break;
case 4:
meth->field_add = &ec_GFp_add_4;
meth->field_sub = &ec_GFp_sub_4;
break;
case 5:
meth->field_add = &ec_GFp_add_5;
meth->field_sub = &ec_GFp_sub_5;
break;
case 6:
meth->field_add = &ec_GFp_add_6;
meth->field_sub = &ec_GFp_sub_6;
break;
default:
meth->field_add = &ec_GFp_add;
meth->field_sub = &ec_GFp_sub;
}
meth->field_neg = &ec_GFp_neg;
meth->field_mod = &ec_GFp_mod;
meth->field_mul = &ec_GFp_mul;
meth->field_sqr = &ec_GFp_sqr;
meth->field_div = &ec_GFp_div;
meth->field_enc = NULL;
meth->field_dec = NULL;
meth->extra1 = NULL;
meth->extra2 = NULL;
meth->extra_free = NULL;
CLEANUP:
if (res != MP_OKAY) {
GFMethod_free(meth);
return NULL;
}
return meth;
}
/* Free the memory allocated (if any) to a GFMethod object. */
void
GFMethod_free(GFMethod *meth)
{
if (meth == NULL)
return;
if (meth->constructed == MP_NO)
return;
mp_clear(&meth->irr);
if (meth->extra_free != NULL)
meth->extra_free(meth);
free(meth);
}
/* Wrapper functions for generic prime field arithmetic. */
/* Add two field elements. Assumes that 0 <= a, b < meth->irr */
mp_err
ec_GFp_add(const mp_int *a, const mp_int *b, mp_int *r,
const GFMethod *meth)
{
/* PRE: 0 <= a, b < p = meth->irr POST: 0 <= r < p, r = a + b (mod p) */
mp_err res;
if ((res = mp_add(a, b, r)) != MP_OKAY) {
return res;
}
if (mp_cmp(r, &meth->irr) >= 0) {
return mp_sub(r, &meth->irr, r);
}
return res;
}
/* Negates a field element. Assumes that 0 <= a < meth->irr */
mp_err
ec_GFp_neg(const mp_int *a, mp_int *r, const GFMethod *meth)
{
/* PRE: 0 <= a < p = meth->irr POST: 0 <= r < p, r = -a (mod p) */
if (mp_cmp_z(a) == 0) {
mp_zero(r);
return MP_OKAY;
}
return mp_sub(&meth->irr, a, r);
}
/* Subtracts two field elements. Assumes that 0 <= a, b < meth->irr */
mp_err
ec_GFp_sub(const mp_int *a, const mp_int *b, mp_int *r,
const GFMethod *meth)
{
mp_err res = MP_OKAY;
/* PRE: 0 <= a, b < p = meth->irr POST: 0 <= r < p, r = a - b (mod p) */
res = mp_sub(a, b, r);
if (res == MP_RANGE) {
MP_CHECKOK(mp_sub(b, a, r));
if (mp_cmp_z(r) < 0) {
MP_CHECKOK(mp_add(r, &meth->irr, r));
}
MP_CHECKOK(ec_GFp_neg(r, r, meth));
}
if (mp_cmp_z(r) < 0) {
MP_CHECKOK(mp_add(r, &meth->irr, r));
}
CLEANUP:
return res;
}
/*
* Inline adds for small curve lengths.
*/
/* 3 words */
mp_err
ec_GFp_add_3(const mp_int *a, const mp_int *b, mp_int *r,
const GFMethod *meth)
{
mp_err res = MP_OKAY;
mp_digit a0 = 0, a1 = 0, a2 = 0;
mp_digit r0 = 0, r1 = 0, r2 = 0;
mp_digit carry;
switch (MP_USED(a)) {
case 3:
a2 = MP_DIGIT(a, 2);
case 2:
a1 = MP_DIGIT(a, 1);
case 1:
a0 = MP_DIGIT(a, 0);
}
switch (MP_USED(b)) {
case 3:
r2 = MP_DIGIT(b, 2);
case 2:
r1 = MP_DIGIT(b, 1);
case 1:
r0 = MP_DIGIT(b, 0);
}
#ifndef MPI_AMD64_ADD
carry = 0;
MP_ADD_CARRY(a0, r0, r0, carry);
MP_ADD_CARRY(a1, r1, r1, carry);
MP_ADD_CARRY(a2, r2, r2, carry);
#else
__asm__(
"xorq %3,%3 \n\t"
"addq %4,%0 \n\t"
"adcq %5,%1 \n\t"
"adcq %6,%2 \n\t"
"adcq $0,%3 \n\t"
: "=r"(r0), "=r"(r1), "=r"(r2), "=r"(carry)
: "r"(a0), "r"(a1), "r"(a2),
"0"(r0), "1"(r1), "2"(r2)
: "%cc");
#endif
MP_CHECKOK(s_mp_pad(r, 3));
MP_DIGIT(r, 2) = r2;
MP_DIGIT(r, 1) = r1;
MP_DIGIT(r, 0) = r0;
MP_SIGN(r) = MP_ZPOS;
MP_USED(r) = 3;
/* Do quick 'subract' if we've gone over
* (add the 2's complement of the curve field) */
a2 = MP_DIGIT(&meth->irr, 2);
if (carry || r2 > a2 ||
((r2 == a2) && mp_cmp(r, &meth->irr) != MP_LT)) {
a1 = MP_DIGIT(&meth->irr, 1);
a0 = MP_DIGIT(&meth->irr, 0);
#ifndef MPI_AMD64_ADD
carry = 0;
MP_SUB_BORROW(r0, a0, r0, carry);
MP_SUB_BORROW(r1, a1, r1, carry);
MP_SUB_BORROW(r2, a2, r2, carry);
#else
__asm__(
"subq %3,%0 \n\t"
"sbbq %4,%1 \n\t"
"sbbq %5,%2 \n\t"
: "=r"(r0), "=r"(r1), "=r"(r2)
: "r"(a0), "r"(a1), "r"(a2),
"0"(r0), "1"(r1), "2"(r2)
: "%cc");
#endif
MP_DIGIT(r, 2) = r2;
MP_DIGIT(r, 1) = r1;
MP_DIGIT(r, 0) = r0;
}
s_mp_clamp(r);
CLEANUP:
return res;
}
/* 4 words */
mp_err
ec_GFp_add_4(const mp_int *a, const mp_int *b, mp_int *r,
const GFMethod *meth)
{
mp_err res = MP_OKAY;
mp_digit a0 = 0, a1 = 0, a2 = 0, a3 = 0;
mp_digit r0 = 0, r1 = 0, r2 = 0, r3 = 0;
mp_digit carry;
switch (MP_USED(a)) {
case 4:
a3 = MP_DIGIT(a, 3);
case 3:
a2 = MP_DIGIT(a, 2);
case 2:
a1 = MP_DIGIT(a, 1);
case 1:
a0 = MP_DIGIT(a, 0);
}
switch (MP_USED(b)) {
case 4:
r3 = MP_DIGIT(b, 3);
case 3:
r2 = MP_DIGIT(b, 2);
case 2:
r1 = MP_DIGIT(b, 1);
case 1:
r0 = MP_DIGIT(b, 0);
}
#ifndef MPI_AMD64_ADD
carry = 0;
MP_ADD_CARRY(a0, r0, r0, carry);
MP_ADD_CARRY(a1, r1, r1, carry);
MP_ADD_CARRY(a2, r2, r2, carry);
MP_ADD_CARRY(a3, r3, r3, carry);
#else
__asm__(
"xorq %4,%4 \n\t"
"addq %5,%0 \n\t"
"adcq %6,%1 \n\t"
"adcq %7,%2 \n\t"
"adcq %8,%3 \n\t"
"adcq $0,%4 \n\t"
: "=r"(r0), "=r"(r1), "=r"(r2), "=r"(r3), "=r"(carry)
: "r"(a0), "r"(a1), "r"(a2), "r"(a3),
"0"(r0), "1"(r1), "2"(r2), "3"(r3)
: "%cc");
#endif
MP_CHECKOK(s_mp_pad(r, 4));
MP_DIGIT(r, 3) = r3;
MP_DIGIT(r, 2) = r2;
MP_DIGIT(r, 1) = r1;
MP_DIGIT(r, 0) = r0;
MP_SIGN(r) = MP_ZPOS;
MP_USED(r) = 4;
/* Do quick 'subract' if we've gone over
* (add the 2's complement of the curve field) */
a3 = MP_DIGIT(&meth->irr, 3);
if (carry || r3 > a3 ||
((r3 == a3) && mp_cmp(r, &meth->irr) != MP_LT)) {
a2 = MP_DIGIT(&meth->irr, 2);
a1 = MP_DIGIT(&meth->irr, 1);
a0 = MP_DIGIT(&meth->irr, 0);
#ifndef MPI_AMD64_ADD
carry = 0;
MP_SUB_BORROW(r0, a0, r0, carry);
MP_SUB_BORROW(r1, a1, r1, carry);
MP_SUB_BORROW(r2, a2, r2, carry);
MP_SUB_BORROW(r3, a3, r3, carry);
#else
__asm__(
"subq %4,%0 \n\t"
"sbbq %5,%1 \n\t"
"sbbq %6,%2 \n\t"
"sbbq %7,%3 \n\t"
: "=r"(r0), "=r"(r1), "=r"(r2), "=r"(r3)
: "r"(a0), "r"(a1), "r"(a2), "r"(a3),
"0"(r0), "1"(r1), "2"(r2), "3"(r3)
: "%cc");
#endif
MP_DIGIT(r, 3) = r3;
MP_DIGIT(r, 2) = r2;
MP_DIGIT(r, 1) = r1;
MP_DIGIT(r, 0) = r0;
}
s_mp_clamp(r);
CLEANUP:
return res;
}
/* 5 words */
mp_err
ec_GFp_add_5(const mp_int *a, const mp_int *b, mp_int *r,
const GFMethod *meth)
{
mp_err res = MP_OKAY;
mp_digit a0 = 0, a1 = 0, a2 = 0, a3 = 0, a4 = 0;
mp_digit r0 = 0, r1 = 0, r2 = 0, r3 = 0, r4 = 0;
mp_digit carry;
switch (MP_USED(a)) {
case 5:
a4 = MP_DIGIT(a, 4);
case 4:
a3 = MP_DIGIT(a, 3);
case 3:
a2 = MP_DIGIT(a, 2);
case 2:
a1 = MP_DIGIT(a, 1);
case 1:
a0 = MP_DIGIT(a, 0);
}
switch (MP_USED(b)) {
case 5:
r4 = MP_DIGIT(b, 4);
case 4:
r3 = MP_DIGIT(b, 3);
case 3:
r2 = MP_DIGIT(b, 2);
case 2:
r1 = MP_DIGIT(b, 1);
case 1:
r0 = MP_DIGIT(b, 0);
}
carry = 0;
MP_ADD_CARRY(a0, r0, r0, carry);
MP_ADD_CARRY(a1, r1, r1, carry);
MP_ADD_CARRY(a2, r2, r2, carry);
MP_ADD_CARRY(a3, r3, r3, carry);
MP_ADD_CARRY(a4, r4, r4, carry);
MP_CHECKOK(s_mp_pad(r, 5));
MP_DIGIT(r, 4) = r4;
MP_DIGIT(r, 3) = r3;
MP_DIGIT(r, 2) = r2;
MP_DIGIT(r, 1) = r1;
MP_DIGIT(r, 0) = r0;
MP_SIGN(r) = MP_ZPOS;
MP_USED(r) = 5;
/* Do quick 'subract' if we've gone over
* (add the 2's complement of the curve field) */
a4 = MP_DIGIT(&meth->irr, 4);
if (carry || r4 > a4 ||
((r4 == a4) && mp_cmp(r, &meth->irr) != MP_LT)) {
a3 = MP_DIGIT(&meth->irr, 3);
a2 = MP_DIGIT(&meth->irr, 2);
a1 = MP_DIGIT(&meth->irr, 1);
a0 = MP_DIGIT(&meth->irr, 0);
carry = 0;
MP_SUB_BORROW(r0, a0, r0, carry);
MP_SUB_BORROW(r1, a1, r1, carry);
MP_SUB_BORROW(r2, a2, r2, carry);
MP_SUB_BORROW(r3, a3, r3, carry);
MP_SUB_BORROW(r4, a4, r4, carry);
MP_DIGIT(r, 4) = r4;
MP_DIGIT(r, 3) = r3;
MP_DIGIT(r, 2) = r2;
MP_DIGIT(r, 1) = r1;
MP_DIGIT(r, 0) = r0;
}
s_mp_clamp(r);
CLEANUP:
return res;
}
/* 6 words */
mp_err
ec_GFp_add_6(const mp_int *a, const mp_int *b, mp_int *r,
const GFMethod *meth)
{
mp_err res = MP_OKAY;
mp_digit a0 = 0, a1 = 0, a2 = 0, a3 = 0, a4 = 0, a5 = 0;
mp_digit r0 = 0, r1 = 0, r2 = 0, r3 = 0, r4 = 0, r5 = 0;
mp_digit carry;
switch (MP_USED(a)) {
case 6:
a5 = MP_DIGIT(a, 5);
case 5:
a4 = MP_DIGIT(a, 4);
case 4:
a3 = MP_DIGIT(a, 3);
case 3:
a2 = MP_DIGIT(a, 2);
case 2:
a1 = MP_DIGIT(a, 1);
case 1:
a0 = MP_DIGIT(a, 0);
}
switch (MP_USED(b)) {
case 6:
r5 = MP_DIGIT(b, 5);
case 5:
r4 = MP_DIGIT(b, 4);
case 4:
r3 = MP_DIGIT(b, 3);
case 3:
r2 = MP_DIGIT(b, 2);
case 2:
r1 = MP_DIGIT(b, 1);
case 1:
r0 = MP_DIGIT(b, 0);
}
carry = 0;
MP_ADD_CARRY(a0, r0, r0, carry);
MP_ADD_CARRY(a1, r1, r1, carry);
MP_ADD_CARRY(a2, r2, r2, carry);
MP_ADD_CARRY(a3, r3, r3, carry);
MP_ADD_CARRY(a4, r4, r4, carry);
MP_ADD_CARRY(a5, r5, r5, carry);
MP_CHECKOK(s_mp_pad(r, 6));
MP_DIGIT(r, 5) = r5;
MP_DIGIT(r, 4) = r4;
MP_DIGIT(r, 3) = r3;
MP_DIGIT(r, 2) = r2;
MP_DIGIT(r, 1) = r1;
MP_DIGIT(r, 0) = r0;
MP_SIGN(r) = MP_ZPOS;
MP_USED(r) = 6;
/* Do quick 'subract' if we've gone over
* (add the 2's complement of the curve field) */
a5 = MP_DIGIT(&meth->irr, 5);
if (carry || r5 > a5 ||
((r5 == a5) && mp_cmp(r, &meth->irr) != MP_LT)) {
a4 = MP_DIGIT(&meth->irr, 4);
a3 = MP_DIGIT(&meth->irr, 3);
a2 = MP_DIGIT(&meth->irr, 2);
a1 = MP_DIGIT(&meth->irr, 1);
a0 = MP_DIGIT(&meth->irr, 0);
carry = 0;
MP_SUB_BORROW(r0, a0, r0, carry);
MP_SUB_BORROW(r1, a1, r1, carry);
MP_SUB_BORROW(r2, a2, r2, carry);
MP_SUB_BORROW(r3, a3, r3, carry);
MP_SUB_BORROW(r4, a4, r4, carry);
MP_SUB_BORROW(r5, a5, r5, carry);
MP_DIGIT(r, 5) = r5;
MP_DIGIT(r, 4) = r4;
MP_DIGIT(r, 3) = r3;
MP_DIGIT(r, 2) = r2;
MP_DIGIT(r, 1) = r1;
MP_DIGIT(r, 0) = r0;
}
s_mp_clamp(r);
CLEANUP:
return res;
}
/*
* The following subraction functions do in-line subractions based
* on our curve size.
*
* ... 3 words
*/
mp_err
ec_GFp_sub_3(const mp_int *a, const mp_int *b, mp_int *r,
const GFMethod *meth)
{
mp_err res = MP_OKAY;
mp_digit b0 = 0, b1 = 0, b2 = 0;
mp_digit r0 = 0, r1 = 0, r2 = 0;
mp_digit borrow;
switch (MP_USED(a)) {
case 3:
r2 = MP_DIGIT(a, 2);
case 2:
r1 = MP_DIGIT(a, 1);
case 1:
r0 = MP_DIGIT(a, 0);
}
switch (MP_USED(b)) {
case 3:
b2 = MP_DIGIT(b, 2);
case 2:
b1 = MP_DIGIT(b, 1);
case 1:
b0 = MP_DIGIT(b, 0);
}
#ifndef MPI_AMD64_ADD
borrow = 0;
MP_SUB_BORROW(r0, b0, r0, borrow);
MP_SUB_BORROW(r1, b1, r1, borrow);
MP_SUB_BORROW(r2, b2, r2, borrow);
#else
__asm__(
"xorq %3,%3 \n\t"
"subq %4,%0 \n\t"
"sbbq %5,%1 \n\t"
"sbbq %6,%2 \n\t"
"adcq $0,%3 \n\t"
: "=r"(r0), "=r"(r1), "=r"(r2), "=r"(borrow)
: "r"(b0), "r"(b1), "r"(b2),
"0"(r0), "1"(r1), "2"(r2)
: "%cc");
#endif
/* Do quick 'add' if we've gone under 0
* (subtract the 2's complement of the curve field) */
if (borrow) {
b2 = MP_DIGIT(&meth->irr, 2);
b1 = MP_DIGIT(&meth->irr, 1);
b0 = MP_DIGIT(&meth->irr, 0);
#ifndef MPI_AMD64_ADD
borrow = 0;
MP_ADD_CARRY(b0, r0, r0, borrow);
MP_ADD_CARRY(b1, r1, r1, borrow);
MP_ADD_CARRY(b2, r2, r2, borrow);
#else
__asm__(
"addq %3,%0 \n\t"
"adcq %4,%1 \n\t"
"adcq %5,%2 \n\t"
: "=r"(r0), "=r"(r1), "=r"(r2)
: "r"(b0), "r"(b1), "r"(b2),
"0"(r0), "1"(r1), "2"(r2)
: "%cc");
#endif
}
#ifdef MPI_AMD64_ADD
/* compiler fakeout? */
if ((r2 == b0) && (r1 == b0) && (r0 == b0)) {
MP_CHECKOK(s_mp_pad(r, 4));
}
#endif
MP_CHECKOK(s_mp_pad(r, 3));
MP_DIGIT(r, 2) = r2;
MP_DIGIT(r, 1) = r1;
MP_DIGIT(r, 0) = r0;
MP_SIGN(r) = MP_ZPOS;
MP_USED(r) = 3;
s_mp_clamp(r);
CLEANUP:
return res;
}
/* 4 words */
mp_err
ec_GFp_sub_4(const mp_int *a, const mp_int *b, mp_int *r,
const GFMethod *meth)
{
mp_err res = MP_OKAY;
mp_digit b0 = 0, b1 = 0, b2 = 0, b3 = 0;
mp_digit r0 = 0, r1 = 0, r2 = 0, r3 = 0;
mp_digit borrow;
switch (MP_USED(a)) {
case 4:
r3 = MP_DIGIT(a, 3);
case 3:
r2 = MP_DIGIT(a, 2);
case 2:
r1 = MP_DIGIT(a, 1);
case 1:
r0 = MP_DIGIT(a, 0);
}
switch (MP_USED(b)) {
case 4:
b3 = MP_DIGIT(b, 3);
case 3:
b2 = MP_DIGIT(b, 2);
case 2:
b1 = MP_DIGIT(b, 1);
case 1:
b0 = MP_DIGIT(b, 0);
}
#ifndef MPI_AMD64_ADD
borrow = 0;
MP_SUB_BORROW(r0, b0, r0, borrow);
MP_SUB_BORROW(r1, b1, r1, borrow);
MP_SUB_BORROW(r2, b2, r2, borrow);
MP_SUB_BORROW(r3, b3, r3, borrow);
#else
__asm__(
"xorq %4,%4 \n\t"
"subq %5,%0 \n\t"
"sbbq %6,%1 \n\t"
"sbbq %7,%2 \n\t"
"sbbq %8,%3 \n\t"
"adcq $0,%4 \n\t"
: "=r"(r0), "=r"(r1), "=r"(r2), "=r"(r3), "=r"(borrow)
: "r"(b0), "r"(b1), "r"(b2), "r"(b3),
"0"(r0), "1"(r1), "2"(r2), "3"(r3)
: "%cc");
#endif
/* Do quick 'add' if we've gone under 0
* (subtract the 2's complement of the curve field) */
if (borrow) {
b3 = MP_DIGIT(&meth->irr, 3);
b2 = MP_DIGIT(&meth->irr, 2);
b1 = MP_DIGIT(&meth->irr, 1);
b0 = MP_DIGIT(&meth->irr, 0);
#ifndef MPI_AMD64_ADD
borrow = 0;
MP_ADD_CARRY(b0, r0, r0, borrow);
MP_ADD_CARRY(b1, r1, r1, borrow);
MP_ADD_CARRY(b2, r2, r2, borrow);
MP_ADD_CARRY(b3, r3, r3, borrow);
#else
__asm__(
"addq %4,%0 \n\t"
"adcq %5,%1 \n\t"
"adcq %6,%2 \n\t"
"adcq %7,%3 \n\t"
: "=r"(r0), "=r"(r1), "=r"(r2), "=r"(r3)
: "r"(b0), "r"(b1), "r"(b2), "r"(b3),
"0"(r0), "1"(r1), "2"(r2), "3"(r3)
: "%cc");
#endif
}
#ifdef MPI_AMD64_ADD
/* compiler fakeout? */
if ((r3 == b0) && (r1 == b0) && (r0 == b0)) {
MP_CHECKOK(s_mp_pad(r, 4));
}
#endif
MP_CHECKOK(s_mp_pad(r, 4));
MP_DIGIT(r, 3) = r3;
MP_DIGIT(r, 2) = r2;
MP_DIGIT(r, 1) = r1;
MP_DIGIT(r, 0) = r0;
MP_SIGN(r) = MP_ZPOS;
MP_USED(r) = 4;
s_mp_clamp(r);
CLEANUP:
return res;
}
/* 5 words */
mp_err
ec_GFp_sub_5(const mp_int *a, const mp_int *b, mp_int *r,
const GFMethod *meth)
{
mp_err res = MP_OKAY;
mp_digit b0 = 0, b1 = 0, b2 = 0, b3 = 0, b4 = 0;
mp_digit r0 = 0, r1 = 0, r2 = 0, r3 = 0, r4 = 0;
mp_digit borrow;
switch (MP_USED(a)) {
case 5:
r4 = MP_DIGIT(a, 4);
case 4:
r3 = MP_DIGIT(a, 3);
case 3:
r2 = MP_DIGIT(a, 2);
case 2:
r1 = MP_DIGIT(a, 1);
case 1:
r0 = MP_DIGIT(a, 0);
}
switch (MP_USED(b)) {
case 5:
b4 = MP_DIGIT(b, 4);
case 4:
b3 = MP_DIGIT(b, 3);
case 3:
b2 = MP_DIGIT(b, 2);
case 2:
b1 = MP_DIGIT(b, 1);
case 1:
b0 = MP_DIGIT(b, 0);
}
borrow = 0;
MP_SUB_BORROW(r0, b0, r0, borrow);
MP_SUB_BORROW(r1, b1, r1, borrow);
MP_SUB_BORROW(r2, b2, r2, borrow);
MP_SUB_BORROW(r3, b3, r3, borrow);
MP_SUB_BORROW(r4, b4, r4, borrow);
/* Do quick 'add' if we've gone under 0
* (subtract the 2's complement of the curve field) */
if (borrow) {
b4 = MP_DIGIT(&meth->irr, 4);
b3 = MP_DIGIT(&meth->irr, 3);
b2 = MP_DIGIT(&meth->irr, 2);
b1 = MP_DIGIT(&meth->irr, 1);
b0 = MP_DIGIT(&meth->irr, 0);
borrow = 0;
MP_ADD_CARRY(b0, r0, r0, borrow);
MP_ADD_CARRY(b1, r1, r1, borrow);
MP_ADD_CARRY(b2, r2, r2, borrow);
MP_ADD_CARRY(b3, r3, r3, borrow);
MP_ADD_CARRY(b4, r4, r4, borrow);
}
MP_CHECKOK(s_mp_pad(r, 5));
MP_DIGIT(r, 4) = r4;
MP_DIGIT(r, 3) = r3;
MP_DIGIT(r, 2) = r2;
MP_DIGIT(r, 1) = r1;
MP_DIGIT(r, 0) = r0;
MP_SIGN(r) = MP_ZPOS;
MP_USED(r) = 5;
s_mp_clamp(r);
CLEANUP:
return res;
}
/* 6 words */
mp_err
ec_GFp_sub_6(const mp_int *a, const mp_int *b, mp_int *r,
const GFMethod *meth)
{
mp_err res = MP_OKAY;
mp_digit b0 = 0, b1 = 0, b2 = 0, b3 = 0, b4 = 0, b5 = 0;
mp_digit r0 = 0, r1 = 0, r2 = 0, r3 = 0, r4 = 0, r5 = 0;
mp_digit borrow;
switch (MP_USED(a)) {
case 6:
r5 = MP_DIGIT(a, 5);
case 5:
r4 = MP_DIGIT(a, 4);
case 4:
r3 = MP_DIGIT(a, 3);
case 3:
r2 = MP_DIGIT(a, 2);
case 2:
r1 = MP_DIGIT(a, 1);
case 1:
r0 = MP_DIGIT(a, 0);
}
switch (MP_USED(b)) {
case 6:
b5 = MP_DIGIT(b, 5);
case 5:
b4 = MP_DIGIT(b, 4);
case 4:
b3 = MP_DIGIT(b, 3);
case 3:
b2 = MP_DIGIT(b, 2);
case 2:
b1 = MP_DIGIT(b, 1);
case 1:
b0 = MP_DIGIT(b, 0);
}
borrow = 0;
MP_SUB_BORROW(r0, b0, r0, borrow);
MP_SUB_BORROW(r1, b1, r1, borrow);
MP_SUB_BORROW(r2, b2, r2, borrow);
MP_SUB_BORROW(r3, b3, r3, borrow);
MP_SUB_BORROW(r4, b4, r4, borrow);
MP_SUB_BORROW(r5, b5, r5, borrow);
/* Do quick 'add' if we've gone under 0
* (subtract the 2's complement of the curve field) */
if (borrow) {
b5 = MP_DIGIT(&meth->irr, 5);
b4 = MP_DIGIT(&meth->irr, 4);
b3 = MP_DIGIT(&meth->irr, 3);
b2 = MP_DIGIT(&meth->irr, 2);
b1 = MP_DIGIT(&meth->irr, 1);
b0 = MP_DIGIT(&meth->irr, 0);
borrow = 0;
MP_ADD_CARRY(b0, r0, r0, borrow);
MP_ADD_CARRY(b1, r1, r1, borrow);
MP_ADD_CARRY(b2, r2, r2, borrow);
MP_ADD_CARRY(b3, r3, r3, borrow);
MP_ADD_CARRY(b4, r4, r4, borrow);
MP_ADD_CARRY(b5, r5, r5, borrow);
}
MP_CHECKOK(s_mp_pad(r, 6));
MP_DIGIT(r, 5) = r5;
MP_DIGIT(r, 4) = r4;
MP_DIGIT(r, 3) = r3;
MP_DIGIT(r, 2) = r2;
MP_DIGIT(r, 1) = r1;
MP_DIGIT(r, 0) = r0;
MP_SIGN(r) = MP_ZPOS;
MP_USED(r) = 6;
s_mp_clamp(r);
CLEANUP:
return res;
}
/* Reduces an integer to a field element. */
mp_err
ec_GFp_mod(const mp_int *a, mp_int *r, const GFMethod *meth)
{
return mp_mod(a, &meth->irr, r);
}
/* Multiplies two field elements. */
mp_err
ec_GFp_mul(const mp_int *a, const mp_int *b, mp_int *r,
const GFMethod *meth)
{
return mp_mulmod(a, b, &meth->irr, r);
}
/* Squares a field element. */
mp_err
ec_GFp_sqr(const mp_int *a, mp_int *r, const GFMethod *meth)
{
return mp_sqrmod(a, &meth->irr, r);
}
/* Divides two field elements. If a is NULL, then returns the inverse of
* b. */
mp_err
ec_GFp_div(const mp_int *a, const mp_int *b, mp_int *r,
const GFMethod *meth)
{
mp_err res = MP_OKAY;
mp_int t;
/* If a is NULL, then return the inverse of b, otherwise return a/b. */
if (a == NULL) {
return mp_invmod(b, &meth->irr, r);
} else {
/* MPI doesn't support divmod, so we implement it using invmod and
* mulmod. */
MP_CHECKOK(mp_init(&t));
MP_CHECKOK(mp_invmod(b, &meth->irr, &t));
MP_CHECKOK(mp_mulmod(a, &t, &meth->irr, r));
CLEANUP:
mp_clear(&t);
return res;
}
}
/* Wrapper functions for generic binary polynomial field arithmetic. */
/* Adds two field elements. */
mp_err
ec_GF2m_add(const mp_int *a, const mp_int *b, mp_int *r,
const GFMethod *meth)
{
return mp_badd(a, b, r);
}
/* Negates a field element. Note that for binary polynomial fields, the
* negation of a field element is the field element itself. */
mp_err
ec_GF2m_neg(const mp_int *a, mp_int *r, const GFMethod *meth)
{
if (a == r) {
return MP_OKAY;
} else {
return mp_copy(a, r);
}
}
/* Reduces a binary polynomial to a field element. */
mp_err
ec_GF2m_mod(const mp_int *a, mp_int *r, const GFMethod *meth)
{
return mp_bmod(a, meth->irr_arr, r);
}
/* Multiplies two field elements. */
mp_err
ec_GF2m_mul(const mp_int *a, const mp_int *b, mp_int *r,
const GFMethod *meth)
{
return mp_bmulmod(a, b, meth->irr_arr, r);
}
/* Squares a field element. */
mp_err
ec_GF2m_sqr(const mp_int *a, mp_int *r, const GFMethod *meth)
{
return mp_bsqrmod(a, meth->irr_arr, r);
}
/* Divides two field elements. If a is NULL, then returns the inverse of
* b. */
mp_err
ec_GF2m_div(const mp_int *a, const mp_int *b, mp_int *r,
const GFMethod *meth)
{
mp_err res = MP_OKAY;
mp_int t;
/* If a is NULL, then return the inverse of b, otherwise return a/b. */
if (a == NULL) {
/* The GF(2^m) portion of MPI doesn't support invmod, so we
* compute 1/b. */
MP_CHECKOK(mp_init(&t));
MP_CHECKOK(mp_set_int(&t, 1));
MP_CHECKOK(mp_bdivmod(&t, b, &meth->irr, meth->irr_arr, r));
CLEANUP:
mp_clear(&t);
return res;
} else {
return mp_bdivmod(a, b, &meth->irr, meth->irr_arr, r);
}
}

View file

@ -0,0 +1,305 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "mpi.h"
#include "mplogic.h"
#include "ecl.h"
#include "ecl-priv.h"
#include <stdlib.h>
/* Elliptic curve scalar-point multiplication. Computes R(x, y) = k * P(x,
* y). If x, y = NULL, then P is assumed to be the generator (base point)
* of the group of points on the elliptic curve. Input and output values
* are assumed to be NOT field-encoded. */
mp_err
ECPoint_mul(const ECGroup *group, const mp_int *k, const mp_int *px,
const mp_int *py, mp_int *rx, mp_int *ry)
{
mp_err res = MP_OKAY;
mp_int kt;
ARGCHK((k != NULL) && (group != NULL), MP_BADARG);
MP_DIGITS(&kt) = 0;
/* want scalar to be less than or equal to group order */
if (mp_cmp(k, &group->order) > 0) {
MP_CHECKOK(mp_init(&kt));
MP_CHECKOK(mp_mod(k, &group->order, &kt));
} else {
MP_SIGN(&kt) = MP_ZPOS;
MP_USED(&kt) = MP_USED(k);
MP_ALLOC(&kt) = MP_ALLOC(k);
MP_DIGITS(&kt) = MP_DIGITS(k);
}
if ((px == NULL) || (py == NULL)) {
if (group->base_point_mul) {
MP_CHECKOK(group->base_point_mul(&kt, rx, ry, group));
} else {
MP_CHECKOK(group->point_mul(&kt, &group->genx, &group->geny, rx, ry,
group));
}
} else {
if (group->meth->field_enc) {
MP_CHECKOK(group->meth->field_enc(px, rx, group->meth));
MP_CHECKOK(group->meth->field_enc(py, ry, group->meth));
MP_CHECKOK(group->point_mul(&kt, rx, ry, rx, ry, group));
} else {
MP_CHECKOK(group->point_mul(&kt, px, py, rx, ry, group));
}
}
if (group->meth->field_dec) {
MP_CHECKOK(group->meth->field_dec(rx, rx, group->meth));
MP_CHECKOK(group->meth->field_dec(ry, ry, group->meth));
}
CLEANUP:
if (MP_DIGITS(&kt) != MP_DIGITS(k)) {
mp_clear(&kt);
}
return res;
}
/* Elliptic curve scalar-point multiplication. Computes R(x, y) = k1 * G +
* k2 * P(x, y), where G is the generator (base point) of the group of
* points on the elliptic curve. Allows k1 = NULL or { k2, P } = NULL.
* Input and output values are assumed to be NOT field-encoded. */
mp_err
ec_pts_mul_basic(const mp_int *k1, const mp_int *k2, const mp_int *px,
const mp_int *py, mp_int *rx, mp_int *ry,
const ECGroup *group)
{
mp_err res = MP_OKAY;
mp_int sx, sy;
ARGCHK(group != NULL, MP_BADARG);
ARGCHK(!((k1 == NULL) && ((k2 == NULL) || (px == NULL) || (py == NULL))), MP_BADARG);
/* if some arguments are not defined used ECPoint_mul */
if (k1 == NULL) {
return ECPoint_mul(group, k2, px, py, rx, ry);
} else if ((k2 == NULL) || (px == NULL) || (py == NULL)) {
return ECPoint_mul(group, k1, NULL, NULL, rx, ry);
}
MP_DIGITS(&sx) = 0;
MP_DIGITS(&sy) = 0;
MP_CHECKOK(mp_init(&sx));
MP_CHECKOK(mp_init(&sy));
MP_CHECKOK(ECPoint_mul(group, k1, NULL, NULL, &sx, &sy));
MP_CHECKOK(ECPoint_mul(group, k2, px, py, rx, ry));
if (group->meth->field_enc) {
MP_CHECKOK(group->meth->field_enc(&sx, &sx, group->meth));
MP_CHECKOK(group->meth->field_enc(&sy, &sy, group->meth));
MP_CHECKOK(group->meth->field_enc(rx, rx, group->meth));
MP_CHECKOK(group->meth->field_enc(ry, ry, group->meth));
}
MP_CHECKOK(group->point_add(&sx, &sy, rx, ry, rx, ry, group));
if (group->meth->field_dec) {
MP_CHECKOK(group->meth->field_dec(rx, rx, group->meth));
MP_CHECKOK(group->meth->field_dec(ry, ry, group->meth));
}
CLEANUP:
mp_clear(&sx);
mp_clear(&sy);
return res;
}
/* Elliptic curve scalar-point multiplication. Computes R(x, y) = k1 * G +
* k2 * P(x, y), where G is the generator (base point) of the group of
* points on the elliptic curve. Allows k1 = NULL or { k2, P } = NULL.
* Input and output values are assumed to be NOT field-encoded. Uses
* algorithm 15 (simultaneous multiple point multiplication) from Brown,
* Hankerson, Lopez, Menezes. Software Implementation of the NIST
* Elliptic Curves over Prime Fields. */
mp_err
ec_pts_mul_simul_w2(const mp_int *k1, const mp_int *k2, const mp_int *px,
const mp_int *py, mp_int *rx, mp_int *ry,
const ECGroup *group)
{
mp_err res = MP_OKAY;
mp_int precomp[4][4][2];
const mp_int *a, *b;
unsigned int i, j;
int ai, bi, d;
ARGCHK(group != NULL, MP_BADARG);
ARGCHK(!((k1 == NULL) && ((k2 == NULL) || (px == NULL) || (py == NULL))), MP_BADARG);
/* if some arguments are not defined used ECPoint_mul */
if (k1 == NULL) {
return ECPoint_mul(group, k2, px, py, rx, ry);
} else if ((k2 == NULL) || (px == NULL) || (py == NULL)) {
return ECPoint_mul(group, k1, NULL, NULL, rx, ry);
}
/* initialize precomputation table */
for (i = 0; i < 4; i++) {
for (j = 0; j < 4; j++) {
MP_DIGITS(&precomp[i][j][0]) = 0;
MP_DIGITS(&precomp[i][j][1]) = 0;
}
}
for (i = 0; i < 4; i++) {
for (j = 0; j < 4; j++) {
MP_CHECKOK(mp_init_size(&precomp[i][j][0],
ECL_MAX_FIELD_SIZE_DIGITS));
MP_CHECKOK(mp_init_size(&precomp[i][j][1],
ECL_MAX_FIELD_SIZE_DIGITS));
}
}
/* fill precomputation table */
/* assign {k1, k2} = {a, b} such that len(a) >= len(b) */
if (mpl_significant_bits(k1) < mpl_significant_bits(k2)) {
a = k2;
b = k1;
if (group->meth->field_enc) {
MP_CHECKOK(group->meth->field_enc(px, &precomp[1][0][0], group->meth));
MP_CHECKOK(group->meth->field_enc(py, &precomp[1][0][1], group->meth));
} else {
MP_CHECKOK(mp_copy(px, &precomp[1][0][0]));
MP_CHECKOK(mp_copy(py, &precomp[1][0][1]));
}
MP_CHECKOK(mp_copy(&group->genx, &precomp[0][1][0]));
MP_CHECKOK(mp_copy(&group->geny, &precomp[0][1][1]));
} else {
a = k1;
b = k2;
MP_CHECKOK(mp_copy(&group->genx, &precomp[1][0][0]));
MP_CHECKOK(mp_copy(&group->geny, &precomp[1][0][1]));
if (group->meth->field_enc) {
MP_CHECKOK(group->meth->field_enc(px, &precomp[0][1][0], group->meth));
MP_CHECKOK(group->meth->field_enc(py, &precomp[0][1][1], group->meth));
} else {
MP_CHECKOK(mp_copy(px, &precomp[0][1][0]));
MP_CHECKOK(mp_copy(py, &precomp[0][1][1]));
}
}
/* precompute [*][0][*] */
mp_zero(&precomp[0][0][0]);
mp_zero(&precomp[0][0][1]);
MP_CHECKOK(group->point_dbl(&precomp[1][0][0], &precomp[1][0][1],
&precomp[2][0][0], &precomp[2][0][1], group));
MP_CHECKOK(group->point_add(&precomp[1][0][0], &precomp[1][0][1],
&precomp[2][0][0], &precomp[2][0][1],
&precomp[3][0][0], &precomp[3][0][1], group));
/* precompute [*][1][*] */
for (i = 1; i < 4; i++) {
MP_CHECKOK(group->point_add(&precomp[0][1][0], &precomp[0][1][1],
&precomp[i][0][0], &precomp[i][0][1],
&precomp[i][1][0], &precomp[i][1][1], group));
}
/* precompute [*][2][*] */
MP_CHECKOK(group->point_dbl(&precomp[0][1][0], &precomp[0][1][1],
&precomp[0][2][0], &precomp[0][2][1], group));
for (i = 1; i < 4; i++) {
MP_CHECKOK(group->point_add(&precomp[0][2][0], &precomp[0][2][1],
&precomp[i][0][0], &precomp[i][0][1],
&precomp[i][2][0], &precomp[i][2][1], group));
}
/* precompute [*][3][*] */
MP_CHECKOK(group->point_add(&precomp[0][1][0], &precomp[0][1][1],
&precomp[0][2][0], &precomp[0][2][1],
&precomp[0][3][0], &precomp[0][3][1], group));
for (i = 1; i < 4; i++) {
MP_CHECKOK(group->point_add(&precomp[0][3][0], &precomp[0][3][1],
&precomp[i][0][0], &precomp[i][0][1],
&precomp[i][3][0], &precomp[i][3][1], group));
}
d = (mpl_significant_bits(a) + 1) / 2;
/* R = inf */
mp_zero(rx);
mp_zero(ry);
for (i = d; i-- > 0;) {
ai = MP_GET_BIT(a, 2 * i + 1);
ai <<= 1;
ai |= MP_GET_BIT(a, 2 * i);
bi = MP_GET_BIT(b, 2 * i + 1);
bi <<= 1;
bi |= MP_GET_BIT(b, 2 * i);
/* R = 2^2 * R */
MP_CHECKOK(group->point_dbl(rx, ry, rx, ry, group));
MP_CHECKOK(group->point_dbl(rx, ry, rx, ry, group));
/* R = R + (ai * A + bi * B) */
MP_CHECKOK(group->point_add(rx, ry, &precomp[ai][bi][0],
&precomp[ai][bi][1], rx, ry, group));
}
if (group->meth->field_dec) {
MP_CHECKOK(group->meth->field_dec(rx, rx, group->meth));
MP_CHECKOK(group->meth->field_dec(ry, ry, group->meth));
}
CLEANUP:
for (i = 0; i < 4; i++) {
for (j = 0; j < 4; j++) {
mp_clear(&precomp[i][j][0]);
mp_clear(&precomp[i][j][1]);
}
}
return res;
}
/* Elliptic curve scalar-point multiplication. Computes R(x, y) = k1 * G +
* k2 * P(x, y), where G is the generator (base point) of the group of
* points on the elliptic curve. Allows k1 = NULL or { k2, P } = NULL.
* Input and output values are assumed to be NOT field-encoded. */
mp_err
ECPoints_mul(const ECGroup *group, const mp_int *k1, const mp_int *k2,
const mp_int *px, const mp_int *py, mp_int *rx, mp_int *ry)
{
mp_err res = MP_OKAY;
mp_int k1t, k2t;
const mp_int *k1p, *k2p;
MP_DIGITS(&k1t) = 0;
MP_DIGITS(&k2t) = 0;
ARGCHK(group != NULL, MP_BADARG);
/* want scalar to be less than or equal to group order */
if (k1 != NULL) {
if (mp_cmp(k1, &group->order) >= 0) {
MP_CHECKOK(mp_init(&k1t));
MP_CHECKOK(mp_mod(k1, &group->order, &k1t));
k1p = &k1t;
} else {
k1p = k1;
}
} else {
k1p = k1;
}
if (k2 != NULL) {
if (mp_cmp(k2, &group->order) >= 0) {
MP_CHECKOK(mp_init(&k2t));
MP_CHECKOK(mp_mod(k2, &group->order, &k2t));
k2p = &k2t;
} else {
k2p = k2;
}
} else {
k2p = k2;
}
/* if points_mul is defined, then use it */
if (group->points_mul) {
res = group->points_mul(k1p, k2p, px, py, rx, ry, group);
} else {
res = ec_pts_mul_simul_w2(k1p, k2p, px, py, rx, ry, group);
}
CLEANUP:
mp_clear(&k1t);
mp_clear(&k2t);
return res;
}

View file

@ -0,0 +1,106 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef __ecp_h_
#define __ecp_h_
#include "ecl-priv.h"
/* Checks if point P(px, py) is at infinity. Uses affine coordinates. */
mp_err ec_GFp_pt_is_inf_aff(const mp_int *px, const mp_int *py);
/* Sets P(px, py) to be the point at infinity. Uses affine coordinates. */
mp_err ec_GFp_pt_set_inf_aff(mp_int *px, mp_int *py);
/* Computes R = P + Q where R is (rx, ry), P is (px, py) and Q is (qx,
* qy). Uses affine coordinates. */
mp_err ec_GFp_pt_add_aff(const mp_int *px, const mp_int *py,
const mp_int *qx, const mp_int *qy, mp_int *rx,
mp_int *ry, const ECGroup *group);
/* Computes R = P - Q. Uses affine coordinates. */
mp_err ec_GFp_pt_sub_aff(const mp_int *px, const mp_int *py,
const mp_int *qx, const mp_int *qy, mp_int *rx,
mp_int *ry, const ECGroup *group);
/* Computes R = 2P. Uses affine coordinates. */
mp_err ec_GFp_pt_dbl_aff(const mp_int *px, const mp_int *py, mp_int *rx,
mp_int *ry, const ECGroup *group);
/* Validates a point on a GFp curve. */
mp_err ec_GFp_validate_point(const mp_int *px, const mp_int *py, const ECGroup *group);
#ifdef ECL_ENABLE_GFP_PT_MUL_AFF
/* Computes R = nP where R is (rx, ry) and P is (px, py). The parameters
* a, b and p are the elliptic curve coefficients and the prime that
* determines the field GFp. Uses affine coordinates. */
mp_err ec_GFp_pt_mul_aff(const mp_int *n, const mp_int *px,
const mp_int *py, mp_int *rx, mp_int *ry,
const ECGroup *group);
#endif
/* Converts a point P(px, py) from affine coordinates to Jacobian
* projective coordinates R(rx, ry, rz). */
mp_err ec_GFp_pt_aff2jac(const mp_int *px, const mp_int *py, mp_int *rx,
mp_int *ry, mp_int *rz, const ECGroup *group);
/* Converts a point P(px, py, pz) from Jacobian projective coordinates to
* affine coordinates R(rx, ry). */
mp_err ec_GFp_pt_jac2aff(const mp_int *px, const mp_int *py,
const mp_int *pz, mp_int *rx, mp_int *ry,
const ECGroup *group);
/* Checks if point P(px, py, pz) is at infinity. Uses Jacobian
* coordinates. */
mp_err ec_GFp_pt_is_inf_jac(const mp_int *px, const mp_int *py,
const mp_int *pz);
/* Sets P(px, py, pz) to be the point at infinity. Uses Jacobian
* coordinates. */
mp_err ec_GFp_pt_set_inf_jac(mp_int *px, mp_int *py, mp_int *pz);
/* Computes R = P + Q where R is (rx, ry, rz), P is (px, py, pz) and Q is
* (qx, qy, qz). Uses Jacobian coordinates. */
mp_err ec_GFp_pt_add_jac_aff(const mp_int *px, const mp_int *py,
const mp_int *pz, const mp_int *qx,
const mp_int *qy, mp_int *rx, mp_int *ry,
mp_int *rz, const ECGroup *group);
/* Computes R = 2P. Uses Jacobian coordinates. */
mp_err ec_GFp_pt_dbl_jac(const mp_int *px, const mp_int *py,
const mp_int *pz, mp_int *rx, mp_int *ry,
mp_int *rz, const ECGroup *group);
#ifdef ECL_ENABLE_GFP_PT_MUL_JAC
/* Computes R = nP where R is (rx, ry) and P is (px, py). The parameters
* a, b and p are the elliptic curve coefficients and the prime that
* determines the field GFp. Uses Jacobian coordinates. */
mp_err ec_GFp_pt_mul_jac(const mp_int *n, const mp_int *px,
const mp_int *py, mp_int *rx, mp_int *ry,
const ECGroup *group);
#endif
/* Computes R(x, y) = k1 * G + k2 * P(x, y), where G is the generator
* (base point) of the group of points on the elliptic curve. Allows k1 =
* NULL or { k2, P } = NULL. Implemented using mixed Jacobian-affine
* coordinates. Input and output values are assumed to be NOT
* field-encoded and are in affine form. */
mp_err
ec_GFp_pts_mul_jac(const mp_int *k1, const mp_int *k2, const mp_int *px,
const mp_int *py, mp_int *rx, mp_int *ry,
const ECGroup *group);
/* Computes R = nP where R is (rx, ry) and P is the base point. Elliptic
* curve points P and R can be identical. Uses mixed Modified-Jacobian
* co-ordinates for doubling and Chudnovsky Jacobian coordinates for
* additions. Assumes input is already field-encoded using field_enc, and
* returns output that is still field-encoded. Uses 5-bit window NAF
* method (algorithm 11) for scalar-point multiplication from Brown,
* Hankerson, Lopez, Menezes. Software Implementation of the NIST Elliptic
* Curves Over Prime Fields. */
mp_err
ec_GFp_pt_mul_jm_wNAF(const mp_int *n, const mp_int *px, const mp_int *py,
mp_int *rx, mp_int *ry, const ECGroup *group);
#endif /* __ecp_h_ */

View file

@ -0,0 +1,120 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
/* curve 25519 https://www.rfc-editor.org/rfc/rfc7748.txt */
#ifdef FREEBL_NO_DEPEND
#include "../stubs.h"
#endif
#include "ecl-priv.h"
#include "ecp.h"
#include "mpi.h"
#include "mplogic.h"
#include "mpi-priv.h"
#include "secmpi.h"
#include "secitem.h"
#include "secport.h"
#include <stdlib.h>
#include <stdio.h>
/*
* point validation is not necessary in general. But this checks a point (px)
* against some known bad values.
*/
SECStatus
ec_Curve25519_pt_validate(const SECItem *px)
{
PRUint8 *p;
int i;
PRUint8 forbiddenValues[12][32] = {
{ 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, 0x00 },
{ 0x01, 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 },
{ 0xe0, 0xeb, 0x7a, 0x7c, 0x3b, 0x41, 0xb8, 0xae,
0x16, 0x56, 0xe3, 0xfa, 0xf1, 0x9f, 0xc4, 0x6a,
0xda, 0x09, 0x8d, 0xeb, 0x9c, 0x32, 0xb1, 0xfd,
0x86, 0x62, 0x05, 0x16, 0x5f, 0x49, 0xb8, 0x00 },
{ 0x5f, 0x9c, 0x95, 0xbc, 0xa3, 0x50, 0x8c, 0x24,
0xb1, 0xd0, 0xb1, 0x55, 0x9c, 0x83, 0xef, 0x5b,
0x04, 0x44, 0x5c, 0xc4, 0x58, 0x1c, 0x8e, 0x86,
0xd8, 0x22, 0x4e, 0xdd, 0xd0, 0x9f, 0x11, 0x57 },
{ 0xec, 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, 0x7f },
{ 0xed, 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, 0x7f },
{ 0xee, 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, 0x7f },
{ 0xcd, 0xeb, 0x7a, 0x7c, 0x3b, 0x41, 0xb8, 0xae,
0x16, 0x56, 0xe3, 0xfa, 0xf1, 0x9f, 0xc4, 0x6a,
0xda, 0x09, 0x8d, 0xeb, 0x9c, 0x32, 0xb1, 0xfd,
0x86, 0x62, 0x05, 0x16, 0x5f, 0x49, 0xb8, 0x80 },
{ 0x4c, 0x9c, 0x95, 0xbc, 0xa3, 0x50, 0x8c, 0x24,
0xb1, 0xd0, 0xb1, 0x55, 0x9c, 0x83, 0xef, 0x5b,
0x04, 0x44, 0x5c, 0xc4, 0x58, 0x1c, 0x8e, 0x86,
0xd8, 0x22, 0x4e, 0xdd, 0xd0, 0x9f, 0x11, 0xd7 },
{ 0xd9, 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 },
{ 0xda, 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 },
{ 0xdb, 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 },
};
/* The point must not be longer than 32 (it can be smaller). */
if (px->len <= 32) {
p = px->data;
} else {
return SECFailure;
}
for (i = 0; i < PR_ARRAY_SIZE(forbiddenValues); ++i) {
if (NSS_SecureMemcmp(p, forbiddenValues[i], px->len) == 0) {
return SECFailure;
}
}
return SECSuccess;
}
/*
* Scalar multiplication for Curve25519.
* If P == NULL, the base point is used.
* Returns X = k*P
*/
SECStatus
ec_Curve25519_pt_mul(SECItem *X, SECItem *k, SECItem *P)
{
PRUint8 *px;
PRUint8 basePoint[32] = { 9 };
if (!P) {
px = basePoint;
} else {
PORT_Assert(P->len == 32);
if (P->len != 32) {
return SECFailure;
}
px = P->data;
}
return ec_Curve25519_mul(X->data, k->data, px);
}

View file

@ -0,0 +1,401 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "ecp.h"
#include "mpi.h"
#include "mplogic.h"
#include "mpi-priv.h"
/* Fast modular reduction for p256 = 2^256 - 2^224 + 2^192+ 2^96 - 1. a can be r.
* Uses algorithm 2.29 from Hankerson, Menezes, Vanstone. Guide to
* Elliptic Curve Cryptography. */
static mp_err
ec_GFp_nistp256_mod(const mp_int *a, mp_int *r, const GFMethod *meth)
{
mp_err res = MP_OKAY;
mp_size a_used = MP_USED(a);
int a_bits = mpl_significant_bits(a);
mp_digit carry;
#ifdef ECL_THIRTY_TWO_BIT
mp_digit a8 = 0, a9 = 0, a10 = 0, a11 = 0, a12 = 0, a13 = 0, a14 = 0, a15 = 0;
mp_digit r0, r1, r2, r3, r4, r5, r6, r7;
int r8; /* must be a signed value ! */
#else
mp_digit a4 = 0, a5 = 0, a6 = 0, a7 = 0;
mp_digit a4h, a4l, a5h, a5l, a6h, a6l, a7h, a7l;
mp_digit r0, r1, r2, r3;
int r4; /* must be a signed value ! */
#endif
/* for polynomials larger than twice the field size
* use regular reduction */
if (a_bits < 256) {
if (a == r)
return MP_OKAY;
return mp_copy(a, r);
}
if (a_bits > 512) {
MP_CHECKOK(mp_mod(a, &meth->irr, r));
} else {
#ifdef ECL_THIRTY_TWO_BIT
switch (a_used) {
case 16:
a15 = MP_DIGIT(a, 15);
case 15:
a14 = MP_DIGIT(a, 14);
case 14:
a13 = MP_DIGIT(a, 13);
case 13:
a12 = MP_DIGIT(a, 12);
case 12:
a11 = MP_DIGIT(a, 11);
case 11:
a10 = MP_DIGIT(a, 10);
case 10:
a9 = MP_DIGIT(a, 9);
case 9:
a8 = MP_DIGIT(a, 8);
}
r0 = MP_DIGIT(a, 0);
r1 = MP_DIGIT(a, 1);
r2 = MP_DIGIT(a, 2);
r3 = MP_DIGIT(a, 3);
r4 = MP_DIGIT(a, 4);
r5 = MP_DIGIT(a, 5);
r6 = MP_DIGIT(a, 6);
r7 = MP_DIGIT(a, 7);
/* sum 1 */
carry = 0;
MP_ADD_CARRY(r3, a11, r3, carry);
MP_ADD_CARRY(r4, a12, r4, carry);
MP_ADD_CARRY(r5, a13, r5, carry);
MP_ADD_CARRY(r6, a14, r6, carry);
MP_ADD_CARRY(r7, a15, r7, carry);
r8 = carry;
carry = 0;
MP_ADD_CARRY(r3, a11, r3, carry);
MP_ADD_CARRY(r4, a12, r4, carry);
MP_ADD_CARRY(r5, a13, r5, carry);
MP_ADD_CARRY(r6, a14, r6, carry);
MP_ADD_CARRY(r7, a15, r7, carry);
r8 += carry;
carry = 0;
/* sum 2 */
MP_ADD_CARRY(r3, a12, r3, carry);
MP_ADD_CARRY(r4, a13, r4, carry);
MP_ADD_CARRY(r5, a14, r5, carry);
MP_ADD_CARRY(r6, a15, r6, carry);
MP_ADD_CARRY(r7, 0, r7, carry);
r8 += carry;
carry = 0;
/* combine last bottom of sum 3 with second sum 2 */
MP_ADD_CARRY(r0, a8, r0, carry);
MP_ADD_CARRY(r1, a9, r1, carry);
MP_ADD_CARRY(r2, a10, r2, carry);
MP_ADD_CARRY(r3, a12, r3, carry);
MP_ADD_CARRY(r4, a13, r4, carry);
MP_ADD_CARRY(r5, a14, r5, carry);
MP_ADD_CARRY(r6, a15, r6, carry);
MP_ADD_CARRY(r7, a15, r7, carry); /* from sum 3 */
r8 += carry;
carry = 0;
/* sum 3 (rest of it)*/
MP_ADD_CARRY(r6, a14, r6, carry);
MP_ADD_CARRY(r7, 0, r7, carry);
r8 += carry;
carry = 0;
/* sum 4 (rest of it)*/
MP_ADD_CARRY(r0, a9, r0, carry);
MP_ADD_CARRY(r1, a10, r1, carry);
MP_ADD_CARRY(r2, a11, r2, carry);
MP_ADD_CARRY(r3, a13, r3, carry);
MP_ADD_CARRY(r4, a14, r4, carry);
MP_ADD_CARRY(r5, a15, r5, carry);
MP_ADD_CARRY(r6, a13, r6, carry);
MP_ADD_CARRY(r7, a8, r7, carry);
r8 += carry;
carry = 0;
/* diff 5 */
MP_SUB_BORROW(r0, a11, r0, carry);
MP_SUB_BORROW(r1, a12, r1, carry);
MP_SUB_BORROW(r2, a13, r2, carry);
MP_SUB_BORROW(r3, 0, r3, carry);
MP_SUB_BORROW(r4, 0, r4, carry);
MP_SUB_BORROW(r5, 0, r5, carry);
MP_SUB_BORROW(r6, a8, r6, carry);
MP_SUB_BORROW(r7, a10, r7, carry);
r8 -= carry;
carry = 0;
/* diff 6 */
MP_SUB_BORROW(r0, a12, r0, carry);
MP_SUB_BORROW(r1, a13, r1, carry);
MP_SUB_BORROW(r2, a14, r2, carry);
MP_SUB_BORROW(r3, a15, r3, carry);
MP_SUB_BORROW(r4, 0, r4, carry);
MP_SUB_BORROW(r5, 0, r5, carry);
MP_SUB_BORROW(r6, a9, r6, carry);
MP_SUB_BORROW(r7, a11, r7, carry);
r8 -= carry;
carry = 0;
/* diff 7 */
MP_SUB_BORROW(r0, a13, r0, carry);
MP_SUB_BORROW(r1, a14, r1, carry);
MP_SUB_BORROW(r2, a15, r2, carry);
MP_SUB_BORROW(r3, a8, r3, carry);
MP_SUB_BORROW(r4, a9, r4, carry);
MP_SUB_BORROW(r5, a10, r5, carry);
MP_SUB_BORROW(r6, 0, r6, carry);
MP_SUB_BORROW(r7, a12, r7, carry);
r8 -= carry;
carry = 0;
/* diff 8 */
MP_SUB_BORROW(r0, a14, r0, carry);
MP_SUB_BORROW(r1, a15, r1, carry);
MP_SUB_BORROW(r2, 0, r2, carry);
MP_SUB_BORROW(r3, a9, r3, carry);
MP_SUB_BORROW(r4, a10, r4, carry);
MP_SUB_BORROW(r5, a11, r5, carry);
MP_SUB_BORROW(r6, 0, r6, carry);
MP_SUB_BORROW(r7, a13, r7, carry);
r8 -= carry;
/* reduce the overflows */
while (r8 > 0) {
mp_digit r8_d = r8;
carry = 0;
MP_ADD_CARRY(r0, r8_d, r0, carry);
MP_ADD_CARRY(r1, 0, r1, carry);
MP_ADD_CARRY(r2, 0, r2, carry);
MP_ADD_CARRY(r3, 0 - r8_d, r3, carry);
MP_ADD_CARRY(r4, MP_DIGIT_MAX, r4, carry);
MP_ADD_CARRY(r5, MP_DIGIT_MAX, r5, carry);
MP_ADD_CARRY(r6, 0 - (r8_d + 1), r6, carry);
MP_ADD_CARRY(r7, (r8_d - 1), r7, carry);
r8 = carry;
}
/* reduce the underflows */
while (r8 < 0) {
mp_digit r8_d = -r8;
carry = 0;
MP_SUB_BORROW(r0, r8_d, r0, carry);
MP_SUB_BORROW(r1, 0, r1, carry);
MP_SUB_BORROW(r2, 0, r2, carry);
MP_SUB_BORROW(r3, 0 - r8_d, r3, carry);
MP_SUB_BORROW(r4, MP_DIGIT_MAX, r4, carry);
MP_SUB_BORROW(r5, MP_DIGIT_MAX, r5, carry);
MP_SUB_BORROW(r6, 0 - (r8_d + 1), r6, carry);
MP_SUB_BORROW(r7, (r8_d - 1), r7, carry);
r8 = 0 - carry;
}
if (a != r) {
MP_CHECKOK(s_mp_pad(r, 8));
}
MP_SIGN(r) = MP_ZPOS;
MP_USED(r) = 8;
MP_DIGIT(r, 7) = r7;
MP_DIGIT(r, 6) = r6;
MP_DIGIT(r, 5) = r5;
MP_DIGIT(r, 4) = r4;
MP_DIGIT(r, 3) = r3;
MP_DIGIT(r, 2) = r2;
MP_DIGIT(r, 1) = r1;
MP_DIGIT(r, 0) = r0;
/* final reduction if necessary */
if ((r7 == MP_DIGIT_MAX) &&
((r6 > 1) || ((r6 == 1) &&
(r5 || r4 || r3 ||
((r2 == MP_DIGIT_MAX) && (r1 == MP_DIGIT_MAX) && (r0 == MP_DIGIT_MAX)))))) {
MP_CHECKOK(mp_sub(r, &meth->irr, r));
}
s_mp_clamp(r);
#else
switch (a_used) {
case 8:
a7 = MP_DIGIT(a, 7);
case 7:
a6 = MP_DIGIT(a, 6);
case 6:
a5 = MP_DIGIT(a, 5);
case 5:
a4 = MP_DIGIT(a, 4);
}
a7l = a7 << 32;
a7h = a7 >> 32;
a6l = a6 << 32;
a6h = a6 >> 32;
a5l = a5 << 32;
a5h = a5 >> 32;
a4l = a4 << 32;
a4h = a4 >> 32;
r3 = MP_DIGIT(a, 3);
r2 = MP_DIGIT(a, 2);
r1 = MP_DIGIT(a, 1);
r0 = MP_DIGIT(a, 0);
/* sum 1 */
carry = 0;
MP_ADD_CARRY(r1, a5h << 32, r1, carry);
MP_ADD_CARRY(r2, a6, r2, carry);
MP_ADD_CARRY(r3, a7, r3, carry);
r4 = carry;
carry = 0;
MP_ADD_CARRY(r1, a5h << 32, r1, carry);
MP_ADD_CARRY(r2, a6, r2, carry);
MP_ADD_CARRY(r3, a7, r3, carry);
r4 += carry;
/* sum 2 */
carry = 0;
MP_ADD_CARRY(r1, a6l, r1, carry);
MP_ADD_CARRY(r2, a6h | a7l, r2, carry);
MP_ADD_CARRY(r3, a7h, r3, carry);
r4 += carry;
carry = 0;
MP_ADD_CARRY(r1, a6l, r1, carry);
MP_ADD_CARRY(r2, a6h | a7l, r2, carry);
MP_ADD_CARRY(r3, a7h, r3, carry);
r4 += carry;
/* sum 3 */
carry = 0;
MP_ADD_CARRY(r0, a4, r0, carry);
MP_ADD_CARRY(r1, a5l >> 32, r1, carry);
MP_ADD_CARRY(r2, 0, r2, carry);
MP_ADD_CARRY(r3, a7, r3, carry);
r4 += carry;
/* sum 4 */
carry = 0;
MP_ADD_CARRY(r0, a4h | a5l, r0, carry);
MP_ADD_CARRY(r1, a5h | (a6h << 32), r1, carry);
MP_ADD_CARRY(r2, a7, r2, carry);
MP_ADD_CARRY(r3, a6h | a4l, r3, carry);
r4 += carry;
/* diff 5 */
carry = 0;
MP_SUB_BORROW(r0, a5h | a6l, r0, carry);
MP_SUB_BORROW(r1, a6h, r1, carry);
MP_SUB_BORROW(r2, 0, r2, carry);
MP_SUB_BORROW(r3, (a4l >> 32) | a5l, r3, carry);
r4 -= carry;
/* diff 6 */
carry = 0;
MP_SUB_BORROW(r0, a6, r0, carry);
MP_SUB_BORROW(r1, a7, r1, carry);
MP_SUB_BORROW(r2, 0, r2, carry);
MP_SUB_BORROW(r3, a4h | (a5h << 32), r3, carry);
r4 -= carry;
/* diff 7 */
carry = 0;
MP_SUB_BORROW(r0, a6h | a7l, r0, carry);
MP_SUB_BORROW(r1, a7h | a4l, r1, carry);
MP_SUB_BORROW(r2, a4h | a5l, r2, carry);
MP_SUB_BORROW(r3, a6l, r3, carry);
r4 -= carry;
/* diff 8 */
carry = 0;
MP_SUB_BORROW(r0, a7, r0, carry);
MP_SUB_BORROW(r1, a4h << 32, r1, carry);
MP_SUB_BORROW(r2, a5, r2, carry);
MP_SUB_BORROW(r3, a6h << 32, r3, carry);
r4 -= carry;
/* reduce the overflows */
while (r4 > 0) {
mp_digit r4_long = r4;
mp_digit r4l = (r4_long << 32);
carry = 0;
MP_ADD_CARRY(r0, r4_long, r0, carry);
MP_ADD_CARRY(r1, 0 - r4l, r1, carry);
MP_ADD_CARRY(r2, MP_DIGIT_MAX, r2, carry);
MP_ADD_CARRY(r3, r4l - r4_long - 1, r3, carry);
r4 = carry;
}
/* reduce the underflows */
while (r4 < 0) {
mp_digit r4_long = -r4;
mp_digit r4l = (r4_long << 32);
carry = 0;
MP_SUB_BORROW(r0, r4_long, r0, carry);
MP_SUB_BORROW(r1, 0 - r4l, r1, carry);
MP_SUB_BORROW(r2, MP_DIGIT_MAX, r2, carry);
MP_SUB_BORROW(r3, r4l - r4_long - 1, r3, carry);
r4 = 0 - carry;
}
if (a != r) {
MP_CHECKOK(s_mp_pad(r, 4));
}
MP_SIGN(r) = MP_ZPOS;
MP_USED(r) = 4;
MP_DIGIT(r, 3) = r3;
MP_DIGIT(r, 2) = r2;
MP_DIGIT(r, 1) = r1;
MP_DIGIT(r, 0) = r0;
/* final reduction if necessary */
if ((r3 > 0xFFFFFFFF00000001ULL) ||
((r3 == 0xFFFFFFFF00000001ULL) &&
(r2 || (r1 >> 32) ||
(r1 == 0xFFFFFFFFULL && r0 == MP_DIGIT_MAX)))) {
/* very rare, just use mp_sub */
MP_CHECKOK(mp_sub(r, &meth->irr, r));
}
s_mp_clamp(r);
#endif
}
CLEANUP:
return res;
}
/* Compute the square of polynomial a, reduce modulo p256. Store the
* result in r. r could be a. Uses optimized modular reduction for p256.
*/
static mp_err
ec_GFp_nistp256_sqr(const mp_int *a, mp_int *r, const GFMethod *meth)
{
mp_err res = MP_OKAY;
MP_CHECKOK(mp_sqr(a, r));
MP_CHECKOK(ec_GFp_nistp256_mod(r, r, meth));
CLEANUP:
return res;
}
/* Compute the product of two polynomials a and b, reduce modulo p256.
* Store the result in r. r could be a or b; a could be b. Uses
* optimized modular reduction for p256. */
static mp_err
ec_GFp_nistp256_mul(const mp_int *a, const mp_int *b, mp_int *r,
const GFMethod *meth)
{
mp_err res = MP_OKAY;
MP_CHECKOK(mp_mul(a, b, r));
MP_CHECKOK(ec_GFp_nistp256_mod(r, r, meth));
CLEANUP:
return res;
}
/* Wire in fast field arithmetic and precomputation of base point for
* named curves. */
mp_err
ec_group_set_gfp256(ECGroup *group, ECCurveName name)
{
if (name == ECCurve_NIST_P256) {
group->meth->field_mod = &ec_GFp_nistp256_mod;
group->meth->field_mul = &ec_GFp_nistp256_mul;
group->meth->field_sqr = &ec_GFp_nistp256_sqr;
}
return MP_OKAY;
}

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,258 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "ecp.h"
#include "mpi.h"
#include "mplogic.h"
#include "mpi-priv.h"
/* Fast modular reduction for p384 = 2^384 - 2^128 - 2^96 + 2^32 - 1. a can be r.
* Uses algorithm 2.30 from Hankerson, Menezes, Vanstone. Guide to
* Elliptic Curve Cryptography. */
static mp_err
ec_GFp_nistp384_mod(const mp_int *a, mp_int *r, const GFMethod *meth)
{
mp_err res = MP_OKAY;
int a_bits = mpl_significant_bits(a);
int i;
/* m1, m2 are statically-allocated mp_int of exactly the size we need */
mp_int m[10];
#ifdef ECL_THIRTY_TWO_BIT
mp_digit s[10][12];
for (i = 0; i < 10; i++) {
MP_SIGN(&m[i]) = MP_ZPOS;
MP_ALLOC(&m[i]) = 12;
MP_USED(&m[i]) = 12;
MP_DIGITS(&m[i]) = s[i];
}
#else
mp_digit s[10][6];
for (i = 0; i < 10; i++) {
MP_SIGN(&m[i]) = MP_ZPOS;
MP_ALLOC(&m[i]) = 6;
MP_USED(&m[i]) = 6;
MP_DIGITS(&m[i]) = s[i];
}
#endif
#ifdef ECL_THIRTY_TWO_BIT
/* for polynomials larger than twice the field size or polynomials
* not using all words, use regular reduction */
if ((a_bits > 768) || (a_bits <= 736)) {
MP_CHECKOK(mp_mod(a, &meth->irr, r));
} else {
for (i = 0; i < 12; i++) {
s[0][i] = MP_DIGIT(a, i);
}
s[1][0] = 0;
s[1][1] = 0;
s[1][2] = 0;
s[1][3] = 0;
s[1][4] = MP_DIGIT(a, 21);
s[1][5] = MP_DIGIT(a, 22);
s[1][6] = MP_DIGIT(a, 23);
s[1][7] = 0;
s[1][8] = 0;
s[1][9] = 0;
s[1][10] = 0;
s[1][11] = 0;
for (i = 0; i < 12; i++) {
s[2][i] = MP_DIGIT(a, i + 12);
}
s[3][0] = MP_DIGIT(a, 21);
s[3][1] = MP_DIGIT(a, 22);
s[3][2] = MP_DIGIT(a, 23);
for (i = 3; i < 12; i++) {
s[3][i] = MP_DIGIT(a, i + 9);
}
s[4][0] = 0;
s[4][1] = MP_DIGIT(a, 23);
s[4][2] = 0;
s[4][3] = MP_DIGIT(a, 20);
for (i = 4; i < 12; i++) {
s[4][i] = MP_DIGIT(a, i + 8);
}
s[5][0] = 0;
s[5][1] = 0;
s[5][2] = 0;
s[5][3] = 0;
s[5][4] = MP_DIGIT(a, 20);
s[5][5] = MP_DIGIT(a, 21);
s[5][6] = MP_DIGIT(a, 22);
s[5][7] = MP_DIGIT(a, 23);
s[5][8] = 0;
s[5][9] = 0;
s[5][10] = 0;
s[5][11] = 0;
s[6][0] = MP_DIGIT(a, 20);
s[6][1] = 0;
s[6][2] = 0;
s[6][3] = MP_DIGIT(a, 21);
s[6][4] = MP_DIGIT(a, 22);
s[6][5] = MP_DIGIT(a, 23);
s[6][6] = 0;
s[6][7] = 0;
s[6][8] = 0;
s[6][9] = 0;
s[6][10] = 0;
s[6][11] = 0;
s[7][0] = MP_DIGIT(a, 23);
for (i = 1; i < 12; i++) {
s[7][i] = MP_DIGIT(a, i + 11);
}
s[8][0] = 0;
s[8][1] = MP_DIGIT(a, 20);
s[8][2] = MP_DIGIT(a, 21);
s[8][3] = MP_DIGIT(a, 22);
s[8][4] = MP_DIGIT(a, 23);
s[8][5] = 0;
s[8][6] = 0;
s[8][7] = 0;
s[8][8] = 0;
s[8][9] = 0;
s[8][10] = 0;
s[8][11] = 0;
s[9][0] = 0;
s[9][1] = 0;
s[9][2] = 0;
s[9][3] = MP_DIGIT(a, 23);
s[9][4] = MP_DIGIT(a, 23);
s[9][5] = 0;
s[9][6] = 0;
s[9][7] = 0;
s[9][8] = 0;
s[9][9] = 0;
s[9][10] = 0;
s[9][11] = 0;
MP_CHECKOK(mp_add(&m[0], &m[1], r));
MP_CHECKOK(mp_add(r, &m[1], r));
MP_CHECKOK(mp_add(r, &m[2], r));
MP_CHECKOK(mp_add(r, &m[3], r));
MP_CHECKOK(mp_add(r, &m[4], r));
MP_CHECKOK(mp_add(r, &m[5], r));
MP_CHECKOK(mp_add(r, &m[6], r));
MP_CHECKOK(mp_sub(r, &m[7], r));
MP_CHECKOK(mp_sub(r, &m[8], r));
MP_CHECKOK(mp_submod(r, &m[9], &meth->irr, r));
s_mp_clamp(r);
}
#else
/* for polynomials larger than twice the field size or polynomials
* not using all words, use regular reduction */
if ((a_bits > 768) || (a_bits <= 736)) {
MP_CHECKOK(mp_mod(a, &meth->irr, r));
} else {
for (i = 0; i < 6; i++) {
s[0][i] = MP_DIGIT(a, i);
}
s[1][0] = 0;
s[1][1] = 0;
s[1][2] = (MP_DIGIT(a, 10) >> 32) | (MP_DIGIT(a, 11) << 32);
s[1][3] = MP_DIGIT(a, 11) >> 32;
s[1][4] = 0;
s[1][5] = 0;
for (i = 0; i < 6; i++) {
s[2][i] = MP_DIGIT(a, i + 6);
}
s[3][0] = (MP_DIGIT(a, 10) >> 32) | (MP_DIGIT(a, 11) << 32);
s[3][1] = (MP_DIGIT(a, 11) >> 32) | (MP_DIGIT(a, 6) << 32);
for (i = 2; i < 6; i++) {
s[3][i] = (MP_DIGIT(a, i + 4) >> 32) | (MP_DIGIT(a, i + 5) << 32);
}
s[4][0] = (MP_DIGIT(a, 11) >> 32) << 32;
s[4][1] = MP_DIGIT(a, 10) << 32;
for (i = 2; i < 6; i++) {
s[4][i] = MP_DIGIT(a, i + 4);
}
s[5][0] = 0;
s[5][1] = 0;
s[5][2] = MP_DIGIT(a, 10);
s[5][3] = MP_DIGIT(a, 11);
s[5][4] = 0;
s[5][5] = 0;
s[6][0] = (MP_DIGIT(a, 10) << 32) >> 32;
s[6][1] = (MP_DIGIT(a, 10) >> 32) << 32;
s[6][2] = MP_DIGIT(a, 11);
s[6][3] = 0;
s[6][4] = 0;
s[6][5] = 0;
s[7][0] = (MP_DIGIT(a, 11) >> 32) | (MP_DIGIT(a, 6) << 32);
for (i = 1; i < 6; i++) {
s[7][i] = (MP_DIGIT(a, i + 5) >> 32) | (MP_DIGIT(a, i + 6) << 32);
}
s[8][0] = MP_DIGIT(a, 10) << 32;
s[8][1] = (MP_DIGIT(a, 10) >> 32) | (MP_DIGIT(a, 11) << 32);
s[8][2] = MP_DIGIT(a, 11) >> 32;
s[8][3] = 0;
s[8][4] = 0;
s[8][5] = 0;
s[9][0] = 0;
s[9][1] = (MP_DIGIT(a, 11) >> 32) << 32;
s[9][2] = MP_DIGIT(a, 11) >> 32;
s[9][3] = 0;
s[9][4] = 0;
s[9][5] = 0;
MP_CHECKOK(mp_add(&m[0], &m[1], r));
MP_CHECKOK(mp_add(r, &m[1], r));
MP_CHECKOK(mp_add(r, &m[2], r));
MP_CHECKOK(mp_add(r, &m[3], r));
MP_CHECKOK(mp_add(r, &m[4], r));
MP_CHECKOK(mp_add(r, &m[5], r));
MP_CHECKOK(mp_add(r, &m[6], r));
MP_CHECKOK(mp_sub(r, &m[7], r));
MP_CHECKOK(mp_sub(r, &m[8], r));
MP_CHECKOK(mp_submod(r, &m[9], &meth->irr, r));
s_mp_clamp(r);
}
#endif
CLEANUP:
return res;
}
/* Compute the square of polynomial a, reduce modulo p384. Store the
* result in r. r could be a. Uses optimized modular reduction for p384.
*/
static mp_err
ec_GFp_nistp384_sqr(const mp_int *a, mp_int *r, const GFMethod *meth)
{
mp_err res = MP_OKAY;
MP_CHECKOK(mp_sqr(a, r));
MP_CHECKOK(ec_GFp_nistp384_mod(r, r, meth));
CLEANUP:
return res;
}
/* Compute the product of two polynomials a and b, reduce modulo p384.
* Store the result in r. r could be a or b; a could be b. Uses
* optimized modular reduction for p384. */
static mp_err
ec_GFp_nistp384_mul(const mp_int *a, const mp_int *b, mp_int *r,
const GFMethod *meth)
{
mp_err res = MP_OKAY;
MP_CHECKOK(mp_mul(a, b, r));
MP_CHECKOK(ec_GFp_nistp384_mod(r, r, meth));
CLEANUP:
return res;
}
/* Wire in fast field arithmetic and precomputation of base point for
* named curves. */
mp_err
ec_group_set_gfp384(ECGroup *group, ECCurveName name)
{
if (name == ECCurve_NIST_P384) {
group->meth->field_mod = &ec_GFp_nistp384_mod;
group->meth->field_mul = &ec_GFp_nistp384_mul;
group->meth->field_sqr = &ec_GFp_nistp384_sqr;
}
return MP_OKAY;
}

View file

@ -0,0 +1,137 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "ecp.h"
#include "mpi.h"
#include "mplogic.h"
#include "mpi-priv.h"
#define ECP521_DIGITS ECL_CURVE_DIGITS(521)
/* Fast modular reduction for p521 = 2^521 - 1. a can be r. Uses
* algorithm 2.31 from Hankerson, Menezes, Vanstone. Guide to
* Elliptic Curve Cryptography. */
static mp_err
ec_GFp_nistp521_mod(const mp_int *a, mp_int *r, const GFMethod *meth)
{
mp_err res = MP_OKAY;
int a_bits = mpl_significant_bits(a);
unsigned int i;
/* m1, m2 are statically-allocated mp_int of exactly the size we need */
mp_int m1;
mp_digit s1[ECP521_DIGITS] = { 0 };
MP_SIGN(&m1) = MP_ZPOS;
MP_ALLOC(&m1) = ECP521_DIGITS;
MP_USED(&m1) = ECP521_DIGITS;
MP_DIGITS(&m1) = s1;
if (a_bits < 521) {
if (a == r)
return MP_OKAY;
return mp_copy(a, r);
}
/* for polynomials larger than twice the field size or polynomials
* not using all words, use regular reduction */
if (a_bits > (521 * 2)) {
MP_CHECKOK(mp_mod(a, &meth->irr, r));
} else {
#define FIRST_DIGIT (ECP521_DIGITS - 1)
for (i = FIRST_DIGIT; i < MP_USED(a) - 1; i++) {
s1[i - FIRST_DIGIT] = (MP_DIGIT(a, i) >> 9) | (MP_DIGIT(a, 1 + i) << (MP_DIGIT_BIT - 9));
}
s1[i - FIRST_DIGIT] = MP_DIGIT(a, i) >> 9;
if (a != r) {
MP_CHECKOK(s_mp_pad(r, ECP521_DIGITS));
for (i = 0; i < ECP521_DIGITS; i++) {
MP_DIGIT(r, i) = MP_DIGIT(a, i);
}
}
MP_USED(r) = ECP521_DIGITS;
MP_DIGIT(r, FIRST_DIGIT) &= 0x1FF;
MP_CHECKOK(s_mp_add(r, &m1));
if (MP_DIGIT(r, FIRST_DIGIT) & 0x200) {
MP_CHECKOK(s_mp_add_d(r, 1));
MP_DIGIT(r, FIRST_DIGIT) &= 0x1FF;
} else if (s_mp_cmp(r, &meth->irr) == 0) {
mp_zero(r);
}
s_mp_clamp(r);
}
CLEANUP:
return res;
}
/* Compute the square of polynomial a, reduce modulo p521. Store the
* result in r. r could be a. Uses optimized modular reduction for p521.
*/
static mp_err
ec_GFp_nistp521_sqr(const mp_int *a, mp_int *r, const GFMethod *meth)
{
mp_err res = MP_OKAY;
MP_CHECKOK(mp_sqr(a, r));
MP_CHECKOK(ec_GFp_nistp521_mod(r, r, meth));
CLEANUP:
return res;
}
/* Compute the product of two polynomials a and b, reduce modulo p521.
* Store the result in r. r could be a or b; a could be b. Uses
* optimized modular reduction for p521. */
static mp_err
ec_GFp_nistp521_mul(const mp_int *a, const mp_int *b, mp_int *r,
const GFMethod *meth)
{
mp_err res = MP_OKAY;
MP_CHECKOK(mp_mul(a, b, r));
MP_CHECKOK(ec_GFp_nistp521_mod(r, r, meth));
CLEANUP:
return res;
}
/* Divides two field elements. If a is NULL, then returns the inverse of
* b. */
static mp_err
ec_GFp_nistp521_div(const mp_int *a, const mp_int *b, mp_int *r,
const GFMethod *meth)
{
mp_err res = MP_OKAY;
mp_int t;
/* If a is NULL, then return the inverse of b, otherwise return a/b. */
if (a == NULL) {
return mp_invmod(b, &meth->irr, r);
} else {
/* MPI doesn't support divmod, so we implement it using invmod and
* mulmod. */
MP_CHECKOK(mp_init(&t));
MP_CHECKOK(mp_invmod(b, &meth->irr, &t));
MP_CHECKOK(mp_mul(a, &t, r));
MP_CHECKOK(ec_GFp_nistp521_mod(r, r, meth));
CLEANUP:
mp_clear(&t);
return res;
}
}
/* Wire in fast field arithmetic and precomputation of base point for
* named curves. */
mp_err
ec_group_set_gfp521(ECGroup *group, ECCurveName name)
{
if (name == ECCurve_NIST_P521) {
group->meth->field_mod = &ec_GFp_nistp521_mod;
group->meth->field_mul = &ec_GFp_nistp521_mul;
group->meth->field_sqr = &ec_GFp_nistp521_sqr;
group->meth->field_div = &ec_GFp_nistp521_div;
}
return MP_OKAY;
}

View file

@ -0,0 +1,308 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "ecp.h"
#include "mplogic.h"
#include <stdlib.h>
/* Checks if point P(px, py) is at infinity. Uses affine coordinates. */
mp_err
ec_GFp_pt_is_inf_aff(const mp_int *px, const mp_int *py)
{
if ((mp_cmp_z(px) == 0) && (mp_cmp_z(py) == 0)) {
return MP_YES;
} else {
return MP_NO;
}
}
/* Sets P(px, py) to be the point at infinity. Uses affine coordinates. */
mp_err
ec_GFp_pt_set_inf_aff(mp_int *px, mp_int *py)
{
mp_zero(px);
mp_zero(py);
return MP_OKAY;
}
/* Computes R = P + Q based on IEEE P1363 A.10.1. Elliptic curve points P,
* Q, and R can all be identical. Uses affine coordinates. Assumes input
* is already field-encoded using field_enc, and returns output that is
* still field-encoded. */
mp_err
ec_GFp_pt_add_aff(const mp_int *px, const mp_int *py, const mp_int *qx,
const mp_int *qy, mp_int *rx, mp_int *ry,
const ECGroup *group)
{
mp_err res = MP_OKAY;
mp_int lambda, temp, tempx, tempy;
MP_DIGITS(&lambda) = 0;
MP_DIGITS(&temp) = 0;
MP_DIGITS(&tempx) = 0;
MP_DIGITS(&tempy) = 0;
MP_CHECKOK(mp_init(&lambda));
MP_CHECKOK(mp_init(&temp));
MP_CHECKOK(mp_init(&tempx));
MP_CHECKOK(mp_init(&tempy));
/* if P = inf, then R = Q */
if (ec_GFp_pt_is_inf_aff(px, py) == 0) {
MP_CHECKOK(mp_copy(qx, rx));
MP_CHECKOK(mp_copy(qy, ry));
res = MP_OKAY;
goto CLEANUP;
}
/* if Q = inf, then R = P */
if (ec_GFp_pt_is_inf_aff(qx, qy) == 0) {
MP_CHECKOK(mp_copy(px, rx));
MP_CHECKOK(mp_copy(py, ry));
res = MP_OKAY;
goto CLEANUP;
}
/* if px != qx, then lambda = (py-qy) / (px-qx) */
if (mp_cmp(px, qx) != 0) {
MP_CHECKOK(group->meth->field_sub(py, qy, &tempy, group->meth));
MP_CHECKOK(group->meth->field_sub(px, qx, &tempx, group->meth));
MP_CHECKOK(group->meth->field_div(&tempy, &tempx, &lambda, group->meth));
} else {
/* if py != qy or qy = 0, then R = inf */
if (((mp_cmp(py, qy) != 0)) || (mp_cmp_z(qy) == 0)) {
mp_zero(rx);
mp_zero(ry);
res = MP_OKAY;
goto CLEANUP;
}
/* lambda = (3qx^2+a) / (2qy) */
MP_CHECKOK(group->meth->field_sqr(qx, &tempx, group->meth));
MP_CHECKOK(mp_set_int(&temp, 3));
if (group->meth->field_enc) {
MP_CHECKOK(group->meth->field_enc(&temp, &temp, group->meth));
}
MP_CHECKOK(group->meth->field_mul(&tempx, &temp, &tempx, group->meth));
MP_CHECKOK(group->meth->field_add(&tempx, &group->curvea, &tempx, group->meth));
MP_CHECKOK(mp_set_int(&temp, 2));
if (group->meth->field_enc) {
MP_CHECKOK(group->meth->field_enc(&temp, &temp, group->meth));
}
MP_CHECKOK(group->meth->field_mul(qy, &temp, &tempy, group->meth));
MP_CHECKOK(group->meth->field_div(&tempx, &tempy, &lambda, group->meth));
}
/* rx = lambda^2 - px - qx */
MP_CHECKOK(group->meth->field_sqr(&lambda, &tempx, group->meth));
MP_CHECKOK(group->meth->field_sub(&tempx, px, &tempx, group->meth));
MP_CHECKOK(group->meth->field_sub(&tempx, qx, &tempx, group->meth));
/* ry = (x1-x2) * lambda - y1 */
MP_CHECKOK(group->meth->field_sub(qx, &tempx, &tempy, group->meth));
MP_CHECKOK(group->meth->field_mul(&tempy, &lambda, &tempy, group->meth));
MP_CHECKOK(group->meth->field_sub(&tempy, qy, &tempy, group->meth));
MP_CHECKOK(mp_copy(&tempx, rx));
MP_CHECKOK(mp_copy(&tempy, ry));
CLEANUP:
mp_clear(&lambda);
mp_clear(&temp);
mp_clear(&tempx);
mp_clear(&tempy);
return res;
}
/* Computes R = P - Q. Elliptic curve points P, Q, and R can all be
* identical. Uses affine coordinates. Assumes input is already
* field-encoded using field_enc, and returns output that is still
* field-encoded. */
mp_err
ec_GFp_pt_sub_aff(const mp_int *px, const mp_int *py, const mp_int *qx,
const mp_int *qy, mp_int *rx, mp_int *ry,
const ECGroup *group)
{
mp_err res = MP_OKAY;
mp_int nqy;
MP_DIGITS(&nqy) = 0;
MP_CHECKOK(mp_init(&nqy));
/* nqy = -qy */
MP_CHECKOK(group->meth->field_neg(qy, &nqy, group->meth));
res = group->point_add(px, py, qx, &nqy, rx, ry, group);
CLEANUP:
mp_clear(&nqy);
return res;
}
/* Computes R = 2P. Elliptic curve points P and R can be identical. Uses
* affine coordinates. Assumes input is already field-encoded using
* field_enc, and returns output that is still field-encoded. */
mp_err
ec_GFp_pt_dbl_aff(const mp_int *px, const mp_int *py, mp_int *rx,
mp_int *ry, const ECGroup *group)
{
return ec_GFp_pt_add_aff(px, py, px, py, rx, ry, group);
}
/* by default, this routine is unused and thus doesn't need to be compiled */
#ifdef ECL_ENABLE_GFP_PT_MUL_AFF
/* Computes R = nP based on IEEE P1363 A.10.3. Elliptic curve points P and
* R can be identical. Uses affine coordinates. Assumes input is already
* field-encoded using field_enc, and returns output that is still
* field-encoded. */
mp_err
ec_GFp_pt_mul_aff(const mp_int *n, const mp_int *px, const mp_int *py,
mp_int *rx, mp_int *ry, const ECGroup *group)
{
mp_err res = MP_OKAY;
mp_int k, k3, qx, qy, sx, sy;
int b1, b3, i, l;
MP_DIGITS(&k) = 0;
MP_DIGITS(&k3) = 0;
MP_DIGITS(&qx) = 0;
MP_DIGITS(&qy) = 0;
MP_DIGITS(&sx) = 0;
MP_DIGITS(&sy) = 0;
MP_CHECKOK(mp_init(&k));
MP_CHECKOK(mp_init(&k3));
MP_CHECKOK(mp_init(&qx));
MP_CHECKOK(mp_init(&qy));
MP_CHECKOK(mp_init(&sx));
MP_CHECKOK(mp_init(&sy));
/* if n = 0 then r = inf */
if (mp_cmp_z(n) == 0) {
mp_zero(rx);
mp_zero(ry);
res = MP_OKAY;
goto CLEANUP;
}
/* Q = P, k = n */
MP_CHECKOK(mp_copy(px, &qx));
MP_CHECKOK(mp_copy(py, &qy));
MP_CHECKOK(mp_copy(n, &k));
/* if n < 0 then Q = -Q, k = -k */
if (mp_cmp_z(n) < 0) {
MP_CHECKOK(group->meth->field_neg(&qy, &qy, group->meth));
MP_CHECKOK(mp_neg(&k, &k));
}
#ifdef ECL_DEBUG /* basic double and add method */
l = mpl_significant_bits(&k) - 1;
MP_CHECKOK(mp_copy(&qx, &sx));
MP_CHECKOK(mp_copy(&qy, &sy));
for (i = l - 1; i >= 0; i--) {
/* S = 2S */
MP_CHECKOK(group->point_dbl(&sx, &sy, &sx, &sy, group));
/* if k_i = 1, then S = S + Q */
if (mpl_get_bit(&k, i) != 0) {
MP_CHECKOK(group->point_add(&sx, &sy, &qx, &qy, &sx, &sy, group));
}
}
#else /* double and add/subtract method from \
* standard */
/* k3 = 3 * k */
MP_CHECKOK(mp_set_int(&k3, 3));
MP_CHECKOK(mp_mul(&k, &k3, &k3));
/* S = Q */
MP_CHECKOK(mp_copy(&qx, &sx));
MP_CHECKOK(mp_copy(&qy, &sy));
/* l = index of high order bit in binary representation of 3*k */
l = mpl_significant_bits(&k3) - 1;
/* for i = l-1 downto 1 */
for (i = l - 1; i >= 1; i--) {
/* S = 2S */
MP_CHECKOK(group->point_dbl(&sx, &sy, &sx, &sy, group));
b3 = MP_GET_BIT(&k3, i);
b1 = MP_GET_BIT(&k, i);
/* if k3_i = 1 and k_i = 0, then S = S + Q */
if ((b3 == 1) && (b1 == 0)) {
MP_CHECKOK(group->point_add(&sx, &sy, &qx, &qy, &sx, &sy, group));
/* if k3_i = 0 and k_i = 1, then S = S - Q */
} else if ((b3 == 0) && (b1 == 1)) {
MP_CHECKOK(group->point_sub(&sx, &sy, &qx, &qy, &sx, &sy, group));
}
}
#endif
/* output S */
MP_CHECKOK(mp_copy(&sx, rx));
MP_CHECKOK(mp_copy(&sy, ry));
CLEANUP:
mp_clear(&k);
mp_clear(&k3);
mp_clear(&qx);
mp_clear(&qy);
mp_clear(&sx);
mp_clear(&sy);
return res;
}
#endif
/* Validates a point on a GFp curve. */
mp_err
ec_GFp_validate_point(const mp_int *px, const mp_int *py, const ECGroup *group)
{
mp_err res = MP_NO;
mp_int accl, accr, tmp, pxt, pyt;
MP_DIGITS(&accl) = 0;
MP_DIGITS(&accr) = 0;
MP_DIGITS(&tmp) = 0;
MP_DIGITS(&pxt) = 0;
MP_DIGITS(&pyt) = 0;
MP_CHECKOK(mp_init(&accl));
MP_CHECKOK(mp_init(&accr));
MP_CHECKOK(mp_init(&tmp));
MP_CHECKOK(mp_init(&pxt));
MP_CHECKOK(mp_init(&pyt));
/* 1: Verify that publicValue is not the point at infinity */
if (ec_GFp_pt_is_inf_aff(px, py) == MP_YES) {
res = MP_NO;
goto CLEANUP;
}
/* 2: Verify that the coordinates of publicValue are elements
* of the field.
*/
if ((MP_SIGN(px) == MP_NEG) || (mp_cmp(px, &group->meth->irr) >= 0) ||
(MP_SIGN(py) == MP_NEG) || (mp_cmp(py, &group->meth->irr) >= 0)) {
res = MP_NO;
goto CLEANUP;
}
/* 3: Verify that publicValue is on the curve. */
if (group->meth->field_enc) {
group->meth->field_enc(px, &pxt, group->meth);
group->meth->field_enc(py, &pyt, group->meth);
} else {
MP_CHECKOK(mp_copy(px, &pxt));
MP_CHECKOK(mp_copy(py, &pyt));
}
/* left-hand side: y^2 */
MP_CHECKOK(group->meth->field_sqr(&pyt, &accl, group->meth));
/* right-hand side: x^3 + a*x + b = (x^2 + a)*x + b by Horner's rule */
MP_CHECKOK(group->meth->field_sqr(&pxt, &tmp, group->meth));
MP_CHECKOK(group->meth->field_add(&tmp, &group->curvea, &tmp, group->meth));
MP_CHECKOK(group->meth->field_mul(&tmp, &pxt, &accr, group->meth));
MP_CHECKOK(group->meth->field_add(&accr, &group->curveb, &accr, group->meth));
/* check LHS - RHS == 0 */
MP_CHECKOK(group->meth->field_sub(&accl, &accr, &accr, group->meth));
if (mp_cmp_z(&accr) != 0) {
res = MP_NO;
goto CLEANUP;
}
/* 4: Verify that the order of the curve times the publicValue
* is the point at infinity.
*/
MP_CHECKOK(ECPoint_mul(group, &group->order, px, py, &pxt, &pyt));
if (ec_GFp_pt_is_inf_aff(&pxt, &pyt) != MP_YES) {
res = MP_NO;
goto CLEANUP;
}
res = MP_YES;
CLEANUP:
mp_clear(&accl);
mp_clear(&accr);
mp_clear(&tmp);
mp_clear(&pxt);
mp_clear(&pyt);
return res;
}

View file

@ -0,0 +1,513 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "ecp.h"
#include "mplogic.h"
#include <stdlib.h>
#ifdef ECL_DEBUG
#include <assert.h>
#endif
/* Converts a point P(px, py) from affine coordinates to Jacobian
* projective coordinates R(rx, ry, rz). Assumes input is already
* field-encoded using field_enc, and returns output that is still
* field-encoded. */
mp_err
ec_GFp_pt_aff2jac(const mp_int *px, const mp_int *py, mp_int *rx,
mp_int *ry, mp_int *rz, const ECGroup *group)
{
mp_err res = MP_OKAY;
if (ec_GFp_pt_is_inf_aff(px, py) == MP_YES) {
MP_CHECKOK(ec_GFp_pt_set_inf_jac(rx, ry, rz));
} else {
MP_CHECKOK(mp_copy(px, rx));
MP_CHECKOK(mp_copy(py, ry));
MP_CHECKOK(mp_set_int(rz, 1));
if (group->meth->field_enc) {
MP_CHECKOK(group->meth->field_enc(rz, rz, group->meth));
}
}
CLEANUP:
return res;
}
/* Converts a point P(px, py, pz) from Jacobian projective coordinates to
* affine coordinates R(rx, ry). P and R can share x and y coordinates.
* Assumes input is already field-encoded using field_enc, and returns
* output that is still field-encoded. */
mp_err
ec_GFp_pt_jac2aff(const mp_int *px, const mp_int *py, const mp_int *pz,
mp_int *rx, mp_int *ry, const ECGroup *group)
{
mp_err res = MP_OKAY;
mp_int z1, z2, z3;
MP_DIGITS(&z1) = 0;
MP_DIGITS(&z2) = 0;
MP_DIGITS(&z3) = 0;
MP_CHECKOK(mp_init(&z1));
MP_CHECKOK(mp_init(&z2));
MP_CHECKOK(mp_init(&z3));
/* if point at infinity, then set point at infinity and exit */
if (ec_GFp_pt_is_inf_jac(px, py, pz) == MP_YES) {
MP_CHECKOK(ec_GFp_pt_set_inf_aff(rx, ry));
goto CLEANUP;
}
/* transform (px, py, pz) into (px / pz^2, py / pz^3) */
if (mp_cmp_d(pz, 1) == 0) {
MP_CHECKOK(mp_copy(px, rx));
MP_CHECKOK(mp_copy(py, ry));
} else {
MP_CHECKOK(group->meth->field_div(NULL, pz, &z1, group->meth));
MP_CHECKOK(group->meth->field_sqr(&z1, &z2, group->meth));
MP_CHECKOK(group->meth->field_mul(&z1, &z2, &z3, group->meth));
MP_CHECKOK(group->meth->field_mul(px, &z2, rx, group->meth));
MP_CHECKOK(group->meth->field_mul(py, &z3, ry, group->meth));
}
CLEANUP:
mp_clear(&z1);
mp_clear(&z2);
mp_clear(&z3);
return res;
}
/* Checks if point P(px, py, pz) is at infinity. Uses Jacobian
* coordinates. */
mp_err
ec_GFp_pt_is_inf_jac(const mp_int *px, const mp_int *py, const mp_int *pz)
{
return mp_cmp_z(pz);
}
/* Sets P(px, py, pz) to be the point at infinity. Uses Jacobian
* coordinates. */
mp_err
ec_GFp_pt_set_inf_jac(mp_int *px, mp_int *py, mp_int *pz)
{
mp_zero(pz);
return MP_OKAY;
}
/* Computes R = P + Q where R is (rx, ry, rz), P is (px, py, pz) and Q is
* (qx, qy, 1). Elliptic curve points P, Q, and R can all be identical.
* Uses mixed Jacobian-affine coordinates. Assumes input is already
* field-encoded using field_enc, and returns output that is still
* field-encoded. Uses equation (2) from Brown, Hankerson, Lopez, and
* Menezes. Software Implementation of the NIST Elliptic Curves Over Prime
* Fields. */
mp_err
ec_GFp_pt_add_jac_aff(const mp_int *px, const mp_int *py, const mp_int *pz,
const mp_int *qx, const mp_int *qy, mp_int *rx,
mp_int *ry, mp_int *rz, const ECGroup *group)
{
mp_err res = MP_OKAY;
mp_int A, B, C, D, C2, C3;
MP_DIGITS(&A) = 0;
MP_DIGITS(&B) = 0;
MP_DIGITS(&C) = 0;
MP_DIGITS(&D) = 0;
MP_DIGITS(&C2) = 0;
MP_DIGITS(&C3) = 0;
MP_CHECKOK(mp_init(&A));
MP_CHECKOK(mp_init(&B));
MP_CHECKOK(mp_init(&C));
MP_CHECKOK(mp_init(&D));
MP_CHECKOK(mp_init(&C2));
MP_CHECKOK(mp_init(&C3));
/* If either P or Q is the point at infinity, then return the other
* point */
if (ec_GFp_pt_is_inf_jac(px, py, pz) == MP_YES) {
MP_CHECKOK(ec_GFp_pt_aff2jac(qx, qy, rx, ry, rz, group));
goto CLEANUP;
}
if (ec_GFp_pt_is_inf_aff(qx, qy) == MP_YES) {
MP_CHECKOK(mp_copy(px, rx));
MP_CHECKOK(mp_copy(py, ry));
MP_CHECKOK(mp_copy(pz, rz));
goto CLEANUP;
}
/* A = qx * pz^2, B = qy * pz^3 */
MP_CHECKOK(group->meth->field_sqr(pz, &A, group->meth));
MP_CHECKOK(group->meth->field_mul(&A, pz, &B, group->meth));
MP_CHECKOK(group->meth->field_mul(&A, qx, &A, group->meth));
MP_CHECKOK(group->meth->field_mul(&B, qy, &B, group->meth));
/* C = A - px, D = B - py */
MP_CHECKOK(group->meth->field_sub(&A, px, &C, group->meth));
MP_CHECKOK(group->meth->field_sub(&B, py, &D, group->meth));
if (mp_cmp_z(&C) == 0) {
/* P == Q or P == -Q */
if (mp_cmp_z(&D) == 0) {
/* P == Q */
/* It is cheaper to double (qx, qy, 1) than (px, py, pz). */
MP_DIGIT(&D, 0) = 1; /* Set D to 1. */
MP_CHECKOK(ec_GFp_pt_dbl_jac(qx, qy, &D, rx, ry, rz, group));
} else {
/* P == -Q */
MP_CHECKOK(ec_GFp_pt_set_inf_jac(rx, ry, rz));
}
goto CLEANUP;
}
/* C2 = C^2, C3 = C^3 */
MP_CHECKOK(group->meth->field_sqr(&C, &C2, group->meth));
MP_CHECKOK(group->meth->field_mul(&C, &C2, &C3, group->meth));
/* rz = pz * C */
MP_CHECKOK(group->meth->field_mul(pz, &C, rz, group->meth));
/* C = px * C^2 */
MP_CHECKOK(group->meth->field_mul(px, &C2, &C, group->meth));
/* A = D^2 */
MP_CHECKOK(group->meth->field_sqr(&D, &A, group->meth));
/* rx = D^2 - (C^3 + 2 * (px * C^2)) */
MP_CHECKOK(group->meth->field_add(&C, &C, rx, group->meth));
MP_CHECKOK(group->meth->field_add(&C3, rx, rx, group->meth));
MP_CHECKOK(group->meth->field_sub(&A, rx, rx, group->meth));
/* C3 = py * C^3 */
MP_CHECKOK(group->meth->field_mul(py, &C3, &C3, group->meth));
/* ry = D * (px * C^2 - rx) - py * C^3 */
MP_CHECKOK(group->meth->field_sub(&C, rx, ry, group->meth));
MP_CHECKOK(group->meth->field_mul(&D, ry, ry, group->meth));
MP_CHECKOK(group->meth->field_sub(ry, &C3, ry, group->meth));
CLEANUP:
mp_clear(&A);
mp_clear(&B);
mp_clear(&C);
mp_clear(&D);
mp_clear(&C2);
mp_clear(&C3);
return res;
}
/* Computes R = 2P. Elliptic curve points P and R can be identical. Uses
* Jacobian coordinates.
*
* Assumes input is already field-encoded using field_enc, and returns
* output that is still field-encoded.
*
* This routine implements Point Doubling in the Jacobian Projective
* space as described in the paper "Efficient elliptic curve exponentiation
* using mixed coordinates", by H. Cohen, A Miyaji, T. Ono.
*/
mp_err
ec_GFp_pt_dbl_jac(const mp_int *px, const mp_int *py, const mp_int *pz,
mp_int *rx, mp_int *ry, mp_int *rz, const ECGroup *group)
{
mp_err res = MP_OKAY;
mp_int t0, t1, M, S;
MP_DIGITS(&t0) = 0;
MP_DIGITS(&t1) = 0;
MP_DIGITS(&M) = 0;
MP_DIGITS(&S) = 0;
MP_CHECKOK(mp_init(&t0));
MP_CHECKOK(mp_init(&t1));
MP_CHECKOK(mp_init(&M));
MP_CHECKOK(mp_init(&S));
/* P == inf or P == -P */
if (ec_GFp_pt_is_inf_jac(px, py, pz) == MP_YES || mp_cmp_z(py) == 0) {
MP_CHECKOK(ec_GFp_pt_set_inf_jac(rx, ry, rz));
goto CLEANUP;
}
if (mp_cmp_d(pz, 1) == 0) {
/* M = 3 * px^2 + a */
MP_CHECKOK(group->meth->field_sqr(px, &t0, group->meth));
MP_CHECKOK(group->meth->field_add(&t0, &t0, &M, group->meth));
MP_CHECKOK(group->meth->field_add(&t0, &M, &t0, group->meth));
MP_CHECKOK(group->meth->field_add(&t0, &group->curvea, &M, group->meth));
} else if (MP_SIGN(&group->curvea) == MP_NEG &&
MP_USED(&group->curvea) == 1 &&
MP_DIGIT(&group->curvea, 0) == 3) {
/* M = 3 * (px + pz^2) * (px - pz^2) */
MP_CHECKOK(group->meth->field_sqr(pz, &M, group->meth));
MP_CHECKOK(group->meth->field_add(px, &M, &t0, group->meth));
MP_CHECKOK(group->meth->field_sub(px, &M, &t1, group->meth));
MP_CHECKOK(group->meth->field_mul(&t0, &t1, &M, group->meth));
MP_CHECKOK(group->meth->field_add(&M, &M, &t0, group->meth));
MP_CHECKOK(group->meth->field_add(&t0, &M, &M, group->meth));
} else {
/* M = 3 * (px^2) + a * (pz^4) */
MP_CHECKOK(group->meth->field_sqr(px, &t0, group->meth));
MP_CHECKOK(group->meth->field_add(&t0, &t0, &M, group->meth));
MP_CHECKOK(group->meth->field_add(&t0, &M, &t0, group->meth));
MP_CHECKOK(group->meth->field_sqr(pz, &M, group->meth));
MP_CHECKOK(group->meth->field_sqr(&M, &M, group->meth));
MP_CHECKOK(group->meth->field_mul(&M, &group->curvea, &M, group->meth));
MP_CHECKOK(group->meth->field_add(&M, &t0, &M, group->meth));
}
/* rz = 2 * py * pz */
/* t0 = 4 * py^2 */
if (mp_cmp_d(pz, 1) == 0) {
MP_CHECKOK(group->meth->field_add(py, py, rz, group->meth));
MP_CHECKOK(group->meth->field_sqr(rz, &t0, group->meth));
} else {
MP_CHECKOK(group->meth->field_add(py, py, &t0, group->meth));
MP_CHECKOK(group->meth->field_mul(&t0, pz, rz, group->meth));
MP_CHECKOK(group->meth->field_sqr(&t0, &t0, group->meth));
}
/* S = 4 * px * py^2 = px * (2 * py)^2 */
MP_CHECKOK(group->meth->field_mul(px, &t0, &S, group->meth));
/* rx = M^2 - 2 * S */
MP_CHECKOK(group->meth->field_add(&S, &S, &t1, group->meth));
MP_CHECKOK(group->meth->field_sqr(&M, rx, group->meth));
MP_CHECKOK(group->meth->field_sub(rx, &t1, rx, group->meth));
/* ry = M * (S - rx) - 8 * py^4 */
MP_CHECKOK(group->meth->field_sqr(&t0, &t1, group->meth));
if (mp_isodd(&t1)) {
MP_CHECKOK(mp_add(&t1, &group->meth->irr, &t1));
}
MP_CHECKOK(mp_div_2(&t1, &t1));
MP_CHECKOK(group->meth->field_sub(&S, rx, &S, group->meth));
MP_CHECKOK(group->meth->field_mul(&M, &S, &M, group->meth));
MP_CHECKOK(group->meth->field_sub(&M, &t1, ry, group->meth));
CLEANUP:
mp_clear(&t0);
mp_clear(&t1);
mp_clear(&M);
mp_clear(&S);
return res;
}
/* by default, this routine is unused and thus doesn't need to be compiled */
#ifdef ECL_ENABLE_GFP_PT_MUL_JAC
/* Computes R = nP where R is (rx, ry) and P is (px, py). The parameters
* a, b and p are the elliptic curve coefficients and the prime that
* determines the field GFp. Elliptic curve points P and R can be
* identical. Uses mixed Jacobian-affine coordinates. Assumes input is
* already field-encoded using field_enc, and returns output that is still
* field-encoded. Uses 4-bit window method. */
mp_err
ec_GFp_pt_mul_jac(const mp_int *n, const mp_int *px, const mp_int *py,
mp_int *rx, mp_int *ry, const ECGroup *group)
{
mp_err res = MP_OKAY;
mp_int precomp[16][2], rz;
int i, ni, d;
MP_DIGITS(&rz) = 0;
for (i = 0; i < 16; i++) {
MP_DIGITS(&precomp[i][0]) = 0;
MP_DIGITS(&precomp[i][1]) = 0;
}
ARGCHK(group != NULL, MP_BADARG);
ARGCHK((n != NULL) && (px != NULL) && (py != NULL), MP_BADARG);
/* initialize precomputation table */
for (i = 0; i < 16; i++) {
MP_CHECKOK(mp_init(&precomp[i][0]));
MP_CHECKOK(mp_init(&precomp[i][1]));
}
/* fill precomputation table */
mp_zero(&precomp[0][0]);
mp_zero(&precomp[0][1]);
MP_CHECKOK(mp_copy(px, &precomp[1][0]));
MP_CHECKOK(mp_copy(py, &precomp[1][1]));
for (i = 2; i < 16; i++) {
MP_CHECKOK(group->point_add(&precomp[1][0], &precomp[1][1],
&precomp[i - 1][0], &precomp[i - 1][1],
&precomp[i][0], &precomp[i][1], group));
}
d = (mpl_significant_bits(n) + 3) / 4;
/* R = inf */
MP_CHECKOK(mp_init(&rz));
MP_CHECKOK(ec_GFp_pt_set_inf_jac(rx, ry, &rz));
for (i = d - 1; i >= 0; i--) {
/* compute window ni */
ni = MP_GET_BIT(n, 4 * i + 3);
ni <<= 1;
ni |= MP_GET_BIT(n, 4 * i + 2);
ni <<= 1;
ni |= MP_GET_BIT(n, 4 * i + 1);
ni <<= 1;
ni |= MP_GET_BIT(n, 4 * i);
/* R = 2^4 * R */
MP_CHECKOK(ec_GFp_pt_dbl_jac(rx, ry, &rz, rx, ry, &rz, group));
MP_CHECKOK(ec_GFp_pt_dbl_jac(rx, ry, &rz, rx, ry, &rz, group));
MP_CHECKOK(ec_GFp_pt_dbl_jac(rx, ry, &rz, rx, ry, &rz, group));
MP_CHECKOK(ec_GFp_pt_dbl_jac(rx, ry, &rz, rx, ry, &rz, group));
/* R = R + (ni * P) */
MP_CHECKOK(ec_GFp_pt_add_jac_aff(rx, ry, &rz, &precomp[ni][0], &precomp[ni][1], rx, ry,
&rz, group));
}
/* convert result S to affine coordinates */
MP_CHECKOK(ec_GFp_pt_jac2aff(rx, ry, &rz, rx, ry, group));
CLEANUP:
mp_clear(&rz);
for (i = 0; i < 16; i++) {
mp_clear(&precomp[i][0]);
mp_clear(&precomp[i][1]);
}
return res;
}
#endif
/* Elliptic curve scalar-point multiplication. Computes R(x, y) = k1 * G +
* k2 * P(x, y), where G is the generator (base point) of the group of
* points on the elliptic curve. Allows k1 = NULL or { k2, P } = NULL.
* Uses mixed Jacobian-affine coordinates. Input and output values are
* assumed to be NOT field-encoded. Uses algorithm 15 (simultaneous
* multiple point multiplication) from Brown, Hankerson, Lopez, Menezes.
* Software Implementation of the NIST Elliptic Curves over Prime Fields. */
mp_err
ec_GFp_pts_mul_jac(const mp_int *k1, const mp_int *k2, const mp_int *px,
const mp_int *py, mp_int *rx, mp_int *ry,
const ECGroup *group)
{
mp_err res = MP_OKAY;
mp_int precomp[4][4][2];
mp_int rz;
const mp_int *a, *b;
unsigned int i, j;
int ai, bi, d;
for (i = 0; i < 4; i++) {
for (j = 0; j < 4; j++) {
MP_DIGITS(&precomp[i][j][0]) = 0;
MP_DIGITS(&precomp[i][j][1]) = 0;
}
}
MP_DIGITS(&rz) = 0;
ARGCHK(group != NULL, MP_BADARG);
ARGCHK(!((k1 == NULL) && ((k2 == NULL) || (px == NULL) || (py == NULL))), MP_BADARG);
/* if some arguments are not defined used ECPoint_mul */
if (k1 == NULL) {
return ECPoint_mul(group, k2, px, py, rx, ry);
} else if ((k2 == NULL) || (px == NULL) || (py == NULL)) {
return ECPoint_mul(group, k1, NULL, NULL, rx, ry);
}
/* initialize precomputation table */
for (i = 0; i < 4; i++) {
for (j = 0; j < 4; j++) {
MP_CHECKOK(mp_init(&precomp[i][j][0]));
MP_CHECKOK(mp_init(&precomp[i][j][1]));
}
}
/* fill precomputation table */
/* assign {k1, k2} = {a, b} such that len(a) >= len(b) */
if (mpl_significant_bits(k1) < mpl_significant_bits(k2)) {
a = k2;
b = k1;
if (group->meth->field_enc) {
MP_CHECKOK(group->meth->field_enc(px, &precomp[1][0][0], group->meth));
MP_CHECKOK(group->meth->field_enc(py, &precomp[1][0][1], group->meth));
} else {
MP_CHECKOK(mp_copy(px, &precomp[1][0][0]));
MP_CHECKOK(mp_copy(py, &precomp[1][0][1]));
}
MP_CHECKOK(mp_copy(&group->genx, &precomp[0][1][0]));
MP_CHECKOK(mp_copy(&group->geny, &precomp[0][1][1]));
} else {
a = k1;
b = k2;
MP_CHECKOK(mp_copy(&group->genx, &precomp[1][0][0]));
MP_CHECKOK(mp_copy(&group->geny, &precomp[1][0][1]));
if (group->meth->field_enc) {
MP_CHECKOK(group->meth->field_enc(px, &precomp[0][1][0], group->meth));
MP_CHECKOK(group->meth->field_enc(py, &precomp[0][1][1], group->meth));
} else {
MP_CHECKOK(mp_copy(px, &precomp[0][1][0]));
MP_CHECKOK(mp_copy(py, &precomp[0][1][1]));
}
}
/* precompute [*][0][*] */
mp_zero(&precomp[0][0][0]);
mp_zero(&precomp[0][0][1]);
MP_CHECKOK(group->point_dbl(&precomp[1][0][0], &precomp[1][0][1],
&precomp[2][0][0], &precomp[2][0][1], group));
MP_CHECKOK(group->point_add(&precomp[1][0][0], &precomp[1][0][1],
&precomp[2][0][0], &precomp[2][0][1],
&precomp[3][0][0], &precomp[3][0][1], group));
/* precompute [*][1][*] */
for (i = 1; i < 4; i++) {
MP_CHECKOK(group->point_add(&precomp[0][1][0], &precomp[0][1][1],
&precomp[i][0][0], &precomp[i][0][1],
&precomp[i][1][0], &precomp[i][1][1], group));
}
/* precompute [*][2][*] */
MP_CHECKOK(group->point_dbl(&precomp[0][1][0], &precomp[0][1][1],
&precomp[0][2][0], &precomp[0][2][1], group));
for (i = 1; i < 4; i++) {
MP_CHECKOK(group->point_add(&precomp[0][2][0], &precomp[0][2][1],
&precomp[i][0][0], &precomp[i][0][1],
&precomp[i][2][0], &precomp[i][2][1], group));
}
/* precompute [*][3][*] */
MP_CHECKOK(group->point_add(&precomp[0][1][0], &precomp[0][1][1],
&precomp[0][2][0], &precomp[0][2][1],
&precomp[0][3][0], &precomp[0][3][1], group));
for (i = 1; i < 4; i++) {
MP_CHECKOK(group->point_add(&precomp[0][3][0], &precomp[0][3][1],
&precomp[i][0][0], &precomp[i][0][1],
&precomp[i][3][0], &precomp[i][3][1], group));
}
d = (mpl_significant_bits(a) + 1) / 2;
/* R = inf */
MP_CHECKOK(mp_init(&rz));
MP_CHECKOK(ec_GFp_pt_set_inf_jac(rx, ry, &rz));
for (i = d; i-- > 0;) {
ai = MP_GET_BIT(a, 2 * i + 1);
ai <<= 1;
ai |= MP_GET_BIT(a, 2 * i);
bi = MP_GET_BIT(b, 2 * i + 1);
bi <<= 1;
bi |= MP_GET_BIT(b, 2 * i);
/* R = 2^2 * R */
MP_CHECKOK(ec_GFp_pt_dbl_jac(rx, ry, &rz, rx, ry, &rz, group));
MP_CHECKOK(ec_GFp_pt_dbl_jac(rx, ry, &rz, rx, ry, &rz, group));
/* R = R + (ai * A + bi * B) */
MP_CHECKOK(ec_GFp_pt_add_jac_aff(rx, ry, &rz, &precomp[ai][bi][0], &precomp[ai][bi][1],
rx, ry, &rz, group));
}
MP_CHECKOK(ec_GFp_pt_jac2aff(rx, ry, &rz, rx, ry, group));
if (group->meth->field_dec) {
MP_CHECKOK(group->meth->field_dec(rx, rx, group->meth));
MP_CHECKOK(group->meth->field_dec(ry, ry, group->meth));
}
CLEANUP:
mp_clear(&rz);
for (i = 0; i < 4; i++) {
for (j = 0; j < 4; j++) {
mp_clear(&precomp[i][j][0]);
mp_clear(&precomp[i][j][1]);
}
}
return res;
}

View file

@ -0,0 +1,283 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "ecp.h"
#include "ecl-priv.h"
#include "mplogic.h"
#include <stdlib.h>
#define MAX_SCRATCH 6
/* Computes R = 2P. Elliptic curve points P and R can be identical. Uses
* Modified Jacobian coordinates.
*
* Assumes input is already field-encoded using field_enc, and returns
* output that is still field-encoded.
*
*/
static mp_err
ec_GFp_pt_dbl_jm(const mp_int *px, const mp_int *py, const mp_int *pz,
const mp_int *paz4, mp_int *rx, mp_int *ry, mp_int *rz,
mp_int *raz4, mp_int scratch[], const ECGroup *group)
{
mp_err res = MP_OKAY;
mp_int *t0, *t1, *M, *S;
t0 = &scratch[0];
t1 = &scratch[1];
M = &scratch[2];
S = &scratch[3];
#if MAX_SCRATCH < 4
#error "Scratch array defined too small "
#endif
/* Check for point at infinity */
if (ec_GFp_pt_is_inf_jac(px, py, pz) == MP_YES) {
/* Set r = pt at infinity by setting rz = 0 */
MP_CHECKOK(ec_GFp_pt_set_inf_jac(rx, ry, rz));
goto CLEANUP;
}
/* M = 3 (px^2) + a*(pz^4) */
MP_CHECKOK(group->meth->field_sqr(px, t0, group->meth));
MP_CHECKOK(group->meth->field_add(t0, t0, M, group->meth));
MP_CHECKOK(group->meth->field_add(t0, M, t0, group->meth));
MP_CHECKOK(group->meth->field_add(t0, paz4, M, group->meth));
/* rz = 2 * py * pz */
MP_CHECKOK(group->meth->field_mul(py, pz, S, group->meth));
MP_CHECKOK(group->meth->field_add(S, S, rz, group->meth));
/* t0 = 2y^2 , t1 = 8y^4 */
MP_CHECKOK(group->meth->field_sqr(py, t0, group->meth));
MP_CHECKOK(group->meth->field_add(t0, t0, t0, group->meth));
MP_CHECKOK(group->meth->field_sqr(t0, t1, group->meth));
MP_CHECKOK(group->meth->field_add(t1, t1, t1, group->meth));
/* S = 4 * px * py^2 = 2 * px * t0 */
MP_CHECKOK(group->meth->field_mul(px, t0, S, group->meth));
MP_CHECKOK(group->meth->field_add(S, S, S, group->meth));
/* rx = M^2 - 2S */
MP_CHECKOK(group->meth->field_sqr(M, rx, group->meth));
MP_CHECKOK(group->meth->field_sub(rx, S, rx, group->meth));
MP_CHECKOK(group->meth->field_sub(rx, S, rx, group->meth));
/* ry = M * (S - rx) - t1 */
MP_CHECKOK(group->meth->field_sub(S, rx, S, group->meth));
MP_CHECKOK(group->meth->field_mul(S, M, ry, group->meth));
MP_CHECKOK(group->meth->field_sub(ry, t1, ry, group->meth));
/* ra*z^4 = 2*t1*(apz4) */
MP_CHECKOK(group->meth->field_mul(paz4, t1, raz4, group->meth));
MP_CHECKOK(group->meth->field_add(raz4, raz4, raz4, group->meth));
CLEANUP:
return res;
}
/* Computes R = P + Q where R is (rx, ry, rz), P is (px, py, pz) and Q is
* (qx, qy, 1). Elliptic curve points P, Q, and R can all be identical.
* Uses mixed Modified_Jacobian-affine coordinates. Assumes input is
* already field-encoded using field_enc, and returns output that is still
* field-encoded. */
static mp_err
ec_GFp_pt_add_jm_aff(const mp_int *px, const mp_int *py, const mp_int *pz,
const mp_int *paz4, const mp_int *qx,
const mp_int *qy, mp_int *rx, mp_int *ry, mp_int *rz,
mp_int *raz4, mp_int scratch[], const ECGroup *group)
{
mp_err res = MP_OKAY;
mp_int *A, *B, *C, *D, *C2, *C3;
A = &scratch[0];
B = &scratch[1];
C = &scratch[2];
D = &scratch[3];
C2 = &scratch[4];
C3 = &scratch[5];
#if MAX_SCRATCH < 6
#error "Scratch array defined too small "
#endif
/* If either P or Q is the point at infinity, then return the other
* point */
if (ec_GFp_pt_is_inf_jac(px, py, pz) == MP_YES) {
MP_CHECKOK(ec_GFp_pt_aff2jac(qx, qy, rx, ry, rz, group));
MP_CHECKOK(group->meth->field_sqr(rz, raz4, group->meth));
MP_CHECKOK(group->meth->field_sqr(raz4, raz4, group->meth));
MP_CHECKOK(group->meth->field_mul(raz4, &group->curvea, raz4, group->meth));
goto CLEANUP;
}
if (ec_GFp_pt_is_inf_aff(qx, qy) == MP_YES) {
MP_CHECKOK(mp_copy(px, rx));
MP_CHECKOK(mp_copy(py, ry));
MP_CHECKOK(mp_copy(pz, rz));
MP_CHECKOK(mp_copy(paz4, raz4));
goto CLEANUP;
}
/* A = qx * pz^2, B = qy * pz^3 */
MP_CHECKOK(group->meth->field_sqr(pz, A, group->meth));
MP_CHECKOK(group->meth->field_mul(A, pz, B, group->meth));
MP_CHECKOK(group->meth->field_mul(A, qx, A, group->meth));
MP_CHECKOK(group->meth->field_mul(B, qy, B, group->meth));
/* C = A - px, D = B - py */
MP_CHECKOK(group->meth->field_sub(A, px, C, group->meth));
MP_CHECKOK(group->meth->field_sub(B, py, D, group->meth));
/* C2 = C^2, C3 = C^3 */
MP_CHECKOK(group->meth->field_sqr(C, C2, group->meth));
MP_CHECKOK(group->meth->field_mul(C, C2, C3, group->meth));
/* rz = pz * C */
MP_CHECKOK(group->meth->field_mul(pz, C, rz, group->meth));
/* C = px * C^2 */
MP_CHECKOK(group->meth->field_mul(px, C2, C, group->meth));
/* A = D^2 */
MP_CHECKOK(group->meth->field_sqr(D, A, group->meth));
/* rx = D^2 - (C^3 + 2 * (px * C^2)) */
MP_CHECKOK(group->meth->field_add(C, C, rx, group->meth));
MP_CHECKOK(group->meth->field_add(C3, rx, rx, group->meth));
MP_CHECKOK(group->meth->field_sub(A, rx, rx, group->meth));
/* C3 = py * C^3 */
MP_CHECKOK(group->meth->field_mul(py, C3, C3, group->meth));
/* ry = D * (px * C^2 - rx) - py * C^3 */
MP_CHECKOK(group->meth->field_sub(C, rx, ry, group->meth));
MP_CHECKOK(group->meth->field_mul(D, ry, ry, group->meth));
MP_CHECKOK(group->meth->field_sub(ry, C3, ry, group->meth));
/* raz4 = a * rz^4 */
MP_CHECKOK(group->meth->field_sqr(rz, raz4, group->meth));
MP_CHECKOK(group->meth->field_sqr(raz4, raz4, group->meth));
MP_CHECKOK(group->meth->field_mul(raz4, &group->curvea, raz4, group->meth));
CLEANUP:
return res;
}
/* Computes R = nP where R is (rx, ry) and P is the base point. Elliptic
* curve points P and R can be identical. Uses mixed Modified-Jacobian
* co-ordinates for doubling and Chudnovsky Jacobian coordinates for
* additions. Assumes input is already field-encoded using field_enc, and
* returns output that is still field-encoded. Uses 5-bit window NAF
* method (algorithm 11) for scalar-point multiplication from Brown,
* Hankerson, Lopez, Menezes. Software Implementation of the NIST Elliptic
* Curves Over Prime Fields. */
mp_err
ec_GFp_pt_mul_jm_wNAF(const mp_int *n, const mp_int *px, const mp_int *py,
mp_int *rx, mp_int *ry, const ECGroup *group)
{
mp_err res = MP_OKAY;
mp_int precomp[16][2], rz, tpx, tpy;
mp_int raz4;
mp_int scratch[MAX_SCRATCH];
signed char *naf = NULL;
int i, orderBitSize;
MP_DIGITS(&rz) = 0;
MP_DIGITS(&raz4) = 0;
MP_DIGITS(&tpx) = 0;
MP_DIGITS(&tpy) = 0;
for (i = 0; i < 16; i++) {
MP_DIGITS(&precomp[i][0]) = 0;
MP_DIGITS(&precomp[i][1]) = 0;
}
for (i = 0; i < MAX_SCRATCH; i++) {
MP_DIGITS(&scratch[i]) = 0;
}
ARGCHK(group != NULL, MP_BADARG);
ARGCHK((n != NULL) && (px != NULL) && (py != NULL), MP_BADARG);
/* initialize precomputation table */
MP_CHECKOK(mp_init(&tpx));
MP_CHECKOK(mp_init(&tpy));
;
MP_CHECKOK(mp_init(&rz));
MP_CHECKOK(mp_init(&raz4));
for (i = 0; i < 16; i++) {
MP_CHECKOK(mp_init(&precomp[i][0]));
MP_CHECKOK(mp_init(&precomp[i][1]));
}
for (i = 0; i < MAX_SCRATCH; i++) {
MP_CHECKOK(mp_init(&scratch[i]));
}
/* Set out[8] = P */
MP_CHECKOK(mp_copy(px, &precomp[8][0]));
MP_CHECKOK(mp_copy(py, &precomp[8][1]));
/* Set (tpx, tpy) = 2P */
MP_CHECKOK(group->point_dbl(&precomp[8][0], &precomp[8][1], &tpx, &tpy,
group));
/* Set 3P, 5P, ..., 15P */
for (i = 8; i < 15; i++) {
MP_CHECKOK(group->point_add(&precomp[i][0], &precomp[i][1], &tpx, &tpy,
&precomp[i + 1][0], &precomp[i + 1][1],
group));
}
/* Set -15P, -13P, ..., -P */
for (i = 0; i < 8; i++) {
MP_CHECKOK(mp_copy(&precomp[15 - i][0], &precomp[i][0]));
MP_CHECKOK(group->meth->field_neg(&precomp[15 - i][1], &precomp[i][1],
group->meth));
}
/* R = inf */
MP_CHECKOK(ec_GFp_pt_set_inf_jac(rx, ry, &rz));
orderBitSize = mpl_significant_bits(&group->order);
/* Allocate memory for NAF */
naf = (signed char *)malloc(sizeof(signed char) * (orderBitSize + 1));
if (naf == NULL) {
res = MP_MEM;
goto CLEANUP;
}
/* Compute 5NAF */
ec_compute_wNAF(naf, orderBitSize, n, 5);
/* wNAF method */
for (i = orderBitSize; i >= 0; i--) {
/* R = 2R */
ec_GFp_pt_dbl_jm(rx, ry, &rz, &raz4, rx, ry, &rz,
&raz4, scratch, group);
if (naf[i] != 0) {
ec_GFp_pt_add_jm_aff(rx, ry, &rz, &raz4,
&precomp[(naf[i] + 15) / 2][0],
&precomp[(naf[i] + 15) / 2][1], rx, ry,
&rz, &raz4, scratch, group);
}
}
/* convert result S to affine coordinates */
MP_CHECKOK(ec_GFp_pt_jac2aff(rx, ry, &rz, rx, ry, group));
CLEANUP:
for (i = 0; i < MAX_SCRATCH; i++) {
mp_clear(&scratch[i]);
}
for (i = 0; i < 16; i++) {
mp_clear(&precomp[i][0]);
mp_clear(&precomp[i][1]);
}
mp_clear(&tpx);
mp_clear(&tpy);
mp_clear(&rz);
mp_clear(&raz4);
free(naf);
return res;
}

View file

@ -0,0 +1,154 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
/* Uses Montgomery reduction for field arithmetic. See mpi/mpmontg.c for
* code implementation. */
#include "mpi.h"
#include "mplogic.h"
#include "mpi-priv.h"
#include "ecl-priv.h"
#include "ecp.h"
#include <stdlib.h>
#include <stdio.h>
/* Construct a generic GFMethod for arithmetic over prime fields with
* irreducible irr. */
GFMethod *
GFMethod_consGFp_mont(const mp_int *irr)
{
mp_err res = MP_OKAY;
GFMethod *meth = NULL;
mp_mont_modulus *mmm;
meth = GFMethod_consGFp(irr);
if (meth == NULL)
return NULL;
mmm = (mp_mont_modulus *)malloc(sizeof(mp_mont_modulus));
if (mmm == NULL) {
res = MP_MEM;
goto CLEANUP;
}
meth->field_mul = &ec_GFp_mul_mont;
meth->field_sqr = &ec_GFp_sqr_mont;
meth->field_div = &ec_GFp_div_mont;
meth->field_enc = &ec_GFp_enc_mont;
meth->field_dec = &ec_GFp_dec_mont;
meth->extra1 = mmm;
meth->extra2 = NULL;
meth->extra_free = &ec_GFp_extra_free_mont;
mmm->N = meth->irr;
mmm->n0prime = 0 - s_mp_invmod_radix(MP_DIGIT(&meth->irr, 0));
CLEANUP:
if (res != MP_OKAY) {
GFMethod_free(meth);
return NULL;
}
return meth;
}
/* Wrapper functions for generic prime field arithmetic. */
/* Field multiplication using Montgomery reduction. */
mp_err
ec_GFp_mul_mont(const mp_int *a, const mp_int *b, mp_int *r,
const GFMethod *meth)
{
mp_err res = MP_OKAY;
#ifdef MP_MONT_USE_MP_MUL
/* if MP_MONT_USE_MP_MUL is defined, then the function s_mp_mul_mont
* is not implemented and we have to use mp_mul and s_mp_redc directly
*/
MP_CHECKOK(mp_mul(a, b, r));
MP_CHECKOK(s_mp_redc(r, (mp_mont_modulus *)meth->extra1));
#else
mp_int s;
MP_DIGITS(&s) = 0;
/* s_mp_mul_mont doesn't allow source and destination to be the same */
if ((a == r) || (b == r)) {
MP_CHECKOK(mp_init(&s));
MP_CHECKOK(s_mp_mul_mont(a, b, &s, (mp_mont_modulus *)meth->extra1));
MP_CHECKOK(mp_copy(&s, r));
mp_clear(&s);
} else {
return s_mp_mul_mont(a, b, r, (mp_mont_modulus *)meth->extra1);
}
#endif
CLEANUP:
return res;
}
/* Field squaring using Montgomery reduction. */
mp_err
ec_GFp_sqr_mont(const mp_int *a, mp_int *r, const GFMethod *meth)
{
return ec_GFp_mul_mont(a, a, r, meth);
}
/* Field division using Montgomery reduction. */
mp_err
ec_GFp_div_mont(const mp_int *a, const mp_int *b, mp_int *r,
const GFMethod *meth)
{
mp_err res = MP_OKAY;
/* if A=aZ represents a encoded in montgomery coordinates with Z and #
* and \ respectively represent multiplication and division in
* montgomery coordinates, then A\B = (a/b)Z = (A/B)Z and Binv =
* (1/b)Z = (1/B)(Z^2) where B # Binv = Z */
MP_CHECKOK(ec_GFp_div(a, b, r, meth));
MP_CHECKOK(ec_GFp_enc_mont(r, r, meth));
if (a == NULL) {
MP_CHECKOK(ec_GFp_enc_mont(r, r, meth));
}
CLEANUP:
return res;
}
/* Encode a field element in Montgomery form. See s_mp_to_mont in
* mpi/mpmontg.c */
mp_err
ec_GFp_enc_mont(const mp_int *a, mp_int *r, const GFMethod *meth)
{
mp_mont_modulus *mmm;
mp_err res = MP_OKAY;
mmm = (mp_mont_modulus *)meth->extra1;
MP_CHECKOK(mp_copy(a, r));
MP_CHECKOK(s_mp_lshd(r, MP_USED(&mmm->N)));
MP_CHECKOK(mp_mod(r, &mmm->N, r));
CLEANUP:
return res;
}
/* Decode a field element from Montgomery form. */
mp_err
ec_GFp_dec_mont(const mp_int *a, mp_int *r, const GFMethod *meth)
{
mp_err res = MP_OKAY;
if (a != r) {
MP_CHECKOK(mp_copy(a, r));
}
MP_CHECKOK(s_mp_redc(r, (mp_mont_modulus *)meth->extra1));
CLEANUP:
return res;
}
/* Free the memory allocated to the extra fields of Montgomery GFMethod
* object. */
void
ec_GFp_extra_free_mont(GFMethod *meth)
{
if (meth->extra1 != NULL) {
free(meth->extra1);
meth->extra1 = NULL;
}
}

View file

@ -0,0 +1,121 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "mpi.h"
#include "mplogic.h"
#include "ecl.h"
#include "ecp.h"
#include "ecl-priv.h"
#include <sys/types.h>
#include <stdio.h>
#include <time.h>
#include <sys/time.h>
#include <sys/resource.h>
/* Returns 2^e as an integer. This is meant to be used for small powers of
* two. */
int ec_twoTo(int e);
/* Number of bits of scalar to test */
#define BITSIZE 160
/* Time k repetitions of operation op. */
#define M_TimeOperation(op, k) \
{ \
double dStart, dNow, dUserTime; \
struct rusage ru; \
int i; \
getrusage(RUSAGE_SELF, &ru); \
dStart = (double)ru.ru_utime.tv_sec + (double)ru.ru_utime.tv_usec * 0.000001; \
for (i = 0; i < k; i++) { \
{ \
op; \
} \
}; \
getrusage(RUSAGE_SELF, &ru); \
dNow = (double)ru.ru_utime.tv_sec + (double)ru.ru_utime.tv_usec * 0.000001; \
dUserTime = dNow - dStart; \
if (dUserTime) \
printf(" %-45s\n k: %6i, t: %6.2f sec\n", #op, k, dUserTime); \
}
/* Tests wNAF computation. Non-adjacent-form is discussed in the paper: D.
* Hankerson, J. Hernandez and A. Menezes, "Software implementation of
* elliptic curve cryptography over binary fields", Proc. CHES 2000. */
mp_err
main(void)
{
signed char naf[BITSIZE + 1];
ECGroup *group = NULL;
mp_int k;
mp_int *scalar;
int i, count;
int res;
int w = 5;
char s[1000];
/* Get a 160 bit scalar to compute wNAF from */
group = ECGroup_fromName(ECCurve_SECG_PRIME_160R1);
scalar = &group->genx;
/* Compute wNAF representation of scalar */
ec_compute_wNAF(naf, BITSIZE, scalar, w);
/* Verify correctness of representation */
mp_init(&k); /* init k to 0 */
for (i = BITSIZE; i >= 0; i--) {
mp_add(&k, &k, &k);
/* digits in mp_???_d are unsigned */
if (naf[i] >= 0) {
mp_add_d(&k, naf[i], &k);
} else {
mp_sub_d(&k, -naf[i], &k);
}
}
if (mp_cmp(&k, scalar) != 0) {
printf("Error: incorrect NAF value.\n");
MP_CHECKOK(mp_toradix(&k, s, 16));
printf("NAF value %s\n", s);
MP_CHECKOK(mp_toradix(scalar, s, 16));
printf("original value %s\n", s);
goto CLEANUP;
}
/* Verify digits of representation are valid */
for (i = 0; i <= BITSIZE; i++) {
if (naf[i] % 2 == 0 && naf[i] != 0) {
printf("Error: Even non-zero digit found.\n");
goto CLEANUP;
}
if (naf[i] < -(ec_twoTo(w - 1)) || naf[i] >= ec_twoTo(w - 1)) {
printf("Error: Magnitude of naf digit too large.\n");
goto CLEANUP;
}
}
/* Verify sparsity of representation */
count = w - 1;
for (i = 0; i <= BITSIZE; i++) {
if (naf[i] != 0) {
if (count < w - 1) {
printf("Error: Sparsity failed.\n");
goto CLEANUP;
}
count = 0;
} else
count++;
}
/* Check timing */
M_TimeOperation(ec_compute_wNAF(naf, BITSIZE, scalar, w), 10000);
printf("Test passed.\n");
CLEANUP:
ECGroup_free(group);
return MP_OKAY;
}

View file

@ -0,0 +1,409 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "mpi.h"
#include "mplogic.h"
#include "mpprime.h"
#include "ecl.h"
#include "ecl-curve.h"
#include "ecp.h"
#include <stdio.h>
#include <strings.h>
#include <assert.h>
#include <time.h>
#include <sys/time.h>
#include <sys/resource.h>
/* Time k repetitions of operation op. */
#define M_TimeOperation(op, k) \
{ \
double dStart, dNow, dUserTime; \
struct rusage ru; \
int i; \
getrusage(RUSAGE_SELF, &ru); \
dStart = (double)ru.ru_utime.tv_sec + (double)ru.ru_utime.tv_usec * 0.000001; \
for (i = 0; i < k; i++) { \
{ \
op; \
} \
}; \
getrusage(RUSAGE_SELF, &ru); \
dNow = (double)ru.ru_utime.tv_sec + (double)ru.ru_utime.tv_usec * 0.000001; \
dUserTime = dNow - dStart; \
if (dUserTime) \
printf(" %-45s k: %6i, t: %6.2f sec\n", #op, k, dUserTime); \
}
/* Test curve using generic field arithmetic. */
#define ECTEST_GENERIC_GFP(name_c, name) \
printf("Testing %s using generic implementation...\n", name_c); \
params = EC_GetNamedCurveParams(name); \
if (params == NULL) { \
printf(" Error: could not construct params.\n"); \
res = MP_NO; \
goto CLEANUP; \
} \
ECGroup_free(group); \
group = ECGroup_fromHex(params); \
if (group == NULL) { \
printf(" Error: could not construct group.\n"); \
res = MP_NO; \
goto CLEANUP; \
} \
MP_CHECKOK(ectest_curve_GFp(group, ectestPrint, ectestTime, 1)); \
printf("... okay.\n");
/* Test curve using specific field arithmetic. */
#define ECTEST_NAMED_GFP(name_c, name) \
printf("Testing %s using specific implementation...\n", name_c); \
ECGroup_free(group); \
group = ECGroup_fromName(name); \
if (group == NULL) { \
printf(" Warning: could not construct group.\n"); \
printf("... failed; continuing with remaining tests.\n"); \
} else { \
MP_CHECKOK(ectest_curve_GFp(group, ectestPrint, ectestTime, 0)); \
printf("... okay.\n"); \
}
/* Performs basic tests of elliptic curve cryptography over prime fields.
* If tests fail, then it prints an error message, aborts, and returns an
* error code. Otherwise, returns 0. */
int
ectest_curve_GFp(ECGroup *group, int ectestPrint, int ectestTime,
int generic)
{
mp_int one, order_1, gx, gy, rx, ry, n;
int size;
mp_err res;
char s[1000];
/* initialize values */
MP_CHECKOK(mp_init(&one));
MP_CHECKOK(mp_init(&order_1));
MP_CHECKOK(mp_init(&gx));
MP_CHECKOK(mp_init(&gy));
MP_CHECKOK(mp_init(&rx));
MP_CHECKOK(mp_init(&ry));
MP_CHECKOK(mp_init(&n));
MP_CHECKOK(mp_set_int(&one, 1));
MP_CHECKOK(mp_sub(&group->order, &one, &order_1));
/* encode base point */
if (group->meth->field_dec) {
MP_CHECKOK(group->meth->field_dec(&group->genx, &gx, group->meth));
MP_CHECKOK(group->meth->field_dec(&group->geny, &gy, group->meth));
} else {
MP_CHECKOK(mp_copy(&group->genx, &gx));
MP_CHECKOK(mp_copy(&group->geny, &gy));
}
if (ectestPrint) {
/* output base point */
printf(" base point P:\n");
MP_CHECKOK(mp_toradix(&gx, s, 16));
printf(" %s\n", s);
MP_CHECKOK(mp_toradix(&gy, s, 16));
printf(" %s\n", s);
if (group->meth->field_enc) {
printf(" base point P (encoded):\n");
MP_CHECKOK(mp_toradix(&group->genx, s, 16));
printf(" %s\n", s);
MP_CHECKOK(mp_toradix(&group->geny, s, 16));
printf(" %s\n", s);
}
}
#ifdef ECL_ENABLE_GFP_PT_MUL_AFF
/* multiply base point by order - 1 and check for negative of base
* point */
MP_CHECKOK(ec_GFp_pt_mul_aff(&order_1, &group->genx, &group->geny, &rx, &ry, group));
if (ectestPrint) {
printf(" (order-1)*P (affine):\n");
MP_CHECKOK(mp_toradix(&rx, s, 16));
printf(" %s\n", s);
MP_CHECKOK(mp_toradix(&ry, s, 16));
printf(" %s\n", s);
}
MP_CHECKOK(group->meth->field_neg(&ry, &ry, group->meth));
if ((mp_cmp(&rx, &group->genx) != 0) || (mp_cmp(&ry, &group->geny) != 0)) {
printf(" Error: invalid result (expected (- base point)).\n");
res = MP_NO;
goto CLEANUP;
}
#endif
#ifdef ECL_ENABLE_GFP_PT_MUL_AFF
/* multiply base point by order - 1 and check for negative of base
* point */
MP_CHECKOK(ec_GFp_pt_mul_jac(&order_1, &group->genx, &group->geny, &rx, &ry, group));
if (ectestPrint) {
printf(" (order-1)*P (jacobian):\n");
MP_CHECKOK(mp_toradix(&rx, s, 16));
printf(" %s\n", s);
MP_CHECKOK(mp_toradix(&ry, s, 16));
printf(" %s\n", s);
}
MP_CHECKOK(group->meth->field_neg(&ry, &ry, group->meth));
if ((mp_cmp(&rx, &group->genx) != 0) || (mp_cmp(&ry, &group->geny) != 0)) {
printf(" Error: invalid result (expected (- base point)).\n");
res = MP_NO;
goto CLEANUP;
}
#endif
/* multiply base point by order - 1 and check for negative of base
* point */
MP_CHECKOK(ECPoint_mul(group, &order_1, NULL, NULL, &rx, &ry));
if (ectestPrint) {
printf(" (order-1)*P (ECPoint_mul):\n");
MP_CHECKOK(mp_toradix(&rx, s, 16));
printf(" %s\n", s);
MP_CHECKOK(mp_toradix(&ry, s, 16));
printf(" %s\n", s);
}
MP_CHECKOK(mp_submod(&group->meth->irr, &ry, &group->meth->irr, &ry));
if ((mp_cmp(&rx, &gx) != 0) || (mp_cmp(&ry, &gy) != 0)) {
printf(" Error: invalid result (expected (- base point)).\n");
res = MP_NO;
goto CLEANUP;
}
/* multiply base point by order - 1 and check for negative of base
* point */
MP_CHECKOK(ECPoint_mul(group, &order_1, &gx, &gy, &rx, &ry));
if (ectestPrint) {
printf(" (order-1)*P (ECPoint_mul):\n");
MP_CHECKOK(mp_toradix(&rx, s, 16));
printf(" %s\n", s);
MP_CHECKOK(mp_toradix(&ry, s, 16));
printf(" %s\n", s);
}
MP_CHECKOK(mp_submod(&group->meth->irr, &ry, &group->meth->irr, &ry));
if ((mp_cmp(&rx, &gx) != 0) || (mp_cmp(&ry, &gy) != 0)) {
printf(" Error: invalid result (expected (- base point)).\n");
res = MP_NO;
goto CLEANUP;
}
#ifdef ECL_ENABLE_GFP_PT_MUL_AFF
/* multiply base point by order and check for point at infinity */
MP_CHECKOK(ec_GFp_pt_mul_aff(&group->order, &group->genx, &group->geny, &rx, &ry,
group));
if (ectestPrint) {
printf(" (order)*P (affine):\n");
MP_CHECKOK(mp_toradix(&rx, s, 16));
printf(" %s\n", s);
MP_CHECKOK(mp_toradix(&ry, s, 16));
printf(" %s\n", s);
}
if (ec_GFp_pt_is_inf_aff(&rx, &ry) != MP_YES) {
printf(" Error: invalid result (expected point at infinity).\n");
res = MP_NO;
goto CLEANUP;
}
#endif
#ifdef ECL_ENABLE_GFP_PT_MUL_JAC
/* multiply base point by order and check for point at infinity */
MP_CHECKOK(ec_GFp_pt_mul_jac(&group->order, &group->genx, &group->geny, &rx, &ry,
group));
if (ectestPrint) {
printf(" (order)*P (jacobian):\n");
MP_CHECKOK(mp_toradix(&rx, s, 16));
printf(" %s\n", s);
MP_CHECKOK(mp_toradix(&ry, s, 16));
printf(" %s\n", s);
}
if (ec_GFp_pt_is_inf_aff(&rx, &ry) != MP_YES) {
printf(" Error: invalid result (expected point at infinity).\n");
res = MP_NO;
goto CLEANUP;
}
#endif
/* multiply base point by order and check for point at infinity */
MP_CHECKOK(ECPoint_mul(group, &group->order, NULL, NULL, &rx, &ry));
if (ectestPrint) {
printf(" (order)*P (ECPoint_mul):\n");
MP_CHECKOK(mp_toradix(&rx, s, 16));
printf(" %s\n", s);
MP_CHECKOK(mp_toradix(&ry, s, 16));
printf(" %s\n", s);
}
if (ec_GFp_pt_is_inf_aff(&rx, &ry) != MP_YES) {
printf(" Error: invalid result (expected point at infinity).\n");
res = MP_NO;
goto CLEANUP;
}
/* multiply base point by order and check for point at infinity */
MP_CHECKOK(ECPoint_mul(group, &group->order, &gx, &gy, &rx, &ry));
if (ectestPrint) {
printf(" (order)*P (ECPoint_mul):\n");
MP_CHECKOK(mp_toradix(&rx, s, 16));
printf(" %s\n", s);
MP_CHECKOK(mp_toradix(&ry, s, 16));
printf(" %s\n", s);
}
if (ec_GFp_pt_is_inf_aff(&rx, &ry) != MP_YES) {
printf(" Error: invalid result (expected point at infinity).\n");
res = MP_NO;
goto CLEANUP;
}
/* check that (order-1)P + (order-1)P + P == (order-1)P */
MP_CHECKOK(ECPoints_mul(group, &order_1, &order_1, &gx, &gy, &rx, &ry));
MP_CHECKOK(ECPoints_mul(group, &one, &one, &rx, &ry, &rx, &ry));
if (ectestPrint) {
printf(" (order-1)*P + (order-1)*P + P == (order-1)*P (ECPoints_mul):\n");
MP_CHECKOK(mp_toradix(&rx, s, 16));
printf(" %s\n", s);
MP_CHECKOK(mp_toradix(&ry, s, 16));
printf(" %s\n", s);
}
MP_CHECKOK(mp_submod(&group->meth->irr, &ry, &group->meth->irr, &ry));
if ((mp_cmp(&rx, &gx) != 0) || (mp_cmp(&ry, &gy) != 0)) {
printf(" Error: invalid result (expected (- base point)).\n");
res = MP_NO;
goto CLEANUP;
}
/* test validate_point function */
if (ECPoint_validate(group, &gx, &gy) != MP_YES) {
printf(" Error: validate point on base point failed.\n");
res = MP_NO;
goto CLEANUP;
}
MP_CHECKOK(mp_add_d(&gy, 1, &ry));
if (ECPoint_validate(group, &gx, &ry) != MP_NO) {
printf(" Error: validate point on invalid point passed.\n");
res = MP_NO;
goto CLEANUP;
}
if (ectestTime) {
/* compute random scalar */
size = mpl_significant_bits(&group->meth->irr);
if (size < MP_OKAY) {
goto CLEANUP;
}
MP_CHECKOK(mpp_random_size(&n, (size + ECL_BITS - 1) / ECL_BITS));
MP_CHECKOK(group->meth->field_mod(&n, &n, group->meth));
/* timed test */
if (generic) {
#ifdef ECL_ENABLE_GFP_PT_MUL_AFF
M_TimeOperation(MP_CHECKOK(ec_GFp_pt_mul_aff(&n, &group->genx, &group->geny, &rx, &ry,
group)),
100);
#endif
M_TimeOperation(MP_CHECKOK(ECPoint_mul(group, &n, NULL, NULL, &rx, &ry)),
100);
M_TimeOperation(MP_CHECKOK(ECPoints_mul(group, &n, &n, &gx, &gy, &rx, &ry)), 100);
} else {
M_TimeOperation(MP_CHECKOK(ECPoint_mul(group, &n, NULL, NULL, &rx, &ry)),
100);
M_TimeOperation(MP_CHECKOK(ECPoint_mul(group, &n, &gx, &gy, &rx, &ry)),
100);
M_TimeOperation(MP_CHECKOK(ECPoints_mul(group, &n, &n, &gx, &gy, &rx, &ry)), 100);
}
}
CLEANUP:
mp_clear(&one);
mp_clear(&order_1);
mp_clear(&gx);
mp_clear(&gy);
mp_clear(&rx);
mp_clear(&ry);
mp_clear(&n);
if (res != MP_OKAY) {
printf(" Error: exiting with error value %i\n", res);
}
return res;
}
/* Prints help information. */
void
printUsage()
{
printf("Usage: ecp_test [--print] [--time]\n");
printf(" --print Print out results of each point arithmetic test.\n");
printf(" --time Benchmark point operations and print results.\n");
}
/* Performs tests of elliptic curve cryptography over prime fields If
* tests fail, then it prints an error message, aborts, and returns an
* error code. Otherwise, returns 0. */
int
main(int argv, char **argc)
{
int ectestTime = 0;
int ectestPrint = 0;
int i;
ECGroup *group = NULL;
ECCurveParams *params = NULL;
mp_err res;
/* read command-line arguments */
for (i = 1; i < argv; i++) {
if ((strcasecmp(argc[i], "time") == 0) || (strcasecmp(argc[i], "-time") == 0) || (strcasecmp(argc[i], "--time") == 0)) {
ectestTime = 1;
} else if ((strcasecmp(argc[i], "print") == 0) || (strcasecmp(argc[i], "-print") == 0) || (strcasecmp(argc[i], "--print") == 0)) {
ectestPrint = 1;
} else {
printUsage();
return 0;
}
}
/* generic arithmetic tests */
ECTEST_GENERIC_GFP("SECP-160R1", ECCurve_SECG_PRIME_160R1);
/* specific arithmetic tests */
ECTEST_NAMED_GFP("NIST-P192", ECCurve_NIST_P192);
ECTEST_NAMED_GFP("NIST-P224", ECCurve_NIST_P224);
ECTEST_NAMED_GFP("NIST-P256", ECCurve_NIST_P256);
ECTEST_NAMED_GFP("NIST-P384", ECCurve_NIST_P384);
ECTEST_NAMED_GFP("NIST-P521", ECCurve_NIST_P521);
ECTEST_NAMED_GFP("ANSI X9.62 PRIME192v1", ECCurve_X9_62_PRIME_192V1);
ECTEST_NAMED_GFP("ANSI X9.62 PRIME192v2", ECCurve_X9_62_PRIME_192V2);
ECTEST_NAMED_GFP("ANSI X9.62 PRIME192v3", ECCurve_X9_62_PRIME_192V3);
ECTEST_NAMED_GFP("ANSI X9.62 PRIME239v1", ECCurve_X9_62_PRIME_239V1);
ECTEST_NAMED_GFP("ANSI X9.62 PRIME239v2", ECCurve_X9_62_PRIME_239V2);
ECTEST_NAMED_GFP("ANSI X9.62 PRIME239v3", ECCurve_X9_62_PRIME_239V3);
ECTEST_NAMED_GFP("ANSI X9.62 PRIME256v1", ECCurve_X9_62_PRIME_256V1);
ECTEST_NAMED_GFP("SECP-112R1", ECCurve_SECG_PRIME_112R1);
ECTEST_NAMED_GFP("SECP-112R2", ECCurve_SECG_PRIME_112R2);
ECTEST_NAMED_GFP("SECP-128R1", ECCurve_SECG_PRIME_128R1);
ECTEST_NAMED_GFP("SECP-128R2", ECCurve_SECG_PRIME_128R2);
ECTEST_NAMED_GFP("SECP-160K1", ECCurve_SECG_PRIME_160K1);
ECTEST_NAMED_GFP("SECP-160R1", ECCurve_SECG_PRIME_160R1);
ECTEST_NAMED_GFP("SECP-160R2", ECCurve_SECG_PRIME_160R2);
ECTEST_NAMED_GFP("SECP-192K1", ECCurve_SECG_PRIME_192K1);
ECTEST_NAMED_GFP("SECP-192R1", ECCurve_SECG_PRIME_192R1);
ECTEST_NAMED_GFP("SECP-224K1", ECCurve_SECG_PRIME_224K1);
ECTEST_NAMED_GFP("SECP-224R1", ECCurve_SECG_PRIME_224R1);
ECTEST_NAMED_GFP("SECP-256K1", ECCurve_SECG_PRIME_256K1);
ECTEST_NAMED_GFP("SECP-256R1", ECCurve_SECG_PRIME_256R1);
ECTEST_NAMED_GFP("SECP-384R1", ECCurve_SECG_PRIME_384R1);
ECTEST_NAMED_GFP("SECP-521R1", ECCurve_SECG_PRIME_521R1);
ECTEST_NAMED_GFP("WTLS-6 (112)", ECCurve_WTLS_6);
ECTEST_NAMED_GFP("WTLS-7 (160)", ECCurve_WTLS_7);
ECTEST_NAMED_GFP("WTLS-8 (112)", ECCurve_WTLS_8);
ECTEST_NAMED_GFP("WTLS-9 (160)", ECCurve_WTLS_9);
ECTEST_NAMED_GFP("WTLS-12 (224)", ECCurve_WTLS_12);
ECTEST_NAMED_GFP("Curve25519", ECCurve25519);
CLEANUP:
EC_FreeCurveParams(params);
ECGroup_free(group);
if (res != MP_OKAY) {
printf("Error: exiting with error value %i\n", res);
}
return res;
}

View file

@ -0,0 +1,87 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "uint128.h"
/* helper functions */
uint64_t
mask51(uint128_t x)
{
return x.lo & MASK51;
}
uint64_t
mask_lower(uint128_t x)
{
return x.lo;
}
uint128_t
mask51full(uint128_t x)
{
uint128_t ret = { x.lo & MASK51, 0 };
return ret;
}
uint128_t
init128x(uint64_t x)
{
uint128_t ret = { x, 0 };
return ret;
}
/* arithmetic */
uint128_t
add128(uint128_t a, uint128_t b)
{
uint128_t ret;
ret.lo = a.lo + b.lo;
ret.hi = a.hi + b.hi + (ret.lo < b.lo);
return ret;
}
/* out = 19 * a */
uint128_t
mul12819(uint128_t a)
{
uint128_t ret = lshift128(a, 4);
ret = add128(ret, a);
ret = add128(ret, a);
ret = add128(ret, a);
return ret;
}
uint128_t
mul6464(uint64_t a, uint64_t b)
{
uint128_t ret;
uint64_t t0 = ((uint64_t)(uint32_t)a) * ((uint64_t)(uint32_t)b);
uint64_t t1 = (a >> 32) * ((uint64_t)(uint32_t)b) + (t0 >> 32);
uint64_t t2 = (b >> 32) * ((uint64_t)(uint32_t)a) + ((uint32_t)t1);
ret.lo = (((uint64_t)((uint32_t)t2)) << 32) + ((uint32_t)t0);
ret.hi = (a >> 32) * (b >> 32);
ret.hi += (t2 >> 32) + (t1 >> 32);
return ret;
}
/* only defined for n < 64 */
uint128_t
rshift128(uint128_t x, uint8_t n)
{
uint128_t ret;
ret.lo = (x.lo >> n) + (x.hi << (64 - n));
ret.hi = x.hi >> n;
return ret;
}
/* only defined for n < 64 */
uint128_t
lshift128(uint128_t x, uint8_t n)
{
uint128_t ret;
ret.hi = (x.hi << n) + (x.lo >> (64 - n));
ret.lo = x.lo << n;
return ret;
}

View file

@ -0,0 +1,35 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include <stdint.h>
#define MASK51 0x7ffffffffffffULL
#ifdef HAVE_INT128_SUPPORT
typedef unsigned __int128 uint128_t;
#define add128(a, b) (a) + (b)
#define mul6464(a, b) (uint128_t)(a) * (uint128_t)(b)
#define mul12819(a) (uint128_t)(a) * 19
#define rshift128(x, n) (x) >> (n)
#define lshift128(x, n) (x) << (n)
#define mask51(x) (x) & 0x7ffffffffffff
#define mask_lower(x) (uint64_t)(x)
#define mask51full(x) (x) & 0x7ffffffffffff
#define init128x(x) (x)
#else /* uint128_t for Windows and 32 bit intel systems */
struct uint128_t_str {
uint64_t lo;
uint64_t hi;
};
typedef struct uint128_t_str uint128_t;
uint128_t add128(uint128_t a, uint128_t b);
uint128_t mul6464(uint64_t a, uint64_t b);
uint128_t mul12819(uint128_t a);
uint128_t rshift128(uint128_t x, uint8_t n);
uint128_t lshift128(uint128_t x, uint8_t n);
uint64_t mask51(uint128_t x);
uint64_t mask_lower(uint128_t x);
uint128_t mask51full(uint128_t x);
uint128_t init128x(uint64_t x);
#endif

View file

@ -0,0 +1,48 @@
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
{
'includes': [
'../../coreconf/config.gypi'
],
'targets': [
{
'target_name': 'lib_freebl_exports',
'type': 'none',
'copies': [
{
'files': [
'blapit.h',
'ecl/ecl-exp.h',
'shsign.h'
],
'conditions': [
[ 'OS=="linux"', {
'files': [
'nsslowhash.h',
],
}],
],
'destination': '<(nss_public_dist_dir)/<(module)'
},
{
'files': [
'alghmac.h',
'blapi.h',
'chacha20poly1305.h',
'ec.h',
'ecl/ecl-curve.h',
'ecl/ecl.h',
'hmacct.h',
'secmpi.h',
'secrng.h'
],
'destination': '<(nss_private_dist_dir)/<(module)'
}
]
}
],
'variables': {
'module': 'nss'
}
}

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,26 @@
;+#
;+# This Source Code Form is subject to the terms of the Mozilla Public
;+# License, v. 2.0. If a copy of the MPL was not distributed with this
;+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
;+#
;+# OK, this file is meant to support SUN, LINUX, AIX and WINDOWS
;+# 1. For all unix platforms, the string ";-" means "remove this line"
;+# 2. For all unix platforms, the string " DATA " will be removed from any
;+# line on which it occurs.
;+# 3. Lines containing ";+" will have ";+" removed on SUN and LINUX.
;+# On AIX, lines containing ";+" will be removed.
;+# 4. For all unix platforms, the string ";;" will thave the ";;" removed.
;+# 5. For all unix platforms, after the above processing has taken place,
;+# all characters after the first ";" on the line will be removed.
;+# And for AIX, the first ";" will also be removed.
;+# This file is passed directly to windows. Since ';' is a comment, all UNIX
;+# directives are hidden behind ";", ";+", and ";-"
;+
;+NSSprivate_3.11 { # NSS 3.11 release
;+ global:
LIBRARY freebl3 ;-
EXPORTS ;-
FREEBL_GetVector;
;+ local:
;+ *;
;+};

View file

@ -0,0 +1,408 @@
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
{
'includes': [
'../../coreconf/config.gypi'
],
'targets': [
{
'target_name': 'intel-gcm-wrap_c_lib',
'type': 'static_library',
'sources': [
'intel-gcm-wrap.c'
],
'dependencies': [
'<(DEPTH)/exports.gyp:nss_exports'
],
'cflags': [
'-mssse3'
],
'cflags_mozilla': [
'-mssse3'
]
},
{
'target_name': 'freebl',
'type': 'static_library',
'sources': [
'loader.c'
],
'dependencies': [
'<(DEPTH)/exports.gyp:nss_exports'
]
},
{
'target_name': '<(freebl_name)',
'type': 'shared_library',
'sources': [
'aeskeywrap.c',
'alg2268.c',
'alghmac.c',
'arcfive.c',
'arcfour.c',
'camellia.c',
'chacha20poly1305.c',
'ctr.c',
'cts.c',
'des.c',
'desblapi.c',
'dh.c',
'drbg.c',
'dsa.c',
'ec.c',
'ecdecode.c',
'ecl/ec_naf.c',
'ecl/ecl.c',
'ecl/ecl_curve.c',
'ecl/ecl_gf.c',
'ecl/ecl_mult.c',
'ecl/ecp_25519.c',
'ecl/ecp_256.c',
'ecl/ecp_256_32.c',
'ecl/ecp_384.c',
'ecl/ecp_521.c',
'ecl/ecp_aff.c',
'ecl/ecp_jac.c',
'ecl/ecp_jm.c',
'ecl/ecp_mont.c',
'fipsfreebl.c',
'freeblver.c',
'gcm.c',
'hmacct.c',
'jpake.c',
'ldvector.c',
'md2.c',
'md5.c',
'mpi/mp_gf2m.c',
'mpi/mpcpucache.c',
'mpi/mpi.c',
'mpi/mplogic.c',
'mpi/mpmontg.c',
'mpi/mpprime.c',
'pqg.c',
'rawhash.c',
'rijndael.c',
'rsa.c',
'rsapkcs.c',
'seed.c',
'sha512.c',
'sha_fast.c',
'shvfy.c',
'sysrand.c',
'tlsprfalg.c'
],
'conditions': [
[ 'OS=="linux"', {
'sources': [
'nsslowhash.c',
'stubs.c',
],
'conditions': [
[ 'test_build==1', {
'dependencies': [
'<(DEPTH)/lib/util/util.gyp:nssutil3',
],
}],
[ 'target_arch=="x64"', {
'sources': [
'arcfour-amd64-gas.s',
'intel-aes.s',
'intel-gcm.s',
'mpi/mpi_amd64.c',
'mpi/mpi_amd64_gas.s',
'mpi/mp_comba.c',
],
'dependencies': [
'intel-gcm-wrap_c_lib',
],
'conditions': [
[ 'cc_is_clang==1', {
'cflags': [
'-no-integrated-as',
],
'cflags_mozilla': [
'-no-integrated-as',
],
'asflags_mozilla': [
'-no-integrated-as',
],
}],
],
}],
[ 'target_arch=="ia32"', {
'sources': [
'mpi/mpi_x86.s',
],
}],
[ 'target_arch=="arm"', {
'sources': [
'mpi/mpi_arm.c',
],
}],
],
}, {
# not Linux
'conditions': [
[ 'moz_fold_libs==0', {
'dependencies': [
'../util/util.gyp:nssutil3',
],
}, {
'libraries': [
'<(moz_folded_library_name)',
],
}],
],
}],
[ 'OS=="win"', {
'sources': [
#TODO: building with mingw should not need this.
'ecl/uint128.c',
#TODO: clang-cl needs -msse3 here
'intel-gcm-wrap.c',
],
'libraries': [
'advapi32.lib',
],
'conditions': [
[ 'target_arch=="x64"', {
'sources': [
'arcfour-amd64-masm.asm',
'mpi/mpi_amd64.c',
'mpi/mpi_amd64_masm.asm',
'mpi/mp_comba_amd64_masm.asm',
'intel-aes-x64-masm.asm',
'intel-gcm-x64-masm.asm',
],
}, {
# not x64
'sources': [
'mpi/mpi_x86_asm.c',
'intel-aes-x86-masm.asm',
'intel-gcm-x86-masm.asm',
],
}],
],
}],
['target_arch=="ia32" or target_arch=="x64"', {
'sources': [
# All intel architectures get the 64 bit version
'ecl/curve25519_64.c',
],
}, {
'sources': [
# All non intel architectures get the generic 32 bit implementation (slow!)
'ecl/curve25519_32.c',
],
}],
#TODO uint128.c
[ 'disable_chachapoly==0', {
'conditions': [
[ 'OS!="win" and target_arch=="x64"', {
'sources': [
'chacha20_vec.c',
'poly1305-donna-x64-sse2-incremental-source.c',
],
}, {
# not x64
'sources': [
'chacha20.c',
'poly1305.c',
],
}],
],
}],
[ 'fuzz==1', {
'sources': [
'det_rng.c',
],
'defines': [
'UNSAFE_FUZZER_MODE',
],
}],
[ 'test_build==1', {
'defines': [
'CT_VERIF',
],
}],
[ 'OS=="mac"', {
'conditions': [
[ 'target_arch=="ia32"', {
'sources': [
'mpi/mpi_sse2.s',
],
'defines': [
'MP_USE_UINT_DIGIT',
'MP_ASSEMBLY_MULTIPLY',
'MP_ASSEMBLY_SQUARE',
'MP_ASSEMBLY_DIV_2DX1D',
],
}],
],
}],
],
'dependencies': [
'<(DEPTH)/exports.gyp:nss_exports',
],
'variables': {
'conditions': [
[ 'OS=="linux"', {
'mapfile': 'freebl_hash_vector.def',
}, {
'mapfile': 'freebl.def',
}],
]
},
'ldflags': [
'-Wl,-Bsymbolic'
]
},
],
'conditions': [
[ 'OS=="linux"', {
# stub build
'targets': [
{
'target_name': 'freebl3',
'type': 'shared_library',
'defines': [
'FREEBL_NO_DEPEND',
],
'sources': [
'lowhash_vector.c'
],
'dependencies': [
'<(DEPTH)/exports.gyp:nss_exports'
],
'variables': {
'mapfile': 'freebl_hash.def'
}
},
],
}],
],
'target_defaults': {
'include_dirs': [
'mpi',
'ecl'
],
'defines': [
'SHLIB_SUFFIX=\"<(dll_suffix)\"',
'SHLIB_PREFIX=\"<(dll_prefix)\"',
'SHLIB_VERSION=\"3\"',
'SOFTOKEN_SHLIB_VERSION=\"3\"',
'RIJNDAEL_INCLUDE_TABLES',
'MP_API_COMPATIBLE'
],
'conditions': [
[ 'OS=="win" and target_arch=="ia32"', {
'msvs_settings': {
'VCCLCompilerTool': {
#TODO: -Ox optimize flags
'PreprocessorDefinitions': [
'NSS_X86_OR_X64',
'NSS_X86',
'MP_ASSEMBLY_MULTIPLY',
'MP_ASSEMBLY_SQUARE',
'MP_ASSEMBLY_DIV_2DX1D',
'MP_USE_UINT_DIGIT',
'MP_NO_MP_WORD',
'USE_HW_AES',
'INTEL_GCM',
],
},
},
}],
[ 'OS=="win" and target_arch=="x64"', {
'msvs_settings': {
'VCCLCompilerTool': {
#TODO: -Ox optimize flags
'PreprocessorDefinitions': [
'NSS_USE_64',
'NSS_X86_OR_X64',
'NSS_X64',
'MP_IS_LITTLE_ENDIAN',
'NSS_BEVAND_ARCFOUR',
'MPI_AMD64',
'MP_ASSEMBLY_MULTIPLY',
'NSS_USE_COMBA',
'USE_HW_AES',
'INTEL_GCM',
],
},
},
}],
[ 'OS!="win"', {
'conditions': [
[ 'target_arch=="x64"', {
'defines': [
'NSS_USE_64',
'NSS_X86_OR_X64',
'NSS_X64',
# The Makefile does version-tests on GCC, but we're not doing that here.
'HAVE_INT128_SUPPORT',
],
}, {
'sources': [
'ecl/uint128.c',
],
}],
[ 'target_arch=="ia32"', {
'defines': [
'NSS_X86_OR_X64',
'NSS_X86',
],
}],
],
}],
[ 'OS=="linux"', {
'defines': [
'FREEBL_LOWHASH',
],
'conditions': [
[ 'test_build==0', {
'defines': [
'FREEBL_NO_DEPEND',
],
}],
[ 'target_arch=="x64"', {
'defines': [
'MP_IS_LITTLE_ENDIAN',
'NSS_BEVAND_ARCFOUR',
'MPI_AMD64',
'MP_ASSEMBLY_MULTIPLY',
'NSS_USE_COMBA',
],
}],
[ 'target_arch=="x64" and use_msan==0', {
'defines': [
'USE_HW_AES',
'INTEL_GCM',
],
}],
[ 'target_arch=="ia32"', {
'defines': [
'MP_IS_LITTLE_ENDIAN',
'MP_ASSEMBLY_MULTIPLY',
'MP_ASSEMBLY_SQUARE',
'MP_ASSEMBLY_DIV_2DX1D',
'MP_USE_UINT_DIGIT',
],
}],
[ 'target_arch=="arm"', {
'defines': [
'MP_ASSEMBLY_MULTIPLY',
'MP_ASSEMBLY_SQUARE',
'MP_USE_UINT_DIGIT',
'SHA_NO_LONG_LONG',
],
}],
],
}],
],
},
'variables': {
'module': 'nss',
}
}

View file

@ -0,0 +1,68 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "softkver.h"
#include <winver.h>
#define MY_LIBNAME "freebl"
#define MY_FILEDESCRIPTION "NSS freebl Library"
#define STRINGIZE(x) #x
#define STRINGIZE2(x) STRINGIZE(x)
#define SOFTOKEN_VMAJOR_STR STRINGIZE2(SOFTOKEN_VMAJOR)
#ifdef _DEBUG
#define MY_DEBUG_STR " (debug)"
#define MY_FILEFLAGS_1 VS_FF_DEBUG
#else
#define MY_DEBUG_STR ""
#define MY_FILEFLAGS_1 0x0L
#endif
#if SOFTOKEN_BETA
#define MY_FILEFLAGS_2 MY_FILEFLAGS_1|VS_FF_PRERELEASE
#else
#define MY_FILEFLAGS_2 MY_FILEFLAGS_1
#endif
#ifdef WINNT
#define MY_FILEOS VOS_NT_WINDOWS32
#else
#define MY_FILEOS VOS__WINDOWS32
#endif
#define MY_INTERNAL_NAME MY_LIBNAME SOFTOKEN_VMAJOR_STR
/////////////////////////////////////////////////////////////////////////////
//
// Version-information resource
//
VS_VERSION_INFO VERSIONINFO
FILEVERSION SOFTOKEN_VMAJOR,SOFTOKEN_VMINOR,SOFTOKEN_VPATCH,SOFTOKEN_VBUILD
PRODUCTVERSION SOFTOKEN_VMAJOR,SOFTOKEN_VMINOR,SOFTOKEN_VPATCH,SOFTOKEN_VBUILD
FILEFLAGSMASK VS_FFI_FILEFLAGSMASK
FILEFLAGS MY_FILEFLAGS_2
FILEOS MY_FILEOS
FILETYPE VFT_DLL
FILESUBTYPE 0x0L // not used
BEGIN
BLOCK "StringFileInfo"
BEGIN
BLOCK "040904B0" // Lang=US English, CharSet=Unicode
BEGIN
VALUE "CompanyName", "Mozilla Foundation\0"
VALUE "FileDescription", MY_FILEDESCRIPTION MY_DEBUG_STR "\0"
VALUE "FileVersion", SOFTOKEN_VERSION "\0"
VALUE "InternalName", MY_INTERNAL_NAME "\0"
VALUE "OriginalFilename", MY_INTERNAL_NAME ".dll\0"
VALUE "ProductName", "Network Security Services\0"
VALUE "ProductVersion", SOFTOKEN_VERSION "\0"
END
END
BLOCK "VarFileInfo"
BEGIN
VALUE "Translation", 0x409, 1200
END
END

View file

@ -0,0 +1,39 @@
;+#
;+# This Source Code Form is subject to the terms of the Mozilla Public
;+# License, v. 2.0. If a copy of the MPL was not distributed with this
;+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
;+#
;+# OK, this file is meant to support SUN, LINUX, AIX and WINDOWS
;+# 1. For all unix platforms, the string ";-" means "remove this line"
;+# 2. For all unix platforms, the string " DATA " will be removed from any
;+# line on which it occurs.
;+# 3. Lines containing ";+" will have ";+" removed on SUN and LINUX.
;+# On AIX, lines containing ";+" will be removed.
;+# 4. For all unix platforms, the string ";;" will thave the ";;" removed.
;+# 5. For all unix platforms, after the above processing has taken place,
;+# all characters after the first ";" on the line will be removed.
;+# And for AIX, the first ";" will also be removed.
;+# This file is passed directly to windows. Since ';' is a comment, all UNIX
;+# directives are hidden behind ";", ";+", and ";-"
;+
;+NSSprivate_3.11 { # NSS 3.11 release
;+ global:
LIBRARY freebl3 ;-
EXPORTS ;-
FREEBL_GetVector;
;+ local:
;+ *;
;+};
;+NSSRAWHASH_3.12.3 { # NSS 3.12.3 release
;+ global:
NSSLOW_Init;
NSSLOW_Shutdown;
NSSLOWHASH_Length;
NSSLOWHASH_Begin;
NSSLOWHASH_Destroy;
NSSLOWHASH_End;
NSSLOWHASH_NewContext;
NSSLOWHASH_Update;
;+ local:
;+ *;
;+};

View file

@ -0,0 +1,34 @@
;+#
;+# This Source Code Form is subject to the terms of the Mozilla Public
;+# License, v. 2.0. If a copy of the MPL was not distributed with this
;+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
;+#
;+# OK, this file is meant to support SUN, LINUX, AIX and WINDOWS
;+# 1. For all unix platforms, the string ";-" means "remove this line"
;+# 2. For all unix platforms, the string " DATA " will be removed from any
;+# line on which it occurs.
;+# 3. Lines containing ";+" will have ";+" removed on SUN and LINUX.
;+# On AIX, lines containing ";+" will be removed.
;+# 4. For all unix platforms, the string ";;" will thave the ";;" removed.
;+# 5. For all unix platforms, after the above processing has taken place,
;+# all characters after the first ";" on the line will be removed.
;+# And for AIX, the first ";" will also be removed.
;+# This file is passed directly to windows. Since ';' is a comment, all UNIX
;+# directives are hidden behind ";", ";+", and ";-"
;+
;+NSSprivate_3.11 { # NSS 3.11 release
;+ global:
LIBRARY freebl3 ;-
EXPORTS ;-
FREEBL_GetVector;
;+ local:
;+ *;
;+};
;+NSSprivate_3.16 { # NSS 3.11 release
;+ global:
LIBRARY freebl3 ;-
EXPORTS ;-
NSSLOW_GetVector;
;+ local:
;+ *;
;+};

View file

@ -0,0 +1,18 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
/* Library identity and versioning */
#include "softkver.h"
#if defined(DEBUG)
#define _DEBUG_STRING " (debug)"
#else
#define _DEBUG_STRING ""
#endif
/*
* Version information
*/
const char __nss_freebl_version[] = "Version: NSS " SOFTOKEN_VERSION _DEBUG_STRING;

View file

@ -0,0 +1,860 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifdef FREEBL_NO_DEPEND
#include "stubs.h"
#endif
#include "blapii.h"
#include "blapit.h"
#include "gcm.h"
#include "ctr.h"
#include "secerr.h"
#include "prtypes.h"
#include "pkcs11t.h"
#include <limits.h>
/**************************************************************************
* First implement the Galois hash function of GCM (gcmHash) *
**************************************************************************/
#define GCM_HASH_LEN_LEN 8 /* gcm hash defines lengths to be 64 bits */
typedef struct gcmHashContextStr gcmHashContext;
static SECStatus gcmHash_InitContext(gcmHashContext *hash,
const unsigned char *H,
unsigned int blocksize);
static void gcmHash_DestroyContext(gcmHashContext *ghash, PRBool freeit);
static SECStatus gcmHash_Update(gcmHashContext *ghash,
const unsigned char *buf, unsigned int len,
unsigned int blocksize);
static SECStatus gcmHash_Sync(gcmHashContext *ghash, unsigned int blocksize);
static SECStatus gcmHash_Final(gcmHashContext *gcm, unsigned char *outbuf,
unsigned int *outlen, unsigned int maxout,
unsigned int blocksize);
static SECStatus gcmHash_Reset(gcmHashContext *ghash,
const unsigned char *inbuf,
unsigned int inbufLen, unsigned int blocksize);
/* compile time defines to select how the GF2 multiply is calculated.
* There are currently 2 algorithms implemented here: MPI and ALGORITHM_1.
*
* MPI uses the GF2m implemented in mpi to support GF2 ECC.
* ALGORITHM_1 is the Algorithm 1 in both NIST SP 800-38D and
* "The Galois/Counter Mode of Operation (GCM)", McGrew & Viega.
*/
#if !defined(GCM_USE_ALGORITHM_1) && !defined(GCM_USE_MPI)
#define GCM_USE_MPI 1 /* MPI is about 5x faster with the \
* same or less complexity. It's possible to use \
* tables to speed things up even more */
#endif
/* GCM defines the bit string to be LSB first, which is exactly
* opposite everyone else, including hardware. build array
* to reverse everything. */
static const unsigned char gcm_byte_rev[256] = {
0x00, 0x80, 0x40, 0xc0, 0x20, 0xa0, 0x60, 0xe0,
0x10, 0x90, 0x50, 0xd0, 0x30, 0xb0, 0x70, 0xf0,
0x08, 0x88, 0x48, 0xc8, 0x28, 0xa8, 0x68, 0xe8,
0x18, 0x98, 0x58, 0xd8, 0x38, 0xb8, 0x78, 0xf8,
0x04, 0x84, 0x44, 0xc4, 0x24, 0xa4, 0x64, 0xe4,
0x14, 0x94, 0x54, 0xd4, 0x34, 0xb4, 0x74, 0xf4,
0x0c, 0x8c, 0x4c, 0xcc, 0x2c, 0xac, 0x6c, 0xec,
0x1c, 0x9c, 0x5c, 0xdc, 0x3c, 0xbc, 0x7c, 0xfc,
0x02, 0x82, 0x42, 0xc2, 0x22, 0xa2, 0x62, 0xe2,
0x12, 0x92, 0x52, 0xd2, 0x32, 0xb2, 0x72, 0xf2,
0x0a, 0x8a, 0x4a, 0xca, 0x2a, 0xaa, 0x6a, 0xea,
0x1a, 0x9a, 0x5a, 0xda, 0x3a, 0xba, 0x7a, 0xfa,
0x06, 0x86, 0x46, 0xc6, 0x26, 0xa6, 0x66, 0xe6,
0x16, 0x96, 0x56, 0xd6, 0x36, 0xb6, 0x76, 0xf6,
0x0e, 0x8e, 0x4e, 0xce, 0x2e, 0xae, 0x6e, 0xee,
0x1e, 0x9e, 0x5e, 0xde, 0x3e, 0xbe, 0x7e, 0xfe,
0x01, 0x81, 0x41, 0xc1, 0x21, 0xa1, 0x61, 0xe1,
0x11, 0x91, 0x51, 0xd1, 0x31, 0xb1, 0x71, 0xf1,
0x09, 0x89, 0x49, 0xc9, 0x29, 0xa9, 0x69, 0xe9,
0x19, 0x99, 0x59, 0xd9, 0x39, 0xb9, 0x79, 0xf9,
0x05, 0x85, 0x45, 0xc5, 0x25, 0xa5, 0x65, 0xe5,
0x15, 0x95, 0x55, 0xd5, 0x35, 0xb5, 0x75, 0xf5,
0x0d, 0x8d, 0x4d, 0xcd, 0x2d, 0xad, 0x6d, 0xed,
0x1d, 0x9d, 0x5d, 0xdd, 0x3d, 0xbd, 0x7d, 0xfd,
0x03, 0x83, 0x43, 0xc3, 0x23, 0xa3, 0x63, 0xe3,
0x13, 0x93, 0x53, 0xd3, 0x33, 0xb3, 0x73, 0xf3,
0x0b, 0x8b, 0x4b, 0xcb, 0x2b, 0xab, 0x6b, 0xeb,
0x1b, 0x9b, 0x5b, 0xdb, 0x3b, 0xbb, 0x7b, 0xfb,
0x07, 0x87, 0x47, 0xc7, 0x27, 0xa7, 0x67, 0xe7,
0x17, 0x97, 0x57, 0xd7, 0x37, 0xb7, 0x77, 0xf7,
0x0f, 0x8f, 0x4f, 0xcf, 0x2f, 0xaf, 0x6f, 0xef,
0x1f, 0x9f, 0x5f, 0xdf, 0x3f, 0xbf, 0x7f, 0xff
};
#ifdef GCM_TRACE
#include <stdio.h>
#define GCM_TRACE_X(ghash, label) \
{ \
unsigned char _X[MAX_BLOCK_SIZE]; \
int i; \
gcm_getX(ghash, _X, blocksize); \
printf(label, (ghash)->m); \
for (i = 0; i < blocksize; i++) \
printf("%02x", _X[i]); \
printf("\n"); \
}
#define GCM_TRACE_BLOCK(label, buf, blocksize) \
{ \
printf(label); \
for (i = 0; i < blocksize; i++) \
printf("%02x", buf[i]); \
printf("\n"); \
}
#else
#define GCM_TRACE_X(ghash, label)
#define GCM_TRACE_BLOCK(label, buf, blocksize)
#endif
#ifdef GCM_USE_MPI
#ifdef GCM_USE_ALGORITHM_1
#error "Only define one of GCM_USE_MPI, GCM_USE_ALGORITHM_1"
#endif
/* use the MPI functions to calculate Xn = (Xn-1^C_i)*H mod poly */
#include "mpi.h"
#include "secmpi.h"
#include "mplogic.h"
#include "mp_gf2m.h"
/* state needed to handle GCM Hash function */
struct gcmHashContextStr {
mp_int H;
mp_int X;
mp_int C_i;
const unsigned int *poly;
unsigned char buffer[MAX_BLOCK_SIZE];
unsigned int bufLen;
int m; /* XXX what is m? */
unsigned char counterBuf[2 * GCM_HASH_LEN_LEN];
PRUint64 cLen;
};
/* f = x^128 + x^7 + x^2 + x + 1 */
static const unsigned int poly_128[] = { 128, 7, 2, 1, 0 };
/* sigh, GCM defines the bit strings exactly backwards from everything else */
static void
gcm_reverse(unsigned char *target, const unsigned char *src,
unsigned int blocksize)
{
unsigned int i;
for (i = 0; i < blocksize; i++) {
target[blocksize - i - 1] = gcm_byte_rev[src[i]];
}
}
/* Initialize a gcmHashContext */
static SECStatus
gcmHash_InitContext(gcmHashContext *ghash, const unsigned char *H,
unsigned int blocksize)
{
mp_err err = MP_OKAY;
unsigned char H_rev[MAX_BLOCK_SIZE];
MP_DIGITS(&ghash->H) = 0;
MP_DIGITS(&ghash->X) = 0;
MP_DIGITS(&ghash->C_i) = 0;
CHECK_MPI_OK(mp_init(&ghash->H));
CHECK_MPI_OK(mp_init(&ghash->X));
CHECK_MPI_OK(mp_init(&ghash->C_i));
mp_zero(&ghash->X);
gcm_reverse(H_rev, H, blocksize);
CHECK_MPI_OK(mp_read_unsigned_octets(&ghash->H, H_rev, blocksize));
/* set the irreducible polynomial. Each blocksize has its own polynomial.
* for now only blocksize 16 (=128 bits) is defined */
switch (blocksize) {
case 16: /* 128 bits */
ghash->poly = poly_128;
break;
default:
PORT_SetError(SEC_ERROR_INVALID_ARGS);
goto cleanup;
}
ghash->cLen = 0;
ghash->bufLen = 0;
ghash->m = 0;
PORT_Memset(ghash->counterBuf, 0, sizeof(ghash->counterBuf));
return SECSuccess;
cleanup:
gcmHash_DestroyContext(ghash, PR_FALSE);
return SECFailure;
}
/* Destroy a HashContext (Note we zero the digits so this function
* is idempotent if called with freeit == PR_FALSE */
static void
gcmHash_DestroyContext(gcmHashContext *ghash, PRBool freeit)
{
mp_clear(&ghash->H);
mp_clear(&ghash->X);
mp_clear(&ghash->C_i);
PORT_Memset(ghash, 0, sizeof(gcmHashContext));
if (freeit) {
PORT_Free(ghash);
}
}
static SECStatus
gcm_getX(gcmHashContext *ghash, unsigned char *T, unsigned int blocksize)
{
int len;
mp_err err;
unsigned char tmp_buf[MAX_BLOCK_SIZE];
unsigned char *X;
len = mp_unsigned_octet_size(&ghash->X);
if (len <= 0) {
PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
return SECFailure;
}
X = tmp_buf;
PORT_Assert((unsigned int)len <= blocksize);
if ((unsigned int)len > blocksize) {
PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
return SECFailure;
}
/* zero pad the result */
if (len != blocksize) {
PORT_Memset(X, 0, blocksize - len);
X += blocksize - len;
}
err = mp_to_unsigned_octets(&ghash->X, X, len);
if (err < 0) {
PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
return SECFailure;
}
gcm_reverse(T, tmp_buf, blocksize);
return SECSuccess;
}
static SECStatus
gcm_HashMult(gcmHashContext *ghash, const unsigned char *buf,
unsigned int count, unsigned int blocksize)
{
SECStatus rv = SECFailure;
mp_err err = MP_OKAY;
unsigned char tmp_buf[MAX_BLOCK_SIZE];
unsigned int i;
for (i = 0; i < count; i++, buf += blocksize) {
ghash->m++;
gcm_reverse(tmp_buf, buf, blocksize);
CHECK_MPI_OK(mp_read_unsigned_octets(&ghash->C_i, tmp_buf, blocksize));
CHECK_MPI_OK(mp_badd(&ghash->X, &ghash->C_i, &ghash->C_i));
/*
* Looking to speed up GCM, this the the place to do it.
* There are two areas that can be exploited to speed up this code.
*
* 1) H is a constant in this multiply. We can precompute H * (0 - 255)
* at init time and this becomes an blockize xors of our table lookup.
*
* 2) poly is a constant for each blocksize. We can calculate the
* modulo reduction by a series of adds and shifts.
*
* For now we are after functionality, so we will go ahead and use
* the builtin bmulmod from mpi
*/
CHECK_MPI_OK(mp_bmulmod(&ghash->C_i, &ghash->H,
ghash->poly, &ghash->X));
GCM_TRACE_X(ghash, "X%d = ")
}
rv = SECSuccess;
cleanup:
PORT_Memset(tmp_buf, 0, sizeof(tmp_buf));
if (rv != SECSuccess) {
MP_TO_SEC_ERROR(err);
}
return rv;
}
static void
gcm_zeroX(gcmHashContext *ghash)
{
mp_zero(&ghash->X);
ghash->m = 0;
}
#endif
#ifdef GCM_USE_ALGORITHM_1
/* use algorithm 1 of McGrew & Viega "The Galois/Counter Mode of Operation" */
#define GCM_ARRAY_SIZE (MAX_BLOCK_SIZE / sizeof(unsigned long))
struct gcmHashContextStr {
unsigned long H[GCM_ARRAY_SIZE];
unsigned long X[GCM_ARRAY_SIZE];
unsigned long R;
unsigned char buffer[MAX_BLOCK_SIZE];
unsigned int bufLen;
int m;
unsigned char counterBuf[2 * GCM_HASH_LEN_LEN];
PRUint64 cLen;
};
static void
gcm_bytes_to_longs(unsigned long *l, const unsigned char *c, unsigned int len)
{
int i, j;
int array_size = len / sizeof(unsigned long);
PORT_Assert(len % sizeof(unsigned long) == 0);
for (i = 0; i < array_size; i++) {
unsigned long tmp = 0;
int byte_offset = i * sizeof(unsigned long);
for (j = sizeof(unsigned long) - 1; j >= 0; j--) {
tmp = (tmp << PR_BITS_PER_BYTE) | gcm_byte_rev[c[byte_offset + j]];
}
l[i] = tmp;
}
}
static void
gcm_longs_to_bytes(const unsigned long *l, unsigned char *c, unsigned int len)
{
int i, j;
int array_size = len / sizeof(unsigned long);
PORT_Assert(len % sizeof(unsigned long) == 0);
for (i = 0; i < array_size; i++) {
unsigned long tmp = l[i];
int byte_offset = i * sizeof(unsigned long);
for (j = 0; j < sizeof(unsigned long); j++) {
c[byte_offset + j] = gcm_byte_rev[tmp & 0xff];
tmp = (tmp >> PR_BITS_PER_BYTE);
}
}
}
/* Initialize a gcmHashContext */
static SECStatus
gcmHash_InitContext(gcmHashContext *ghash, const unsigned char *H,
unsigned int blocksize)
{
PORT_Memset(ghash->X, 0, sizeof(ghash->X));
PORT_Memset(ghash->H, 0, sizeof(ghash->H));
gcm_bytes_to_longs(ghash->H, H, blocksize);
/* set the irreducible polynomial. Each blocksize has its own polynommial
* for now only blocksize 16 (=128 bits) is defined */
switch (blocksize) {
case 16: /* 128 bits */
ghash->R = (unsigned long)0x87; /* x^7 + x^2 + x +1 */
break;
default:
PORT_SetError(SEC_ERROR_INVALID_ARGS);
goto cleanup;
}
ghash->cLen = 0;
ghash->bufLen = 0;
ghash->m = 0;
PORT_Memset(ghash->counterBuf, 0, sizeof(ghash->counterBuf));
return SECSuccess;
cleanup:
return SECFailure;
}
/* Destroy a HashContext (Note we zero the digits so this function
* is idempotent if called with freeit == PR_FALSE */
static void
gcmHash_DestroyContext(gcmHashContext *ghash, PRBool freeit)
{
PORT_Memset(ghash, 0, sizeof(gcmHashContext));
if (freeit) {
PORT_Free(ghash);
}
}
static unsigned long
gcm_shift_one(unsigned long *t, unsigned int count)
{
unsigned long carry = 0;
unsigned long nextcarry = 0;
unsigned int i;
for (i = 0; i < count; i++) {
nextcarry = t[i] >> ((sizeof(unsigned long) * PR_BITS_PER_BYTE) - 1);
t[i] = (t[i] << 1) | carry;
carry = nextcarry;
}
return carry;
}
static SECStatus
gcm_getX(gcmHashContext *ghash, unsigned char *T, unsigned int blocksize)
{
gcm_longs_to_bytes(ghash->X, T, blocksize);
return SECSuccess;
}
#define GCM_XOR(t, s, len) \
for (l = 0; l < len; l++) \
t[l] ^= s[l]
static SECStatus
gcm_HashMult(gcmHashContext *ghash, const unsigned char *buf,
unsigned int count, unsigned int blocksize)
{
unsigned long C_i[GCM_ARRAY_SIZE];
unsigned int arraysize = blocksize / sizeof(unsigned long);
unsigned int i, j, k, l;
for (i = 0; i < count; i++, buf += blocksize) {
ghash->m++;
gcm_bytes_to_longs(C_i, buf, blocksize);
GCM_XOR(C_i, ghash->X, arraysize);
/* multiply X = C_i * H */
PORT_Memset(ghash->X, 0, sizeof(ghash->X));
for (j = 0; j < arraysize; j++) {
unsigned long H = ghash->H[j];
for (k = 0; k < sizeof(unsigned long) * PR_BITS_PER_BYTE; k++) {
if (H & 1) {
GCM_XOR(ghash->X, C_i, arraysize);
}
if (gcm_shift_one(C_i, arraysize)) {
C_i[0] = C_i[0] ^ ghash->R;
}
H = H >> 1;
}
}
GCM_TRACE_X(ghash, "X%d = ")
}
PORT_Memset(C_i, 0, sizeof(C_i));
return SECSuccess;
}
static void
gcm_zeroX(gcmHashContext *ghash)
{
PORT_Memset(ghash->X, 0, sizeof(ghash->X));
ghash->m = 0;
}
#endif
/*
* implement GCM GHASH using the freebl GHASH function. The gcm_HashMult
* function always takes blocksize lengths of data. gcmHash_Update will
* format the data properly.
*/
static SECStatus
gcmHash_Update(gcmHashContext *ghash, const unsigned char *buf,
unsigned int len, unsigned int blocksize)
{
unsigned int blocks;
SECStatus rv;
ghash->cLen += (len * PR_BITS_PER_BYTE);
/* first deal with the current buffer of data. Try to fill it out so
* we can hash it */
if (ghash->bufLen) {
unsigned int needed = PR_MIN(len, blocksize - ghash->bufLen);
if (needed != 0) {
PORT_Memcpy(ghash->buffer + ghash->bufLen, buf, needed);
}
buf += needed;
len -= needed;
ghash->bufLen += needed;
if (len == 0) {
/* didn't add enough to hash the data, nothing more do do */
return SECSuccess;
}
PORT_Assert(ghash->bufLen == blocksize);
/* hash the buffer and clear it */
rv = gcm_HashMult(ghash, ghash->buffer, 1, blocksize);
PORT_Memset(ghash->buffer, 0, blocksize);
ghash->bufLen = 0;
if (rv != SECSuccess) {
return SECFailure;
}
}
/* now hash any full blocks remaining in the data stream */
blocks = len / blocksize;
if (blocks) {
rv = gcm_HashMult(ghash, buf, blocks, blocksize);
if (rv != SECSuccess) {
return SECFailure;
}
buf += blocks * blocksize;
len -= blocks * blocksize;
}
/* save any remainder in the buffer to be hashed with the next call */
if (len != 0) {
PORT_Memcpy(ghash->buffer, buf, len);
ghash->bufLen = len;
}
return SECSuccess;
}
/*
* write out any partial blocks zero padded through the GHASH engine,
* save the lengths for the final completion of the hash
*/
static SECStatus
gcmHash_Sync(gcmHashContext *ghash, unsigned int blocksize)
{
int i;
SECStatus rv;
/* copy the previous counter to the upper block */
PORT_Memcpy(ghash->counterBuf, &ghash->counterBuf[GCM_HASH_LEN_LEN],
GCM_HASH_LEN_LEN);
/* copy the current counter in the lower block */
for (i = 0; i < GCM_HASH_LEN_LEN; i++) {
ghash->counterBuf[GCM_HASH_LEN_LEN + i] =
(ghash->cLen >> ((GCM_HASH_LEN_LEN - 1 - i) * PR_BITS_PER_BYTE)) & 0xff;
}
ghash->cLen = 0;
/* now zero fill the buffer and hash the last block */
if (ghash->bufLen) {
PORT_Memset(ghash->buffer + ghash->bufLen, 0, blocksize - ghash->bufLen);
rv = gcm_HashMult(ghash, ghash->buffer, 1, blocksize);
PORT_Memset(ghash->buffer, 0, blocksize);
ghash->bufLen = 0;
if (rv != SECSuccess) {
return SECFailure;
}
}
return SECSuccess;
}
/*
* This does the final sync, hashes the lengths, then returns
* "T", the hashed output.
*/
static SECStatus
gcmHash_Final(gcmHashContext *ghash, unsigned char *outbuf,
unsigned int *outlen, unsigned int maxout,
unsigned int blocksize)
{
unsigned char T[MAX_BLOCK_SIZE];
SECStatus rv;
rv = gcmHash_Sync(ghash, blocksize);
if (rv != SECSuccess) {
goto cleanup;
}
rv = gcm_HashMult(ghash, ghash->counterBuf, (GCM_HASH_LEN_LEN * 2) / blocksize,
blocksize);
if (rv != SECSuccess) {
goto cleanup;
}
GCM_TRACE_X(ghash, "GHASH(H,A,C) = ")
rv = gcm_getX(ghash, T, blocksize);
if (rv != SECSuccess) {
goto cleanup;
}
if (maxout > blocksize)
maxout = blocksize;
PORT_Memcpy(outbuf, T, maxout);
*outlen = maxout;
rv = SECSuccess;
cleanup:
PORT_Memset(T, 0, sizeof(T));
return rv;
}
SECStatus
gcmHash_Reset(gcmHashContext *ghash, const unsigned char *AAD,
unsigned int AADLen, unsigned int blocksize)
{
SECStatus rv;
ghash->cLen = 0;
PORT_Memset(ghash->counterBuf, 0, GCM_HASH_LEN_LEN * 2);
ghash->bufLen = 0;
gcm_zeroX(ghash);
/* now kick things off by hashing the Additional Authenticated Data */
if (AADLen != 0) {
rv = gcmHash_Update(ghash, AAD, AADLen, blocksize);
if (rv != SECSuccess) {
return SECFailure;
}
rv = gcmHash_Sync(ghash, blocksize);
if (rv != SECSuccess) {
return SECFailure;
}
}
return SECSuccess;
}
/**************************************************************************
* Now implement the GCM using gcmHash and CTR *
**************************************************************************/
/* state to handle the full GCM operation (hash and counter) */
struct GCMContextStr {
gcmHashContext ghash_context;
CTRContext ctr_context;
unsigned long tagBits;
unsigned char tagKey[MAX_BLOCK_SIZE];
};
GCMContext *
GCM_CreateContext(void *context, freeblCipherFunc cipher,
const unsigned char *params, unsigned int blocksize)
{
GCMContext *gcm = NULL;
gcmHashContext *ghash;
unsigned char H[MAX_BLOCK_SIZE];
unsigned int tmp;
PRBool freeCtr = PR_FALSE;
PRBool freeHash = PR_FALSE;
const CK_GCM_PARAMS *gcmParams = (const CK_GCM_PARAMS *)params;
CK_AES_CTR_PARAMS ctrParams;
SECStatus rv;
if (blocksize > MAX_BLOCK_SIZE || blocksize > sizeof(ctrParams.cb)) {
PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
return NULL;
}
gcm = PORT_ZNew(GCMContext);
if (gcm == NULL) {
return NULL;
}
/* first fill in the ghash context */
ghash = &gcm->ghash_context;
PORT_Memset(H, 0, blocksize);
rv = (*cipher)(context, H, &tmp, blocksize, H, blocksize, blocksize);
if (rv != SECSuccess) {
goto loser;
}
rv = gcmHash_InitContext(ghash, H, blocksize);
if (rv != SECSuccess) {
goto loser;
}
freeHash = PR_TRUE;
/* fill in the Counter context */
ctrParams.ulCounterBits = 32;
PORT_Memset(ctrParams.cb, 0, sizeof(ctrParams.cb));
if ((blocksize == 16) && (gcmParams->ulIvLen == 12)) {
PORT_Memcpy(ctrParams.cb, gcmParams->pIv, gcmParams->ulIvLen);
ctrParams.cb[blocksize - 1] = 1;
} else {
rv = gcmHash_Update(ghash, gcmParams->pIv, gcmParams->ulIvLen,
blocksize);
if (rv != SECSuccess) {
goto loser;
}
rv = gcmHash_Final(ghash, ctrParams.cb, &tmp, blocksize, blocksize);
if (rv != SECSuccess) {
goto loser;
}
}
rv = CTR_InitContext(&gcm->ctr_context, context, cipher,
(unsigned char *)&ctrParams, blocksize);
if (rv != SECSuccess) {
goto loser;
}
freeCtr = PR_TRUE;
/* fill in the gcm structure */
gcm->tagBits = gcmParams->ulTagBits; /* save for final step */
/* calculate the final tag key. NOTE: gcm->tagKey is zero to start with.
* if this assumption changes, we would need to explicitly clear it here */
rv = CTR_Update(&gcm->ctr_context, gcm->tagKey, &tmp, blocksize,
gcm->tagKey, blocksize, blocksize);
if (rv != SECSuccess) {
goto loser;
}
/* finally mix in the AAD data */
rv = gcmHash_Reset(ghash, gcmParams->pAAD, gcmParams->ulAADLen, blocksize);
if (rv != SECSuccess) {
goto loser;
}
return gcm;
loser:
if (freeCtr) {
CTR_DestroyContext(&gcm->ctr_context, PR_FALSE);
}
if (freeHash) {
gcmHash_DestroyContext(&gcm->ghash_context, PR_FALSE);
}
if (gcm) {
PORT_Free(gcm);
}
return NULL;
}
void
GCM_DestroyContext(GCMContext *gcm, PRBool freeit)
{
/* these two are statically allocated and will be freed when we free
* gcm. call their destroy functions to free up any locally
* allocated data (like mp_int's) */
CTR_DestroyContext(&gcm->ctr_context, PR_FALSE);
gcmHash_DestroyContext(&gcm->ghash_context, PR_FALSE);
PORT_Memset(&gcm->tagBits, 0, sizeof(gcm->tagBits));
PORT_Memset(gcm->tagKey, 0, sizeof(gcm->tagKey));
if (freeit) {
PORT_Free(gcm);
}
}
static SECStatus
gcm_GetTag(GCMContext *gcm, unsigned char *outbuf,
unsigned int *outlen, unsigned int maxout,
unsigned int blocksize)
{
unsigned int tagBytes;
unsigned int extra;
unsigned int i;
SECStatus rv;
tagBytes = (gcm->tagBits + (PR_BITS_PER_BYTE - 1)) / PR_BITS_PER_BYTE;
extra = tagBytes * PR_BITS_PER_BYTE - gcm->tagBits;
if (outbuf == NULL) {
*outlen = tagBytes;
PORT_SetError(SEC_ERROR_OUTPUT_LEN);
return SECFailure;
}
if (maxout < tagBytes) {
*outlen = tagBytes;
PORT_SetError(SEC_ERROR_OUTPUT_LEN);
return SECFailure;
}
maxout = tagBytes;
rv = gcmHash_Final(&gcm->ghash_context, outbuf, outlen, maxout, blocksize);
if (rv != SECSuccess) {
return SECFailure;
}
GCM_TRACE_BLOCK("GHASH=", outbuf, blocksize);
GCM_TRACE_BLOCK("Y0=", gcm->tagKey, blocksize);
for (i = 0; i < *outlen; i++) {
outbuf[i] ^= gcm->tagKey[i];
}
GCM_TRACE_BLOCK("Y0=", gcm->tagKey, blocksize);
GCM_TRACE_BLOCK("T=", outbuf, blocksize);
/* mask off any extra bits we got */
if (extra) {
outbuf[tagBytes - 1] &= ~((1 << extra) - 1);
}
return SECSuccess;
}
/*
* See The Galois/Counter Mode of Operation, McGrew and Viega.
* GCM is basically counter mode with a specific initialization and
* built in macing operation.
*/
SECStatus
GCM_EncryptUpdate(GCMContext *gcm, unsigned char *outbuf,
unsigned int *outlen, unsigned int maxout,
const unsigned char *inbuf, unsigned int inlen,
unsigned int blocksize)
{
SECStatus rv;
unsigned int tagBytes;
unsigned int len;
tagBytes = (gcm->tagBits + (PR_BITS_PER_BYTE - 1)) / PR_BITS_PER_BYTE;
if (UINT_MAX - inlen < tagBytes) {
PORT_SetError(SEC_ERROR_INPUT_LEN);
return SECFailure;
}
if (maxout < inlen + tagBytes) {
*outlen = inlen + tagBytes;
PORT_SetError(SEC_ERROR_OUTPUT_LEN);
return SECFailure;
}
rv = CTR_Update(&gcm->ctr_context, outbuf, outlen, maxout,
inbuf, inlen, blocksize);
if (rv != SECSuccess) {
return SECFailure;
}
rv = gcmHash_Update(&gcm->ghash_context, outbuf, *outlen, blocksize);
if (rv != SECSuccess) {
PORT_Memset(outbuf, 0, *outlen); /* clear the output buffer */
*outlen = 0;
return SECFailure;
}
rv = gcm_GetTag(gcm, outbuf + *outlen, &len, maxout - *outlen, blocksize);
if (rv != SECSuccess) {
PORT_Memset(outbuf, 0, *outlen); /* clear the output buffer */
*outlen = 0;
return SECFailure;
};
*outlen += len;
return SECSuccess;
}
/*
* See The Galois/Counter Mode of Operation, McGrew and Viega.
* GCM is basically counter mode with a specific initialization and
* built in macing operation. NOTE: the only difference between Encrypt
* and Decrypt is when we calculate the mac. That is because the mac must
* always be calculated on the cipher text, not the plain text, so for
* encrypt, we do the CTR update first and for decrypt we do the mac first.
*/
SECStatus
GCM_DecryptUpdate(GCMContext *gcm, unsigned char *outbuf,
unsigned int *outlen, unsigned int maxout,
const unsigned char *inbuf, unsigned int inlen,
unsigned int blocksize)
{
SECStatus rv;
unsigned int tagBytes;
unsigned char tag[MAX_BLOCK_SIZE];
const unsigned char *intag;
unsigned int len;
tagBytes = (gcm->tagBits + (PR_BITS_PER_BYTE - 1)) / PR_BITS_PER_BYTE;
/* get the authentication block */
if (inlen < tagBytes) {
PORT_SetError(SEC_ERROR_INPUT_LEN);
return SECFailure;
}
inlen -= tagBytes;
intag = inbuf + inlen;
/* verify the block */
rv = gcmHash_Update(&gcm->ghash_context, inbuf, inlen, blocksize);
if (rv != SECSuccess) {
return SECFailure;
}
rv = gcm_GetTag(gcm, tag, &len, blocksize, blocksize);
if (rv != SECSuccess) {
return SECFailure;
}
/* Don't decrypt if we can't authenticate the encrypted data!
* This assumes that if tagBits is not a multiple of 8, intag will
* preserve the masked off missing bits. */
if (NSS_SecureMemcmp(tag, intag, tagBytes) != 0) {
/* force a CKR_ENCRYPTED_DATA_INVALID error at in softoken */
PORT_SetError(SEC_ERROR_BAD_DATA);
PORT_Memset(tag, 0, sizeof(tag));
return SECFailure;
}
PORT_Memset(tag, 0, sizeof(tag));
/* finish the decryption */
return CTR_Update(&gcm->ctr_context, outbuf, outlen, maxout,
inbuf, inlen, blocksize);
}

View file

@ -0,0 +1,31 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef GCM_H
#define GCM_H 1
#include "blapii.h"
typedef struct GCMContextStr GCMContext;
/*
* The context argument is the inner cipher context to use with cipher. The
* GCMContext does not own context. context needs to remain valid for as long
* as the GCMContext is valid.
*
* The cipher argument is a block cipher in the ECB encrypt mode.
*/
GCMContext *GCM_CreateContext(void *context, freeblCipherFunc cipher,
const unsigned char *params, unsigned int blocksize);
void GCM_DestroyContext(GCMContext *gcm, PRBool freeit);
SECStatus GCM_EncryptUpdate(GCMContext *gcm, unsigned char *outbuf,
unsigned int *outlen, unsigned int maxout,
const unsigned char *inbuf, unsigned int inlen,
unsigned int blocksize);
SECStatus GCM_DecryptUpdate(GCMContext *gcm, unsigned char *outbuf,
unsigned int *outlen, unsigned int maxout,
const unsigned char *inbuf, unsigned int inlen,
unsigned int blocksize);
#endif

View file

@ -0,0 +1,167 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
/*
* This file is meant to be included by other .c files.
* This file takes a "parameter", the scope which includes this
* code shall declare this variable:
* const char *NameOfThisSharedLib;
*
* NameOfThisSharedLib:
* The file name of the shared library that shall be used as the
* "reference library". The loader will attempt to load the requested
* library from the same directory as the reference library.
*/
#ifdef XP_UNIX
#include <unistd.h>
#define BL_MAXSYMLINKS 20
/*
* If 'link' is a symbolic link, this function follows the symbolic links
* and returns the pathname of the ultimate source of the symbolic links.
* If 'link' is not a symbolic link, this function returns NULL.
* The caller should call PR_Free to free the string returned by this
* function.
*/
static char*
loader_GetOriginalPathname(const char* link)
{
#ifdef __GLIBC__
char* tmp = realpath(link, NULL);
char* resolved;
if (!tmp)
return NULL;
resolved = PR_Malloc(strlen(tmp) + 1);
strcpy(resolved, tmp); /* This is necessary because PR_Free might not be using free() */
free(tmp);
return resolved;
#else
char* resolved = NULL;
char* input = NULL;
PRUint32 iterations = 0;
PRInt32 len = 0, retlen = 0;
if (!link) {
PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0);
return NULL;
}
len = PR_MAX(1024, strlen(link) + 1);
resolved = PR_Malloc(len);
input = PR_Malloc(len);
if (!resolved || !input) {
if (resolved) {
PR_Free(resolved);
}
if (input) {
PR_Free(input);
}
return NULL;
}
strcpy(input, link);
while ((iterations++ < BL_MAXSYMLINKS) &&
((retlen = readlink(input, resolved, len - 1)) > 0)) {
char* tmp = input;
resolved[retlen] = '\0'; /* NULL termination */
input = resolved;
resolved = tmp;
}
PR_Free(resolved);
if (iterations == 1 && retlen < 0) {
PR_Free(input);
input = NULL;
}
return input;
#endif
}
#endif /* XP_UNIX */
/*
* Load the library with the file name 'name' residing in the same
* directory as the reference library, whose pathname is 'referencePath'.
*/
static PRLibrary*
loader_LoadLibInReferenceDir(const char* referencePath, const char* name)
{
PRLibrary* dlh = NULL;
char* fullName = NULL;
char* c;
PRLibSpec libSpec;
/* Remove the trailing filename from referencePath and add the new one */
c = strrchr(referencePath, PR_GetDirectorySeparator());
if (c) {
size_t referencePathSize = 1 + c - referencePath;
fullName = (char*)PORT_Alloc(strlen(name) + referencePathSize + 1);
if (fullName) {
memcpy(fullName, referencePath, referencePathSize);
strcpy(fullName + referencePathSize, name);
#ifdef DEBUG_LOADER
PR_fprintf(PR_STDOUT, "\nAttempting to load fully-qualified %s\n",
fullName);
#endif
libSpec.type = PR_LibSpec_Pathname;
libSpec.value.pathname = fullName;
dlh = PR_LoadLibraryWithFlags(libSpec, PR_LD_NOW | PR_LD_LOCAL);
PORT_Free(fullName);
}
}
return dlh;
}
/*
* We use PR_GetLibraryFilePathname to get the pathname of the loaded
* shared lib that contains this function, and then do a PR_LoadLibrary
* with an absolute pathname for the softoken shared library.
*/
static PRLibrary*
loader_LoadLibrary(const char* nameToLoad)
{
PRLibrary* lib = NULL;
char* fullPath = NULL;
PRLibSpec libSpec;
/* Get the pathname for nameOfAlreadyLoadedLib, i.e. /usr/lib/libnss3.so
* PR_GetLibraryFilePathname works with either the base library name or a
* function pointer, depending on the platform. We can't query an exported
* symbol such as NSC_GetFunctionList, because on some platforms we can't
* find symbols in loaded implicit dependencies.
* But we can just get the address of this function !
*/
fullPath = PR_GetLibraryFilePathname(NameOfThisSharedLib,
(PRFuncPtr)&loader_LoadLibrary);
if (fullPath) {
lib = loader_LoadLibInReferenceDir(fullPath, nameToLoad);
#ifdef XP_UNIX
if (!lib) {
/*
* If fullPath is a symbolic link, resolve the symbolic
* link and try again.
*/
char* originalfullPath = loader_GetOriginalPathname(fullPath);
if (originalfullPath) {
PR_Free(fullPath);
fullPath = originalfullPath;
lib = loader_LoadLibInReferenceDir(fullPath, nameToLoad);
}
}
#endif
PR_Free(fullPath);
}
if (!lib) {
#ifdef DEBUG_LOADER
PR_fprintf(PR_STDOUT, "\nAttempting to load %s\n", nameToLoad);
#endif
libSpec.type = PR_LibSpec_Pathname;
libSpec.value.pathname = nameToLoad;
lib = PR_LoadLibraryWithFlags(libSpec, PR_LD_NOW | PR_LD_LOCAL);
}
if (NULL == lib) {
#ifdef DEBUG_LOADER
PR_fprintf(PR_STDOUT, "\nLoading failed : %s.\n", nameToLoad);
#endif
}
return lib;
}

View file

@ -0,0 +1,335 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifdef FREEBL_NO_DEPEND
#include "stubs.h"
#endif
#include "secport.h"
#include "hasht.h"
#include "blapit.h"
#include "hmacct.h"
#include "secerr.h"
/* MAX_HASH_BIT_COUNT_BYTES is the maximum number of bytes in the hash's length
* field. (SHA-384/512 have 128-bit length.) */
#define MAX_HASH_BIT_COUNT_BYTES 16
/* Some utility functions are needed:
*
* These macros return the given value with the MSB copied to all the other
* bits. They use the fact that an arithmetic shift shifts-in the sign bit.
* However, this is not ensured by the C standard so you may need to replace
* them with something else on odd CPUs.
*
* Note: the argument to these macros must be an unsigned int.
* */
#define DUPLICATE_MSB_TO_ALL(x) ((unsigned int)((int)(x) >> (sizeof(int) * 8 - 1)))
#define DUPLICATE_MSB_TO_ALL_8(x) ((unsigned char)(DUPLICATE_MSB_TO_ALL(x)))
/* constantTimeGE returns 0xff if a>=b and 0x00 otherwise, where a, b <
* MAX_UINT/2. */
static unsigned char
constantTimeGE(unsigned int a, unsigned int b)
{
a -= b;
return DUPLICATE_MSB_TO_ALL(~a);
}
/* constantTimeEQ8 returns 0xff if a==b and 0x00 otherwise. */
static unsigned char
constantTimeEQ8(unsigned char a, unsigned char b)
{
unsigned int c = a ^ b;
c--;
return DUPLICATE_MSB_TO_ALL_8(c);
}
/* MAC performs a constant time SSLv3/TLS MAC of |dataLen| bytes of |data|,
* where |dataLen| includes both the authenticated bytes and the MAC tag from
* the sender. |dataLen| must be >= the length of the MAC tag.
*
* |dataTotalLen| is >= |dataLen| and also accounts for any padding bytes
* that may follow the sender's MAC. (Only a single block of padding may
* follow in SSLv3, or up to 255 bytes in TLS.)
*
* Since the results of decryption are secret information (otherwise a
* padding-oracle is created), this function is constant-time with respect to
* |dataLen|.
*
* |header| contains either the 13-byte TLS header (containing the sequence
* number, record type etc), or it contains the SSLv3 header with the SSLv3
* padding bytes etc. */
static SECStatus
MAC(unsigned char *mdOut,
unsigned int *mdOutLen,
unsigned int mdOutMax,
const SECHashObject *hashObj,
const unsigned char *macSecret,
unsigned int macSecretLen,
const unsigned char *header,
unsigned int headerLen,
const unsigned char *data,
unsigned int dataLen,
unsigned int dataTotalLen,
unsigned char isSSLv3)
{
void *mdState = hashObj->create();
const unsigned int mdSize = hashObj->length;
const unsigned int mdBlockSize = hashObj->blocklength;
/* mdLengthSize is the number of bytes in the length field that terminates
* the hash.
*
* This assumes that hash functions with a 64 byte block size use a 64-bit
* length, and otherwise they use a 128-bit length. This is true of {MD5,
* SHA*} (which are all of the hash functions specified for use with TLS
* today). */
const unsigned int mdLengthSize = mdBlockSize == 64 ? 8 : 16;
const unsigned int sslv3PadLen = hashObj->type == HASH_AlgMD5 ? 48 : 40;
/* varianceBlocks is the number of blocks of the hash that we have to
* calculate in constant time because they could be altered by the
* padding value.
*
* In SSLv3, the padding must be minimal so the end of the plaintext
* varies by, at most, 15+20 = 35 bytes. (We conservatively assume that
* the MAC size varies from 0..20 bytes.) In case the 9 bytes of hash
* termination (0x80 + 64-bit length) don't fit in the final block, we
* say that the final two blocks can vary based on the padding.
*
* TLSv1 has MACs up to 48 bytes long (SHA-384) and the padding is not
* required to be minimal. Therefore we say that the final six blocks
* can vary based on the padding.
*
* Later in the function, if the message is short and there obviously
* cannot be this many blocks then varianceBlocks can be reduced. */
unsigned int varianceBlocks = isSSLv3 ? 2 : 6;
/* From now on we're dealing with the MAC, which conceptually has 13
* bytes of `header' before the start of the data (TLS) or 71/75 bytes
* (SSLv3) */
const unsigned int len = dataTotalLen + headerLen;
/* maxMACBytes contains the maximum bytes of bytes in the MAC, including
* |header|, assuming that there's no padding. */
const unsigned int maxMACBytes = len - mdSize - 1;
/* numBlocks is the maximum number of hash blocks. */
const unsigned int numBlocks =
(maxMACBytes + 1 + mdLengthSize + mdBlockSize - 1) / mdBlockSize;
/* macEndOffset is the index just past the end of the data to be
* MACed. */
const unsigned int macEndOffset = dataLen + headerLen - mdSize;
/* c is the index of the 0x80 byte in the final hash block that
* contains application data. */
const unsigned int c = macEndOffset % mdBlockSize;
/* indexA is the hash block number that contains the 0x80 terminating
* value. */
const unsigned int indexA = macEndOffset / mdBlockSize;
/* indexB is the hash block number that contains the 64-bit hash
* length, in bits. */
const unsigned int indexB = (macEndOffset + mdLengthSize) / mdBlockSize;
/* bits is the hash-length in bits. It includes the additional hash
* block for the masked HMAC key, or whole of |header| in the case of
* SSLv3. */
unsigned int bits;
/* In order to calculate the MAC in constant time we have to handle
* the final blocks specially because the padding value could cause the
* end to appear somewhere in the final |varianceBlocks| blocks and we
* can't leak where. However, |numStartingBlocks| worth of data can
* be hashed right away because no padding value can affect whether
* they are plaintext. */
unsigned int numStartingBlocks = 0;
/* k is the starting byte offset into the conceptual header||data where
* we start processing. */
unsigned int k = 0;
unsigned char lengthBytes[MAX_HASH_BIT_COUNT_BYTES];
/* hmacPad is the masked HMAC key. */
unsigned char hmacPad[HASH_BLOCK_LENGTH_MAX];
unsigned char firstBlock[HASH_BLOCK_LENGTH_MAX];
unsigned char macOut[HASH_LENGTH_MAX];
unsigned i, j;
/* For SSLv3, if we're going to have any starting blocks then we need
* at least two because the header is larger than a single block. */
if (numBlocks > varianceBlocks + (isSSLv3 ? 1 : 0)) {
numStartingBlocks = numBlocks - varianceBlocks;
k = mdBlockSize * numStartingBlocks;
}
bits = 8 * macEndOffset;
hashObj->begin(mdState);
if (!isSSLv3) {
/* Compute the initial HMAC block. For SSLv3, the padding and
* secret bytes are included in |header| because they take more
* than a single block. */
bits += 8 * mdBlockSize;
memset(hmacPad, 0, mdBlockSize);
PORT_Assert(macSecretLen <= sizeof(hmacPad));
memcpy(hmacPad, macSecret, macSecretLen);
for (i = 0; i < mdBlockSize; i++)
hmacPad[i] ^= 0x36;
hashObj->update(mdState, hmacPad, mdBlockSize);
}
j = 0;
memset(lengthBytes, 0, sizeof(lengthBytes));
if (mdLengthSize == 16) {
j = 8;
}
if (hashObj->type == HASH_AlgMD5) {
/* MD5 appends a little-endian length. */
for (i = 0; i < 4; i++) {
lengthBytes[i + j] = bits >> (8 * i);
}
} else {
/* All other TLS hash functions use a big-endian length. */
for (i = 0; i < 4; i++) {
lengthBytes[4 + i + j] = bits >> (8 * (3 - i));
}
}
if (k > 0) {
if (isSSLv3) {
/* The SSLv3 header is larger than a single block.
* overhang is the number of bytes beyond a single
* block that the header consumes: either 7 bytes
* (SHA1) or 11 bytes (MD5). */
const unsigned int overhang = headerLen - mdBlockSize;
hashObj->update(mdState, header, mdBlockSize);
memcpy(firstBlock, header + mdBlockSize, overhang);
memcpy(firstBlock + overhang, data, mdBlockSize - overhang);
hashObj->update(mdState, firstBlock, mdBlockSize);
for (i = 1; i < k / mdBlockSize - 1; i++) {
hashObj->update(mdState, data + mdBlockSize * i - overhang,
mdBlockSize);
}
} else {
/* k is a multiple of mdBlockSize. */
memcpy(firstBlock, header, 13);
memcpy(firstBlock + 13, data, mdBlockSize - 13);
hashObj->update(mdState, firstBlock, mdBlockSize);
for (i = 1; i < k / mdBlockSize; i++) {
hashObj->update(mdState, data + mdBlockSize * i - 13,
mdBlockSize);
}
}
}
memset(macOut, 0, sizeof(macOut));
/* We now process the final hash blocks. For each block, we construct
* it in constant time. If i == indexA then we'll include the 0x80
* bytes and zero pad etc. For each block we selectively copy it, in
* constant time, to |macOut|. */
for (i = numStartingBlocks; i <= numStartingBlocks + varianceBlocks; i++) {
unsigned char block[HASH_BLOCK_LENGTH_MAX];
unsigned char isBlockA = constantTimeEQ8(i, indexA);
unsigned char isBlockB = constantTimeEQ8(i, indexB);
for (j = 0; j < mdBlockSize; j++) {
unsigned char isPastC = isBlockA & constantTimeGE(j, c);
unsigned char isPastCPlus1 = isBlockA & constantTimeGE(j, c + 1);
unsigned char b = 0;
if (k < headerLen) {
b = header[k];
} else if (k < dataTotalLen + headerLen) {
b = data[k - headerLen];
}
k++;
/* If this is the block containing the end of the
* application data, and we are at the offset for the
* 0x80 value, then overwrite b with 0x80. */
b = (b & ~isPastC) | (0x80 & isPastC);
/* If this the the block containing the end of the
* application data and we're past the 0x80 value then
* just write zero. */
b = b & ~isPastCPlus1;
/* If this is indexB (the final block), but not
* indexA (the end of the data), then the 64-bit
* length didn't fit into indexA and we're having to
* add an extra block of zeros. */
b &= ~isBlockB | isBlockA;
/* The final bytes of one of the blocks contains the length. */
if (j >= mdBlockSize - mdLengthSize) {
/* If this is indexB, write a length byte. */
b = (b & ~isBlockB) |
(isBlockB & lengthBytes[j - (mdBlockSize - mdLengthSize)]);
}
block[j] = b;
}
hashObj->update(mdState, block, mdBlockSize);
hashObj->end_raw(mdState, block, NULL, mdSize);
/* If this is indexB, copy the hash value to |macOut|. */
for (j = 0; j < mdSize; j++) {
macOut[j] |= block[j] & isBlockB;
}
}
hashObj->begin(mdState);
if (isSSLv3) {
/* We repurpose |hmacPad| to contain the SSLv3 pad2 block. */
for (i = 0; i < sslv3PadLen; i++)
hmacPad[i] = 0x5c;
hashObj->update(mdState, macSecret, macSecretLen);
hashObj->update(mdState, hmacPad, sslv3PadLen);
hashObj->update(mdState, macOut, mdSize);
} else {
/* Complete the HMAC in the standard manner. */
for (i = 0; i < mdBlockSize; i++)
hmacPad[i] ^= 0x6a;
hashObj->update(mdState, hmacPad, mdBlockSize);
hashObj->update(mdState, macOut, mdSize);
}
hashObj->end(mdState, mdOut, mdOutLen, mdOutMax);
hashObj->destroy(mdState, PR_TRUE);
return SECSuccess;
}
SECStatus
HMAC_ConstantTime(
unsigned char *result,
unsigned int *resultLen,
unsigned int maxResultLen,
const SECHashObject *hashObj,
const unsigned char *secret,
unsigned int secretLen,
const unsigned char *header,
unsigned int headerLen,
const unsigned char *body,
unsigned int bodyLen,
unsigned int bodyTotalLen)
{
if (hashObj->end_raw == NULL)
return SECFailure;
return MAC(result, resultLen, maxResultLen, hashObj, secret, secretLen,
header, headerLen, body, bodyLen, bodyTotalLen,
0 /* not SSLv3 */);
}
SECStatus
SSLv3_MAC_ConstantTime(
unsigned char *result,
unsigned int *resultLen,
unsigned int maxResultLen,
const SECHashObject *hashObj,
const unsigned char *secret,
unsigned int secretLen,
const unsigned char *header,
unsigned int headerLen,
const unsigned char *body,
unsigned int bodyLen,
unsigned int bodyTotalLen)
{
if (hashObj->end_raw == NULL)
return SECFailure;
return MAC(result, resultLen, maxResultLen, hashObj, secret, secretLen,
header, headerLen, body, bodyLen, bodyTotalLen,
1 /* SSLv3 */);
}

View file

@ -0,0 +1,38 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef _HMACCT_H_
#define _HMACCT_H_
SEC_BEGIN_PROTOS
extern SECStatus HMAC_ConstantTime(
unsigned char *result,
unsigned int *resultLen,
unsigned int maxResultLen,
const SECHashObject *hashObj,
const unsigned char *secret,
unsigned int secretLen,
const unsigned char *header,
unsigned int headerLen,
const unsigned char *body,
unsigned int bodyLen,
unsigned int bodyTotalLen);
extern SECStatus SSLv3_MAC_ConstantTime(
unsigned char *result,
unsigned int *resultLen,
unsigned int maxResultLen,
const SECHashObject *hashObj,
const unsigned char *secret,
unsigned int secretLen,
const unsigned char *header,
unsigned int headerLen,
const unsigned char *body,
unsigned int bodyLen,
unsigned int bodyTotalLen);
SEC_END_PROTOS
#endif

View file

@ -0,0 +1,971 @@
; LICENSE:
; This submission to NSS is to be made available under the terms of the
; Mozilla Public License, v. 2.0. You can obtain one at http:
; //mozilla.org/MPL/2.0/.
;###############################################################################
; Copyright(c) 2014, Intel Corp.
; Developers and authors:
; Shay Gueron and Vlad Krasnov
; Intel Corporation, Israel Development Centre, Haifa, Israel
; Please send feedback directly to crypto.feedback.alias@intel.com
.DATA
ALIGN 16
Lmask dd 0c0f0e0dh,0c0f0e0dh,0c0f0e0dh,0c0f0e0dh
Lmask192 dd 004070605h, 004070605h, 004070605h, 004070605h
Lmask256 dd 00c0f0e0dh, 00c0f0e0dh, 00c0f0e0dh, 00c0f0e0dh
Lcon1 dd 1,1,1,1
Lcon2 dd 1bh,1bh,1bh,1bh
.CODE
ctx textequ <rcx>
output textequ <rdx>
input textequ <r8>
inputLen textequ <r9d>
aes_rnd MACRO i
movdqu xmm8, [i*16 + ctx]
aesenc xmm0, xmm8
aesenc xmm1, xmm8
aesenc xmm2, xmm8
aesenc xmm3, xmm8
aesenc xmm4, xmm8
aesenc xmm5, xmm8
aesenc xmm6, xmm8
aesenc xmm7, xmm8
ENDM
aes_last_rnd MACRO i
movdqu xmm8, [i*16 + ctx]
aesenclast xmm0, xmm8
aesenclast xmm1, xmm8
aesenclast xmm2, xmm8
aesenclast xmm3, xmm8
aesenclast xmm4, xmm8
aesenclast xmm5, xmm8
aesenclast xmm6, xmm8
aesenclast xmm7, xmm8
ENDM
aes_dec_rnd MACRO i
movdqu xmm8, [i*16 + ctx]
aesdec xmm0, xmm8
aesdec xmm1, xmm8
aesdec xmm2, xmm8
aesdec xmm3, xmm8
aesdec xmm4, xmm8
aesdec xmm5, xmm8
aesdec xmm6, xmm8
aesdec xmm7, xmm8
ENDM
aes_dec_last_rnd MACRO i
movdqu xmm8, [i*16 + ctx]
aesdeclast xmm0, xmm8
aesdeclast xmm1, xmm8
aesdeclast xmm2, xmm8
aesdeclast xmm3, xmm8
aesdeclast xmm4, xmm8
aesdeclast xmm5, xmm8
aesdeclast xmm6, xmm8
aesdeclast xmm7, xmm8
ENDM
gen_aes_ecb_func MACRO enc, rnds
LOCAL loop8
LOCAL loop1
LOCAL bail
xor inputLen, inputLen
mov input, [rsp + 1*8 + 8*4]
mov inputLen, [rsp + 1*8 + 8*5]
sub rsp, 3*16
movdqu [rsp + 0*16], xmm6
movdqu [rsp + 1*16], xmm7
movdqu [rsp + 2*16], xmm8
lea ctx, [48+ctx]
loop8:
cmp inputLen, 8*16
jb loop1
movdqu xmm0, [0*16 + input]
movdqu xmm1, [1*16 + input]
movdqu xmm2, [2*16 + input]
movdqu xmm3, [3*16 + input]
movdqu xmm4, [4*16 + input]
movdqu xmm5, [5*16 + input]
movdqu xmm6, [6*16 + input]
movdqu xmm7, [7*16 + input]
movdqu xmm8, [0*16 + ctx]
pxor xmm0, xmm8
pxor xmm1, xmm8
pxor xmm2, xmm8
pxor xmm3, xmm8
pxor xmm4, xmm8
pxor xmm5, xmm8
pxor xmm6, xmm8
pxor xmm7, xmm8
IF enc eq 1
rnd textequ <aes_rnd>
lastrnd textequ <aes_last_rnd>
aesinst textequ <aesenc>
aeslastinst textequ <aesenclast>
ELSE
rnd textequ <aes_dec_rnd>
lastrnd textequ <aes_dec_last_rnd>
aesinst textequ <aesdec>
aeslastinst textequ <aesdeclast>
ENDIF
i = 1
WHILE i LT rnds
rnd i
i = i+1
ENDM
lastrnd rnds
movdqu [0*16 + output], xmm0
movdqu [1*16 + output], xmm1
movdqu [2*16 + output], xmm2
movdqu [3*16 + output], xmm3
movdqu [4*16 + output], xmm4
movdqu [5*16 + output], xmm5
movdqu [6*16 + output], xmm6
movdqu [7*16 + output], xmm7
lea input, [8*16 + input]
lea output, [8*16 + output]
sub inputLen, 8*16
jmp loop8
loop1:
cmp inputLen, 1*16
jb bail
movdqu xmm0, [input]
movdqu xmm7, [0*16 + ctx]
pxor xmm0, xmm7
i = 1
WHILE i LT rnds
movdqu xmm7, [i*16 + ctx]
aesinst xmm0, xmm7
i = i+1
ENDM
movdqu xmm7, [rnds*16 + ctx]
aeslastinst xmm0, xmm7
movdqu [output], xmm0
lea input, [1*16 + input]
lea output, [1*16 + output]
sub inputLen, 1*16
jmp loop1
bail:
xor rax, rax
movdqu xmm6, [rsp + 0*16]
movdqu xmm7, [rsp + 1*16]
movdqu xmm8, [rsp + 2*16]
add rsp, 3*16
ret
ENDM
intel_aes_encrypt_ecb_128 PROC
gen_aes_ecb_func 1, 10
intel_aes_encrypt_ecb_128 ENDP
intel_aes_encrypt_ecb_192 PROC
gen_aes_ecb_func 1, 12
intel_aes_encrypt_ecb_192 ENDP
intel_aes_encrypt_ecb_256 PROC
gen_aes_ecb_func 1, 14
intel_aes_encrypt_ecb_256 ENDP
intel_aes_decrypt_ecb_128 PROC
gen_aes_ecb_func 0, 10
intel_aes_decrypt_ecb_128 ENDP
intel_aes_decrypt_ecb_192 PROC
gen_aes_ecb_func 0, 12
intel_aes_decrypt_ecb_192 ENDP
intel_aes_decrypt_ecb_256 PROC
gen_aes_ecb_func 0, 14
intel_aes_decrypt_ecb_256 ENDP
KEY textequ <rcx>
KS textequ <rdx>
ITR textequ <r8>
intel_aes_encrypt_init_128 PROC
movdqu xmm1, [KEY]
movdqu [KS], xmm1
movdqa xmm2, xmm1
lea ITR, Lcon1
movdqa xmm0, [ITR]
lea ITR, Lmask
movdqa xmm4, [ITR]
mov ITR, 8
Lenc_128_ks_loop:
lea KS, [16 + KS]
dec ITR
pshufb xmm2, xmm4
aesenclast xmm2, xmm0
pslld xmm0, 1
movdqa xmm3, xmm1
pslldq xmm3, 4
pxor xmm1, xmm3
pslldq xmm3, 4
pxor xmm1, xmm3
pslldq xmm3, 4
pxor xmm1, xmm3
pxor xmm1, xmm2
movdqu [KS], xmm1
movdqa xmm2, xmm1
jne Lenc_128_ks_loop
lea ITR, Lcon2
movdqa xmm0, [ITR]
pshufb xmm2, xmm4
aesenclast xmm2, xmm0
pslld xmm0, 1
movdqa xmm3, xmm1
pslldq xmm3, 4
pxor xmm1, xmm3
pslldq xmm3, 4
pxor xmm1, xmm3
pslldq xmm3, 4
pxor xmm1, xmm3
pxor xmm1, xmm2
movdqu [16 + KS], xmm1
movdqa xmm2, xmm1
pshufb xmm2, xmm4
aesenclast xmm2, xmm0
movdqa xmm3, xmm1
pslldq xmm3, 4
pxor xmm1, xmm3
pslldq xmm3, 4
pxor xmm1, xmm3
pslldq xmm3, 4
pxor xmm1, xmm3
pxor xmm1, xmm2
movdqu [32 + KS], xmm1
movdqa xmm2, xmm1
ret
intel_aes_encrypt_init_128 ENDP
intel_aes_decrypt_init_128 PROC
push KS
push KEY
call intel_aes_encrypt_init_128
pop KEY
pop KS
movdqu xmm0, [0*16 + KS]
movdqu xmm1, [10*16 + KS]
movdqu [10*16 + KS], xmm0
movdqu [0*16 + KS], xmm1
i = 1
WHILE i LT 5
movdqu xmm0, [i*16 + KS]
movdqu xmm1, [(10-i)*16 + KS]
aesimc xmm0, xmm0
aesimc xmm1, xmm1
movdqu [(10-i)*16 + KS], xmm0
movdqu [i*16 + KS], xmm1
i = i+1
ENDM
movdqu xmm0, [5*16 + KS]
aesimc xmm0, xmm0
movdqu [5*16 + KS], xmm0
ret
intel_aes_decrypt_init_128 ENDP
intel_aes_encrypt_init_192 PROC
sub rsp, 16*2
movdqu [16*0 + rsp], xmm6
movdqu [16*1 + rsp], xmm7
movdqu xmm1, [KEY]
mov ITR, [16 + KEY]
movd xmm3, ITR
movdqu [KS], xmm1
movdqa xmm5, xmm3
lea ITR, Lcon1
movdqu xmm0, [ITR]
lea ITR, Lmask192
movdqu xmm4, [ITR]
mov ITR, 4
Lenc_192_ks_loop:
movdqa xmm2, xmm3
pshufb xmm2, xmm4
aesenclast xmm2, xmm0
pslld xmm0, 1
movdqa xmm6, xmm1
movdqa xmm7, xmm3
pslldq xmm6, 4
pslldq xmm7, 4
pxor xmm1, xmm6
pxor xmm3, xmm7
pslldq xmm6, 4
pxor xmm1, xmm6
pslldq xmm6, 4
pxor xmm1, xmm6
pxor xmm1, xmm2
pshufd xmm2, xmm1, 0ffh
pxor xmm3, xmm2
movdqa xmm6, xmm1
shufpd xmm5, xmm1, 00h
shufpd xmm6, xmm3, 01h
movdqu [16 + KS], xmm5
movdqu [32 + KS], xmm6
movdqa xmm2, xmm3
pshufb xmm2, xmm4
aesenclast xmm2, xmm0
pslld xmm0, 1
movdqa xmm6, xmm1
movdqa xmm7, xmm3
pslldq xmm6, 4
pslldq xmm7, 4
pxor xmm1, xmm6
pxor xmm3, xmm7
pslldq xmm6, 4
pxor xmm1, xmm6
pslldq xmm6, 4
pxor xmm1, xmm6
pxor xmm1, xmm2
pshufd xmm2, xmm1, 0ffh
pxor xmm3, xmm2
movdqu [48 + KS], xmm1
movdqa xmm5, xmm3
lea KS, [48 + KS]
dec ITR
jnz Lenc_192_ks_loop
movdqu [16 + KS], xmm5
movdqu xmm7, [16*1 + rsp]
movdqu xmm6, [16*0 + rsp]
add rsp, 16*2
ret
intel_aes_encrypt_init_192 ENDP
intel_aes_decrypt_init_192 PROC
push KS
push KEY
call intel_aes_encrypt_init_192
pop KEY
pop KS
movdqu xmm0, [0*16 + KS]
movdqu xmm1, [12*16 + KS]
movdqu [12*16 + KS], xmm0
movdqu [0*16 + KS], xmm1
i = 1
WHILE i LT 6
movdqu xmm0, [i*16 + KS]
movdqu xmm1, [(12-i)*16 + KS]
aesimc xmm0, xmm0
aesimc xmm1, xmm1
movdqu [(12-i)*16 + KS], xmm0
movdqu [i*16 + KS], xmm1
i = i+1
ENDM
movdqu xmm0, [6*16 + KS]
aesimc xmm0, xmm0
movdqu [6*16 + KS], xmm0
ret
intel_aes_decrypt_init_192 ENDP
intel_aes_encrypt_init_256 PROC
sub rsp, 16*2
movdqu [16*0 + rsp], xmm6
movdqu [16*1 + rsp], xmm7
movdqu xmm1, [16*0 + KEY]
movdqu xmm3, [16*1 + KEY]
movdqu [16*0 + KS], xmm1
movdqu [16*1 + KS], xmm3
lea ITR, Lcon1
movdqu xmm0, [ITR]
lea ITR, Lmask256
movdqu xmm5, [ITR]
pxor xmm6, xmm6
mov ITR, 6
Lenc_256_ks_loop:
movdqa xmm2, xmm3
pshufb xmm2, xmm5
aesenclast xmm2, xmm0
pslld xmm0, 1
movdqa xmm4, xmm1
pslldq xmm4, 4
pxor xmm1, xmm4
pslldq xmm4, 4
pxor xmm1, xmm4
pslldq xmm4, 4
pxor xmm1, xmm4
pxor xmm1, xmm2
movdqu [16*2 + KS], xmm1
pshufd xmm2, xmm1, 0ffh
aesenclast xmm2, xmm6
movdqa xmm4, xmm3
pslldq xmm4, 4
pxor xmm3, xmm4
pslldq xmm4, 4
pxor xmm3, xmm4
pslldq xmm4, 4
pxor xmm3, xmm4
pxor xmm3, xmm2
movdqu [16*3 + KS], xmm3
lea KS, [32 + KS]
dec ITR
jnz Lenc_256_ks_loop
movdqa xmm2, xmm3
pshufb xmm2, xmm5
aesenclast xmm2, xmm0
movdqa xmm4, xmm1
pslldq xmm4, 4
pxor xmm1, xmm4
pslldq xmm4, 4
pxor xmm1, xmm4
pslldq xmm4, 4
pxor xmm1, xmm4
pxor xmm1, xmm2
movdqu [16*2 + KS], xmm1
movdqu xmm7, [16*1 + rsp]
movdqu xmm6, [16*0 + rsp]
add rsp, 16*2
ret
intel_aes_encrypt_init_256 ENDP
intel_aes_decrypt_init_256 PROC
push KS
push KEY
call intel_aes_encrypt_init_256
pop KEY
pop KS
movdqu xmm0, [0*16 + KS]
movdqu xmm1, [14*16 + KS]
movdqu [14*16 + KS], xmm0
movdqu [0*16 + KS], xmm1
i = 1
WHILE i LT 7
movdqu xmm0, [i*16 + KS]
movdqu xmm1, [(14-i)*16 + KS]
aesimc xmm0, xmm0
aesimc xmm1, xmm1
movdqu [(14-i)*16 + KS], xmm0
movdqu [i*16 + KS], xmm1
i = i+1
ENDM
movdqu xmm0, [7*16 + KS]
aesimc xmm0, xmm0
movdqu [7*16 + KS], xmm0
ret
intel_aes_decrypt_init_256 ENDP
gen_aes_cbc_enc_func MACRO rnds
LOCAL loop1
LOCAL bail
mov input, [rsp + 1*8 + 8*4]
mov inputLen, [rsp + 1*8 + 8*5]
sub rsp, 3*16
movdqu [rsp + 0*16], xmm6
movdqu [rsp + 1*16], xmm7
movdqu [rsp + 2*16], xmm8
lea ctx, [48+ctx]
movdqu xmm0, [-32+ctx]
movdqu xmm2, [0*16 + ctx]
movdqu xmm3, [1*16 + ctx]
movdqu xmm4, [2*16 + ctx]
movdqu xmm5, [3*16 + ctx]
movdqu xmm6, [4*16 + ctx]
movdqu xmm7, [5*16 + ctx]
loop1:
cmp inputLen, 1*16
jb bail
movdqu xmm1, [input]
pxor xmm1, xmm2
pxor xmm0, xmm1
aesenc xmm0, xmm3
aesenc xmm0, xmm4
aesenc xmm0, xmm5
aesenc xmm0, xmm6
aesenc xmm0, xmm7
i = 6
WHILE i LT rnds
movdqu xmm8, [i*16 + ctx]
aesenc xmm0, xmm8
i = i+1
ENDM
movdqu xmm8, [rnds*16 + ctx]
aesenclast xmm0, xmm8
movdqu [output], xmm0
lea input, [1*16 + input]
lea output, [1*16 + output]
sub inputLen, 1*16
jmp loop1
bail:
movdqu [-32+ctx], xmm0
xor rax, rax
movdqu xmm6, [rsp + 0*16]
movdqu xmm7, [rsp + 1*16]
movdqu xmm8, [rsp + 2*16]
add rsp, 3*16
ret
ENDM
gen_aes_cbc_dec_func MACRO rnds
LOCAL loop8
LOCAL loop1
LOCAL dec1
LOCAL bail
mov input, [rsp + 1*8 + 8*4]
mov inputLen, [rsp + 1*8 + 8*5]
sub rsp, 3*16
movdqu [rsp + 0*16], xmm6
movdqu [rsp + 1*16], xmm7
movdqu [rsp + 2*16], xmm8
lea ctx, [48+ctx]
loop8:
cmp inputLen, 8*16
jb dec1
movdqu xmm0, [0*16 + input]
movdqu xmm1, [1*16 + input]
movdqu xmm2, [2*16 + input]
movdqu xmm3, [3*16 + input]
movdqu xmm4, [4*16 + input]
movdqu xmm5, [5*16 + input]
movdqu xmm6, [6*16 + input]
movdqu xmm7, [7*16 + input]
movdqu xmm8, [0*16 + ctx]
pxor xmm0, xmm8
pxor xmm1, xmm8
pxor xmm2, xmm8
pxor xmm3, xmm8
pxor xmm4, xmm8
pxor xmm5, xmm8
pxor xmm6, xmm8
pxor xmm7, xmm8
i = 1
WHILE i LT rnds
aes_dec_rnd i
i = i+1
ENDM
aes_dec_last_rnd rnds
movdqu xmm8, [-32 + ctx]
pxor xmm0, xmm8
movdqu xmm8, [0*16 + input]
pxor xmm1, xmm8
movdqu xmm8, [1*16 + input]
pxor xmm2, xmm8
movdqu xmm8, [2*16 + input]
pxor xmm3, xmm8
movdqu xmm8, [3*16 + input]
pxor xmm4, xmm8
movdqu xmm8, [4*16 + input]
pxor xmm5, xmm8
movdqu xmm8, [5*16 + input]
pxor xmm6, xmm8
movdqu xmm8, [6*16 + input]
pxor xmm7, xmm8
movdqu xmm8, [7*16 + input]
movdqu [0*16 + output], xmm0
movdqu [1*16 + output], xmm1
movdqu [2*16 + output], xmm2
movdqu [3*16 + output], xmm3
movdqu [4*16 + output], xmm4
movdqu [5*16 + output], xmm5
movdqu [6*16 + output], xmm6
movdqu [7*16 + output], xmm7
movdqu [-32 + ctx], xmm8
lea input, [8*16 + input]
lea output, [8*16 + output]
sub inputLen, 8*16
jmp loop8
dec1:
movdqu xmm3, [-32 + ctx]
loop1:
cmp inputLen, 1*16
jb bail
movdqu xmm0, [input]
movdqa xmm4, xmm0
movdqu xmm7, [0*16 + ctx]
pxor xmm0, xmm7
i = 1
WHILE i LT rnds
movdqu xmm7, [i*16 + ctx]
aesdec xmm0, xmm7
i = i+1
ENDM
movdqu xmm7, [rnds*16 + ctx]
aesdeclast xmm0, xmm7
pxor xmm3, xmm0
movdqu [output], xmm3
movdqa xmm3, xmm4
lea input, [1*16 + input]
lea output, [1*16 + output]
sub inputLen, 1*16
jmp loop1
bail:
movdqu [-32 + ctx], xmm3
xor rax, rax
movdqu xmm6, [rsp + 0*16]
movdqu xmm7, [rsp + 1*16]
movdqu xmm8, [rsp + 2*16]
add rsp, 3*16
ret
ENDM
intel_aes_encrypt_cbc_128 PROC
gen_aes_cbc_enc_func 10
intel_aes_encrypt_cbc_128 ENDP
intel_aes_encrypt_cbc_192 PROC
gen_aes_cbc_enc_func 12
intel_aes_encrypt_cbc_192 ENDP
intel_aes_encrypt_cbc_256 PROC
gen_aes_cbc_enc_func 14
intel_aes_encrypt_cbc_256 ENDP
intel_aes_decrypt_cbc_128 PROC
gen_aes_cbc_dec_func 10
intel_aes_decrypt_cbc_128 ENDP
intel_aes_decrypt_cbc_192 PROC
gen_aes_cbc_dec_func 12
intel_aes_decrypt_cbc_192 ENDP
intel_aes_decrypt_cbc_256 PROC
gen_aes_cbc_dec_func 14
intel_aes_decrypt_cbc_256 ENDP
ctrCtx textequ <r10>
CTR textequ <r11d>
CTRSave textequ <eax>
gen_aes_ctr_func MACRO rnds
LOCAL loop8
LOCAL loop1
LOCAL enc1
LOCAL bail
mov input, [rsp + 8*1 + 4*8]
mov inputLen, [rsp + 8*1 + 5*8]
mov ctrCtx, ctx
mov ctx, [8+ctrCtx]
lea ctx, [48+ctx]
sub rsp, 3*16
movdqu [rsp + 0*16], xmm6
movdqu [rsp + 1*16], xmm7
movdqu [rsp + 2*16], xmm8
push rbp
mov rbp, rsp
sub rsp, 8*16
and rsp, -16
movdqu xmm0, [16+ctrCtx]
mov CTRSave, DWORD PTR [ctrCtx + 16 + 3*4]
bswap CTRSave
movdqu xmm1, [ctx + 0*16]
pxor xmm0, xmm1
movdqa [rsp + 0*16], xmm0
movdqa [rsp + 1*16], xmm0
movdqa [rsp + 2*16], xmm0
movdqa [rsp + 3*16], xmm0
movdqa [rsp + 4*16], xmm0
movdqa [rsp + 5*16], xmm0
movdqa [rsp + 6*16], xmm0
movdqa [rsp + 7*16], xmm0
inc CTRSave
mov CTR, CTRSave
bswap CTR
xor CTR, DWORD PTR [ctx + 3*4]
mov DWORD PTR [rsp + 1*16 + 3*4], CTR
inc CTRSave
mov CTR, CTRSave
bswap CTR
xor CTR, DWORD PTR [ctx + 3*4]
mov DWORD PTR [rsp + 2*16 + 3*4], CTR
inc CTRSave
mov CTR, CTRSave
bswap CTR
xor CTR, DWORD PTR [ctx + 3*4]
mov DWORD PTR [rsp + 3*16 + 3*4], CTR
inc CTRSave
mov CTR, CTRSave
bswap CTR
xor CTR, DWORD PTR [ctx + 3*4]
mov DWORD PTR [rsp + 4*16 + 3*4], CTR
inc CTRSave
mov CTR, CTRSave
bswap CTR
xor CTR, DWORD PTR [ctx + 3*4]
mov DWORD PTR [rsp + 5*16 + 3*4], CTR
inc CTRSave
mov CTR, CTRSave
bswap CTR
xor CTR, DWORD PTR [ctx + 3*4]
mov DWORD PTR [rsp + 6*16 + 3*4], CTR
inc CTRSave
mov CTR, CTRSave
bswap CTR
xor CTR, DWORD PTR [ctx + 3*4]
mov DWORD PTR [rsp + 7*16 + 3*4], CTR
loop8:
cmp inputLen, 8*16
jb loop1
movdqu xmm0, [0*16 + rsp]
movdqu xmm1, [1*16 + rsp]
movdqu xmm2, [2*16 + rsp]
movdqu xmm3, [3*16 + rsp]
movdqu xmm4, [4*16 + rsp]
movdqu xmm5, [5*16 + rsp]
movdqu xmm6, [6*16 + rsp]
movdqu xmm7, [7*16 + rsp]
i = 1
WHILE i LE 8
aes_rnd i
inc CTRSave
mov CTR, CTRSave
bswap CTR
xor CTR, DWORD PTR [ctx + 3*4]
mov DWORD PTR [rsp + (i-1)*16 + 3*4], CTR
i = i+1
ENDM
WHILE i LT rnds
aes_rnd i
i = i+1
ENDM
aes_last_rnd rnds
movdqu xmm8, [0*16 + input]
pxor xmm0, xmm8
movdqu xmm8, [1*16 + input]
pxor xmm1, xmm8
movdqu xmm8, [2*16 + input]
pxor xmm2, xmm8
movdqu xmm8, [3*16 + input]
pxor xmm3, xmm8
movdqu xmm8, [4*16 + input]
pxor xmm4, xmm8
movdqu xmm8, [5*16 + input]
pxor xmm5, xmm8
movdqu xmm8, [6*16 + input]
pxor xmm6, xmm8
movdqu xmm8, [7*16 + input]
pxor xmm7, xmm8
movdqu [0*16 + output], xmm0
movdqu [1*16 + output], xmm1
movdqu [2*16 + output], xmm2
movdqu [3*16 + output], xmm3
movdqu [4*16 + output], xmm4
movdqu [5*16 + output], xmm5
movdqu [6*16 + output], xmm6
movdqu [7*16 + output], xmm7
lea input, [8*16 + input]
lea output, [8*16 + output]
sub inputLen, 8*16
jmp loop8
loop1:
cmp inputLen, 1*16
jb bail
movdqu xmm0, [rsp]
add rsp, 16
i = 1
WHILE i LT rnds
movdqu xmm7, [i*16 + ctx]
aesenc xmm0, xmm7
i = i+1
ENDM
movdqu xmm7, [rnds*16 + ctx]
aesenclast xmm0, xmm7
movdqu xmm7, [input]
pxor xmm0, xmm7
movdqu [output], xmm0
lea input, [1*16 + input]
lea output, [1*16 + output]
sub inputLen, 1*16
jmp loop1
bail:
movdqu xmm0, [rsp]
movdqu xmm1, [ctx + 0*16]
pxor xmm0, xmm1
movdqu [16+ctrCtx], xmm0
xor rax, rax
mov rsp, rbp
pop rbp
movdqu xmm6, [rsp + 0*16]
movdqu xmm7, [rsp + 1*16]
movdqu xmm8, [rsp + 2*16]
add rsp, 3*16
ret
ENDM
intel_aes_encrypt_ctr_128 PROC
gen_aes_ctr_func 10
intel_aes_encrypt_ctr_128 ENDP
intel_aes_encrypt_ctr_192 PROC
gen_aes_ctr_func 12
intel_aes_encrypt_ctr_192 ENDP
intel_aes_encrypt_ctr_256 PROC
gen_aes_ctr_func 14
intel_aes_encrypt_ctr_256 ENDP
END

View file

@ -0,0 +1,949 @@
; LICENSE:
; This submission to NSS is to be made available under the terms of the
; Mozilla Public License, v. 2.0. You can obtain one at http:
; //mozilla.org/MPL/2.0/.
;###############################################################################
; Copyright(c) 2014, Intel Corp.
; Developers and authors:
; Shay Gueron and Vlad Krasnov
; Intel Corporation, Israel Development Centre, Haifa, Israel
; Please send feedback directly to crypto.feedback.alias@intel.com
.MODEL FLAT, C
.XMM
.DATA
ALIGN 16
Lmask dd 0c0f0e0dh,0c0f0e0dh,0c0f0e0dh,0c0f0e0dh
Lmask192 dd 004070605h, 004070605h, 004070605h, 004070605h
Lmask256 dd 00c0f0e0dh, 00c0f0e0dh, 00c0f0e0dh, 00c0f0e0dh
Lcon1 dd 1,1,1,1
Lcon2 dd 1bh,1bh,1bh,1bh
.CODE
ctx textequ <ecx>
output textequ <edx>
input textequ <eax>
inputLen textequ <edi>
aes_rnd MACRO i
movdqu xmm7, [i*16 + ctx]
aesenc xmm0, xmm7
aesenc xmm1, xmm7
aesenc xmm2, xmm7
aesenc xmm3, xmm7
aesenc xmm4, xmm7
aesenc xmm5, xmm7
aesenc xmm6, xmm7
ENDM
aes_last_rnd MACRO i
movdqu xmm7, [i*16 + ctx]
aesenclast xmm0, xmm7
aesenclast xmm1, xmm7
aesenclast xmm2, xmm7
aesenclast xmm3, xmm7
aesenclast xmm4, xmm7
aesenclast xmm5, xmm7
aesenclast xmm6, xmm7
ENDM
aes_dec_rnd MACRO i
movdqu xmm7, [i*16 + ctx]
aesdec xmm0, xmm7
aesdec xmm1, xmm7
aesdec xmm2, xmm7
aesdec xmm3, xmm7
aesdec xmm4, xmm7
aesdec xmm5, xmm7
aesdec xmm6, xmm7
ENDM
aes_dec_last_rnd MACRO i
movdqu xmm7, [i*16 + ctx]
aesdeclast xmm0, xmm7
aesdeclast xmm1, xmm7
aesdeclast xmm2, xmm7
aesdeclast xmm3, xmm7
aesdeclast xmm4, xmm7
aesdeclast xmm5, xmm7
aesdeclast xmm6, xmm7
ENDM
gen_aes_ecb_func MACRO enc, rnds
LOCAL loop7
LOCAL loop1
LOCAL bail
push inputLen
mov ctx, [esp + 2*4 + 0*4]
mov output, [esp + 2*4 + 1*4]
mov input, [esp + 2*4 + 4*4]
mov inputLen, [esp + 2*4 + 5*4]
lea ctx, [44+ctx]
loop7:
cmp inputLen, 7*16
jb loop1
movdqu xmm0, [0*16 + input]
movdqu xmm1, [1*16 + input]
movdqu xmm2, [2*16 + input]
movdqu xmm3, [3*16 + input]
movdqu xmm4, [4*16 + input]
movdqu xmm5, [5*16 + input]
movdqu xmm6, [6*16 + input]
movdqu xmm7, [0*16 + ctx]
pxor xmm0, xmm7
pxor xmm1, xmm7
pxor xmm2, xmm7
pxor xmm3, xmm7
pxor xmm4, xmm7
pxor xmm5, xmm7
pxor xmm6, xmm7
IF enc eq 1
rnd textequ <aes_rnd>
lastrnd textequ <aes_last_rnd>
aesinst textequ <aesenc>
aeslastinst textequ <aesenclast>
ELSE
rnd textequ <aes_dec_rnd>
lastrnd textequ <aes_dec_last_rnd>
aesinst textequ <aesdec>
aeslastinst textequ <aesdeclast>
ENDIF
i = 1
WHILE i LT rnds
rnd i
i = i+1
ENDM
lastrnd rnds
movdqu [0*16 + output], xmm0
movdqu [1*16 + output], xmm1
movdqu [2*16 + output], xmm2
movdqu [3*16 + output], xmm3
movdqu [4*16 + output], xmm4
movdqu [5*16 + output], xmm5
movdqu [6*16 + output], xmm6
lea input, [7*16 + input]
lea output, [7*16 + output]
sub inputLen, 7*16
jmp loop7
loop1:
cmp inputLen, 1*16
jb bail
movdqu xmm0, [input]
movdqu xmm7, [0*16 + ctx]
pxor xmm0, xmm7
i = 1
WHILE i LT rnds
movdqu xmm7, [i*16 + ctx]
aesinst xmm0, xmm7
i = i+1
ENDM
movdqu xmm7, [rnds*16 + ctx]
aeslastinst xmm0, xmm7
movdqu [output], xmm0
lea input, [1*16 + input]
lea output, [1*16 + output]
sub inputLen, 1*16
jmp loop1
bail:
xor eax, eax
pop inputLen
ret
ENDM
ALIGN 16
intel_aes_encrypt_ecb_128 PROC
gen_aes_ecb_func 1, 10
intel_aes_encrypt_ecb_128 ENDP
ALIGN 16
intel_aes_encrypt_ecb_192 PROC
gen_aes_ecb_func 1, 12
intel_aes_encrypt_ecb_192 ENDP
ALIGN 16
intel_aes_encrypt_ecb_256 PROC
gen_aes_ecb_func 1, 14
intel_aes_encrypt_ecb_256 ENDP
ALIGN 16
intel_aes_decrypt_ecb_128 PROC
gen_aes_ecb_func 0, 10
intel_aes_decrypt_ecb_128 ENDP
ALIGN 16
intel_aes_decrypt_ecb_192 PROC
gen_aes_ecb_func 0, 12
intel_aes_decrypt_ecb_192 ENDP
ALIGN 16
intel_aes_decrypt_ecb_256 PROC
gen_aes_ecb_func 0, 14
intel_aes_decrypt_ecb_256 ENDP
KEY textequ <ecx>
KS textequ <edx>
ITR textequ <eax>
ALIGN 16
intel_aes_encrypt_init_128 PROC
mov KEY, [esp + 1*4 + 0*4]
mov KS, [esp + 1*4 + 1*4]
movdqu xmm1, [KEY]
movdqu [KS], xmm1
movdqa xmm2, xmm1
lea ITR, Lcon1
movdqa xmm0, [ITR]
lea ITR, Lmask
movdqa xmm4, [ITR]
mov ITR, 8
Lenc_128_ks_loop:
lea KS, [16 + KS]
dec ITR
pshufb xmm2, xmm4
aesenclast xmm2, xmm0
pslld xmm0, 1
movdqa xmm3, xmm1
pslldq xmm3, 4
pxor xmm1, xmm3
pslldq xmm3, 4
pxor xmm1, xmm3
pslldq xmm3, 4
pxor xmm1, xmm3
pxor xmm1, xmm2
movdqu [KS], xmm1
movdqa xmm2, xmm1
jne Lenc_128_ks_loop
lea ITR, Lcon2
movdqa xmm0, [ITR]
pshufb xmm2, xmm4
aesenclast xmm2, xmm0
pslld xmm0, 1
movdqa xmm3, xmm1
pslldq xmm3, 4
pxor xmm1, xmm3
pslldq xmm3, 4
pxor xmm1, xmm3
pslldq xmm3, 4
pxor xmm1, xmm3
pxor xmm1, xmm2
movdqu [16 + KS], xmm1
movdqa xmm2, xmm1
pshufb xmm2, xmm4
aesenclast xmm2, xmm0
movdqa xmm3, xmm1
pslldq xmm3, 4
pxor xmm1, xmm3
pslldq xmm3, 4
pxor xmm1, xmm3
pslldq xmm3, 4
pxor xmm1, xmm3
pxor xmm1, xmm2
movdqu [32 + KS], xmm1
movdqa xmm2, xmm1
ret
intel_aes_encrypt_init_128 ENDP
ALIGN 16
intel_aes_decrypt_init_128 PROC
mov KEY, [esp + 1*4 + 0*4]
mov KS, [esp + 1*4 + 1*4]
push KS
push KEY
call intel_aes_encrypt_init_128
pop KEY
pop KS
movdqu xmm0, [0*16 + KS]
movdqu xmm1, [10*16 + KS]
movdqu [10*16 + KS], xmm0
movdqu [0*16 + KS], xmm1
i = 1
WHILE i LT 5
movdqu xmm0, [i*16 + KS]
movdqu xmm1, [(10-i)*16 + KS]
aesimc xmm0, xmm0
aesimc xmm1, xmm1
movdqu [(10-i)*16 + KS], xmm0
movdqu [i*16 + KS], xmm1
i = i+1
ENDM
movdqu xmm0, [5*16 + KS]
aesimc xmm0, xmm0
movdqu [5*16 + KS], xmm0
ret
intel_aes_decrypt_init_128 ENDP
ALIGN 16
intel_aes_encrypt_init_192 PROC
mov KEY, [esp + 1*4 + 0*4]
mov KS, [esp + 1*4 + 1*4]
pxor xmm3, xmm3
movdqu xmm1, [KEY]
pinsrd xmm3, DWORD PTR [16 + KEY], 0
pinsrd xmm3, DWORD PTR [20 + KEY], 1
movdqu [KS], xmm1
movdqa xmm5, xmm3
lea ITR, Lcon1
movdqu xmm0, [ITR]
lea ITR, Lmask192
movdqu xmm4, [ITR]
mov ITR, 4
Lenc_192_ks_loop:
movdqa xmm2, xmm3
pshufb xmm2, xmm4
aesenclast xmm2, xmm0
pslld xmm0, 1
movdqa xmm6, xmm1
movdqa xmm7, xmm3
pslldq xmm6, 4
pslldq xmm7, 4
pxor xmm1, xmm6
pxor xmm3, xmm7
pslldq xmm6, 4
pxor xmm1, xmm6
pslldq xmm6, 4
pxor xmm1, xmm6
pxor xmm1, xmm2
pshufd xmm2, xmm1, 0ffh
pxor xmm3, xmm2
movdqa xmm6, xmm1
shufpd xmm5, xmm1, 00h
shufpd xmm6, xmm3, 01h
movdqu [16 + KS], xmm5
movdqu [32 + KS], xmm6
movdqa xmm2, xmm3
pshufb xmm2, xmm4
aesenclast xmm2, xmm0
pslld xmm0, 1
movdqa xmm6, xmm1
movdqa xmm7, xmm3
pslldq xmm6, 4
pslldq xmm7, 4
pxor xmm1, xmm6
pxor xmm3, xmm7
pslldq xmm6, 4
pxor xmm1, xmm6
pslldq xmm6, 4
pxor xmm1, xmm6
pxor xmm1, xmm2
pshufd xmm2, xmm1, 0ffh
pxor xmm3, xmm2
movdqu [48 + KS], xmm1
movdqa xmm5, xmm3
lea KS, [48 + KS]
dec ITR
jnz Lenc_192_ks_loop
movdqu [16 + KS], xmm5
ret
intel_aes_encrypt_init_192 ENDP
ALIGN 16
intel_aes_decrypt_init_192 PROC
mov KEY, [esp + 1*4 + 0*4]
mov KS, [esp + 1*4 + 1*4]
push KS
push KEY
call intel_aes_encrypt_init_192
pop KEY
pop KS
movdqu xmm0, [0*16 + KS]
movdqu xmm1, [12*16 + KS]
movdqu [12*16 + KS], xmm0
movdqu [0*16 + KS], xmm1
i = 1
WHILE i LT 6
movdqu xmm0, [i*16 + KS]
movdqu xmm1, [(12-i)*16 + KS]
aesimc xmm0, xmm0
aesimc xmm1, xmm1
movdqu [(12-i)*16 + KS], xmm0
movdqu [i*16 + KS], xmm1
i = i+1
ENDM
movdqu xmm0, [6*16 + KS]
aesimc xmm0, xmm0
movdqu [6*16 + KS], xmm0
ret
intel_aes_decrypt_init_192 ENDP
ALIGN 16
intel_aes_encrypt_init_256 PROC
mov KEY, [esp + 1*4 + 0*4]
mov KS, [esp + 1*4 + 1*4]
movdqu xmm1, [16*0 + KEY]
movdqu xmm3, [16*1 + KEY]
movdqu [16*0 + KS], xmm1
movdqu [16*1 + KS], xmm3
lea ITR, Lcon1
movdqu xmm0, [ITR]
lea ITR, Lmask256
movdqu xmm5, [ITR]
pxor xmm6, xmm6
mov ITR, 6
Lenc_256_ks_loop:
movdqa xmm2, xmm3
pshufb xmm2, xmm5
aesenclast xmm2, xmm0
pslld xmm0, 1
movdqa xmm4, xmm1
pslldq xmm4, 4
pxor xmm1, xmm4
pslldq xmm4, 4
pxor xmm1, xmm4
pslldq xmm4, 4
pxor xmm1, xmm4
pxor xmm1, xmm2
movdqu [16*2 + KS], xmm1
pshufd xmm2, xmm1, 0ffh
aesenclast xmm2, xmm6
movdqa xmm4, xmm3
pslldq xmm4, 4
pxor xmm3, xmm4
pslldq xmm4, 4
pxor xmm3, xmm4
pslldq xmm4, 4
pxor xmm3, xmm4
pxor xmm3, xmm2
movdqu [16*3 + KS], xmm3
lea KS, [32 + KS]
dec ITR
jnz Lenc_256_ks_loop
movdqa xmm2, xmm3
pshufb xmm2, xmm5
aesenclast xmm2, xmm0
movdqa xmm4, xmm1
pslldq xmm4, 4
pxor xmm1, xmm4
pslldq xmm4, 4
pxor xmm1, xmm4
pslldq xmm4, 4
pxor xmm1, xmm4
pxor xmm1, xmm2
movdqu [16*2 + KS], xmm1
ret
intel_aes_encrypt_init_256 ENDP
ALIGN 16
intel_aes_decrypt_init_256 PROC
mov KEY, [esp + 1*4 + 0*4]
mov KS, [esp + 1*4 + 1*4]
push KS
push KEY
call intel_aes_encrypt_init_256
pop KEY
pop KS
movdqu xmm0, [0*16 + KS]
movdqu xmm1, [14*16 + KS]
movdqu [14*16 + KS], xmm0
movdqu [0*16 + KS], xmm1
i = 1
WHILE i LT 7
movdqu xmm0, [i*16 + KS]
movdqu xmm1, [(14-i)*16 + KS]
aesimc xmm0, xmm0
aesimc xmm1, xmm1
movdqu [(14-i)*16 + KS], xmm0
movdqu [i*16 + KS], xmm1
i = i+1
ENDM
movdqu xmm0, [7*16 + KS]
aesimc xmm0, xmm0
movdqu [7*16 + KS], xmm0
ret
intel_aes_decrypt_init_256 ENDP
gen_aes_cbc_enc_func MACRO rnds
LOCAL loop1
LOCAL bail
push inputLen
mov ctx, [esp + 2*4 + 0*4]
mov output, [esp + 2*4 + 1*4]
mov input, [esp + 2*4 + 4*4]
mov inputLen, [esp + 2*4 + 5*4]
lea ctx, [44+ctx]
movdqu xmm0, [-32+ctx]
movdqu xmm2, [0*16 + ctx]
movdqu xmm3, [1*16 + ctx]
movdqu xmm4, [2*16 + ctx]
movdqu xmm5, [3*16 + ctx]
movdqu xmm6, [4*16 + ctx]
loop1:
cmp inputLen, 1*16
jb bail
movdqu xmm1, [input]
pxor xmm1, xmm2
pxor xmm0, xmm1
aesenc xmm0, xmm3
aesenc xmm0, xmm4
aesenc xmm0, xmm5
aesenc xmm0, xmm6
i = 5
WHILE i LT rnds
movdqu xmm7, [i*16 + ctx]
aesenc xmm0, xmm7
i = i+1
ENDM
movdqu xmm7, [rnds*16 + ctx]
aesenclast xmm0, xmm7
movdqu [output], xmm0
lea input, [1*16 + input]
lea output, [1*16 + output]
sub inputLen, 1*16
jmp loop1
bail:
movdqu [-32+ctx], xmm0
xor eax, eax
pop inputLen
ret
ENDM
gen_aes_cbc_dec_func MACRO rnds
LOCAL loop7
LOCAL loop1
LOCAL dec1
LOCAL bail
push inputLen
mov ctx, [esp + 2*4 + 0*4]
mov output, [esp + 2*4 + 1*4]
mov input, [esp + 2*4 + 4*4]
mov inputLen, [esp + 2*4 + 5*4]
lea ctx, [44+ctx]
loop7:
cmp inputLen, 7*16
jb dec1
movdqu xmm0, [0*16 + input]
movdqu xmm1, [1*16 + input]
movdqu xmm2, [2*16 + input]
movdqu xmm3, [3*16 + input]
movdqu xmm4, [4*16 + input]
movdqu xmm5, [5*16 + input]
movdqu xmm6, [6*16 + input]
movdqu xmm7, [0*16 + ctx]
pxor xmm0, xmm7
pxor xmm1, xmm7
pxor xmm2, xmm7
pxor xmm3, xmm7
pxor xmm4, xmm7
pxor xmm5, xmm7
pxor xmm6, xmm7
i = 1
WHILE i LT rnds
aes_dec_rnd i
i = i+1
ENDM
aes_dec_last_rnd rnds
movdqu xmm7, [-32 + ctx]
pxor xmm0, xmm7
movdqu xmm7, [0*16 + input]
pxor xmm1, xmm7
movdqu xmm7, [1*16 + input]
pxor xmm2, xmm7
movdqu xmm7, [2*16 + input]
pxor xmm3, xmm7
movdqu xmm7, [3*16 + input]
pxor xmm4, xmm7
movdqu xmm7, [4*16 + input]
pxor xmm5, xmm7
movdqu xmm7, [5*16 + input]
pxor xmm6, xmm7
movdqu xmm7, [6*16 + input]
movdqu [0*16 + output], xmm0
movdqu [1*16 + output], xmm1
movdqu [2*16 + output], xmm2
movdqu [3*16 + output], xmm3
movdqu [4*16 + output], xmm4
movdqu [5*16 + output], xmm5
movdqu [6*16 + output], xmm6
movdqu [-32 + ctx], xmm7
lea input, [7*16 + input]
lea output, [7*16 + output]
sub inputLen, 7*16
jmp loop7
dec1:
movdqu xmm3, [-32 + ctx]
loop1:
cmp inputLen, 1*16
jb bail
movdqu xmm0, [input]
movdqa xmm4, xmm0
movdqu xmm7, [0*16 + ctx]
pxor xmm0, xmm7
i = 1
WHILE i LT rnds
movdqu xmm7, [i*16 + ctx]
aesdec xmm0, xmm7
i = i+1
ENDM
movdqu xmm7, [rnds*16 + ctx]
aesdeclast xmm0, xmm7
pxor xmm3, xmm0
movdqu [output], xmm3
movdqa xmm3, xmm4
lea input, [1*16 + input]
lea output, [1*16 + output]
sub inputLen, 1*16
jmp loop1
bail:
movdqu [-32 + ctx], xmm3
xor eax, eax
pop inputLen
ret
ENDM
ALIGN 16
intel_aes_encrypt_cbc_128 PROC
gen_aes_cbc_enc_func 10
intel_aes_encrypt_cbc_128 ENDP
ALIGN 16
intel_aes_encrypt_cbc_192 PROC
gen_aes_cbc_enc_func 12
intel_aes_encrypt_cbc_192 ENDP
ALIGN 16
intel_aes_encrypt_cbc_256 PROC
gen_aes_cbc_enc_func 14
intel_aes_encrypt_cbc_256 ENDP
ALIGN 16
intel_aes_decrypt_cbc_128 PROC
gen_aes_cbc_dec_func 10
intel_aes_decrypt_cbc_128 ENDP
ALIGN 16
intel_aes_decrypt_cbc_192 PROC
gen_aes_cbc_dec_func 12
intel_aes_decrypt_cbc_192 ENDP
ALIGN 16
intel_aes_decrypt_cbc_256 PROC
gen_aes_cbc_dec_func 14
intel_aes_decrypt_cbc_256 ENDP
ctrCtx textequ <esi>
CTR textequ <ebx>
gen_aes_ctr_func MACRO rnds
LOCAL loop7
LOCAL loop1
LOCAL enc1
LOCAL bail
push inputLen
push ctrCtx
push CTR
push ebp
mov ctrCtx, [esp + 4*5 + 0*4]
mov output, [esp + 4*5 + 1*4]
mov input, [esp + 4*5 + 4*4]
mov inputLen, [esp + 4*5 + 5*4]
mov ctx, [4+ctrCtx]
lea ctx, [44+ctx]
mov ebp, esp
sub esp, 7*16
and esp, -16
movdqu xmm0, [8+ctrCtx]
mov ctrCtx, [ctrCtx + 8 + 3*4]
bswap ctrCtx
movdqu xmm1, [ctx + 0*16]
pxor xmm0, xmm1
movdqa [esp + 0*16], xmm0
movdqa [esp + 1*16], xmm0
movdqa [esp + 2*16], xmm0
movdqa [esp + 3*16], xmm0
movdqa [esp + 4*16], xmm0
movdqa [esp + 5*16], xmm0
movdqa [esp + 6*16], xmm0
inc ctrCtx
mov CTR, ctrCtx
bswap CTR
xor CTR, [ctx + 3*4]
mov [esp + 1*16 + 3*4], CTR
inc ctrCtx
mov CTR, ctrCtx
bswap CTR
xor CTR, [ctx + 3*4]
mov [esp + 2*16 + 3*4], CTR
inc ctrCtx
mov CTR, ctrCtx
bswap CTR
xor CTR, [ctx + 3*4]
mov [esp + 3*16 + 3*4], CTR
inc ctrCtx
mov CTR, ctrCtx
bswap CTR
xor CTR, [ctx + 3*4]
mov [esp + 4*16 + 3*4], CTR
inc ctrCtx
mov CTR, ctrCtx
bswap CTR
xor CTR, [ctx + 3*4]
mov [esp + 5*16 + 3*4], CTR
inc ctrCtx
mov CTR, ctrCtx
bswap CTR
xor CTR, [ctx + 3*4]
mov [esp + 6*16 + 3*4], CTR
loop7:
cmp inputLen, 7*16
jb loop1
movdqu xmm0, [0*16 + esp]
movdqu xmm1, [1*16 + esp]
movdqu xmm2, [2*16 + esp]
movdqu xmm3, [3*16 + esp]
movdqu xmm4, [4*16 + esp]
movdqu xmm5, [5*16 + esp]
movdqu xmm6, [6*16 + esp]
i = 1
WHILE i LE 7
aes_rnd i
inc ctrCtx
mov CTR, ctrCtx
bswap CTR
xor CTR, [ctx + 3*4]
mov [esp + (i-1)*16 + 3*4], CTR
i = i+1
ENDM
WHILE i LT rnds
aes_rnd i
i = i+1
ENDM
aes_last_rnd rnds
movdqu xmm7, [0*16 + input]
pxor xmm0, xmm7
movdqu xmm7, [1*16 + input]
pxor xmm1, xmm7
movdqu xmm7, [2*16 + input]
pxor xmm2, xmm7
movdqu xmm7, [3*16 + input]
pxor xmm3, xmm7
movdqu xmm7, [4*16 + input]
pxor xmm4, xmm7
movdqu xmm7, [5*16 + input]
pxor xmm5, xmm7
movdqu xmm7, [6*16 + input]
pxor xmm6, xmm7
movdqu [0*16 + output], xmm0
movdqu [1*16 + output], xmm1
movdqu [2*16 + output], xmm2
movdqu [3*16 + output], xmm3
movdqu [4*16 + output], xmm4
movdqu [5*16 + output], xmm5
movdqu [6*16 + output], xmm6
lea input, [7*16 + input]
lea output, [7*16 + output]
sub inputLen, 7*16
jmp loop7
loop1:
cmp inputLen, 1*16
jb bail
movdqu xmm0, [esp]
add esp, 16
i = 1
WHILE i LT rnds
movdqu xmm7, [i*16 + ctx]
aesenc xmm0, xmm7
i = i+1
ENDM
movdqu xmm7, [rnds*16 + ctx]
aesenclast xmm0, xmm7
movdqu xmm7, [input]
pxor xmm0, xmm7
movdqu [output], xmm0
lea input, [1*16 + input]
lea output, [1*16 + output]
sub inputLen, 1*16
jmp loop1
bail:
mov ctrCtx, [ebp + 4*5 + 0*4]
movdqu xmm0, [esp]
movdqu xmm1, [ctx + 0*16]
pxor xmm0, xmm1
movdqu [8+ctrCtx], xmm0
xor eax, eax
mov esp, ebp
pop ebp
pop CTR
pop ctrCtx
pop inputLen
ret
ENDM
ALIGN 16
intel_aes_encrypt_ctr_128 PROC
gen_aes_ctr_func 10
intel_aes_encrypt_ctr_128 ENDP
ALIGN 16
intel_aes_encrypt_ctr_192 PROC
gen_aes_ctr_func 12
intel_aes_encrypt_ctr_192 ENDP
ALIGN 16
intel_aes_encrypt_ctr_256 PROC
gen_aes_ctr_func 14
intel_aes_encrypt_ctr_256 ENDP
END

View file

@ -0,0 +1,143 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
/* Prototypes of the functions defined in the assembler file. */
void intel_aes_encrypt_init_128(const unsigned char *key, PRUint32 *expanded);
void intel_aes_encrypt_init_192(const unsigned char *key, PRUint32 *expanded);
void intel_aes_encrypt_init_256(const unsigned char *key, PRUint32 *expanded);
void intel_aes_decrypt_init_128(const unsigned char *key, PRUint32 *expanded);
void intel_aes_decrypt_init_192(const unsigned char *key, PRUint32 *expanded);
void intel_aes_decrypt_init_256(const unsigned char *key, PRUint32 *expanded);
SECStatus intel_aes_encrypt_ecb_128(AESContext *cx, unsigned char *output,
unsigned int *outputLen,
unsigned int maxOutputLen,
const unsigned char *input,
unsigned int inputLen,
unsigned int blocksize);
SECStatus intel_aes_decrypt_ecb_128(AESContext *cx, unsigned char *output,
unsigned int *outputLen,
unsigned int maxOutputLen,
const unsigned char *input,
unsigned int inputLen,
unsigned int blocksize);
SECStatus intel_aes_encrypt_cbc_128(AESContext *cx, unsigned char *output,
unsigned int *outputLen,
unsigned int maxOutputLen,
const unsigned char *input,
unsigned int inputLen,
unsigned int blocksize);
SECStatus intel_aes_decrypt_cbc_128(AESContext *cx, unsigned char *output,
unsigned int *outputLen,
unsigned int maxOutputLen,
const unsigned char *input,
unsigned int inputLen,
unsigned int blocksize);
SECStatus intel_aes_encrypt_ctr_128(CTRContext *cx, unsigned char *output,
unsigned int *outputLen,
unsigned int maxOutputLen,
const unsigned char *input,
unsigned int inputLen,
unsigned int blocksize);
SECStatus intel_aes_encrypt_ecb_192(AESContext *cx, unsigned char *output,
unsigned int *outputLen,
unsigned int maxOutputLen,
const unsigned char *input,
unsigned int inputLen,
unsigned int blocksize);
SECStatus intel_aes_decrypt_ecb_192(AESContext *cx, unsigned char *output,
unsigned int *outputLen,
unsigned int maxOutputLen,
const unsigned char *input,
unsigned int inputLen,
unsigned int blocksize);
SECStatus intel_aes_encrypt_cbc_192(AESContext *cx, unsigned char *output,
unsigned int *outputLen,
unsigned int maxOutputLen,
const unsigned char *input,
unsigned int inputLen,
unsigned int blocksize);
SECStatus intel_aes_decrypt_cbc_192(AESContext *cx, unsigned char *output,
unsigned int *outputLen,
unsigned int maxOutputLen,
const unsigned char *input,
unsigned int inputLen,
unsigned int blocksize);
SECStatus intel_aes_encrypt_ctr_192(CTRContext *cx, unsigned char *output,
unsigned int *outputLen,
unsigned int maxOutputLen,
const unsigned char *input,
unsigned int inputLen,
unsigned int blocksize);
SECStatus intel_aes_encrypt_ecb_256(AESContext *cx, unsigned char *output,
unsigned int *outputLen,
unsigned int maxOutputLen,
const unsigned char *input,
unsigned int inputLen,
unsigned int blocksize);
SECStatus intel_aes_decrypt_ecb_256(AESContext *cx, unsigned char *output,
unsigned int *outputLen,
unsigned int maxOutputLen,
const unsigned char *input,
unsigned int inputLen,
unsigned int blocksize);
SECStatus intel_aes_encrypt_cbc_256(AESContext *cx, unsigned char *output,
unsigned int *outputLen,
unsigned int maxOutputLen,
const unsigned char *input,
unsigned int inputLen,
unsigned int blocksize);
SECStatus intel_aes_decrypt_cbc_256(AESContext *cx, unsigned char *output,
unsigned int *outputLen,
unsigned int maxOutputLen,
const unsigned char *input,
unsigned int inputLen,
unsigned int blocksize);
SECStatus intel_aes_encrypt_ctr_256(CTRContext *cx, unsigned char *output,
unsigned int *outputLen,
unsigned int maxOutputLen,
const unsigned char *input,
unsigned int inputLen,
unsigned int blocksize);
#define intel_aes_ecb_worker(encrypt, keysize) \
((encrypt) \
? ((keysize) == 16 ? intel_aes_encrypt_ecb_128 \
: (keysize) == 24 ? intel_aes_encrypt_ecb_192 \
: intel_aes_encrypt_ecb_256) \
: ((keysize) == 16 ? intel_aes_decrypt_ecb_128 \
: (keysize) == 24 ? intel_aes_decrypt_ecb_192 \
: intel_aes_decrypt_ecb_256))
#define intel_aes_cbc_worker(encrypt, keysize) \
((encrypt) \
? ((keysize) == 16 ? intel_aes_encrypt_cbc_128 \
: (keysize) == 24 ? intel_aes_encrypt_cbc_192 \
: intel_aes_encrypt_cbc_256) \
: ((keysize) == 16 ? intel_aes_decrypt_cbc_128 \
: (keysize) == 24 ? intel_aes_decrypt_cbc_192 \
: intel_aes_decrypt_cbc_256))
#define intel_aes_ctr_worker(nr) \
((nr) == 10 ? intel_aes_encrypt_ctr_128 \
: (nr) == 12 ? intel_aes_encrypt_ctr_192 \
: intel_aes_encrypt_ctr_256)
#define intel_aes_init(encrypt, keysize) \
do { \
if (encrypt) { \
if (keysize == 16) \
intel_aes_encrypt_init_128(key, cx->expandedKey); \
else if (keysize == 24) \
intel_aes_encrypt_init_192(key, cx->expandedKey); \
else \
intel_aes_encrypt_init_256(key, cx->expandedKey); \
} else { \
if (keysize == 16) \
intel_aes_decrypt_init_128(key, cx->expandedKey); \
else if (keysize == 24) \
intel_aes_decrypt_init_192(key, cx->expandedKey); \
else \
intel_aes_decrypt_init_256(key, cx->expandedKey); \
} \
} while (0)

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,254 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
/* Copyright(c) 2013, Intel Corp. */
/* Wrapper functions for Intel optimized implementation of AES-GCM */
#ifdef USE_HW_AES
#ifdef FREEBL_NO_DEPEND
#include "stubs.h"
#endif
#include "blapii.h"
#include "blapit.h"
#include "gcm.h"
#include "ctr.h"
#include "secerr.h"
#include "prtypes.h"
#include "pkcs11t.h"
#include <limits.h>
#include "intel-gcm.h"
#include "rijndael.h"
#include <emmintrin.h>
#include <tmmintrin.h>
struct intel_AES_GCMContextStr {
unsigned char Htbl[16 * AES_BLOCK_SIZE];
unsigned char X0[AES_BLOCK_SIZE];
unsigned char T[AES_BLOCK_SIZE];
unsigned char CTR[AES_BLOCK_SIZE];
AESContext *aes_context;
unsigned long tagBits;
unsigned long Alen;
unsigned long Mlen;
};
intel_AES_GCMContext *
intel_AES_GCM_CreateContext(void *context,
freeblCipherFunc cipher,
const unsigned char *params,
unsigned int blocksize)
{
intel_AES_GCMContext *gcm = NULL;
AESContext *aes = (AESContext *)context;
const CK_GCM_PARAMS *gcmParams = (const CK_GCM_PARAMS *)params;
unsigned char buff[AES_BLOCK_SIZE]; /* aux buffer */
unsigned long IV_whole_len = gcmParams->ulIvLen & (~0xful);
unsigned int IV_remainder_len = gcmParams->ulIvLen & 0xful;
unsigned long AAD_whole_len = gcmParams->ulAADLen & (~0xful);
unsigned int AAD_remainder_len = gcmParams->ulAADLen & 0xful;
__m128i BSWAP_MASK = _mm_setr_epi8(15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0);
__m128i ONE = _mm_set_epi32(0, 0, 0, 1);
unsigned int j;
SECStatus rv;
if (blocksize != AES_BLOCK_SIZE) {
PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
return NULL;
}
gcm = PORT_ZNew(intel_AES_GCMContext);
if (gcm == NULL) {
return NULL;
}
/* initialize context fields */
gcm->aes_context = aes;
gcm->tagBits = gcmParams->ulTagBits;
gcm->Alen = 0;
gcm->Mlen = 0;
/* first prepare H and its derivatives for ghash */
intel_aes_gcmINIT(gcm->Htbl, (unsigned char *)aes->expandedKey, aes->Nr);
/* Initial TAG value is zero */
_mm_storeu_si128((__m128i *)gcm->T, _mm_setzero_si128());
_mm_storeu_si128((__m128i *)gcm->X0, _mm_setzero_si128());
/* Init the counter */
if (gcmParams->ulIvLen == 12) {
_mm_storeu_si128((__m128i *)gcm->CTR,
_mm_setr_epi32(((unsigned int *)gcmParams->pIv)[0],
((unsigned int *)gcmParams->pIv)[1],
((unsigned int *)gcmParams->pIv)[2],
0x01000000));
} else {
/* If IV size is not 96 bits, then the initial counter value is GHASH
* of the IV */
intel_aes_gcmAAD(gcm->Htbl, gcmParams->pIv, IV_whole_len, gcm->T);
/* Partial block */
if (IV_remainder_len) {
PORT_Memset(buff, 0, AES_BLOCK_SIZE);
PORT_Memcpy(buff, gcmParams->pIv + IV_whole_len, IV_remainder_len);
intel_aes_gcmAAD(gcm->Htbl, buff, AES_BLOCK_SIZE, gcm->T);
}
intel_aes_gcmTAG(
gcm->Htbl,
gcm->T,
gcmParams->ulIvLen,
0,
gcm->X0,
gcm->CTR);
/* TAG should be zero again */
_mm_storeu_si128((__m128i *)gcm->T, _mm_setzero_si128());
}
/* Encrypt the initial counter, will be used to encrypt the GHASH value,
* in the end */
rv = (*cipher)(context, gcm->X0, &j, AES_BLOCK_SIZE, gcm->CTR,
AES_BLOCK_SIZE, AES_BLOCK_SIZE);
if (rv != SECSuccess) {
goto loser;
}
/* Promote the counter by 1 */
_mm_storeu_si128((__m128i *)gcm->CTR, _mm_shuffle_epi8(_mm_add_epi32(ONE, _mm_shuffle_epi8(_mm_loadu_si128((__m128i *)gcm->CTR), BSWAP_MASK)), BSWAP_MASK));
/* Now hash AAD - it would actually make sense to seperate the context
* creation from the AAD, because that would allow to reuse the H, which
* only changes when the AES key changes, and not every package, like the
* IV and AAD */
intel_aes_gcmAAD(gcm->Htbl, gcmParams->pAAD, AAD_whole_len, gcm->T);
if (AAD_remainder_len) {
PORT_Memset(buff, 0, AES_BLOCK_SIZE);
PORT_Memcpy(buff, gcmParams->pAAD + AAD_whole_len, AAD_remainder_len);
intel_aes_gcmAAD(gcm->Htbl, buff, AES_BLOCK_SIZE, gcm->T);
}
gcm->Alen += gcmParams->ulAADLen;
return gcm;
loser:
PORT_Free(gcm);
return NULL;
}
void
intel_AES_GCM_DestroyContext(intel_AES_GCMContext *gcm, PRBool freeit)
{
if (freeit) {
PORT_Free(gcm);
}
}
SECStatus
intel_AES_GCM_EncryptUpdate(intel_AES_GCMContext *gcm,
unsigned char *outbuf,
unsigned int *outlen, unsigned int maxout,
const unsigned char *inbuf, unsigned int inlen,
unsigned int blocksize)
{
unsigned int tagBytes;
unsigned char T[AES_BLOCK_SIZE];
unsigned int j;
tagBytes = (gcm->tagBits + (PR_BITS_PER_BYTE - 1)) / PR_BITS_PER_BYTE;
if (UINT_MAX - inlen < tagBytes) {
PORT_SetError(SEC_ERROR_INPUT_LEN);
return SECFailure;
}
if (maxout < inlen + tagBytes) {
*outlen = inlen + tagBytes;
PORT_SetError(SEC_ERROR_OUTPUT_LEN);
return SECFailure;
}
intel_aes_gcmENC(
inbuf,
outbuf,
gcm,
inlen);
gcm->Mlen += inlen;
intel_aes_gcmTAG(
gcm->Htbl,
gcm->T,
gcm->Mlen,
gcm->Alen,
gcm->X0,
T);
*outlen = inlen + tagBytes;
for (j = 0; j < tagBytes; j++) {
outbuf[inlen + j] = T[j];
}
return SECSuccess;
}
SECStatus
intel_AES_GCM_DecryptUpdate(intel_AES_GCMContext *gcm,
unsigned char *outbuf,
unsigned int *outlen, unsigned int maxout,
const unsigned char *inbuf, unsigned int inlen,
unsigned int blocksize)
{
unsigned int tagBytes;
unsigned char T[AES_BLOCK_SIZE];
const unsigned char *intag;
tagBytes = (gcm->tagBits + (PR_BITS_PER_BYTE - 1)) / PR_BITS_PER_BYTE;
/* get the authentication block */
if (inlen < tagBytes) {
PORT_SetError(SEC_ERROR_INPUT_LEN);
return SECFailure;
}
inlen -= tagBytes;
intag = inbuf + inlen;
if (maxout < inlen) {
*outlen = inlen;
PORT_SetError(SEC_ERROR_OUTPUT_LEN);
return SECFailure;
}
intel_aes_gcmDEC(
inbuf,
outbuf,
gcm,
inlen);
gcm->Mlen += inlen;
intel_aes_gcmTAG(
gcm->Htbl,
gcm->T,
gcm->Mlen,
gcm->Alen,
gcm->X0,
T);
if (NSS_SecureMemcmp(T, intag, tagBytes) != 0) {
memset(outbuf, 0, inlen);
*outlen = 0;
/* force a CKR_ENCRYPTED_DATA_INVALID error at in softoken */
PORT_SetError(SEC_ERROR_BAD_DATA);
return SECFailure;
}
*outlen = inlen;
return SECSuccess;
}
#endif

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,83 @@
/******************************************************************************/
/* LICENSE: */
/* This submission to NSS is to be made available under the terms of the */
/* Mozilla Public License, v. 2.0. You can obtain one at http: */
/* //mozilla.org/MPL/2.0/. */
/******************************************************************************/
/* Copyright(c) 2013, Intel Corp. */
/******************************************************************************/
/* Reference: */
/* [1] Shay Gueron, Michael E. Kounavis: Intel(R) Carry-Less Multiplication */
/* Instruction and its Usage for Computing the GCM Mode (Rev. 2.01) */
/* http://software.intel.com/sites/default/files/article/165685/clmul-wp-r*/
/*ev-2.01-2012-09-21.pdf */
/* [2] S. Gueron, M. E. Kounavis: Efficient Implementation of the Galois */
/* Counter Mode Using a Carry-less Multiplier and a Fast Reduction */
/* Algorithm. Information Processing Letters 110: 549-553 (2010). */
/* [3] S. Gueron: AES Performance on the 2nd Generation Intel(R) Core(TM) */
/* Processor Family (to be posted) (2012). */
/* [4] S. Gueron: Fast GHASH computations for speeding up AES-GCM (to be */
/* published) (2012). */
#ifndef INTEL_GCM_H
#define INTEL_GCM_H 1
#include "blapii.h"
typedef struct intel_AES_GCMContextStr intel_AES_GCMContext;
intel_AES_GCMContext *intel_AES_GCM_CreateContext(void *context, freeblCipherFunc cipher,
const unsigned char *params, unsigned int blocksize);
void intel_AES_GCM_DestroyContext(intel_AES_GCMContext *gcm, PRBool freeit);
SECStatus intel_AES_GCM_EncryptUpdate(intel_AES_GCMContext *gcm, unsigned char *outbuf,
unsigned int *outlen, unsigned int maxout,
const unsigned char *inbuf, unsigned int inlen,
unsigned int blocksize);
SECStatus intel_AES_GCM_DecryptUpdate(intel_AES_GCMContext *gcm, unsigned char *outbuf,
unsigned int *outlen, unsigned int maxout,
const unsigned char *inbuf, unsigned int inlen,
unsigned int blocksize);
/* Prototypes of functions in the assembler file for fast AES-GCM, using
Intel AES-NI and CLMUL-NI, as described in [1]
[1] Shay Gueron, Michael E. Kounavis: Intel(R) Carry-Less Multiplication
Instruction and its Usage for Computing the GCM Mode */
/* Prepares the constants used in the aggregated reduction method */
void intel_aes_gcmINIT(unsigned char Htbl[16 * 16],
unsigned char *KS,
int NR);
/* Produces the final GHASH value */
void intel_aes_gcmTAG(unsigned char Htbl[16 * 16],
unsigned char *Tp,
unsigned long Mlen,
unsigned long Alen,
unsigned char *X0,
unsigned char *TAG);
/* Hashes the Additional Authenticated Data, should be used before enc/dec.
Operates on whole blocks only. Partial blocks should be padded externally. */
void intel_aes_gcmAAD(unsigned char Htbl[16 * 16],
unsigned char *AAD,
unsigned long Alen,
unsigned char *Tp);
/* Encrypts and hashes the Plaintext.
Operates on any length of data, however partial block should only be encrypted
at the last call, otherwise the result will be incorrect. */
void intel_aes_gcmENC(const unsigned char *PT,
unsigned char *CT,
void *Gctx,
unsigned long len);
/* Similar to ENC, but decrypts the Ciphertext. */
void intel_aes_gcmDEC(const unsigned char *CT,
unsigned char *PT,
void *Gctx,
unsigned long len);
#endif

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,495 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifdef FREEBL_NO_DEPEND
#include "stubs.h"
#endif
#include "blapi.h"
#include "secerr.h"
#include "secitem.h"
#include "secmpi.h"
/* Hash an item's length and then its value. Only items smaller than 2^16 bytes
* are allowed. Lengths are hashed in network byte order. This is designed
* to match the OpenSSL J-PAKE implementation.
*/
static mp_err
hashSECItem(HASHContext *hash, const SECItem *it)
{
unsigned char length[2];
if (it->len > 0xffff)
return MP_BADARG;
length[0] = (unsigned char)(it->len >> 8);
length[1] = (unsigned char)(it->len);
hash->hashobj->update(hash->hash_context, length, 2);
hash->hashobj->update(hash->hash_context, it->data, it->len);
return MP_OKAY;
}
/* Hash all public components of the signature, each prefixed with its
length, and then convert the hash to an mp_int. */
static mp_err
hashPublicParams(HASH_HashType hashType, const SECItem *g,
const SECItem *gv, const SECItem *gx,
const SECItem *signerID, mp_int *h)
{
mp_err err;
unsigned char hBuf[HASH_LENGTH_MAX];
SECItem hItem;
HASHContext hash;
hash.hashobj = HASH_GetRawHashObject(hashType);
if (hash.hashobj == NULL || hash.hashobj->length > sizeof hBuf) {
return MP_BADARG;
}
hash.hash_context = hash.hashobj->create();
if (hash.hash_context == NULL) {
return MP_MEM;
}
hItem.data = hBuf;
hItem.len = hash.hashobj->length;
hash.hashobj->begin(hash.hash_context);
CHECK_MPI_OK(hashSECItem(&hash, g));
CHECK_MPI_OK(hashSECItem(&hash, gv));
CHECK_MPI_OK(hashSECItem(&hash, gx));
CHECK_MPI_OK(hashSECItem(&hash, signerID));
hash.hashobj->end(hash.hash_context, hItem.data, &hItem.len,
sizeof hBuf);
SECITEM_TO_MPINT(hItem, h);
cleanup:
if (hash.hash_context != NULL) {
hash.hashobj->destroy(hash.hash_context, PR_TRUE);
}
return err;
}
/* Generate a Schnorr signature for round 1 or round 2 */
SECStatus
JPAKE_Sign(PLArenaPool *arena, const PQGParams *pqg, HASH_HashType hashType,
const SECItem *signerID, const SECItem *x,
const SECItem *testRandom, const SECItem *gxIn, SECItem *gxOut,
SECItem *gv, SECItem *r)
{
SECStatus rv = SECSuccess;
mp_err err;
mp_int p;
mp_int q;
mp_int g;
mp_int X;
mp_int GX;
mp_int V;
mp_int GV;
mp_int h;
mp_int tmp;
mp_int R;
SECItem v;
if (!arena ||
!pqg || !pqg->prime.data || pqg->prime.len == 0 ||
!pqg->subPrime.data || pqg->subPrime.len == 0 ||
!pqg->base.data || pqg->base.len == 0 ||
!signerID || !signerID->data || signerID->len == 0 ||
!x || !x->data || x->len == 0 ||
(testRandom && (!testRandom->data || testRandom->len == 0)) ||
(gxIn == NULL && (!gxOut || gxOut->data != NULL)) ||
(gxIn != NULL && (!gxIn->data || gxIn->len == 0 || gxOut != NULL)) ||
!gv || gv->data != NULL ||
!r || r->data != NULL) {
PORT_SetError(SEC_ERROR_INVALID_ARGS);
return SECFailure;
}
MP_DIGITS(&p) = 0;
MP_DIGITS(&q) = 0;
MP_DIGITS(&g) = 0;
MP_DIGITS(&X) = 0;
MP_DIGITS(&GX) = 0;
MP_DIGITS(&V) = 0;
MP_DIGITS(&GV) = 0;
MP_DIGITS(&h) = 0;
MP_DIGITS(&tmp) = 0;
MP_DIGITS(&R) = 0;
CHECK_MPI_OK(mp_init(&p));
CHECK_MPI_OK(mp_init(&q));
CHECK_MPI_OK(mp_init(&g));
CHECK_MPI_OK(mp_init(&X));
CHECK_MPI_OK(mp_init(&GX));
CHECK_MPI_OK(mp_init(&V));
CHECK_MPI_OK(mp_init(&GV));
CHECK_MPI_OK(mp_init(&h));
CHECK_MPI_OK(mp_init(&tmp));
CHECK_MPI_OK(mp_init(&R));
SECITEM_TO_MPINT(pqg->prime, &p);
SECITEM_TO_MPINT(pqg->subPrime, &q);
SECITEM_TO_MPINT(pqg->base, &g);
SECITEM_TO_MPINT(*x, &X);
/* gx = g^x */
if (gxIn == NULL) {
CHECK_MPI_OK(mp_exptmod(&g, &X, &p, &GX));
MPINT_TO_SECITEM(&GX, gxOut, arena);
gxIn = gxOut;
} else {
SECITEM_TO_MPINT(*gxIn, &GX);
}
/* v is a random value in the q subgroup */
if (testRandom == NULL) {
v.data = NULL;
rv = DSA_NewRandom(arena, &pqg->subPrime, &v);
if (rv != SECSuccess) {
goto cleanup;
}
} else {
v.data = testRandom->data;
v.len = testRandom->len;
}
SECITEM_TO_MPINT(v, &V);
/* gv = g^v (mod q), random v, 1 <= v < q */
CHECK_MPI_OK(mp_exptmod(&g, &V, &p, &GV));
MPINT_TO_SECITEM(&GV, gv, arena);
/* h = H(g, gv, gx, signerID) */
CHECK_MPI_OK(hashPublicParams(hashType, &pqg->base, gv, gxIn, signerID,
&h));
/* r = v - x*h (mod q) */
CHECK_MPI_OK(mp_mulmod(&X, &h, &q, &tmp));
CHECK_MPI_OK(mp_submod(&V, &tmp, &q, &R));
MPINT_TO_SECITEM(&R, r, arena);
cleanup:
mp_clear(&p);
mp_clear(&q);
mp_clear(&g);
mp_clear(&X);
mp_clear(&GX);
mp_clear(&V);
mp_clear(&GV);
mp_clear(&h);
mp_clear(&tmp);
mp_clear(&R);
if (rv == SECSuccess && err != MP_OKAY) {
MP_TO_SEC_ERROR(err);
rv = SECFailure;
}
return rv;
}
/* Verify a Schnorr signature generated by the peer in round 1 or round 2. */
SECStatus
JPAKE_Verify(PLArenaPool *arena, const PQGParams *pqg, HASH_HashType hashType,
const SECItem *signerID, const SECItem *peerID,
const SECItem *gx, const SECItem *gv, const SECItem *r)
{
SECStatus rv = SECSuccess;
mp_err err;
mp_int p;
mp_int q;
mp_int g;
mp_int p_minus_1;
mp_int GX;
mp_int h;
mp_int one;
mp_int R;
mp_int gr;
mp_int gxh;
mp_int gr_gxh;
SECItem calculated;
if (!arena ||
!pqg || !pqg->prime.data || pqg->prime.len == 0 ||
!pqg->subPrime.data || pqg->subPrime.len == 0 ||
!pqg->base.data || pqg->base.len == 0 ||
!signerID || !signerID->data || signerID->len == 0 ||
!peerID || !peerID->data || peerID->len == 0 ||
!gx || !gx->data || gx->len == 0 ||
!gv || !gv->data || gv->len == 0 ||
!r || !r->data || r->len == 0 ||
SECITEM_CompareItem(signerID, peerID) == SECEqual) {
PORT_SetError(SEC_ERROR_INVALID_ARGS);
return SECFailure;
}
MP_DIGITS(&p) = 0;
MP_DIGITS(&q) = 0;
MP_DIGITS(&g) = 0;
MP_DIGITS(&p_minus_1) = 0;
MP_DIGITS(&GX) = 0;
MP_DIGITS(&h) = 0;
MP_DIGITS(&one) = 0;
MP_DIGITS(&R) = 0;
MP_DIGITS(&gr) = 0;
MP_DIGITS(&gxh) = 0;
MP_DIGITS(&gr_gxh) = 0;
calculated.data = NULL;
CHECK_MPI_OK(mp_init(&p));
CHECK_MPI_OK(mp_init(&q));
CHECK_MPI_OK(mp_init(&g));
CHECK_MPI_OK(mp_init(&p_minus_1));
CHECK_MPI_OK(mp_init(&GX));
CHECK_MPI_OK(mp_init(&h));
CHECK_MPI_OK(mp_init(&one));
CHECK_MPI_OK(mp_init(&R));
CHECK_MPI_OK(mp_init(&gr));
CHECK_MPI_OK(mp_init(&gxh));
CHECK_MPI_OK(mp_init(&gr_gxh));
SECITEM_TO_MPINT(pqg->prime, &p);
SECITEM_TO_MPINT(pqg->subPrime, &q);
SECITEM_TO_MPINT(pqg->base, &g);
SECITEM_TO_MPINT(*gx, &GX);
SECITEM_TO_MPINT(*r, &R);
CHECK_MPI_OK(mp_sub_d(&p, 1, &p_minus_1));
CHECK_MPI_OK(mp_exptmod(&GX, &q, &p, &one));
/* Check g^x is in [1, p-2], R is in [0, q-1], and (g^x)^q mod p == 1 */
if (!(mp_cmp_z(&GX) > 0 &&
mp_cmp(&GX, &p_minus_1) < 0 &&
mp_cmp(&R, &q) < 0 &&
mp_cmp_d(&one, 1) == 0)) {
goto badSig;
}
CHECK_MPI_OK(hashPublicParams(hashType, &pqg->base, gv, gx, peerID,
&h));
/* Calculate g^v = g^r * g^x^h */
CHECK_MPI_OK(mp_exptmod(&g, &R, &p, &gr));
CHECK_MPI_OK(mp_exptmod(&GX, &h, &p, &gxh));
CHECK_MPI_OK(mp_mulmod(&gr, &gxh, &p, &gr_gxh));
/* Compare calculated g^v to given g^v */
MPINT_TO_SECITEM(&gr_gxh, &calculated, arena);
if (calculated.len == gv->len &&
NSS_SecureMemcmp(calculated.data, gv->data, calculated.len) == 0) {
rv = SECSuccess;
} else {
badSig:
PORT_SetError(SEC_ERROR_BAD_SIGNATURE);
rv = SECFailure;
}
cleanup:
mp_clear(&p);
mp_clear(&q);
mp_clear(&g);
mp_clear(&p_minus_1);
mp_clear(&GX);
mp_clear(&h);
mp_clear(&one);
mp_clear(&R);
mp_clear(&gr);
mp_clear(&gxh);
mp_clear(&gr_gxh);
if (rv == SECSuccess && err != MP_OKAY) {
MP_TO_SEC_ERROR(err);
rv = SECFailure;
}
return rv;
}
/* Calculate base = gx1*gx3*gx4 (mod p), i.e. g^(x1+x3+x4) (mod p) */
static mp_err
jpake_Round2Base(const SECItem *gx1, const SECItem *gx3,
const SECItem *gx4, const mp_int *p, mp_int *base)
{
mp_err err;
mp_int GX1;
mp_int GX3;
mp_int GX4;
mp_int tmp;
MP_DIGITS(&GX1) = 0;
MP_DIGITS(&GX3) = 0;
MP_DIGITS(&GX4) = 0;
MP_DIGITS(&tmp) = 0;
CHECK_MPI_OK(mp_init(&GX1));
CHECK_MPI_OK(mp_init(&GX3));
CHECK_MPI_OK(mp_init(&GX4));
CHECK_MPI_OK(mp_init(&tmp));
SECITEM_TO_MPINT(*gx1, &GX1);
SECITEM_TO_MPINT(*gx3, &GX3);
SECITEM_TO_MPINT(*gx4, &GX4);
/* In round 2, the peer/attacker sends us g^x3 and g^x4 and the protocol
requires that these values are distinct. */
if (mp_cmp(&GX3, &GX4) == 0) {
return MP_BADARG;
}
CHECK_MPI_OK(mp_mul(&GX1, &GX3, &tmp));
CHECK_MPI_OK(mp_mul(&tmp, &GX4, &tmp));
CHECK_MPI_OK(mp_mod(&tmp, p, base));
cleanup:
mp_clear(&GX1);
mp_clear(&GX3);
mp_clear(&GX4);
mp_clear(&tmp);
return err;
}
SECStatus
JPAKE_Round2(PLArenaPool *arena,
const SECItem *p, const SECItem *q, const SECItem *gx1,
const SECItem *gx3, const SECItem *gx4, SECItem *base,
const SECItem *x2, const SECItem *s, SECItem *x2s)
{
mp_err err;
mp_int P;
mp_int Q;
mp_int X2;
mp_int S;
mp_int result;
if (!arena ||
!p || !p->data || p->len == 0 ||
!q || !q->data || q->len == 0 ||
!gx1 || !gx1->data || gx1->len == 0 ||
!gx3 || !gx3->data || gx3->len == 0 ||
!gx4 || !gx4->data || gx4->len == 0 ||
!base || base->data != NULL ||
(x2s != NULL && (x2s->data != NULL ||
!x2 || !x2->data || x2->len == 0 ||
!s || !s->data || s->len == 0))) {
PORT_SetError(SEC_ERROR_INVALID_ARGS);
return SECFailure;
}
MP_DIGITS(&P) = 0;
MP_DIGITS(&Q) = 0;
MP_DIGITS(&X2) = 0;
MP_DIGITS(&S) = 0;
MP_DIGITS(&result) = 0;
CHECK_MPI_OK(mp_init(&P));
CHECK_MPI_OK(mp_init(&Q));
CHECK_MPI_OK(mp_init(&result));
if (x2s != NULL) {
CHECK_MPI_OK(mp_init(&X2));
CHECK_MPI_OK(mp_init(&S));
SECITEM_TO_MPINT(*q, &Q);
SECITEM_TO_MPINT(*x2, &X2);
SECITEM_TO_MPINT(*s, &S);
/* S must be in [1, Q-1] */
if (mp_cmp_z(&S) <= 0 || mp_cmp(&S, &Q) >= 0) {
err = MP_BADARG;
goto cleanup;
}
CHECK_MPI_OK(mp_mulmod(&X2, &S, &Q, &result));
MPINT_TO_SECITEM(&result, x2s, arena);
}
SECITEM_TO_MPINT(*p, &P);
CHECK_MPI_OK(jpake_Round2Base(gx1, gx3, gx4, &P, &result));
MPINT_TO_SECITEM(&result, base, arena);
cleanup:
mp_clear(&P);
mp_clear(&Q);
mp_clear(&X2);
mp_clear(&S);
mp_clear(&result);
if (err != MP_OKAY) {
MP_TO_SEC_ERROR(err);
return SECFailure;
}
return SECSuccess;
}
SECStatus
JPAKE_Final(PLArenaPool *arena, const SECItem *p, const SECItem *q,
const SECItem *x2, const SECItem *gx4, const SECItem *x2s,
const SECItem *B, SECItem *K)
{
mp_err err;
mp_int P;
mp_int Q;
mp_int tmp;
mp_int exponent;
mp_int divisor;
mp_int base;
if (!arena ||
!p || !p->data || p->len == 0 ||
!q || !q->data || q->len == 0 ||
!x2 || !x2->data || x2->len == 0 ||
!gx4 || !gx4->data || gx4->len == 0 ||
!x2s || !x2s->data || x2s->len == 0 ||
!B || !B->data || B->len == 0 ||
!K || K->data != NULL) {
PORT_SetError(SEC_ERROR_INVALID_ARGS);
return SECFailure;
}
MP_DIGITS(&P) = 0;
MP_DIGITS(&Q) = 0;
MP_DIGITS(&tmp) = 0;
MP_DIGITS(&exponent) = 0;
MP_DIGITS(&divisor) = 0;
MP_DIGITS(&base) = 0;
CHECK_MPI_OK(mp_init(&P));
CHECK_MPI_OK(mp_init(&Q));
CHECK_MPI_OK(mp_init(&tmp));
CHECK_MPI_OK(mp_init(&exponent));
CHECK_MPI_OK(mp_init(&divisor));
CHECK_MPI_OK(mp_init(&base));
/* exponent = -x2s (mod q) */
SECITEM_TO_MPINT(*q, &Q);
SECITEM_TO_MPINT(*x2s, &tmp);
/* q == 0 (mod q), so q - x2s == -x2s (mod q) */
CHECK_MPI_OK(mp_sub(&Q, &tmp, &exponent));
/* divisor = gx4^-x2s = 1/(gx4^x2s) (mod p) */
SECITEM_TO_MPINT(*p, &P);
SECITEM_TO_MPINT(*gx4, &tmp);
CHECK_MPI_OK(mp_exptmod(&tmp, &exponent, &P, &divisor));
/* base = B*divisor = B/(gx4^x2s) (mod p) */
SECITEM_TO_MPINT(*B, &tmp);
CHECK_MPI_OK(mp_mulmod(&divisor, &tmp, &P, &base));
/* tmp = base^x2 (mod p) */
SECITEM_TO_MPINT(*x2, &exponent);
CHECK_MPI_OK(mp_exptmod(&base, &exponent, &P, &tmp));
MPINT_TO_SECITEM(&tmp, K, arena);
cleanup:
mp_clear(&P);
mp_clear(&Q);
mp_clear(&tmp);
mp_clear(&exponent);
mp_clear(&divisor);
mp_clear(&base);
if (err != MP_OKAY) {
MP_TO_SEC_ERROR(err);
return SECFailure;
}
return SECSuccess;
}

View file

@ -0,0 +1,353 @@
/*
* ldvector.c - platform dependent DSO containing freebl implementation.
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifdef FREEBL_NO_DEPEND
extern int FREEBL_InitStubs(void);
#endif
#include "loader.h"
#include "alghmac.h"
#include "hmacct.h"
#include "blapii.h"
static const struct FREEBLVectorStr vector =
{
sizeof vector,
FREEBL_VERSION,
RSA_NewKey,
RSA_PublicKeyOp,
RSA_PrivateKeyOp,
DSA_NewKey,
DSA_SignDigest,
DSA_VerifyDigest,
DSA_NewKeyFromSeed,
DSA_SignDigestWithSeed,
DH_GenParam,
DH_NewKey,
DH_Derive,
KEA_Derive,
KEA_Verify,
RC4_CreateContext,
RC4_DestroyContext,
RC4_Encrypt,
RC4_Decrypt,
RC2_CreateContext,
RC2_DestroyContext,
RC2_Encrypt,
RC2_Decrypt,
RC5_CreateContext,
RC5_DestroyContext,
RC5_Encrypt,
RC5_Decrypt,
DES_CreateContext,
DES_DestroyContext,
DES_Encrypt,
DES_Decrypt,
AES_CreateContext,
AES_DestroyContext,
AES_Encrypt,
AES_Decrypt,
MD5_Hash,
MD5_HashBuf,
MD5_NewContext,
MD5_DestroyContext,
MD5_Begin,
MD5_Update,
MD5_End,
MD5_FlattenSize,
MD5_Flatten,
MD5_Resurrect,
MD5_TraceState,
MD2_Hash,
MD2_NewContext,
MD2_DestroyContext,
MD2_Begin,
MD2_Update,
MD2_End,
MD2_FlattenSize,
MD2_Flatten,
MD2_Resurrect,
SHA1_Hash,
SHA1_HashBuf,
SHA1_NewContext,
SHA1_DestroyContext,
SHA1_Begin,
SHA1_Update,
SHA1_End,
SHA1_TraceState,
SHA1_FlattenSize,
SHA1_Flatten,
SHA1_Resurrect,
RNG_RNGInit,
RNG_RandomUpdate,
RNG_GenerateGlobalRandomBytes,
RNG_RNGShutdown,
PQG_ParamGen,
PQG_ParamGenSeedLen,
PQG_VerifyParams,
/* End of Version 3.001. */
RSA_PrivateKeyOpDoubleChecked,
RSA_PrivateKeyCheck,
BL_Cleanup,
/* End of Version 3.002. */
SHA256_NewContext,
SHA256_DestroyContext,
SHA256_Begin,
SHA256_Update,
SHA256_End,
SHA256_HashBuf,
SHA256_Hash,
SHA256_TraceState,
SHA256_FlattenSize,
SHA256_Flatten,
SHA256_Resurrect,
SHA512_NewContext,
SHA512_DestroyContext,
SHA512_Begin,
SHA512_Update,
SHA512_End,
SHA512_HashBuf,
SHA512_Hash,
SHA512_TraceState,
SHA512_FlattenSize,
SHA512_Flatten,
SHA512_Resurrect,
SHA384_NewContext,
SHA384_DestroyContext,
SHA384_Begin,
SHA384_Update,
SHA384_End,
SHA384_HashBuf,
SHA384_Hash,
SHA384_TraceState,
SHA384_FlattenSize,
SHA384_Flatten,
SHA384_Resurrect,
/* End of Version 3.003. */
AESKeyWrap_CreateContext,
AESKeyWrap_DestroyContext,
AESKeyWrap_Encrypt,
AESKeyWrap_Decrypt,
/* End of Version 3.004. */
BLAPI_SHVerify,
BLAPI_VerifySelf,
/* End of Version 3.005. */
EC_NewKey,
EC_NewKeyFromSeed,
EC_ValidatePublicKey,
ECDH_Derive,
ECDSA_SignDigest,
ECDSA_VerifyDigest,
ECDSA_SignDigestWithSeed,
/* End of Version 3.006. */
/* End of Version 3.007. */
AES_InitContext,
AESKeyWrap_InitContext,
DES_InitContext,
RC2_InitContext,
RC4_InitContext,
AES_AllocateContext,
AESKeyWrap_AllocateContext,
DES_AllocateContext,
RC2_AllocateContext,
RC4_AllocateContext,
MD2_Clone,
MD5_Clone,
SHA1_Clone,
SHA256_Clone,
SHA384_Clone,
SHA512_Clone,
TLS_PRF,
HASH_GetRawHashObject,
HMAC_Create,
HMAC_Init,
HMAC_Begin,
HMAC_Update,
HMAC_Clone,
HMAC_Finish,
HMAC_Destroy,
RNG_SystemInfoForRNG,
/* End of Version 3.008. */
FIPS186Change_GenerateX,
FIPS186Change_ReduceModQForDSA,
/* End of Version 3.009. */
Camellia_InitContext,
Camellia_AllocateContext,
Camellia_CreateContext,
Camellia_DestroyContext,
Camellia_Encrypt,
Camellia_Decrypt,
PQG_DestroyParams,
PQG_DestroyVerify,
/* End of Version 3.010. */
SEED_InitContext,
SEED_AllocateContext,
SEED_CreateContext,
SEED_DestroyContext,
SEED_Encrypt,
SEED_Decrypt,
BL_Init,
BL_SetForkState,
PRNGTEST_Instantiate,
PRNGTEST_Reseed,
PRNGTEST_Generate,
PRNGTEST_Uninstantiate,
/* End of Version 3.011. */
RSA_PopulatePrivateKey,
DSA_NewRandom,
JPAKE_Sign,
JPAKE_Verify,
JPAKE_Round2,
JPAKE_Final,
/* End of Version 3.012 */
TLS_P_hash,
SHA224_NewContext,
SHA224_DestroyContext,
SHA224_Begin,
SHA224_Update,
SHA224_End,
SHA224_HashBuf,
SHA224_Hash,
SHA224_TraceState,
SHA224_FlattenSize,
SHA224_Flatten,
SHA224_Resurrect,
SHA224_Clone,
BLAPI_SHVerifyFile,
/* End of Version 3.013 */
PQG_ParamGenV2,
PRNGTEST_RunHealthTests,
/* End of Version 3.014 */
HMAC_ConstantTime,
SSLv3_MAC_ConstantTime,
/* End of Version 3.015 */
RSA_SignRaw,
RSA_CheckSignRaw,
RSA_CheckSignRecoverRaw,
RSA_EncryptRaw,
RSA_DecryptRaw,
RSA_EncryptOAEP,
RSA_DecryptOAEP,
RSA_EncryptBlock,
RSA_DecryptBlock,
RSA_SignPSS,
RSA_CheckSignPSS,
RSA_Sign,
RSA_CheckSign,
RSA_CheckSignRecover,
/* End of Version 3.016 */
EC_FillParams,
EC_DecodeParams,
EC_CopyParams,
/* End of Version 3.017 */
ChaCha20Poly1305_InitContext,
ChaCha20Poly1305_CreateContext,
ChaCha20Poly1305_DestroyContext,
ChaCha20Poly1305_Seal,
ChaCha20Poly1305_Open,
/* End of Version 3.018 */
EC_GetPointSize
/* End of Version 3.019 */
};
const FREEBLVector*
FREEBL_GetVector(void)
{
#ifdef FREEBL_NO_DEPEND
SECStatus rv;
#endif
#define NSS_VERSION_VARIABLE __nss_freebl_version
#include "verref.h"
#ifdef FREEBL_NO_DEPEND
/* this entry point is only valid if nspr and nss-util has been loaded */
rv = FREEBL_InitStubs();
if (rv != SECSuccess) {
return NULL;
}
#endif
/* make sure the Full self tests have been run before continuing */
BL_POSTRan(PR_FALSE);
return &vector;
}
#ifdef FREEBL_LOWHASH
static const struct NSSLOWVectorStr nssvector =
{
sizeof nssvector,
NSSLOW_VERSION,
FREEBL_GetVector,
NSSLOW_Init,
NSSLOW_Shutdown,
NSSLOW_Reset,
NSSLOWHASH_NewContext,
NSSLOWHASH_Begin,
NSSLOWHASH_Update,
NSSLOWHASH_End,
NSSLOWHASH_Destroy,
NSSLOWHASH_Length
};
const NSSLOWVector*
NSSLOW_GetVector(void)
{
/* POST check and stub init happens in FREEBL_GetVector() and
* NSSLOW_Init() respectively */
return &nssvector;
}
#endif

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,788 @@
/*
* loader.h - load platform dependent DSO containing freebl implementation.
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef _LOADER_H_
#define _LOADER_H_ 1
#include "blapi.h"
#define FREEBL_VERSION 0x0313
struct FREEBLVectorStr {
unsigned short length; /* of this struct in bytes */
unsigned short version; /* of this struct. */
RSAPrivateKey *(*p_RSA_NewKey)(int keySizeInBits,
SECItem *publicExponent);
SECStatus (*p_RSA_PublicKeyOp)(RSAPublicKey *key,
unsigned char *output,
const unsigned char *input);
SECStatus (*p_RSA_PrivateKeyOp)(RSAPrivateKey *key,
unsigned char *output,
const unsigned char *input);
SECStatus (*p_DSA_NewKey)(const PQGParams *params,
DSAPrivateKey **privKey);
SECStatus (*p_DSA_SignDigest)(DSAPrivateKey *key,
SECItem *signature,
const SECItem *digest);
SECStatus (*p_DSA_VerifyDigest)(DSAPublicKey *key,
const SECItem *signature,
const SECItem *digest);
SECStatus (*p_DSA_NewKeyFromSeed)(const PQGParams *params,
const unsigned char *seed,
DSAPrivateKey **privKey);
SECStatus (*p_DSA_SignDigestWithSeed)(DSAPrivateKey *key,
SECItem *signature,
const SECItem *digest,
const unsigned char *seed);
SECStatus (*p_DH_GenParam)(int primeLen, DHParams **params);
SECStatus (*p_DH_NewKey)(DHParams *params,
DHPrivateKey **privKey);
SECStatus (*p_DH_Derive)(SECItem *publicValue,
SECItem *prime,
SECItem *privateValue,
SECItem *derivedSecret,
unsigned int maxOutBytes);
SECStatus (*p_KEA_Derive)(SECItem *prime,
SECItem *public1,
SECItem *public2,
SECItem *private1,
SECItem *private2,
SECItem *derivedSecret);
PRBool (*p_KEA_Verify)(SECItem *Y, SECItem *prime, SECItem *subPrime);
RC4Context *(*p_RC4_CreateContext)(const unsigned char *key, int len);
void (*p_RC4_DestroyContext)(RC4Context *cx, PRBool freeit);
SECStatus (*p_RC4_Encrypt)(RC4Context *cx, unsigned char *output,
unsigned int *outputLen, unsigned int maxOutputLen,
const unsigned char *input, unsigned int inputLen);
SECStatus (*p_RC4_Decrypt)(RC4Context *cx, unsigned char *output,
unsigned int *outputLen, unsigned int maxOutputLen,
const unsigned char *input, unsigned int inputLen);
RC2Context *(*p_RC2_CreateContext)(const unsigned char *key,
unsigned int len, const unsigned char *iv,
int mode, unsigned effectiveKeyLen);
void (*p_RC2_DestroyContext)(RC2Context *cx, PRBool freeit);
SECStatus (*p_RC2_Encrypt)(RC2Context *cx, unsigned char *output,
unsigned int *outputLen, unsigned int maxOutputLen,
const unsigned char *input, unsigned int inputLen);
SECStatus (*p_RC2_Decrypt)(RC2Context *cx, unsigned char *output,
unsigned int *outputLen, unsigned int maxOutputLen,
const unsigned char *input, unsigned int inputLen);
RC5Context *(*p_RC5_CreateContext)(const SECItem *key, unsigned int rounds,
unsigned int wordSize, const unsigned char *iv, int mode);
void (*p_RC5_DestroyContext)(RC5Context *cx, PRBool freeit);
SECStatus (*p_RC5_Encrypt)(RC5Context *cx, unsigned char *output,
unsigned int *outputLen, unsigned int maxOutputLen,
const unsigned char *input, unsigned int inputLen);
SECStatus (*p_RC5_Decrypt)(RC5Context *cx, unsigned char *output,
unsigned int *outputLen, unsigned int maxOutputLen,
const unsigned char *input, unsigned int inputLen);
DESContext *(*p_DES_CreateContext)(const unsigned char *key,
const unsigned char *iv,
int mode, PRBool encrypt);
void (*p_DES_DestroyContext)(DESContext *cx, PRBool freeit);
SECStatus (*p_DES_Encrypt)(DESContext *cx, unsigned char *output,
unsigned int *outputLen, unsigned int maxOutputLen,
const unsigned char *input, unsigned int inputLen);
SECStatus (*p_DES_Decrypt)(DESContext *cx, unsigned char *output,
unsigned int *outputLen, unsigned int maxOutputLen,
const unsigned char *input, unsigned int inputLen);
AESContext *(*p_AES_CreateContext)(const unsigned char *key,
const unsigned char *iv,
int mode, int encrypt, unsigned int keylen,
unsigned int blocklen);
void (*p_AES_DestroyContext)(AESContext *cx, PRBool freeit);
SECStatus (*p_AES_Encrypt)(AESContext *cx, unsigned char *output,
unsigned int *outputLen, unsigned int maxOutputLen,
const unsigned char *input, unsigned int inputLen);
SECStatus (*p_AES_Decrypt)(AESContext *cx, unsigned char *output,
unsigned int *outputLen, unsigned int maxOutputLen,
const unsigned char *input, unsigned int inputLen);
SECStatus (*p_MD5_Hash)(unsigned char *dest, const char *src);
SECStatus (*p_MD5_HashBuf)(unsigned char *dest, const unsigned char *src,
PRUint32 src_length);
MD5Context *(*p_MD5_NewContext)(void);
void (*p_MD5_DestroyContext)(MD5Context *cx, PRBool freeit);
void (*p_MD5_Begin)(MD5Context *cx);
void (*p_MD5_Update)(MD5Context *cx,
const unsigned char *input, unsigned int inputLen);
void (*p_MD5_End)(MD5Context *cx, unsigned char *digest,
unsigned int *digestLen, unsigned int maxDigestLen);
unsigned int (*p_MD5_FlattenSize)(MD5Context *cx);
SECStatus (*p_MD5_Flatten)(MD5Context *cx, unsigned char *space);
MD5Context *(*p_MD5_Resurrect)(unsigned char *space, void *arg);
void (*p_MD5_TraceState)(MD5Context *cx);
SECStatus (*p_MD2_Hash)(unsigned char *dest, const char *src);
MD2Context *(*p_MD2_NewContext)(void);
void (*p_MD2_DestroyContext)(MD2Context *cx, PRBool freeit);
void (*p_MD2_Begin)(MD2Context *cx);
void (*p_MD2_Update)(MD2Context *cx,
const unsigned char *input, unsigned int inputLen);
void (*p_MD2_End)(MD2Context *cx, unsigned char *digest,
unsigned int *digestLen, unsigned int maxDigestLen);
unsigned int (*p_MD2_FlattenSize)(MD2Context *cx);
SECStatus (*p_MD2_Flatten)(MD2Context *cx, unsigned char *space);
MD2Context *(*p_MD2_Resurrect)(unsigned char *space, void *arg);
SECStatus (*p_SHA1_Hash)(unsigned char *dest, const char *src);
SECStatus (*p_SHA1_HashBuf)(unsigned char *dest, const unsigned char *src,
PRUint32 src_length);
SHA1Context *(*p_SHA1_NewContext)(void);
void (*p_SHA1_DestroyContext)(SHA1Context *cx, PRBool freeit);
void (*p_SHA1_Begin)(SHA1Context *cx);
void (*p_SHA1_Update)(SHA1Context *cx, const unsigned char *input,
unsigned int inputLen);
void (*p_SHA1_End)(SHA1Context *cx, unsigned char *digest,
unsigned int *digestLen, unsigned int maxDigestLen);
void (*p_SHA1_TraceState)(SHA1Context *cx);
unsigned int (*p_SHA1_FlattenSize)(SHA1Context *cx);
SECStatus (*p_SHA1_Flatten)(SHA1Context *cx, unsigned char *space);
SHA1Context *(*p_SHA1_Resurrect)(unsigned char *space, void *arg);
SECStatus (*p_RNG_RNGInit)(void);
SECStatus (*p_RNG_RandomUpdate)(const void *data, size_t bytes);
SECStatus (*p_RNG_GenerateGlobalRandomBytes)(void *dest, size_t len);
void (*p_RNG_RNGShutdown)(void);
SECStatus (*p_PQG_ParamGen)(unsigned int j, PQGParams **pParams,
PQGVerify **pVfy);
SECStatus (*p_PQG_ParamGenSeedLen)(unsigned int j, unsigned int seedBytes,
PQGParams **pParams, PQGVerify **pVfy);
SECStatus (*p_PQG_VerifyParams)(const PQGParams *params,
const PQGVerify *vfy, SECStatus *result);
/* Version 3.001 came to here */
SECStatus (*p_RSA_PrivateKeyOpDoubleChecked)(RSAPrivateKey *key,
unsigned char *output,
const unsigned char *input);
SECStatus (*p_RSA_PrivateKeyCheck)(const RSAPrivateKey *key);
void (*p_BL_Cleanup)(void);
/* Version 3.002 came to here */
SHA256Context *(*p_SHA256_NewContext)(void);
void (*p_SHA256_DestroyContext)(SHA256Context *cx, PRBool freeit);
void (*p_SHA256_Begin)(SHA256Context *cx);
void (*p_SHA256_Update)(SHA256Context *cx, const unsigned char *input,
unsigned int inputLen);
void (*p_SHA256_End)(SHA256Context *cx, unsigned char *digest,
unsigned int *digestLen, unsigned int maxDigestLen);
SECStatus (*p_SHA256_HashBuf)(unsigned char *dest, const unsigned char *src,
PRUint32 src_length);
SECStatus (*p_SHA256_Hash)(unsigned char *dest, const char *src);
void (*p_SHA256_TraceState)(SHA256Context *cx);
unsigned int (*p_SHA256_FlattenSize)(SHA256Context *cx);
SECStatus (*p_SHA256_Flatten)(SHA256Context *cx, unsigned char *space);
SHA256Context *(*p_SHA256_Resurrect)(unsigned char *space, void *arg);
SHA512Context *(*p_SHA512_NewContext)(void);
void (*p_SHA512_DestroyContext)(SHA512Context *cx, PRBool freeit);
void (*p_SHA512_Begin)(SHA512Context *cx);
void (*p_SHA512_Update)(SHA512Context *cx, const unsigned char *input,
unsigned int inputLen);
void (*p_SHA512_End)(SHA512Context *cx, unsigned char *digest,
unsigned int *digestLen, unsigned int maxDigestLen);
SECStatus (*p_SHA512_HashBuf)(unsigned char *dest, const unsigned char *src,
PRUint32 src_length);
SECStatus (*p_SHA512_Hash)(unsigned char *dest, const char *src);
void (*p_SHA512_TraceState)(SHA512Context *cx);
unsigned int (*p_SHA512_FlattenSize)(SHA512Context *cx);
SECStatus (*p_SHA512_Flatten)(SHA512Context *cx, unsigned char *space);
SHA512Context *(*p_SHA512_Resurrect)(unsigned char *space, void *arg);
SHA384Context *(*p_SHA384_NewContext)(void);
void (*p_SHA384_DestroyContext)(SHA384Context *cx, PRBool freeit);
void (*p_SHA384_Begin)(SHA384Context *cx);
void (*p_SHA384_Update)(SHA384Context *cx, const unsigned char *input,
unsigned int inputLen);
void (*p_SHA384_End)(SHA384Context *cx, unsigned char *digest,
unsigned int *digestLen, unsigned int maxDigestLen);
SECStatus (*p_SHA384_HashBuf)(unsigned char *dest, const unsigned char *src,
PRUint32 src_length);
SECStatus (*p_SHA384_Hash)(unsigned char *dest, const char *src);
void (*p_SHA384_TraceState)(SHA384Context *cx);
unsigned int (*p_SHA384_FlattenSize)(SHA384Context *cx);
SECStatus (*p_SHA384_Flatten)(SHA384Context *cx, unsigned char *space);
SHA384Context *(*p_SHA384_Resurrect)(unsigned char *space, void *arg);
/* Version 3.003 came to here */
AESKeyWrapContext *(*p_AESKeyWrap_CreateContext)(const unsigned char *key,
const unsigned char *iv, int encrypt, unsigned int keylen);
void (*p_AESKeyWrap_DestroyContext)(AESKeyWrapContext *cx, PRBool freeit);
SECStatus (*p_AESKeyWrap_Encrypt)(AESKeyWrapContext *cx,
unsigned char *output,
unsigned int *outputLen, unsigned int maxOutputLen,
const unsigned char *input, unsigned int inputLen);
SECStatus (*p_AESKeyWrap_Decrypt)(AESKeyWrapContext *cx,
unsigned char *output,
unsigned int *outputLen, unsigned int maxOutputLen,
const unsigned char *input, unsigned int inputLen);
/* Version 3.004 came to here */
PRBool (*p_BLAPI_SHVerify)(const char *name, PRFuncPtr addr);
PRBool (*p_BLAPI_VerifySelf)(const char *name);
/* Version 3.005 came to here */
SECStatus (*p_EC_NewKey)(ECParams *params,
ECPrivateKey **privKey);
SECStatus (*p_EC_NewKeyFromSeed)(ECParams *params,
ECPrivateKey **privKey,
const unsigned char *seed,
int seedlen);
SECStatus (*p_EC_ValidatePublicKey)(ECParams *params,
SECItem *publicValue);
SECStatus (*p_ECDH_Derive)(SECItem *publicValue,
ECParams *params,
SECItem *privateValue,
PRBool withCofactor,
SECItem *derivedSecret);
SECStatus (*p_ECDSA_SignDigest)(ECPrivateKey *key,
SECItem *signature,
const SECItem *digest);
SECStatus (*p_ECDSA_VerifyDigest)(ECPublicKey *key,
const SECItem *signature,
const SECItem *digest);
SECStatus (*p_ECDSA_SignDigestWithSeed)(ECPrivateKey *key,
SECItem *signature,
const SECItem *digest,
const unsigned char *seed,
const int seedlen);
/* Version 3.006 came to here */
/* no modification to FREEBLVectorStr itself
* but ECParamStr was modified
*/
/* Version 3.007 came to here */
SECStatus (*p_AES_InitContext)(AESContext *cx,
const unsigned char *key,
unsigned int keylen,
const unsigned char *iv,
int mode,
unsigned int encrypt,
unsigned int blocklen);
SECStatus (*p_AESKeyWrap_InitContext)(AESKeyWrapContext *cx,
const unsigned char *key,
unsigned int keylen,
const unsigned char *iv,
int mode,
unsigned int encrypt,
unsigned int blocklen);
SECStatus (*p_DES_InitContext)(DESContext *cx,
const unsigned char *key,
unsigned int keylen,
const unsigned char *iv,
int mode,
unsigned int encrypt,
unsigned int);
SECStatus (*p_RC2_InitContext)(RC2Context *cx,
const unsigned char *key,
unsigned int keylen,
const unsigned char *iv,
int mode,
unsigned int effectiveKeyLen,
unsigned int);
SECStatus (*p_RC4_InitContext)(RC4Context *cx,
const unsigned char *key,
unsigned int keylen,
const unsigned char *,
int,
unsigned int,
unsigned int);
AESContext *(*p_AES_AllocateContext)(void);
AESKeyWrapContext *(*p_AESKeyWrap_AllocateContext)(void);
DESContext *(*p_DES_AllocateContext)(void);
RC2Context *(*p_RC2_AllocateContext)(void);
RC4Context *(*p_RC4_AllocateContext)(void);
void (*p_MD2_Clone)(MD2Context *dest, MD2Context *src);
void (*p_MD5_Clone)(MD5Context *dest, MD5Context *src);
void (*p_SHA1_Clone)(SHA1Context *dest, SHA1Context *src);
void (*p_SHA256_Clone)(SHA256Context *dest, SHA256Context *src);
void (*p_SHA384_Clone)(SHA384Context *dest, SHA384Context *src);
void (*p_SHA512_Clone)(SHA512Context *dest, SHA512Context *src);
SECStatus (*p_TLS_PRF)(const SECItem *secret, const char *label,
SECItem *seed, SECItem *result, PRBool isFIPS);
const SECHashObject *(*p_HASH_GetRawHashObject)(HASH_HashType hashType);
HMACContext *(*p_HMAC_Create)(const SECHashObject *hashObj,
const unsigned char *secret,
unsigned int secret_len, PRBool isFIPS);
SECStatus (*p_HMAC_Init)(HMACContext *cx, const SECHashObject *hash_obj,
const unsigned char *secret,
unsigned int secret_len, PRBool isFIPS);
void (*p_HMAC_Begin)(HMACContext *cx);
void (*p_HMAC_Update)(HMACContext *cx, const unsigned char *data,
unsigned int data_len);
HMACContext *(*p_HMAC_Clone)(HMACContext *cx);
SECStatus (*p_HMAC_Finish)(HMACContext *cx, unsigned char *result,
unsigned int *result_len,
unsigned int max_result_len);
void (*p_HMAC_Destroy)(HMACContext *cx, PRBool freeit);
void (*p_RNG_SystemInfoForRNG)(void);
/* Version 3.008 came to here */
SECStatus (*p_FIPS186Change_GenerateX)(unsigned char *XKEY,
const unsigned char *XSEEDj,
unsigned char *x_j);
SECStatus (*p_FIPS186Change_ReduceModQForDSA)(const unsigned char *w,
const unsigned char *q,
unsigned char *xj);
/* Version 3.009 came to here */
SECStatus (*p_Camellia_InitContext)(CamelliaContext *cx,
const unsigned char *key,
unsigned int keylen,
const unsigned char *iv,
int mode,
unsigned int encrypt,
unsigned int unused);
CamelliaContext *(*p_Camellia_AllocateContext)(void);
CamelliaContext *(*p_Camellia_CreateContext)(const unsigned char *key,
const unsigned char *iv,
int mode, int encrypt,
unsigned int keylen);
void (*p_Camellia_DestroyContext)(CamelliaContext *cx, PRBool freeit);
SECStatus (*p_Camellia_Encrypt)(CamelliaContext *cx, unsigned char *output,
unsigned int *outputLen,
unsigned int maxOutputLen,
const unsigned char *input,
unsigned int inputLen);
SECStatus (*p_Camellia_Decrypt)(CamelliaContext *cx, unsigned char *output,
unsigned int *outputLen,
unsigned int maxOutputLen,
const unsigned char *input,
unsigned int inputLen);
void (*p_PQG_DestroyParams)(PQGParams *params);
void (*p_PQG_DestroyVerify)(PQGVerify *vfy);
/* Version 3.010 came to here */
SECStatus (*p_SEED_InitContext)(SEEDContext *cx,
const unsigned char *key,
unsigned int keylen,
const unsigned char *iv,
int mode,
unsigned int encrypt,
unsigned int);
SEEDContext *(*p_SEED_AllocateContext)(void);
SEEDContext *(*p_SEED_CreateContext)(const unsigned char *key,
const unsigned char *iv,
int mode, PRBool encrypt);
void (*p_SEED_DestroyContext)(SEEDContext *cx, PRBool freeit);
SECStatus (*p_SEED_Encrypt)(SEEDContext *cx, unsigned char *output,
unsigned int *outputLen, unsigned int maxOutputLen,
const unsigned char *input, unsigned int inputLen);
SECStatus (*p_SEED_Decrypt)(SEEDContext *cx, unsigned char *output,
unsigned int *outputLen, unsigned int maxOutputLen,
const unsigned char *input, unsigned int inputLen);
SECStatus (*p_BL_Init)(void);
void (*p_BL_SetForkState)(PRBool);
SECStatus (*p_PRNGTEST_Instantiate)(const PRUint8 *entropy,
unsigned int entropy_len,
const PRUint8 *nonce,
unsigned int nonce_len,
const PRUint8 *personal_string,
unsigned int ps_len);
SECStatus (*p_PRNGTEST_Reseed)(const PRUint8 *entropy,
unsigned int entropy_len,
const PRUint8 *additional,
unsigned int additional_len);
SECStatus (*p_PRNGTEST_Generate)(PRUint8 *bytes,
unsigned int bytes_len,
const PRUint8 *additional,
unsigned int additional_len);
SECStatus (*p_PRNGTEST_Uninstantiate)(void);
/* Version 3.011 came to here */
SECStatus (*p_RSA_PopulatePrivateKey)(RSAPrivateKey *key);
SECStatus (*p_DSA_NewRandom)(PLArenaPool *arena, const SECItem *q,
SECItem *seed);
SECStatus (*p_JPAKE_Sign)(PLArenaPool *arena, const PQGParams *pqg,
HASH_HashType hashType, const SECItem *signerID,
const SECItem *x, const SECItem *testRandom,
const SECItem *gxIn, SECItem *gxOut,
SECItem *gv, SECItem *r);
SECStatus (*p_JPAKE_Verify)(PLArenaPool *arena, const PQGParams *pqg,
HASH_HashType hashType, const SECItem *signerID,
const SECItem *peerID, const SECItem *gx,
const SECItem *gv, const SECItem *r);
SECStatus (*p_JPAKE_Round2)(PLArenaPool *arena, const SECItem *p,
const SECItem *q, const SECItem *gx1,
const SECItem *gx3, const SECItem *gx4,
SECItem *base, const SECItem *x2,
const SECItem *s, SECItem *x2s);
SECStatus (*p_JPAKE_Final)(PLArenaPool *arena, const SECItem *p,
const SECItem *q, const SECItem *x2,
const SECItem *gx4, const SECItem *x2s,
const SECItem *B, SECItem *K);
/* Version 3.012 came to here */
SECStatus (*p_TLS_P_hash)(HASH_HashType hashAlg,
const SECItem *secret,
const char *label,
SECItem *seed,
SECItem *result,
PRBool isFIPS);
SHA224Context *(*p_SHA224_NewContext)(void);
void (*p_SHA224_DestroyContext)(SHA224Context *cx, PRBool freeit);
void (*p_SHA224_Begin)(SHA224Context *cx);
void (*p_SHA224_Update)(SHA224Context *cx, const unsigned char *input,
unsigned int inputLen);
void (*p_SHA224_End)(SHA224Context *cx, unsigned char *digest,
unsigned int *digestLen, unsigned int maxDigestLen);
SECStatus (*p_SHA224_HashBuf)(unsigned char *dest, const unsigned char *src,
PRUint32 src_length);
SECStatus (*p_SHA224_Hash)(unsigned char *dest, const char *src);
void (*p_SHA224_TraceState)(SHA224Context *cx);
unsigned int (*p_SHA224_FlattenSize)(SHA224Context *cx);
SECStatus (*p_SHA224_Flatten)(SHA224Context *cx, unsigned char *space);
SHA224Context *(*p_SHA224_Resurrect)(unsigned char *space, void *arg);
void (*p_SHA224_Clone)(SHA224Context *dest, SHA224Context *src);
PRBool (*p_BLAPI_SHVerifyFile)(const char *name);
/* Version 3.013 came to here */
SECStatus (*p_PQG_ParamGenV2)(unsigned int L, unsigned int N,
unsigned int seedBytes,
PQGParams **pParams, PQGVerify **pVfy);
SECStatus (*p_PRNGTEST_RunHealthTests)(void);
/* Version 3.014 came to here */
SECStatus (*p_HMAC_ConstantTime)(
unsigned char *result,
unsigned int *resultLen,
unsigned int maxResultLen,
const SECHashObject *hashObj,
const unsigned char *secret,
unsigned int secretLen,
const unsigned char *header,
unsigned int headerLen,
const unsigned char *body,
unsigned int bodyLen,
unsigned int bodyTotalLen);
SECStatus (*p_SSLv3_MAC_ConstantTime)(
unsigned char *result,
unsigned int *resultLen,
unsigned int maxResultLen,
const SECHashObject *hashObj,
const unsigned char *secret,
unsigned int secretLen,
const unsigned char *header,
unsigned int headerLen,
const unsigned char *body,
unsigned int bodyLen,
unsigned int bodyTotalLen);
/* Version 3.015 came to here */
SECStatus (*p_RSA_SignRaw)(RSAPrivateKey *key,
unsigned char *output,
unsigned int *outputLen,
unsigned int maxOutputLen,
const unsigned char *input,
unsigned int inputLen);
SECStatus (*p_RSA_CheckSignRaw)(RSAPublicKey *key,
const unsigned char *sig,
unsigned int sigLen,
const unsigned char *hash,
unsigned int hashLen);
SECStatus (*p_RSA_CheckSignRecoverRaw)(RSAPublicKey *key,
unsigned char *data,
unsigned int *dataLen,
unsigned int maxDataLen,
const unsigned char *sig,
unsigned int sigLen);
SECStatus (*p_RSA_EncryptRaw)(RSAPublicKey *key,
unsigned char *output,
unsigned int *outputLen,
unsigned int maxOutputLen,
const unsigned char *input,
unsigned int inputLen);
SECStatus (*p_RSA_DecryptRaw)(RSAPrivateKey *key,
unsigned char *output,
unsigned int *outputLen,
unsigned int maxOutputLen,
const unsigned char *input,
unsigned int inputLen);
SECStatus (*p_RSA_EncryptOAEP)(RSAPublicKey *key,
HASH_HashType hashAlg,
HASH_HashType maskHashAlg,
const unsigned char *label,
unsigned int labelLen,
const unsigned char *seed,
unsigned int seedLen,
unsigned char *output,
unsigned int *outputLen,
unsigned int maxOutputLen,
const unsigned char *input,
unsigned int inputLen);
SECStatus (*p_RSA_DecryptOAEP)(RSAPrivateKey *key,
HASH_HashType hashAlg,
HASH_HashType maskHashAlg,
const unsigned char *label,
unsigned int labelLen,
unsigned char *output,
unsigned int *outputLen,
unsigned int maxOutputLen,
const unsigned char *input,
unsigned int inputLen);
SECStatus (*p_RSA_EncryptBlock)(RSAPublicKey *key,
unsigned char *output,
unsigned int *outputLen,
unsigned int maxOutputLen,
const unsigned char *input,
unsigned int inputLen);
SECStatus (*p_RSA_DecryptBlock)(RSAPrivateKey *key,
unsigned char *output,
unsigned int *outputLen,
unsigned int maxOutputLen,
const unsigned char *input,
unsigned int inputLen);
SECStatus (*p_RSA_SignPSS)(RSAPrivateKey *key,
HASH_HashType hashAlg,
HASH_HashType maskHashAlg,
const unsigned char *salt,
unsigned int saltLen,
unsigned char *output,
unsigned int *outputLen,
unsigned int maxOutputLen,
const unsigned char *input,
unsigned int inputLen);
SECStatus (*p_RSA_CheckSignPSS)(RSAPublicKey *key,
HASH_HashType hashAlg,
HASH_HashType maskHashAlg,
unsigned int saltLen,
const unsigned char *sig,
unsigned int sigLen,
const unsigned char *hash,
unsigned int hashLen);
SECStatus (*p_RSA_Sign)(RSAPrivateKey *key,
unsigned char *output,
unsigned int *outputLen,
unsigned int maxOutputLen,
const unsigned char *input,
unsigned int inputLen);
SECStatus (*p_RSA_CheckSign)(RSAPublicKey *key,
const unsigned char *sig,
unsigned int sigLen,
const unsigned char *data,
unsigned int dataLen);
SECStatus (*p_RSA_CheckSignRecover)(RSAPublicKey *key,
unsigned char *output,
unsigned int *outputLen,
unsigned int maxOutputLen,
const unsigned char *sig,
unsigned int sigLen);
/* Version 3.016 came to here */
SECStatus (*p_EC_FillParams)(PLArenaPool *arena,
const SECItem *encodedParams, ECParams *params);
SECStatus (*p_EC_DecodeParams)(const SECItem *encodedParams,
ECParams **ecparams);
SECStatus (*p_EC_CopyParams)(PLArenaPool *arena, ECParams *dstParams,
const ECParams *srcParams);
/* Version 3.017 came to here */
SECStatus (*p_ChaCha20Poly1305_InitContext)(ChaCha20Poly1305Context *ctx,
const unsigned char *key,
unsigned int keyLen,
unsigned int tagLen);
ChaCha20Poly1305Context *(*p_ChaCha20Poly1305_CreateContext)(
const unsigned char *key, unsigned int keyLen, unsigned int tagLen);
void (*p_ChaCha20Poly1305_DestroyContext)(ChaCha20Poly1305Context *ctx,
PRBool freeit);
SECStatus (*p_ChaCha20Poly1305_Seal)(
const ChaCha20Poly1305Context *ctx, unsigned char *output,
unsigned int *outputLen, unsigned int maxOutputLen,
const unsigned char *input, unsigned int inputLen,
const unsigned char *nonce, unsigned int nonceLen,
const unsigned char *ad, unsigned int adLen);
SECStatus (*p_ChaCha20Poly1305_Open)(
const ChaCha20Poly1305Context *ctx, unsigned char *output,
unsigned int *outputLen, unsigned int maxOutputLen,
const unsigned char *input, unsigned int inputLen,
const unsigned char *nonce, unsigned int nonceLen,
const unsigned char *ad, unsigned int adLen);
/* Version 3.018 came to here */
int (*p_EC_GetPointSize)(const ECParams *);
/* Version 3.019 came to here */
/* Add new function pointers at the end of this struct and bump
* FREEBL_VERSION at the beginning of this file. */
};
typedef struct FREEBLVectorStr FREEBLVector;
#ifdef FREEBL_LOWHASH
#include "nsslowhash.h"
#define NSSLOW_VERSION 0x0300
struct NSSLOWVectorStr {
unsigned short length; /* of this struct in bytes */
unsigned short version; /* of this struct. */
const FREEBLVector *(*p_FREEBL_GetVector)(void);
NSSLOWInitContext *(*p_NSSLOW_Init)(void);
void (*p_NSSLOW_Shutdown)(NSSLOWInitContext *context);
void (*p_NSSLOW_Reset)(NSSLOWInitContext *context);
NSSLOWHASHContext *(*p_NSSLOWHASH_NewContext)(
NSSLOWInitContext *initContext,
HASH_HashType hashType);
void (*p_NSSLOWHASH_Begin)(NSSLOWHASHContext *context);
void (*p_NSSLOWHASH_Update)(NSSLOWHASHContext *context,
const unsigned char *buf,
unsigned int len);
void (*p_NSSLOWHASH_End)(NSSLOWHASHContext *context,
unsigned char *buf,
unsigned int *ret, unsigned int len);
void (*p_NSSLOWHASH_Destroy)(NSSLOWHASHContext *context);
unsigned int (*p_NSSLOWHASH_Length)(NSSLOWHASHContext *context);
};
typedef struct NSSLOWVectorStr NSSLOWVector;
#endif
SEC_BEGIN_PROTOS
#ifdef FREEBL_LOWHASH
typedef const NSSLOWVector *NSSLOWGetVectorFn(void);
extern NSSLOWGetVectorFn NSSLOW_GetVector;
#endif
typedef const FREEBLVector *FREEBLGetVectorFn(void);
extern FREEBLGetVectorFn FREEBL_GetVector;
SEC_END_PROTOS
#endif

View file

@ -0,0 +1,217 @@
/*
* loader.c - load platform dependent DSO containing freebl implementation.
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#define _GNU_SOURCE 1
#include "loader.h"
#include "prmem.h"
#include "prerror.h"
#include "prinit.h"
#include "prenv.h"
#include "blname.c"
#include "prio.h"
#include "prprf.h"
#include <stdio.h>
#include "prsystem.h"
#include "nsslowhash.h"
#include <dlfcn.h>
#include "pratom.h"
static PRLibrary *blLib;
#define LSB(x) ((x)&0xff)
#define MSB(x) ((x) >> 8)
static const NSSLOWVector *vector;
static const char *libraryName = NULL;
/* pretty much only glibc uses this, make sure we don't have any depenencies
* on nspr.. */
#undef PORT_Alloc
#undef PORT_Free
#define PORT_Alloc malloc
#define PR_Malloc malloc
#define PORT_Free free
#define PR_Free free
#define PR_GetDirectorySeparator() '/'
#define PR_LoadLibraryWithFlags(libspec, flags) \
(PRLibrary *)dlopen(libSpec.value.pathname, RTLD_NOW | RTLD_LOCAL)
#define PR_GetLibraryFilePathname(name, addr) \
freebl_lowhash_getLibraryFilePath(addr)
static char *
freebl_lowhash_getLibraryFilePath(void *addr)
{
Dl_info dli;
if (dladdr(addr, &dli) == 0) {
return NULL;
}
return strdup(dli.dli_fname);
}
/*
* The PR_LoadLibraryWithFlags call above defines this variable away, so we
* don't need it..
*/
#ifdef nodef
static const char *NameOfThisSharedLib =
SHLIB_PREFIX "freebl" SHLIB_VERSION "." SHLIB_SUFFIX;
#endif
#include "genload.c"
/* This function must be run only once. */
/* determine if hybrid platform, then actually load the DSO. */
static PRStatus
freebl_LoadDSO(void)
{
PRLibrary *handle;
const char *name = getLibName();
if (!name) {
/*PR_SetError(PR_LOAD_LIBRARY_ERROR,0); */
return PR_FAILURE;
}
handle = loader_LoadLibrary(name);
if (handle) {
void *address = dlsym(handle, "NSSLOW_GetVector");
if (address) {
NSSLOWGetVectorFn *getVector = (NSSLOWGetVectorFn *)address;
const NSSLOWVector *dsoVector = getVector();
if (dsoVector) {
unsigned short dsoVersion = dsoVector->version;
unsigned short myVersion = NSSLOW_VERSION;
if (MSB(dsoVersion) == MSB(myVersion) &&
LSB(dsoVersion) >= LSB(myVersion) &&
dsoVector->length >= sizeof(NSSLOWVector)) {
vector = dsoVector;
libraryName = name;
blLib = handle;
return PR_SUCCESS;
}
}
}
(void)dlclose(handle);
}
return PR_FAILURE;
}
static PRCallOnceType loadFreeBLOnce;
static PRStatus
freebl_RunLoaderOnce(void)
{
/* Don't have NSPR, so can use the real PR_CallOnce, implement a stripped
* down version. */
if (loadFreeBLOnce.initialized) {
return loadFreeBLOnce.status;
}
if (__sync_lock_test_and_set(&loadFreeBLOnce.inProgress, 1) == 0) {
loadFreeBLOnce.status = freebl_LoadDSO();
loadFreeBLOnce.initialized = 1;
} else {
/* shouldn't have a lot of takers on the else clause, which is good
* since we don't have condition variables yet.
* 'initialized' only ever gets set (not cleared) so we don't
* need the traditional locks. */
while (!loadFreeBLOnce.initialized) {
sleep(1); /* don't have condition variables, just give up the CPU */
}
}
return loadFreeBLOnce.status;
}
const FREEBLVector *
FREEBL_GetVector(void)
{
if (!vector && PR_SUCCESS != freebl_RunLoaderOnce()) {
return NULL;
}
if (vector) {
return (vector->p_FREEBL_GetVector)();
}
return NULL;
}
NSSLOWInitContext *
NSSLOW_Init(void)
{
if (!vector && PR_SUCCESS != freebl_RunLoaderOnce())
return NULL;
return (vector->p_NSSLOW_Init)();
}
void
NSSLOW_Shutdown(NSSLOWInitContext *context)
{
if (!vector && PR_SUCCESS != freebl_RunLoaderOnce())
return;
(vector->p_NSSLOW_Shutdown)(context);
}
void
NSSLOW_Reset(NSSLOWInitContext *context)
{
if (!vector && PR_SUCCESS != freebl_RunLoaderOnce())
return;
(vector->p_NSSLOW_Reset)(context);
}
NSSLOWHASHContext *
NSSLOWHASH_NewContext(
NSSLOWInitContext *initContext,
HASH_HashType hashType)
{
if (!vector && PR_SUCCESS != freebl_RunLoaderOnce())
return NULL;
return (vector->p_NSSLOWHASH_NewContext)(initContext, hashType);
}
void
NSSLOWHASH_Begin(NSSLOWHASHContext *context)
{
if (!vector && PR_SUCCESS != freebl_RunLoaderOnce())
return;
(vector->p_NSSLOWHASH_Begin)(context);
}
void
NSSLOWHASH_Update(NSSLOWHASHContext *context,
const unsigned char *buf,
unsigned int len)
{
if (!vector && PR_SUCCESS != freebl_RunLoaderOnce())
return;
(vector->p_NSSLOWHASH_Update)(context, buf, len);
}
void
NSSLOWHASH_End(NSSLOWHASHContext *context,
unsigned char *buf,
unsigned int *ret, unsigned int len)
{
if (!vector && PR_SUCCESS != freebl_RunLoaderOnce())
return;
(vector->p_NSSLOWHASH_End)(context, buf, ret, len);
}
void
NSSLOWHASH_Destroy(NSSLOWHASHContext *context)
{
if (!vector && PR_SUCCESS != freebl_RunLoaderOnce())
return;
(vector->p_NSSLOWHASH_Destroy)(context);
}
unsigned int
NSSLOWHASH_Length(NSSLOWHASHContext *context)
{
if (!vector && PR_SUCCESS != freebl_RunLoaderOnce())
return -1;
return (vector->p_NSSLOWHASH_Length)(context);
}

View file

@ -0,0 +1,195 @@
#
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
# NOTE: any ifdefs in this file must be defined on the gmake command line
# (if anywhere). They cannot come from Makefile or config.mk
CORE_DEPTH = ../..
MODULE = nss
# copied from Linux.mk. We have a chicken and egg issue here. We need to set
# Library name before we call the platform code in coreconf, but we need to
# Pick up the automatic setting of FREEBL_LOWHASH before we can set the
# Library name... so for now we mimic the code in Linux.mk to get the
# automatic setting early...
#
# On Linux 2.6 or later, build libfreebl3.so with no NSPR and libnssutil3.so
# dependencies by default. Set FREEBL_NO_DEPEND to 0 in the environment to
# override this.
#
#
include $(CORE_DEPTH)/coreconf/arch.mk
ifeq ($(OS_ARCH),Linux)
ifneq ($(OS_TARGET),Android)
ifeq (2.6,$(firstword $(sort 2.6 $(OS_RELEASE))))
ifndef FREEBL_NO_DEPEND
FREEBL_NO_DEPEND = 1
FREEBL_LOWHASH = 1
endif
endif
endif
endif
LIBRARY_NAME = freebl
LIBRARY_VERSION = 3
ifdef FREEBL_CHILD_BUILD
ifdef USE_ABI32_INT32
LIBRARY_NAME = freebl_32int
endif
ifdef USE_ABI32_INT64
LIBRARY_NAME = freebl_32int64
endif
ifdef USE_ABI32_FPU
LIBRARY_NAME = freebl_32fpu
endif
ifdef USE_ABI64_INT
LIBRARY_NAME = freebl_64int
endif
ifdef USE_ABI64_FPU
LIBRARY_NAME = freebl_64fpu
endif
ifdef FREEBL_LOWHASH
LIBRARY_NAME = freeblpriv
endif
ifdef USE_STUB_BUILD
# for the stub build, reset name to the default (from freeblpriv)
LIBRARY_NAME = freebl
endif
endif
# if the library name contains _, we prefix the version with _
ifneq (,$(findstring _,$(LIBRARY_NAME)))
LIBRARY_VERSION := _$(LIBRARY_VERSION)
endif
MAPFILE = $(OBJDIR)/$(LIBRARY_NAME).def
SOFTOKEN_LIBRARY_VERSION = 3
DEFINES += -DSHLIB_SUFFIX=\"$(DLL_SUFFIX)\" -DSHLIB_PREFIX=\"$(DLL_PREFIX)\" \
-DSHLIB_VERSION=\"$(LIBRARY_VERSION)\" \
-DSOFTOKEN_SHLIB_VERSION=\"$(SOFTOKEN_LIBRARY_VERSION)\"
REQUIRES =
EXPORTS = \
blapit.h \
shsign.h \
ecl-exp.h \
$(LOWHASH_EXPORTS) \
$(NULL)
PRIVATE_EXPORTS = \
alghmac.h \
blapi.h \
chacha20poly1305.h \
hmacct.h \
secmpi.h \
secrng.h \
ec.h \
ecl.h \
ecl-curve.h \
$(NULL)
MPI_HDRS = mpi-config.h mpi.h mpi-priv.h mplogic.h mpprime.h logtab.h mp_gf2m.h
MPI_SRCS = mpprime.c mpmontg.c mplogic.c mpi.c mp_gf2m.c
ECL_HDRS = ecl-exp.h ecl.h ecp.h ecl-priv.h
ifndef NSS_DISABLE_ECC
ECL_SRCS = ecl.c ecl_curve.c ecl_mult.c ecl_gf.c \
ecp_aff.c ecp_jac.c ecp_mont.c \
ec_naf.c ecp_jm.c ecp_256.c ecp_384.c ecp_521.c \
ecp_256_32.c ecp_25519.c
else
ECL_SRCS = $(NULL)
endif
SHA_SRCS = sha_fast.c
MPCPU_SRCS = mpcpucache.c
CSRCS = \
freeblver.c \
ldvector.c \
sysrand.c \
$(SHA_SRCS) \
md2.c \
md5.c \
sha512.c \
alghmac.c \
rawhash.c \
alg2268.c \
arcfour.c \
arcfive.c \
desblapi.c \
des.c \
drbg.c \
chacha20poly1305.c \
cts.c \
ctr.c \
fipsfreebl.c \
gcm.c \
hmacct.c \
rijndael.c \
aeskeywrap.c \
camellia.c \
dh.c \
ec.c \
ecdecode.c \
pqg.c \
dsa.c \
rsa.c \
rsapkcs.c \
shvfy.c \
tlsprfalg.c \
seed.c \
jpake.c \
$(MPI_SRCS) \
$(MPCPU_SRCS) \
$(ECL_SRCS) \
$(STUBS_SRCS) \
$(LOWHASH_SRCS) \
$(EXTRA_SRCS) \
$(NULL)
ALL_CSRCS := $(CSRCS)
ALL_HDRS = \
alghmac.h \
blapi.h \
blapit.h \
des.h \
ec.h \
loader.h \
rijndael.h \
camellia.h \
secmpi.h \
sha_fast.h \
sha256.h \
shsign.h \
vis_proto.h \
seed.h \
$(NULL)
ifdef AES_GEN_TBL
DEFINES += -DRIJNDAEL_GENERATE_TABLES
else
ifdef AES_GEN_TBL_M
DEFINES += -DRIJNDAEL_GENERATE_TABLES_MACRO
else
ifdef AES_GEN_VAL
DEFINES += -DRIJNDAEL_GENERATE_VALUES
else
ifdef AES_GEN_VAL_M
DEFINES += -DRIJNDAEL_GENERATE_VALUES_MACRO
else
DEFINES += -DRIJNDAEL_INCLUDE_TABLES
endif
endif
endif
endif

View file

@ -0,0 +1,269 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifdef FREEBL_NO_DEPEND
#include "stubs.h"
#endif
#include "prerr.h"
#include "secerr.h"
#include "prtypes.h"
#include "blapi.h"
#define MD2_DIGEST_LEN 16
#define MD2_BUFSIZE 16
#define MD2_X_SIZE 48 /* The X array, [CV | INPUT | TMP VARS] */
#define MD2_CV 0 /* index into X for chaining variables */
#define MD2_INPUT 16 /* index into X for input */
#define MD2_TMPVARS 32 /* index into X for temporary variables */
#define MD2_CHECKSUM_SIZE 16
struct MD2ContextStr {
unsigned char checksum[MD2_BUFSIZE];
unsigned char X[MD2_X_SIZE];
PRUint8 unusedBuffer;
};
static const PRUint8 MD2S[256] = {
0051, 0056, 0103, 0311, 0242, 0330, 0174, 0001,
0075, 0066, 0124, 0241, 0354, 0360, 0006, 0023,
0142, 0247, 0005, 0363, 0300, 0307, 0163, 0214,
0230, 0223, 0053, 0331, 0274, 0114, 0202, 0312,
0036, 0233, 0127, 0074, 0375, 0324, 0340, 0026,
0147, 0102, 0157, 0030, 0212, 0027, 0345, 0022,
0276, 0116, 0304, 0326, 0332, 0236, 0336, 0111,
0240, 0373, 0365, 0216, 0273, 0057, 0356, 0172,
0251, 0150, 0171, 0221, 0025, 0262, 0007, 0077,
0224, 0302, 0020, 0211, 0013, 0042, 0137, 0041,
0200, 0177, 0135, 0232, 0132, 0220, 0062, 0047,
0065, 0076, 0314, 0347, 0277, 0367, 0227, 0003,
0377, 0031, 0060, 0263, 0110, 0245, 0265, 0321,
0327, 0136, 0222, 0052, 0254, 0126, 0252, 0306,
0117, 0270, 0070, 0322, 0226, 0244, 0175, 0266,
0166, 0374, 0153, 0342, 0234, 0164, 0004, 0361,
0105, 0235, 0160, 0131, 0144, 0161, 0207, 0040,
0206, 0133, 0317, 0145, 0346, 0055, 0250, 0002,
0033, 0140, 0045, 0255, 0256, 0260, 0271, 0366,
0034, 0106, 0141, 0151, 0064, 0100, 0176, 0017,
0125, 0107, 0243, 0043, 0335, 0121, 0257, 0072,
0303, 0134, 0371, 0316, 0272, 0305, 0352, 0046,
0054, 0123, 0015, 0156, 0205, 0050, 0204, 0011,
0323, 0337, 0315, 0364, 0101, 0201, 0115, 0122,
0152, 0334, 0067, 0310, 0154, 0301, 0253, 0372,
0044, 0341, 0173, 0010, 0014, 0275, 0261, 0112,
0170, 0210, 0225, 0213, 0343, 0143, 0350, 0155,
0351, 0313, 0325, 0376, 0073, 0000, 0035, 0071,
0362, 0357, 0267, 0016, 0146, 0130, 0320, 0344,
0246, 0167, 0162, 0370, 0353, 0165, 0113, 0012,
0061, 0104, 0120, 0264, 0217, 0355, 0037, 0032,
0333, 0231, 0215, 0063, 0237, 0021, 0203, 0024
};
SECStatus
MD2_Hash(unsigned char *dest, const char *src)
{
unsigned int len;
MD2Context *cx = MD2_NewContext();
if (!cx) {
PORT_SetError(PR_OUT_OF_MEMORY_ERROR);
return SECFailure;
}
MD2_Begin(cx);
MD2_Update(cx, (const unsigned char *)src, PORT_Strlen(src));
MD2_End(cx, dest, &len, MD2_DIGEST_LEN);
MD2_DestroyContext(cx, PR_TRUE);
return SECSuccess;
}
MD2Context *
MD2_NewContext(void)
{
MD2Context *cx = (MD2Context *)PORT_ZAlloc(sizeof(MD2Context));
if (cx == NULL) {
PORT_SetError(PR_OUT_OF_MEMORY_ERROR);
return NULL;
}
return cx;
}
void
MD2_DestroyContext(MD2Context *cx, PRBool freeit)
{
if (freeit)
PORT_ZFree(cx, sizeof(*cx));
}
void
MD2_Begin(MD2Context *cx)
{
memset(cx, 0, sizeof(*cx));
cx->unusedBuffer = MD2_BUFSIZE;
}
static void
md2_compress(MD2Context *cx)
{
int j;
unsigned char P;
P = cx->checksum[MD2_CHECKSUM_SIZE - 1];
/* Compute the running checksum, and set the tmp variables to be
* CV[i] XOR input[i]
*/
#define CKSUMFN(n) \
P = cx->checksum[n] ^ MD2S[cx->X[MD2_INPUT + n] ^ P]; \
cx->checksum[n] = P; \
cx->X[MD2_TMPVARS + n] = cx->X[n] ^ cx->X[MD2_INPUT + n];
CKSUMFN(0);
CKSUMFN(1);
CKSUMFN(2);
CKSUMFN(3);
CKSUMFN(4);
CKSUMFN(5);
CKSUMFN(6);
CKSUMFN(7);
CKSUMFN(8);
CKSUMFN(9);
CKSUMFN(10);
CKSUMFN(11);
CKSUMFN(12);
CKSUMFN(13);
CKSUMFN(14);
CKSUMFN(15);
/* The compression function. */
#define COMPRESS(n) \
P = cx->X[n] ^ MD2S[P]; \
cx->X[n] = P;
P = 0x00;
for (j = 0; j < 18; j++) {
COMPRESS(0);
COMPRESS(1);
COMPRESS(2);
COMPRESS(3);
COMPRESS(4);
COMPRESS(5);
COMPRESS(6);
COMPRESS(7);
COMPRESS(8);
COMPRESS(9);
COMPRESS(10);
COMPRESS(11);
COMPRESS(12);
COMPRESS(13);
COMPRESS(14);
COMPRESS(15);
COMPRESS(16);
COMPRESS(17);
COMPRESS(18);
COMPRESS(19);
COMPRESS(20);
COMPRESS(21);
COMPRESS(22);
COMPRESS(23);
COMPRESS(24);
COMPRESS(25);
COMPRESS(26);
COMPRESS(27);
COMPRESS(28);
COMPRESS(29);
COMPRESS(30);
COMPRESS(31);
COMPRESS(32);
COMPRESS(33);
COMPRESS(34);
COMPRESS(35);
COMPRESS(36);
COMPRESS(37);
COMPRESS(38);
COMPRESS(39);
COMPRESS(40);
COMPRESS(41);
COMPRESS(42);
COMPRESS(43);
COMPRESS(44);
COMPRESS(45);
COMPRESS(46);
COMPRESS(47);
P = (P + j) % 256;
}
cx->unusedBuffer = MD2_BUFSIZE;
}
void
MD2_Update(MD2Context *cx, const unsigned char *input, unsigned int inputLen)
{
PRUint32 bytesToConsume;
/* Fill the remaining input buffer. */
if (cx->unusedBuffer != MD2_BUFSIZE) {
bytesToConsume = PR_MIN(inputLen, cx->unusedBuffer);
memcpy(&cx->X[MD2_INPUT + (MD2_BUFSIZE - cx->unusedBuffer)],
input, bytesToConsume);
if (cx->unusedBuffer + bytesToConsume >= MD2_BUFSIZE)
md2_compress(cx);
inputLen -= bytesToConsume;
input += bytesToConsume;
}
/* Iterate over 16-byte chunks of the input. */
while (inputLen >= MD2_BUFSIZE) {
memcpy(&cx->X[MD2_INPUT], input, MD2_BUFSIZE);
md2_compress(cx);
inputLen -= MD2_BUFSIZE;
input += MD2_BUFSIZE;
}
/* Copy any input that remains into the buffer. */
if (inputLen)
memcpy(&cx->X[MD2_INPUT], input, inputLen);
cx->unusedBuffer = MD2_BUFSIZE - inputLen;
}
void
MD2_End(MD2Context *cx, unsigned char *digest,
unsigned int *digestLen, unsigned int maxDigestLen)
{
PRUint8 padStart;
if (maxDigestLen < MD2_BUFSIZE) {
PORT_SetError(SEC_ERROR_INVALID_ARGS);
return;
}
padStart = MD2_BUFSIZE - cx->unusedBuffer;
memset(&cx->X[MD2_INPUT + padStart], cx->unusedBuffer,
cx->unusedBuffer);
md2_compress(cx);
memcpy(&cx->X[MD2_INPUT], cx->checksum, MD2_BUFSIZE);
md2_compress(cx);
*digestLen = MD2_DIGEST_LEN;
memcpy(digest, &cx->X[MD2_CV], MD2_DIGEST_LEN);
}
unsigned int
MD2_FlattenSize(MD2Context *cx)
{
return sizeof(*cx);
}
SECStatus
MD2_Flatten(MD2Context *cx, unsigned char *space)
{
memcpy(space, cx, sizeof(*cx));
return SECSuccess;
}
MD2Context *
MD2_Resurrect(unsigned char *space, void *arg)
{
MD2Context *cx = MD2_NewContext();
if (cx)
memcpy(cx, space, sizeof(*cx));
return cx;
}
void
MD2_Clone(MD2Context *dest, MD2Context *src)
{
memcpy(dest, src, sizeof *dest);
}

View file

@ -0,0 +1,598 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifdef FREEBL_NO_DEPEND
#include "stubs.h"
#endif
#include "prerr.h"
#include "secerr.h"
#include "prtypes.h"
#include "prlong.h"
#include "blapi.h"
#include "blapii.h"
#define MD5_HASH_LEN 16
#define MD5_BUFFER_SIZE 64
#define MD5_END_BUFFER (MD5_BUFFER_SIZE - 8)
#define CV0_1 0x67452301
#define CV0_2 0xefcdab89
#define CV0_3 0x98badcfe
#define CV0_4 0x10325476
#define T1_0 0xd76aa478
#define T1_1 0xe8c7b756
#define T1_2 0x242070db
#define T1_3 0xc1bdceee
#define T1_4 0xf57c0faf
#define T1_5 0x4787c62a
#define T1_6 0xa8304613
#define T1_7 0xfd469501
#define T1_8 0x698098d8
#define T1_9 0x8b44f7af
#define T1_10 0xffff5bb1
#define T1_11 0x895cd7be
#define T1_12 0x6b901122
#define T1_13 0xfd987193
#define T1_14 0xa679438e
#define T1_15 0x49b40821
#define T2_0 0xf61e2562
#define T2_1 0xc040b340
#define T2_2 0x265e5a51
#define T2_3 0xe9b6c7aa
#define T2_4 0xd62f105d
#define T2_5 0x02441453
#define T2_6 0xd8a1e681
#define T2_7 0xe7d3fbc8
#define T2_8 0x21e1cde6
#define T2_9 0xc33707d6
#define T2_10 0xf4d50d87
#define T2_11 0x455a14ed
#define T2_12 0xa9e3e905
#define T2_13 0xfcefa3f8
#define T2_14 0x676f02d9
#define T2_15 0x8d2a4c8a
#define T3_0 0xfffa3942
#define T3_1 0x8771f681
#define T3_2 0x6d9d6122
#define T3_3 0xfde5380c
#define T3_4 0xa4beea44
#define T3_5 0x4bdecfa9
#define T3_6 0xf6bb4b60
#define T3_7 0xbebfbc70
#define T3_8 0x289b7ec6
#define T3_9 0xeaa127fa
#define T3_10 0xd4ef3085
#define T3_11 0x04881d05
#define T3_12 0xd9d4d039
#define T3_13 0xe6db99e5
#define T3_14 0x1fa27cf8
#define T3_15 0xc4ac5665
#define T4_0 0xf4292244
#define T4_1 0x432aff97
#define T4_2 0xab9423a7
#define T4_3 0xfc93a039
#define T4_4 0x655b59c3
#define T4_5 0x8f0ccc92
#define T4_6 0xffeff47d
#define T4_7 0x85845dd1
#define T4_8 0x6fa87e4f
#define T4_9 0xfe2ce6e0
#define T4_10 0xa3014314
#define T4_11 0x4e0811a1
#define T4_12 0xf7537e82
#define T4_13 0xbd3af235
#define T4_14 0x2ad7d2bb
#define T4_15 0xeb86d391
#define R1B0 0
#define R1B1 1
#define R1B2 2
#define R1B3 3
#define R1B4 4
#define R1B5 5
#define R1B6 6
#define R1B7 7
#define R1B8 8
#define R1B9 9
#define R1B10 10
#define R1B11 11
#define R1B12 12
#define R1B13 13
#define R1B14 14
#define R1B15 15
#define R2B0 1
#define R2B1 6
#define R2B2 11
#define R2B3 0
#define R2B4 5
#define R2B5 10
#define R2B6 15
#define R2B7 4
#define R2B8 9
#define R2B9 14
#define R2B10 3
#define R2B11 8
#define R2B12 13
#define R2B13 2
#define R2B14 7
#define R2B15 12
#define R3B0 5
#define R3B1 8
#define R3B2 11
#define R3B3 14
#define R3B4 1
#define R3B5 4
#define R3B6 7
#define R3B7 10
#define R3B8 13
#define R3B9 0
#define R3B10 3
#define R3B11 6
#define R3B12 9
#define R3B13 12
#define R3B14 15
#define R3B15 2
#define R4B0 0
#define R4B1 7
#define R4B2 14
#define R4B3 5
#define R4B4 12
#define R4B5 3
#define R4B6 10
#define R4B7 1
#define R4B8 8
#define R4B9 15
#define R4B10 6
#define R4B11 13
#define R4B12 4
#define R4B13 11
#define R4B14 2
#define R4B15 9
#define S1_0 7
#define S1_1 12
#define S1_2 17
#define S1_3 22
#define S2_0 5
#define S2_1 9
#define S2_2 14
#define S2_3 20
#define S3_0 4
#define S3_1 11
#define S3_2 16
#define S3_3 23
#define S4_0 6
#define S4_1 10
#define S4_2 15
#define S4_3 21
struct MD5ContextStr {
PRUint32 lsbInput;
PRUint32 msbInput;
PRUint32 cv[4];
union {
PRUint8 b[64];
PRUint32 w[16];
} u;
};
#define inBuf u.b
SECStatus
MD5_Hash(unsigned char *dest, const char *src)
{
return MD5_HashBuf(dest, (const unsigned char *)src, PORT_Strlen(src));
}
SECStatus
MD5_HashBuf(unsigned char *dest, const unsigned char *src, PRUint32 src_length)
{
unsigned int len;
MD5Context cx;
MD5_Begin(&cx);
MD5_Update(&cx, src, src_length);
MD5_End(&cx, dest, &len, MD5_HASH_LEN);
memset(&cx, 0, sizeof cx);
return SECSuccess;
}
MD5Context *
MD5_NewContext(void)
{
/* no need to ZAlloc, MD5_Begin will init the context */
MD5Context *cx = (MD5Context *)PORT_Alloc(sizeof(MD5Context));
if (cx == NULL) {
PORT_SetError(PR_OUT_OF_MEMORY_ERROR);
return NULL;
}
return cx;
}
void
MD5_DestroyContext(MD5Context *cx, PRBool freeit)
{
memset(cx, 0, sizeof *cx);
if (freeit) {
PORT_Free(cx);
}
}
void
MD5_Begin(MD5Context *cx)
{
cx->lsbInput = 0;
cx->msbInput = 0;
/* memset(cx->inBuf, 0, sizeof(cx->inBuf)); */
cx->cv[0] = CV0_1;
cx->cv[1] = CV0_2;
cx->cv[2] = CV0_3;
cx->cv[3] = CV0_4;
}
#define cls(i32, s) (tmp = i32, tmp << s | tmp >> (32 - s))
#if defined(SOLARIS) || defined(HPUX)
#define addto64(sumhigh, sumlow, addend) \
sumlow += addend; \
sumhigh += (sumlow < addend);
#else
#define addto64(sumhigh, sumlow, addend) \
sumlow += addend; \
if (sumlow < addend) \
++sumhigh;
#endif
#define MASK 0x00ff00ff
#ifdef IS_LITTLE_ENDIAN
#define lendian(i32) \
(i32)
#else
#define lendian(i32) \
(tmp = (i32 >> 16) | (i32 << 16), ((tmp & MASK) << 8) | ((tmp >> 8) & MASK))
#endif
#ifndef IS_LITTLE_ENDIAN
#define lebytes(b4) \
((b4)[3] << 24 | (b4)[2] << 16 | (b4)[1] << 8 | (b4)[0])
static void
md5_prep_state_le(MD5Context *cx)
{
PRUint32 tmp;
cx->u.w[0] = lendian(cx->u.w[0]);
cx->u.w[1] = lendian(cx->u.w[1]);
cx->u.w[2] = lendian(cx->u.w[2]);
cx->u.w[3] = lendian(cx->u.w[3]);
cx->u.w[4] = lendian(cx->u.w[4]);
cx->u.w[5] = lendian(cx->u.w[5]);
cx->u.w[6] = lendian(cx->u.w[6]);
cx->u.w[7] = lendian(cx->u.w[7]);
cx->u.w[8] = lendian(cx->u.w[8]);
cx->u.w[9] = lendian(cx->u.w[9]);
cx->u.w[10] = lendian(cx->u.w[10]);
cx->u.w[11] = lendian(cx->u.w[11]);
cx->u.w[12] = lendian(cx->u.w[12]);
cx->u.w[13] = lendian(cx->u.w[13]);
cx->u.w[14] = lendian(cx->u.w[14]);
cx->u.w[15] = lendian(cx->u.w[15]);
}
static void
md5_prep_buffer_le(MD5Context *cx, const PRUint8 *beBuf)
{
cx->u.w[0] = lebytes(&beBuf[0]);
cx->u.w[1] = lebytes(&beBuf[4]);
cx->u.w[2] = lebytes(&beBuf[8]);
cx->u.w[3] = lebytes(&beBuf[12]);
cx->u.w[4] = lebytes(&beBuf[16]);
cx->u.w[5] = lebytes(&beBuf[20]);
cx->u.w[6] = lebytes(&beBuf[24]);
cx->u.w[7] = lebytes(&beBuf[28]);
cx->u.w[8] = lebytes(&beBuf[32]);
cx->u.w[9] = lebytes(&beBuf[36]);
cx->u.w[10] = lebytes(&beBuf[40]);
cx->u.w[11] = lebytes(&beBuf[44]);
cx->u.w[12] = lebytes(&beBuf[48]);
cx->u.w[13] = lebytes(&beBuf[52]);
cx->u.w[14] = lebytes(&beBuf[56]);
cx->u.w[15] = lebytes(&beBuf[60]);
}
#endif
#define F(X, Y, Z) \
((X & Y) | ((~X) & Z))
#define G(X, Y, Z) \
((X & Z) | (Y & (~Z)))
#define H(X, Y, Z) \
(X ^ Y ^ Z)
#define I(X, Y, Z) \
(Y ^ (X | (~Z)))
#define FF(a, b, c, d, bufint, s, ti) \
a = b + cls(a + F(b, c, d) + bufint + ti, s)
#define GG(a, b, c, d, bufint, s, ti) \
a = b + cls(a + G(b, c, d) + bufint + ti, s)
#define HH(a, b, c, d, bufint, s, ti) \
a = b + cls(a + H(b, c, d) + bufint + ti, s)
#define II(a, b, c, d, bufint, s, ti) \
a = b + cls(a + I(b, c, d) + bufint + ti, s)
static void NO_SANITIZE_ALIGNMENT
md5_compress(MD5Context *cx, const PRUint32 *wBuf)
{
PRUint32 a, b, c, d;
PRUint32 tmp;
a = cx->cv[0];
b = cx->cv[1];
c = cx->cv[2];
d = cx->cv[3];
FF(a, b, c, d, wBuf[R1B0], S1_0, T1_0);
FF(d, a, b, c, wBuf[R1B1], S1_1, T1_1);
FF(c, d, a, b, wBuf[R1B2], S1_2, T1_2);
FF(b, c, d, a, wBuf[R1B3], S1_3, T1_3);
FF(a, b, c, d, wBuf[R1B4], S1_0, T1_4);
FF(d, a, b, c, wBuf[R1B5], S1_1, T1_5);
FF(c, d, a, b, wBuf[R1B6], S1_2, T1_6);
FF(b, c, d, a, wBuf[R1B7], S1_3, T1_7);
FF(a, b, c, d, wBuf[R1B8], S1_0, T1_8);
FF(d, a, b, c, wBuf[R1B9], S1_1, T1_9);
FF(c, d, a, b, wBuf[R1B10], S1_2, T1_10);
FF(b, c, d, a, wBuf[R1B11], S1_3, T1_11);
FF(a, b, c, d, wBuf[R1B12], S1_0, T1_12);
FF(d, a, b, c, wBuf[R1B13], S1_1, T1_13);
FF(c, d, a, b, wBuf[R1B14], S1_2, T1_14);
FF(b, c, d, a, wBuf[R1B15], S1_3, T1_15);
GG(a, b, c, d, wBuf[R2B0], S2_0, T2_0);
GG(d, a, b, c, wBuf[R2B1], S2_1, T2_1);
GG(c, d, a, b, wBuf[R2B2], S2_2, T2_2);
GG(b, c, d, a, wBuf[R2B3], S2_3, T2_3);
GG(a, b, c, d, wBuf[R2B4], S2_0, T2_4);
GG(d, a, b, c, wBuf[R2B5], S2_1, T2_5);
GG(c, d, a, b, wBuf[R2B6], S2_2, T2_6);
GG(b, c, d, a, wBuf[R2B7], S2_3, T2_7);
GG(a, b, c, d, wBuf[R2B8], S2_0, T2_8);
GG(d, a, b, c, wBuf[R2B9], S2_1, T2_9);
GG(c, d, a, b, wBuf[R2B10], S2_2, T2_10);
GG(b, c, d, a, wBuf[R2B11], S2_3, T2_11);
GG(a, b, c, d, wBuf[R2B12], S2_0, T2_12);
GG(d, a, b, c, wBuf[R2B13], S2_1, T2_13);
GG(c, d, a, b, wBuf[R2B14], S2_2, T2_14);
GG(b, c, d, a, wBuf[R2B15], S2_3, T2_15);
HH(a, b, c, d, wBuf[R3B0], S3_0, T3_0);
HH(d, a, b, c, wBuf[R3B1], S3_1, T3_1);
HH(c, d, a, b, wBuf[R3B2], S3_2, T3_2);
HH(b, c, d, a, wBuf[R3B3], S3_3, T3_3);
HH(a, b, c, d, wBuf[R3B4], S3_0, T3_4);
HH(d, a, b, c, wBuf[R3B5], S3_1, T3_5);
HH(c, d, a, b, wBuf[R3B6], S3_2, T3_6);
HH(b, c, d, a, wBuf[R3B7], S3_3, T3_7);
HH(a, b, c, d, wBuf[R3B8], S3_0, T3_8);
HH(d, a, b, c, wBuf[R3B9], S3_1, T3_9);
HH(c, d, a, b, wBuf[R3B10], S3_2, T3_10);
HH(b, c, d, a, wBuf[R3B11], S3_3, T3_11);
HH(a, b, c, d, wBuf[R3B12], S3_0, T3_12);
HH(d, a, b, c, wBuf[R3B13], S3_1, T3_13);
HH(c, d, a, b, wBuf[R3B14], S3_2, T3_14);
HH(b, c, d, a, wBuf[R3B15], S3_3, T3_15);
II(a, b, c, d, wBuf[R4B0], S4_0, T4_0);
II(d, a, b, c, wBuf[R4B1], S4_1, T4_1);
II(c, d, a, b, wBuf[R4B2], S4_2, T4_2);
II(b, c, d, a, wBuf[R4B3], S4_3, T4_3);
II(a, b, c, d, wBuf[R4B4], S4_0, T4_4);
II(d, a, b, c, wBuf[R4B5], S4_1, T4_5);
II(c, d, a, b, wBuf[R4B6], S4_2, T4_6);
II(b, c, d, a, wBuf[R4B7], S4_3, T4_7);
II(a, b, c, d, wBuf[R4B8], S4_0, T4_8);
II(d, a, b, c, wBuf[R4B9], S4_1, T4_9);
II(c, d, a, b, wBuf[R4B10], S4_2, T4_10);
II(b, c, d, a, wBuf[R4B11], S4_3, T4_11);
II(a, b, c, d, wBuf[R4B12], S4_0, T4_12);
II(d, a, b, c, wBuf[R4B13], S4_1, T4_13);
II(c, d, a, b, wBuf[R4B14], S4_2, T4_14);
II(b, c, d, a, wBuf[R4B15], S4_3, T4_15);
cx->cv[0] += a;
cx->cv[1] += b;
cx->cv[2] += c;
cx->cv[3] += d;
}
void
MD5_Update(MD5Context *cx, const unsigned char *input, unsigned int inputLen)
{
PRUint32 bytesToConsume;
PRUint32 inBufIndex = cx->lsbInput & 63;
const PRUint32 *wBuf;
/* Add the number of input bytes to the 64-bit input counter. */
addto64(cx->msbInput, cx->lsbInput, inputLen);
if (inBufIndex) {
/* There is already data in the buffer. Fill with input. */
bytesToConsume = PR_MIN(inputLen, MD5_BUFFER_SIZE - inBufIndex);
memcpy(&cx->inBuf[inBufIndex], input, bytesToConsume);
if (inBufIndex + bytesToConsume >= MD5_BUFFER_SIZE) {
/* The buffer is filled. Run the compression function. */
#ifndef IS_LITTLE_ENDIAN
md5_prep_state_le(cx);
#endif
md5_compress(cx, cx->u.w);
}
/* Remaining input. */
inputLen -= bytesToConsume;
input += bytesToConsume;
}
/* Iterate over 64-byte chunks of the message. */
while (inputLen >= MD5_BUFFER_SIZE) {
#ifdef IS_LITTLE_ENDIAN
#ifdef HAVE_UNALIGNED_ACCESS
/* x86 can handle arithmetic on non-word-aligned buffers */
wBuf = (PRUint32 *)input;
#else
if ((ptrdiff_t)input & 0x3) {
/* buffer not aligned, copy it to force alignment */
memcpy(cx->inBuf, input, MD5_BUFFER_SIZE);
wBuf = cx->u.w;
} else {
/* buffer is aligned */
wBuf = (PRUint32 *)input;
}
#endif
#else
md5_prep_buffer_le(cx, input);
wBuf = cx->u.w;
#endif
md5_compress(cx, wBuf);
inputLen -= MD5_BUFFER_SIZE;
input += MD5_BUFFER_SIZE;
}
/* Tail of message (message bytes mod 64). */
if (inputLen)
memcpy(cx->inBuf, input, inputLen);
}
static const unsigned char padbytes[] = {
0x80, 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, 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, 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, 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
};
void
MD5_End(MD5Context *cx, unsigned char *digest,
unsigned int *digestLen, unsigned int maxDigestLen)
{
#ifndef IS_LITTLE_ENDIAN
PRUint32 tmp;
#endif
PRUint32 lowInput, highInput;
PRUint32 inBufIndex = cx->lsbInput & 63;
if (maxDigestLen < MD5_HASH_LEN) {
PORT_SetError(SEC_ERROR_INVALID_ARGS);
return;
}
/* Copy out the length of bits input before padding. */
lowInput = cx->lsbInput;
highInput = (cx->msbInput << 3) | (lowInput >> 29);
lowInput <<= 3;
if (inBufIndex < MD5_END_BUFFER) {
MD5_Update(cx, padbytes, MD5_END_BUFFER - inBufIndex);
} else {
MD5_Update(cx, padbytes,
MD5_END_BUFFER + MD5_BUFFER_SIZE - inBufIndex);
}
/* Store the number of bytes input (before padding) in final 64 bits. */
cx->u.w[14] = lendian(lowInput);
cx->u.w[15] = lendian(highInput);
/* Final call to compress. */
#ifndef IS_LITTLE_ENDIAN
md5_prep_state_le(cx);
#endif
md5_compress(cx, cx->u.w);
/* Copy the resulting values out of the chain variables into return buf. */
if (digestLen)
*digestLen = MD5_HASH_LEN;
#ifndef IS_LITTLE_ENDIAN
cx->cv[0] = lendian(cx->cv[0]);
cx->cv[1] = lendian(cx->cv[1]);
cx->cv[2] = lendian(cx->cv[2]);
cx->cv[3] = lendian(cx->cv[3]);
#endif
memcpy(digest, cx->cv, MD5_HASH_LEN);
}
void
MD5_EndRaw(MD5Context *cx, unsigned char *digest,
unsigned int *digestLen, unsigned int maxDigestLen)
{
#ifndef IS_LITTLE_ENDIAN
PRUint32 tmp;
#endif
PRUint32 cv[4];
if (maxDigestLen < MD5_HASH_LEN) {
PORT_SetError(SEC_ERROR_INVALID_ARGS);
return;
}
memcpy(cv, cx->cv, sizeof(cv));
#ifndef IS_LITTLE_ENDIAN
cv[0] = lendian(cv[0]);
cv[1] = lendian(cv[1]);
cv[2] = lendian(cv[2]);
cv[3] = lendian(cv[3]);
#endif
memcpy(digest, cv, MD5_HASH_LEN);
if (digestLen)
*digestLen = MD5_HASH_LEN;
}
unsigned int
MD5_FlattenSize(MD5Context *cx)
{
return sizeof(*cx);
}
SECStatus
MD5_Flatten(MD5Context *cx, unsigned char *space)
{
memcpy(space, cx, sizeof(*cx));
return SECSuccess;
}
MD5Context *
MD5_Resurrect(unsigned char *space, void *arg)
{
MD5Context *cx = MD5_NewContext();
if (cx)
memcpy(cx, space, sizeof(*cx));
return cx;
}
void
MD5_Clone(MD5Context *dest, MD5Context *src)
{
memcpy(dest, src, sizeof *dest);
}
void
MD5_TraceState(MD5Context *cx)
{
PORT_SetError(PR_NOT_IMPLEMENTED_ERROR);
}

View file

@ -0,0 +1,208 @@
/*
* mknewpc2.c
*
* Generate PC-2 tables for DES-150 library
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
typedef unsigned char BYTE;
typedef unsigned int HALF;
#define DES_ENCRYPT 0
#define DES_DECRYPT 1
/* two 28-bit registers defined in key schedule production process */
static HALF C0, D0;
static HALF L0, R0;
/* key schedule, 16 internal keys, each with 8 6-bit parts */
static BYTE KS[8][16];
/*
* This table takes the 56 bits in C0 and D0 and shows show they are
* permuted into the 8 6-bit parts of the key in the key schedule.
* The bits of C0 are numbered left to right, 1-28.
* The bits of D0 are numbered left to right, 29-56.
* Zeros in this table represent bits that are always zero.
* Note that all the bits in the first 4 rows come from C0,
* and all the bits in the second 4 rows come from D0.
*/
static const BYTE PC2[64] = {
14, 17, 11, 24, 1, 5, 0, 0, /* S1 */
3, 28, 15, 6, 21, 10, 0, 0, /* S2 */
23, 19, 12, 4, 26, 8, 0, 0, /* S3 */
16, 7, 27, 20, 13, 2, 0, 0, /* S4 */
41, 52, 31, 37, 47, 55, 0, 0, /* S5 */
30, 40, 51, 45, 33, 48, 0, 0, /* S6 */
44, 49, 39, 56, 34, 53, 0, 0, /* S7 */
46, 42, 50, 36, 29, 32, 0, 0 /* S8 */
};
/* This table represents the same info as PC2, except that
* The bits of C0 and D0 are each numbered right to left, 0-27.
* -1 values indicate bits that are always zero.
* As before all the bits in the first 4 rows come from C0,
* and all the bits in the second 4 rows come from D0.
*/
static signed char PC2a[64] = {
/* bits of C0 */
14, 11, 17, 4, 27, 23, -1, -1, /* S1 */
25, 0, 13, 22, 7, 18, -1, -1, /* S2 */
5, 9, 16, 24, 2, 20, -1, -1, /* S3 */
12, 21, 1, 8, 15, 26, -1, -1, /* S4 */
/* bits of D0 */
15, 4, 25, 19, 9, 1, -1, -1, /* S5 */
26, 16, 5, 11, 23, 8, -1, -1, /* S6 */
12, 7, 17, 0, 22, 3, -1, -1, /* S7 */
10, 14, 6, 20, 27, 24, -1, -1 /* S8 */
};
/* This table represents the same info as PC2a, except that
* The order of of the rows has been changed to increase the efficiency
* with which the key sechedule is created.
* Fewer shifts and ANDs are required to make the KS from these.
*/
static const signed char PC2b[64] = {
/* bits of C0 */
14, 11, 17, 4, 27, 23, -1, -1, /* S1 */
5, 9, 16, 24, 2, 20, -1, -1, /* S3 */
25, 0, 13, 22, 7, 18, -1, -1, /* S2 */
12, 21, 1, 8, 15, 26, -1, -1, /* S4 */
/* bits of D0 */
26, 16, 5, 11, 23, 8, -1, -1, /* S6 */
10, 14, 6, 20, 27, 24, -1, -1, /* S8 */
15, 4, 25, 19, 9, 1, -1, -1, /* S5 */
12, 7, 17, 0, 22, 3, -1, -1 /* S7 */
};
/* Only 24 of the 28 bits in C0 and D0 are used in PC2.
* The used bits of C0 and D0 are grouped into 4 groups of 6,
* so that the PC2 permutation can be accomplished with 4 lookups
* in tables of 64 entries.
* The following table shows how the bits of C0 and D0 are grouped
* into indexes for the respective table lookups.
* Bits are numbered right-to-left, 0-27, as in PC2b.
*/
static BYTE NDX[48] = {
/* Bits of C0 */
27, 26, 25, 24, 23, 22, /* C0 table 0 */
18, 17, 16, 15, 14, 13, /* C0 table 1 */
9, 8, 7, 2, 1, 0, /* C0 table 2 */
5, 4, 21, 20, 12, 11, /* C0 table 3 */
/* bits of D0 */
27, 26, 25, 24, 23, 22, /* D0 table 0 */
20, 19, 17, 16, 15, 14, /* D0 table 1 */
12, 11, 10, 9, 8, 7, /* D0 table 2 */
6, 5, 4, 3, 1, 0 /* D0 table 3 */
};
/* Here's the code that does that grouping.
left = PC2LOOKUP(0, 0, ((c0 >> 22) & 0x3F) );
left |= PC2LOOKUP(0, 1, ((c0 >> 13) & 0x3F) );
left |= PC2LOOKUP(0, 2, ((c0 >> 4) & 0x38) | (c0 & 0x7) );
left |= PC2LOOKUP(0, 3, ((c0>>18)&0xC) | ((c0>>11)&0x3) | (c0&0x30));
right = PC2LOOKUP(1, 0, ((d0 >> 22) & 0x3F) );
right |= PC2LOOKUP(1, 1, ((d0 >> 15) & 0x30) | ((d0 >> 14) & 0xf) );
right |= PC2LOOKUP(1, 2, ((d0 >> 7) & 0x3F) );
right |= PC2LOOKUP(1, 3, ((d0 >> 1) & 0x3C) | (d0 & 0x3));
*/
void
make_pc2a(void)
{
int i, j;
for (i = 0; i < 64; ++i) {
j = PC2[i];
if (j == 0)
j = -1;
else if (j < 29)
j = 28 - j;
else
j = 56 - j;
PC2a[i] = j;
}
for (i = 0; i < 64; i += 8) {
printf("%3d,%3d,%3d,%3d,%3d,%3d,%3d,%3d,\n",
PC2a[i + 0], PC2a[i + 1], PC2a[i + 2], PC2a[i + 3],
PC2a[i + 4], PC2a[i + 5], PC2a[i + 6], PC2a[i + 7]);
}
}
HALF PC2cd0[64];
HALF PC_2H[8][64];
void
mktable()
{
int i;
int table;
const BYTE* ndx = NDX;
HALF mask;
mask = 0x80000000;
for (i = 0; i < 32; ++i, mask >>= 1) {
int bit = PC2b[i];
if (bit < 0)
continue;
PC2cd0[bit + 32] = mask;
}
mask = 0x80000000;
for (i = 32; i < 64; ++i, mask >>= 1) {
int bit = PC2b[i];
if (bit < 0)
continue;
PC2cd0[bit] = mask;
}
#if DEBUG
for (i = 0; i < 64; ++i) {
printf("0x%08x,\n", PC2cd0[i]);
}
#endif
for (i = 0; i < 24; ++i) {
NDX[i] += 32; /* because c0 is the upper half */
}
for (table = 0; table < 8; ++table) {
HALF bitvals[6];
for (i = 0; i < 6; ++i) {
bitvals[5 - i] = PC2cd0[*ndx++];
}
for (i = 0; i < 64; ++i) {
int j;
int k = 0;
HALF value = 0;
for (j = i; j; j >>= 1, ++k) {
if (j & 1) {
value |= bitvals[k];
}
}
PC_2H[table][i] = value;
}
printf("/* table %d */ {\n", table);
for (i = 0; i < 64; i += 4) {
printf(" 0x%08x, 0x%08x, 0x%08x, 0x%08x, \n",
PC_2H[table][i], PC_2H[table][i + 1],
PC_2H[table][i + 2], PC_2H[table][i + 3]);
}
printf(" },\n");
}
}
int
main(void)
{
/* make_pc2a(); */
mktable();
return 0;
}

View file

@ -0,0 +1,119 @@
/*
* mksp.c
*
* Generate SP tables for DES-150 library
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include <stdio.h>
/*
* sboxes - the tables for the s-box functions
* from FIPS 46, pages 15-16.
*/
unsigned char S[8][64] = {
/* Func S1 = */
{ 14, 0, 4, 15, 13, 7, 1, 4, 2, 14, 15, 2, 11, 13, 8, 1,
3, 10, 10, 6, 6, 12, 12, 11, 5, 9, 9, 5, 0, 3, 7, 8,
4, 15, 1, 12, 14, 8, 8, 2, 13, 4, 6, 9, 2, 1, 11, 7,
15, 5, 12, 11, 9, 3, 7, 14, 3, 10, 10, 0, 5, 6, 0, 13 },
/* Func S2 = */
{ 15, 3, 1, 13, 8, 4, 14, 7, 6, 15, 11, 2, 3, 8, 4, 14,
9, 12, 7, 0, 2, 1, 13, 10, 12, 6, 0, 9, 5, 11, 10, 5,
0, 13, 14, 8, 7, 10, 11, 1, 10, 3, 4, 15, 13, 4, 1, 2,
5, 11, 8, 6, 12, 7, 6, 12, 9, 0, 3, 5, 2, 14, 15, 9 },
/* Func S3 = */
{ 10, 13, 0, 7, 9, 0, 14, 9, 6, 3, 3, 4, 15, 6, 5, 10,
1, 2, 13, 8, 12, 5, 7, 14, 11, 12, 4, 11, 2, 15, 8, 1,
13, 1, 6, 10, 4, 13, 9, 0, 8, 6, 15, 9, 3, 8, 0, 7,
11, 4, 1, 15, 2, 14, 12, 3, 5, 11, 10, 5, 14, 2, 7, 12 },
/* Func S4 = */
{ 7, 13, 13, 8, 14, 11, 3, 5, 0, 6, 6, 15, 9, 0, 10, 3,
1, 4, 2, 7, 8, 2, 5, 12, 11, 1, 12, 10, 4, 14, 15, 9,
10, 3, 6, 15, 9, 0, 0, 6, 12, 10, 11, 1, 7, 13, 13, 8,
15, 9, 1, 4, 3, 5, 14, 11, 5, 12, 2, 7, 8, 2, 4, 14 },
/* Func S5 = */
{ 2, 14, 12, 11, 4, 2, 1, 12, 7, 4, 10, 7, 11, 13, 6, 1,
8, 5, 5, 0, 3, 15, 15, 10, 13, 3, 0, 9, 14, 8, 9, 6,
4, 11, 2, 8, 1, 12, 11, 7, 10, 1, 13, 14, 7, 2, 8, 13,
15, 6, 9, 15, 12, 0, 5, 9, 6, 10, 3, 4, 0, 5, 14, 3 },
/* Func S6 = */
{ 12, 10, 1, 15, 10, 4, 15, 2, 9, 7, 2, 12, 6, 9, 8, 5,
0, 6, 13, 1, 3, 13, 4, 14, 14, 0, 7, 11, 5, 3, 11, 8,
9, 4, 14, 3, 15, 2, 5, 12, 2, 9, 8, 5, 12, 15, 3, 10,
7, 11, 0, 14, 4, 1, 10, 7, 1, 6, 13, 0, 11, 8, 6, 13 },
/* Func S7 = */
{ 4, 13, 11, 0, 2, 11, 14, 7, 15, 4, 0, 9, 8, 1, 13, 10,
3, 14, 12, 3, 9, 5, 7, 12, 5, 2, 10, 15, 6, 8, 1, 6,
1, 6, 4, 11, 11, 13, 13, 8, 12, 1, 3, 4, 7, 10, 14, 7,
10, 9, 15, 5, 6, 0, 8, 15, 0, 14, 5, 2, 9, 3, 2, 12 },
/* Func S8 = */
{ 13, 1, 2, 15, 8, 13, 4, 8, 6, 10, 15, 3, 11, 7, 1, 4,
10, 12, 9, 5, 3, 6, 14, 11, 5, 0, 0, 14, 12, 9, 7, 2,
7, 2, 11, 1, 4, 14, 1, 7, 9, 4, 12, 10, 14, 8, 2, 13,
0, 15, 6, 12, 10, 9, 13, 0, 15, 3, 3, 5, 5, 6, 8, 11 }
};
/*
* Permutation function for results from s-boxes
* from FIPS 46 pages 12 and 16.
* P =
*/
unsigned char P[32] = {
16, 7, 20, 21, 29, 12, 28, 17,
1, 15, 23, 26, 5, 18, 31, 10,
2, 8, 24, 14, 32, 27, 3, 9,
19, 13, 30, 6, 22, 11, 4, 25
};
unsigned int Pinv[32];
unsigned int SP[8][64];
void
makePinv(void)
{
int i;
unsigned int Pi = 0x80000000;
for (i = 0; i < 32; ++i) {
int j = 32 - P[i];
Pinv[j] = Pi;
Pi >>= 1;
}
}
void
makeSP(void)
{
int box;
for (box = 0; box < 8; ++box) {
int item;
printf("/* box S%d */ {\n", box + 1);
for (item = 0; item < 64; ++item) {
unsigned int s = S[box][item];
unsigned int val = 0;
unsigned int bitnum = (7 - box) * 4;
for (; s; s >>= 1, ++bitnum) {
if (s & 1) {
val |= Pinv[bitnum];
}
}
val = (val << 3) | (val >> 29);
SP[box][item] = val;
}
for (item = 0; item < 64; item += 4) {
printf("\t0x%08x, 0x%08x, 0x%08x, 0x%08x,\n",
SP[box][item], SP[box][item + 1], SP[box][item + 2], SP[box][item + 3]);
}
printf(" },\n");
}
}
int
main()
{
makePinv();
makeSP();
return 0;
}

View file

@ -0,0 +1,244 @@
#
# Makefile for MPI library
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
## Define CC to be the C compiler you wish to use. The GNU cc
## compiler (gcc) should work, at the very least
#CC=cc
#CC=gcc
##
## Define PERL to point to your local Perl interpreter. It
## should be Perl 5.x, although it's conceivable that Perl 4
## might work ... I haven't tested it.
##
#PERL=/usr/bin/perl
#PERL=perl
include target.mk
CFLAGS+= $(XCFLAGS)
##
## Define LIBS to include any libraries you need to link against.
## If NO_TABLE is define, LIBS should include '-lm' or whatever is
## necessary to bring in the math library. Otherwise, it can be
## left alone, unless your system has other peculiar requirements.
##
LIBS=#-lmalloc#-lefence#-lm
##
## Define RANLIB to be the library header randomizer; you might not
## need this on some systems (just set it to 'echo' on these systems,
## such as IRIX)
##
RANLIB=echo
##
## This is the version string used for the documentation and
## building the distribution tarball. Don't mess with it unless
## you are releasing a new version
VERS=1.7p6
## ----------------------------------------------------------------------
## You probably don't need to change anything below this line...
##
##
## This is the list of source files that need to be packed into
## the distribution file
SRCS= mpi.c mpprime.c mplogic.c mp_gf2m.c mpmontg.c mpi-test.c primes.c \
mpcpucache.c tests/ \
utils/gcd.c utils/invmod.c utils/lap.c \
utils/ptab.pl utils/sieve.c utils/isprime.c\
utils/dec2hex.c utils/hex2dec.c utils/bbs_rand.c \
utils/bbsrand.c utils/prng.c utils/primegen.c \
utils/basecvt.c utils/makeprime.c\
utils/fact.c utils/exptmod.c utils/pi.c utils/metime.c \
utils/mpi.h utils/mpprime.h mulsqr.c \
make-test-arrays test-arrays.txt all-tests make-logtab \
types.pl stats timetest multest
## These are the header files that go into the distribution file
HDRS=mpi.h mpi-config.h utils/mpi.h utils/mpi-config.h mpprime.h mplogic.h mp_gf2m.h \
mp_gf2m-priv.h utils/bbs_rand.h tests/mpi.h tests/mpprime.h
## These are the documentation files that go into the distribution file
DOCS=README doc utils/README utils/PRIMES
## This is the list of tools built by 'make tools'
TOOLS=gcd invmod isprime lap dec2hex hex2dec primegen prng \
basecvt fact exptmod pi makeprime identest
LIBOBJS = mpprime.o mpmontg.o mplogic.o mp_gf2m.o mpi.o mpcpucache.o $(AS_OBJS)
LIBHDRS = mpi-config.h mpi-priv.h mpi.h
APPHDRS = mpi-config.h mpi.h mplogic.h mp_gf2m.h mpprime.h
help:
@ echo ""
@ echo "The following targets can be built with this Makefile:"
@ echo ""
@ echo "libmpi.a - arithmetic and prime testing library"
@ echo "mpi-test - test driver (requires MP_IOFUNC)"
@ echo "tools - command line tools"
@ echo "doc - manual pages for tools"
@ echo "clean - clean up objects and such"
@ echo "distclean - get ready for distribution"
@ echo "dist - distribution tarball"
@ echo ""
.SUFFIXES: .c .o .i
.c.i:
$(CC) $(CFLAGS) -E $< > $@
#.c.o: $*.h $*.c
# $(CC) $(CFLAGS) -c $<
#---------------------------------------
$(LIBOBJS): $(LIBHDRS)
logtab.h: make-logtab
$(PERL) make-logtab > logtab.h
mpi.o: mpi.c logtab.h $(LIBHDRS)
mplogic.o: mplogic.c mpi-priv.h mplogic.h $(LIBHDRS)
mp_gf2m.o: mp_gf2m.c mpi-priv.h mp_gf2m.h mp_gf2m-priv.h $(LIBHDRS)
mpmontg.o: mpmontg.c mpi-priv.h mplogic.h mpprime.h $(LIBHDRS)
mpprime.o: mpprime.c mpi-priv.h mpprime.h mplogic.h primes.c $(LIBHDRS)
mpcpucache.o: mpcpucache.c $(LIBHDRS)
mpi_mips.o: mpi_mips.s
$(CC) -o $@ $(ASFLAGS) -c mpi_mips.s
mpi_sparc.o : montmulf.h
mpv_sparcv9.s: vis_64.il mpv_sparc.c
$(CC) -o $@ $(SOLARIS_FPU_FLAGS) -S vis_64.il mpv_sparc.c
mpv_sparcv8.s: vis_64.il mpv_sparc.c
$(CC) -o $@ $(SOLARIS_FPU_FLAGS) -S vis_32.il mpv_sparc.c
montmulfv8.o montmulfv9.o mpv_sparcv8.o mpv_sparcv9.o : %.o : %.s
$(CC) -o $@ $(SOLARIS_ASM_FLAGS) -c $<
mpi_arm.o: mpi_arm.c $(LIBHDRS)
# This rule is used to build the .s sources, which are then hand optimized.
#montmulfv8.s montmulfv9.s : montmulf%.s : montmulf%.il montmulf.c montmulf.h
# $(CC) -o $@ $(SOLARIS_ASM_FLAGS) -S montmulf$*.il montmulf.c
libmpi.a: $(LIBOBJS)
ar -cvr libmpi.a $(LIBOBJS)
$(RANLIB) libmpi.a
lib libs: libmpi.a
mpi.i: mpi.h
#---------------------------------------
MPTESTOBJS = mptest1.o mptest2.o mptest3.o mptest3a.o mptest4.o mptest4a.o \
mptest4b.o mptest6.o mptest7.o mptest8.o mptest9.o mptestb.o
MPTESTS = $(MPTESTOBJS:.o=)
$(MPTESTOBJS): mptest%.o: tests/mptest-%.c $(LIBHDRS)
$(CC) $(CFLAGS) -o $@ -c $<
$(MPTESTS): mptest%: mptest%.o libmpi.a
$(CC) $(CFLAGS) -o $@ $^ $(LIBS)
tests: mptest1 mptest2 mptest3 mptest3a mptest4 mptest4a mptest4b mptest6 \
mptestb bbsrand
utests: mptest7 mptest8 mptest9
#---------------------------------------
EXTRAOBJS = bbsrand.o bbs_rand.o prng.o
UTILOBJS = primegen.o metime.o identest.o basecvt.o fact.o exptmod.o pi.o \
makeprime.o gcd.o invmod.o lap.o isprime.o \
dec2hex.o hex2dec.o
UTILS = $(UTILOBJS:.o=)
$(UTILS): % : %.o libmpi.a
$(CC) $(CFLAGS) -o $@ $^ $(LIBS)
$(UTILOBJS) $(EXTRAOBJS): %.o : utils/%.c $(LIBHDRS)
$(CC) $(CFLAGS) -o $@ -c $<
prng: prng.o bbs_rand.o libmpi.a
$(CC) $(CFLAGS) -o $@ $^ $(LIBS)
bbsrand: bbsrand.o bbs_rand.o libmpi.a
$(CC) $(CFLAGS) -o $@ $^ $(LIBS)
utils: $(UTILS) prng bbsrand
#---------------------------------------
test-info.c: test-arrays.txt
$(PERL) make-test-arrays test-arrays.txt > test-info.c
mpi-test.o: mpi-test.c test-info.c $(LIBHDRS)
$(CC) $(CFLAGS) -o $@ -c $<
mpi-test: mpi-test.o libmpi.a
$(CC) $(CFLAGS) -o $@ $^ $(LIBS)
mdxptest.o: mdxptest.c $(LIBHDRS) mpi-priv.h
mdxptest: mdxptest.o libmpi.a
$(CC) $(CFLAGS) -o $@ $^ $(LIBS)
mulsqr.o: mulsqr.c logtab.h mpi.h mpi-config.h mpprime.h
$(CC) $(CFLAGS) -DMP_SQUARE=1 -o $@ -c mulsqr.c
mulsqr: mulsqr.o libmpi.a
$(CC) $(CFLAGS) -o $@ $^ $(LIBS)
#---------------------------------------
alltests: tests utests mpi-test
tools: $(TOOLS)
doc:
(cd doc; ./build)
clean:
rm -f *.o *.a *.i
rm -f core
rm -f *~ .*~
rm -f utils/*.o
rm -f utils/core
rm -f utils/*~ utils/.*~
clobber: clean
rm -f $(TOOLS) $(UTILS)
distclean: clean
rm -f mptest? mpi-test metime mulsqr karatsuba
rm -f mptest?a mptest?b
rm -f utils/mptest?
rm -f test-info.c logtab.h
rm -f libmpi.a
rm -f $(TOOLS)
dist: Makefile $(HDRS) $(SRCS) $(DOCS)
tar -cvf mpi-$(VERS).tar Makefile $(HDRS) $(SRCS) $(DOCS)
pgps -ab mpi-$(VERS).tar
chmod +r mpi-$(VERS).tar.asc
gzip -9 mpi-$(VERS).tar
# END

View file

@ -0,0 +1,243 @@
#
# Makefile.win - gmake Makefile for building MPI with VACPP on OS/2
#
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
## Define CC to be the C compiler you wish to use. The GNU cc
## compiler (gcc) should work, at the very least
#CC=cc
#CC=gcc
CC=icc.exe
AS=alp.exe
##
## Define PERL to point to your local Perl interpreter. It
## should be Perl 5.x, although it's conceivable that Perl 4
## might work ... I haven't tested it.
##
#PERL=/usr/bin/perl
#PERL=perl
##
## Define CFLAGS to contain any local options your compiler
## setup requires.
##
## Conditional compilation options are no longer here; see
## the file 'mpi-config.h' instead.
##
MPICMN = -I. -DMP_API_COMPATIBLE -DMP_IOFUNC -DMP_USE_UINT_DIGIT -DMP_NO_MP_WORD
#OS/2
AS_SRCS = mpi_x86.asm
MPICMN += -DMP_ASSEMBLY_MULTIPLY -DMP_ASSEMBLY_SQUARE -DMP_ASSEMBLY_DIV_2DX1D
#CFLAGS= -Od -Z7 -MD -W3 -nologo -D_X86_ -DXP_PC \
-DDEBUG -D_DEBUG -UNDEBUG -DWIN32 -D_WINDOWS -DWIN95 $(MPICMN)
#CFLAGS = -O2 -MD -W3 -nologo -D_X86_ -DXP_PC -UDEBUG -U_DEBUG -DNDEBUG \
-DWIN32 -D_WINDOWS -DWIN95 $(MPICMN)
#CFLAGS = -Od -Z7 -MD -W3 -nologo -D_X86_ -DXP_PC -UDEBUG -U_DEBUG -DNDEBUG \
-DWIN32 -D_WINDOWS -DWIN95 $(MPICMN)
CFLAGS = /Ti+ -D_X86_ -DXP_PC -UDEBUG -U_DEBUG -DNDEBUG \
$(MPICMN)
ASFLAGS =
##
## Define LIBS to include any libraries you need to link against.
## If NO_TABLE is define, LIBS should include '-lm' or whatever is
## necessary to bring in the math library. Otherwise, it can be
## left alone, unless your system has other peculiar requirements.
##
LIBS=#-lmalloc#-lefence#-lm
##
## Define RANLIB to be the library header randomizer; you might not
## need this on some systems (just set it to 'echo' on these systems,
## such as IRIX)
##
RANLIB=echo
##
## This is the version string used for the documentation and
## building the distribution tarball. Don't mess with it unless
## you are releasing a new version
VERS=1.7p6
## ----------------------------------------------------------------------
## You probably don't need to change anything below this line...
##
##
## This is the list of source files that need to be packed into
## the distribution file
SRCS= mpi.c mpprime.c mplogic.c mpmontg.c mpi-test.c primes.c tests/ \
utils/gcd.c utils/invmod.c utils/lap.c \
utils/ptab.pl utils/sieve.c utils/isprime.c\
utils/dec2hex.c utils/hex2dec.c utils/bbs_rand.c \
utils/bbsrand.c utils/prng.c utils/primegen.c \
utils/basecvt.c utils/makeprime.c\
utils/fact.c utils/exptmod.c utils/pi.c utils/metime.c \
utils/mpi.h utils/mpprime.h mulsqr.c \
make-test-arrays test-arrays.txt all-tests make-logtab \
types.pl stats timetest multest
## These are the header files that go into the distribution file
HDRS=mpi.h mpi-config.h utils/mpi.h utils/mpi-config.h mpprime.h mplogic.h \
utils/bbs_rand.h tests/mpi.h tests/mpprime.h
## These are the documentation files that go into the distribution file
DOCS=README doc utils/README utils/PRIMES
## This is the list of tools built by 'make tools'
TOOLS=gcd.exe invmod.exe isprime.exe lap.exe dec2hex.exe hex2dec.exe \
primegen.exe prng.exe basecvt.exe fact.exe exptmod.exe pi.exe makeprime.exe
AS_OBJS = $(AS_SRCS:.asm=.obj)
LIBOBJS = mpprime.obj mpmontg.obj mplogic.obj mpi.obj $(AS_OBJS)
LIBHDRS = mpi-config.h mpi-priv.h mpi.h
APPHDRS = mpi-config.h mpi.h mplogic.h mpprime.h
help:
@ echo ""
@ echo "The following targets can be built with this Makefile:"
@ echo ""
@ echo "mpi.lib - arithmetic and prime testing library"
@ echo "mpi-test.exe - test driver (requires MP_IOFUNC)"
@ echo "tools - command line tools"
@ echo "doc - manual pages for tools"
@ echo "clean - clean up objects and such"
@ echo "distclean - get ready for distribution"
@ echo "dist - distribution tarball"
@ echo ""
.SUFFIXES: .c .obj .i .lib .exe .asm
.c.i:
$(CC) $(CFLAGS) -E $< > $@
.c.obj:
$(CC) $(CFLAGS) -c $<
.asm.obj:
$(AS) $(ASFLAGS) $<
.obj.exe:
$(CC) $(CFLAGS) -Fo$@ $<
#---------------------------------------
$(LIBOBJS): $(LIBHDRS)
logtab.h: make-logtab
$(PERL) make-logtab > logtab.h
mpi.obj: mpi.c logtab.h $(LIBHDRS)
mplogic.obj: mplogic.c mpi-priv.h mplogic.h $(LIBHDRS)
mpmontg.obj: mpmontg.c mpi-priv.h mplogic.h mpprime.h $(LIBHDRS)
mpprime.obj: mpprime.c mpi-priv.h mpprime.h mplogic.h primes.c $(LIBHDRS)
mpi_mips.obj: mpi_mips.s
$(CC) -Fo$@ $(ASFLAGS) -c mpi_mips.s
mpi.lib: $(LIBOBJS)
ilib /out:mpi.lib $(LIBOBJS)
$(RANLIB) mpi.lib
lib libs: mpi.lib
#---------------------------------------
MPTESTOBJS = mptest1.obj mptest2.obj mptest3.obj mptest3a.obj mptest4.obj \
mptest4a.obj mptest4b.obj mptest6.obj mptest7.obj mptest8.obj mptest9.obj
MPTESTS = $(MPTESTOBJS:.obj=.exe)
$(MPTESTOBJS): mptest%.obj: tests/mptest-%.c $(LIBHDRS)
$(CC) $(CFLAGS) -Fo$@ -c $<
$(MPTESTS): mptest%.exe: mptest%.obj mpi.lib $(LIBS)
$(CC) $(CFLAGS) -Fo$@ $^
tests: mptest1.exe mptest2.exe mptest3.exe mptest3a.exe mptest4.exe \
mptest4a.exe mptest4b.exe mptest6.exe bbsrand.exe
utests: mptest7.exe mptest8.exe mptest9.exe
#---------------------------------------
EXTRAOBJS = bbsrand.obj bbs_rand.obj prng.obj
UTILOBJS = primegen.obj metime.obj identest.obj basecvt.obj fact.obj \
exptmod.obj pi.obj makeprime.obj karatsuba.obj gcd.obj invmod.obj lap.obj \
isprime.obj dec2hex.obj hex2dec.obj
UTILS = $(UTILOBJS:.obj=.exe)
$(UTILS): %.exe : %.obj mpi.lib $(LIBS)
$(CC) $(CFLAGS) -Fo$@ $^
$(UTILOBJS) $(EXTRAOBJS): %.obj : utils/%.c $(LIBHDRS)
$(CC) $(CFLAGS) -Fo$@ -c $<
prng.exe: prng.obj bbs_rand.obj mpi.lib $(LIBS)
$(CC) $(CFLAGS) -Fo$@ $^
bbsrand.exe: bbsrand.obj bbs_rand.obj mpi.lib $(LIBS)
$(CC) $(CFLAGS) -Fo$@ $^
utils: $(UTILS) prng.exe bbsrand.exe
#---------------------------------------
test-info.c: test-arrays.txt
$(PERL) make-test-arrays test-arrays.txt > test-info.c
mpi-test.obj: mpi-test.c test-info.c $(LIBHDRS)
$(CC) $(CFLAGS) -Fo$@ -c $<
mpi-test.exe: mpi-test.obj mpi.lib $(LIBS)
$(CC) $(CFLAGS) -Fo$@ $^
mdxptest.obj: mdxptest.c $(LIBHDRS) mpi-priv.h
mdxptest.exe: mdxptest.obj mpi.lib $(LIBS)
$(CC) $(CFLAGS) -Fo$@ $^
mulsqr.obj: mulsqr.c logtab.h mpi.h mpi-config.h mpprime.h
$(CC) $(CFLAGS) -DMP_SQUARE=1 -Fo$@ -c mulsqr.c
mulsqr.exe: mulsqr.obj mpi.lib $(LIBS)
$(CC) $(CFLAGS) -Fo$@ $^
#---------------------------------------
alltests: tests utests mpi-test.exe
tools: $(TOOLS)
doc:
(cd doc; ./build)
clean:
rm -f *.obj *.lib *.pdb *.ilk
cd utils; rm -f *.obj *.lib *.pdb *.ilk
distclean: clean
rm -f mptest? mpi-test metime mulsqr karatsuba
rm -f mptest?a mptest?b
rm -f utils/mptest?
rm -f test-info.c logtab.h
rm -f mpi.lib
rm -f $(TOOLS)
dist: Makefile $(HDRS) $(SRCS) $(DOCS)
tar -cvf mpi-$(VERS).tar Makefile $(HDRS) $(SRCS) $(DOCS)
pgps -ab mpi-$(VERS).tar
chmod +r mpi-$(VERS).tar.asc
gzip -9 mpi-$(VERS).tar
print:
@echo LIBOBJS = $(LIBOBJS)
# END

View file

@ -0,0 +1,254 @@
#
# Makefile.win - gmake Makefile for building MPI with MSVC on NT
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
## Define CC to be the C compiler you wish to use. The GNU cc
## compiler (gcc) should work, at the very least
#CC=cc
#CC=gcc
CC=cl.exe
ifeq ($(CPU_ARCH),x86_64)
AS=ml64.exe
else
AS=ml.exe
endif
##
## Define PERL to point to your local Perl interpreter. It
## should be Perl 5.x, although it's conceivable that Perl 4
## might work ... I haven't tested it.
##
#PERL=/usr/bin/perl
#PERL=perl
##
## Define CFLAGS to contain any local options your compiler
## setup requires.
##
## Conditional compilation options are no longer here; see
## the file 'mpi-config.h' instead.
##
MPICMN = -I. -DMP_API_COMPATIBLE -DMP_IOFUNC
ifeq ($(CPU_ARCH),x86_64)
AS_SRCS = mpi_x86_64.asm
CFLAGS = -O2 -Z7 -MD -W3 -nologo -DXP_PC -UDEBUG -U_DEBUG -DNDEBUG \
-DWIN32 -D_WIN64 -D_AMD64_ -D_M_AMD64 -D_WINDOWS -DWIN95 $(MPICMN)
ASFLAGS = -Cp -Sn -Zi -I.
else
#NT
AS_SRCS = mpi_x86.asm
MPICMN += -DMP_ASSEMBLY_MULTIPLY -DMP_ASSEMBLY_SQUARE -DMP_ASSEMBLY_DIV_2DX1D
#CFLAGS= -Od -Z7 -MD -W3 -nologo -D_X86_ -DXP_PC \
-DDEBUG -D_DEBUG -UNDEBUG -DWIN32 -D_WINDOWS -DWIN95 $(MPICMN)
#CFLAGS = -O2 -MD -W3 -nologo -D_X86_ -DXP_PC -UDEBUG -U_DEBUG -DNDEBUG \
-DWIN32 -D_WINDOWS -DWIN95 $(MPICMN)
#CFLAGS = -Od -Z7 -MD -W3 -nologo -D_X86_ -DXP_PC -UDEBUG -U_DEBUG -DNDEBUG \
-DWIN32 -D_WINDOWS -DWIN95 $(MPICMN)
CFLAGS = -O2 -Z7 -MD -W3 -nologo -D_X86_ -DXP_PC -UDEBUG -U_DEBUG -DNDEBUG \
-DWIN32 -D_WINDOWS -DWIN95 $(MPICMN)
ASFLAGS = -Cp -Sn -Zi -coff -I.
endif
##
## Define LIBS to include any libraries you need to link against.
## If NO_TABLE is define, LIBS should include '-lm' or whatever is
## necessary to bring in the math library. Otherwise, it can be
## left alone, unless your system has other peculiar requirements.
##
LIBS=#-lmalloc#-lefence#-lm
##
## Define RANLIB to be the library header randomizer; you might not
## need this on some systems (just set it to 'echo' on these systems,
## such as IRIX)
##
RANLIB=echo
##
## This is the version string used for the documentation and
## building the distribution tarball. Don't mess with it unless
## you are releasing a new version
VERS=1.7p6
## ----------------------------------------------------------------------
## You probably don't need to change anything below this line...
##
##
## This is the list of source files that need to be packed into
## the distribution file
SRCS= mpi.c mpprime.c mplogic.c mpmontg.c mpi-test.c primes.c tests/ \
utils/gcd.c utils/invmod.c utils/lap.c \
utils/ptab.pl utils/sieve.c utils/isprime.c\
utils/dec2hex.c utils/hex2dec.c utils/bbs_rand.c \
utils/bbsrand.c utils/prng.c utils/primegen.c \
utils/basecvt.c utils/makeprime.c\
utils/fact.c utils/exptmod.c utils/pi.c utils/metime.c \
utils/mpi.h utils/mpprime.h mulsqr.c \
make-test-arrays test-arrays.txt all-tests make-logtab \
types.pl stats timetest multest
## These are the header files that go into the distribution file
HDRS=mpi.h mpi-config.h utils/mpi.h utils/mpi-config.h mpprime.h mplogic.h \
utils/bbs_rand.h tests/mpi.h tests/mpprime.h
## These are the documentation files that go into the distribution file
DOCS=README doc utils/README utils/PRIMES
## This is the list of tools built by 'make tools'
TOOLS=gcd.exe invmod.exe isprime.exe lap.exe dec2hex.exe hex2dec.exe \
primegen.exe prng.exe basecvt.exe fact.exe exptmod.exe pi.exe makeprime.exe
AS_OBJS = $(AS_SRCS:.asm=.obj)
LIBOBJS = mpprime.obj mpmontg.obj mplogic.obj mpi.obj $(AS_OBJS)
LIBHDRS = mpi-config.h mpi-priv.h mpi.h
APPHDRS = mpi-config.h mpi.h mplogic.h mpprime.h
help:
@ echo ""
@ echo "The following targets can be built with this Makefile:"
@ echo ""
@ echo "mpi.lib - arithmetic and prime testing library"
@ echo "mpi-test - test driver (requires MP_IOFUNC)"
@ echo "tools - command line tools"
@ echo "doc - manual pages for tools"
@ echo "clean - clean up objects and such"
@ echo "distclean - get ready for distribution"
@ echo "dist - distribution tarball"
@ echo ""
.SUFFIXES: .c .obj .i .lib .exe .asm
.c.i:
$(CC) $(CFLAGS) -E $< > $@
.c.obj:
$(CC) $(CFLAGS) -c $<
.asm.obj:
$(AS) $(ASFLAGS) -c $<
.obj.exe:
$(CC) $(CFLAGS) -Fo$@ $<
#---------------------------------------
$(LIBOBJS): $(LIBHDRS)
logtab.h: make-logtab
$(PERL) make-logtab > logtab.h
mpi.obj: mpi.c logtab.h $(LIBHDRS)
mplogic.obj: mplogic.c mpi-priv.h mplogic.h $(LIBHDRS)
mpmontg.obj: mpmontg.c mpi-priv.h mplogic.h mpprime.h $(LIBHDRS)
mpprime.obj: mpprime.c mpi-priv.h mpprime.h mplogic.h primes.c $(LIBHDRS)
mpi_mips.obj: mpi_mips.s
$(CC) -Fo$@ $(ASFLAGS) -c mpi_mips.s
mpi.lib: $(LIBOBJS)
ar -cvr mpi.lib $(LIBOBJS)
$(RANLIB) mpi.lib
lib libs: mpi.lib
#---------------------------------------
MPTESTOBJS = mptest1.obj mptest2.obj mptest3.obj mptest3a.obj mptest4.obj \
mptest4a.obj mptest4b.obj mptest6.obj mptest7.obj mptest8.obj mptest9.obj
MPTESTS = $(MPTESTOBJS:.obj=.exe)
$(MPTESTOBJS): mptest%.obj: tests/mptest-%.c $(LIBHDRS)
$(CC) $(CFLAGS) -Fo$@ -c $<
$(MPTESTS): mptest%.exe: mptest%.obj mpi.lib $(LIBS)
$(CC) $(CFLAGS) -Fo$@ $^
tests: mptest1.exe mptest2.exe mptest3.exe mptest3a.exe mptest4.exe \
mptest4a.exe mptest4b.exe mptest6.exe bbsrand.exe
utests: mptest7.exe mptest8.exe mptest9.exe
#---------------------------------------
EXTRAOBJS = bbsrand.obj bbs_rand.obj prng.obj
UTILOBJS = primegen.obj metime.obj identest.obj basecvt.obj fact.obj \
exptmod.obj pi.obj makeprime.obj karatsuba.obj gcd.obj invmod.obj lap.obj \
isprime.obj dec2hex.obj hex2dec.obj
UTILS = $(UTILOBJS:.obj=.exe)
$(UTILS): %.exe : %.obj mpi.lib $(LIBS)
$(CC) $(CFLAGS) -Fo$@ $^
$(UTILOBJS) $(EXTRAOBJS): %.obj : utils/%.c $(LIBHDRS)
$(CC) $(CFLAGS) -Fo$@ -c $<
prng.exe: prng.obj bbs_rand.obj mpi.lib $(LIBS)
$(CC) $(CFLAGS) -Fo$@ $^
bbsrand.exe: bbsrand.obj bbs_rand.obj mpi.lib $(LIBS)
$(CC) $(CFLAGS) -Fo$@ $^
utils: $(UTILS) prng.exe bbsrand.exe
#---------------------------------------
test-info.c: test-arrays.txt
$(PERL) make-test-arrays test-arrays.txt > test-info.c
mpi-test.obj: mpi-test.c test-info.c $(LIBHDRS)
$(CC) $(CFLAGS) -Fo$@ -c $<
mpi-test.exe: mpi-test.obj mpi.lib $(LIBS)
$(CC) $(CFLAGS) -Fo$@ $^
mdxptest.obj: mdxptest.c $(LIBHDRS) mpi-priv.h
mdxptest.exe: mdxptest.obj mpi.lib $(LIBS)
$(CC) $(CFLAGS) -Fo$@ $^
mulsqr.obj: mulsqr.c logtab.h mpi.h mpi-config.h mpprime.h
$(CC) $(CFLAGS) -DMP_SQUARE=1 -Fo$@ -c mulsqr.c
mulsqr.exe: mulsqr.obj mpi.lib $(LIBS)
$(CC) $(CFLAGS) -Fo$@ $^
#---------------------------------------
alltests: tests utests mpi-test.exe
tools: $(TOOLS)
doc:
(cd doc; ./build)
clean:
rm -f *.obj *.lib *.pdb *.ilk
cd utils; rm -f *.obj *.lib *.pdb *.ilk
distclean: clean
rm -f mptest? mpi-test metime mulsqr karatsuba
rm -f mptest?a mptest?b
rm -f utils/mptest?
rm -f test-info.c logtab.h
rm -f mpi.lib
rm -f $(TOOLS)
dist: Makefile $(HDRS) $(SRCS) $(DOCS)
tar -cvf mpi-$(VERS).tar Makefile $(HDRS) $(SRCS) $(DOCS)
pgps -ab mpi-$(VERS).tar
chmod +r mpi-$(VERS).tar.asc
gzip -9 mpi-$(VERS).tar
print:
@echo LIBOBJS = $(LIBOBJS)
# END

View file

@ -0,0 +1,749 @@
This Source Code Form is subject to the terms of the Mozilla Public
License, v. 2.0. If a copy of the MPL was not distributed with this
file, You can obtain one at http://mozilla.org/MPL/2.0/.
About the MPI Library
---------------------
The files 'mpi.h' and 'mpi.c' define a simple, arbitrary precision
signed integer arithmetic package. The implementation is not the most
efficient possible, but the code is small and should be fairly easily
portable to just about any machine that supports an ANSI C compiler,
as long as it is capable of at least 16-bit arithmetic (but also see
below for more on this).
This library was written with an eye to cryptographic applications;
thus, some care is taken to make sure that temporary values are not
left lying around in memory when they are no longer in use. This adds
some overhead for zeroing buffers before they are released back into
the free pool; however, it gives you the assurance that there is only
one copy of your important values residing in your process's address
space at a time. Obviously, it is difficult to guarantee anything, in
a pre-emptive multitasking environment, but this at least helps you
keep a lid on the more obvious ways your data can get spread around in
memory.
Using the Library
-----------------
To use the MPI library in your program, you must include the header:
#include "mpi.h"
This header provides all the type and function declarations you'll
need to use the library. Almost all the names defined by the library
begin with the prefix 'mp_', so it should be easy to keep them from
clashing with your program's namespace (he says, glibly, knowing full
well there are always pathological cases).
There are a few things you may want to configure about the library.
By default, the MPI library uses an unsigned short for its digit type,
and an unsigned int for its word type. The word type must be big
enough to contain at least two digits, for the primitive arithmetic to
work out. On my machine, a short is 2 bytes and an int is 4 bytes --
but if you have 64-bit ints, you might want to use a 4-byte digit and
an 8-byte word. I have tested the library using 1-byte digits and
2-byte words, as well. Whatever you choose to do, the things you need
to change are:
(1) The type definitions for mp_digit and mp_word.
(2) The macro DIGIT_FMT which tells mp_print() how to display a
single digit. This is just a printf() format string, so you
can adjust it appropriately.
(3) The macros DIGIT_MAX and MP_WORD_MAX, which specify the
largest value expressible in an mp_digit and an mp_word,
respectively.
Both the mp_digit and mp_word should be UNSIGNED integer types. The
code relies on having the full positive precision of the type used for
digits and words.
The remaining type definitions should be left alone, for the most
part. The code in the library does not make any significant
assumptions about the sizes of things, but there is little if any
reason to change the other parameters, so I would recommend you leave
them as you found them.
The library comes with a Perl script, 'types.pl', which will scan your
current Makefile settings, and attempt to find good definitions for
these types. It relies on a Unix sort of build environment, so it
probably won't work under MacOS or Windows, but it can be convenient
if you're porting to a new flavour of Unix. Just run 'types.pl' at
the command line, and it will spit out its results to the standard
output.
Conventions
-----------
Most functions in the library return a value of type mp_err. This
permits the library to communicate success or various kinds of failure
to the calling program. The return values currently defined are:
MP_OKAY - okay, operation succeeded, all's well
MP_YES - okay, the answer is yes (same as MP_OKAY)
MP_NO - okay, but answer is no (not MP_OKAY)
MP_MEM - operation ran out of memory
MP_RANGE - input parameter was out of range
MP_BADARG - an invalid input parameter was provided
MP_UNDEF - no output value is defined for this input
The only function which currently uses MP_UNDEF is mp_invmod().
Division by zero is undefined, but the division functions will return
MP_RANGE for a zero divisor. MP_BADARG usually means you passed a
bogus mp_int structure to the function. MP_YES and MP_NO are not used
by the library itself; they're defined so you can use them in your own
extensions.
If you need a readable interpretation of these error codes in your
program, you may also use the mp_strerror() function. This function
takes an mp_err as input, and returns a pointer to a human-readable
string describing the meaning of the error. These strings are stored
as constants within the library, so the caller should not attempt to
modify or free the memory associated with these strings.
The library represents values in signed-magnitude format. Values
strictly less than zero are negative, all others are considered
positive (zero is positive by fiat). You can access the 'sign' member
of the mp_int structure directly, but better is to use the mp_cmp_z()
function, to find out which side of zero the value lies on.
Most arithmetic functions have a single-digit variant, as well as the
full arbitrary-precision. An mp_digit is an unsigned value between 0
and DIGIT_MAX inclusive. The radix is available as RADIX. The number
of bits in a given digit is given as DIGIT_BIT.
Generally, input parameters are given before output parameters.
Unless otherwise specified, any input parameter can be re-used as an
output parameter, without confusing anything.
The basic numeric type defined by the library is an mp_int. Virtually
all the functions in the library take a pointer to an mp_int as one of
their parameters. An explanation of how to create and use these
structures follows. And so, without further ado...
Initialization and Cleanup
--------------------------
The basic numeric type defined by the library is an 'mp_int'.
However, it is not sufficient to simply declare a variable of type
mp_int in your program. These variables also need to be initialized
before they can be used, to allocate the internal storage they require
for computation.
This is done using one of the following functions:
mp_init(mp_int *mp);
mp_init_copy(mp_int *mp, mp_int *from);
mp_init_size(mp_int *mp, mp_size p);
Each of these requires a pointer to a structure of type mp_int. The
basic mp_init() simply initializes the mp_int to a default size, and
sets its value to zero. If you would like to initialize a copy of an
existing mp_int, use mp_init_copy(), where the 'from' parameter is the
mp_int you'd like to make a copy of. The third function,
mp_init_size(), permits you to specify how many digits of precision
should be preallocated for your mp_int. This can help the library
avoid unnecessary re-allocations later on.
The default precision used by mp_init() can be retrieved using:
precision = mp_get_prec();
This returns the number of digits that will be allocated. You can
change this value by using:
mp_set_prec(unsigned int prec);
Any positive value is acceptable -- if you pass zero, the default
precision will be re-set to the compiled-in library default (this is
specified in the header file 'mpi-config.h', and typically defaults to
8 or 16).
Just as you must allocate an mp_int before you can use it, you must
clean up the structure when you are done with it. This is performed
using the mp_clear() function. Remember that any mp_int that you
create as a local variable in a function must be mp_clear()'d before
that function exits, or else the memory allocated to that mp_int will
be orphaned and unrecoverable.
To set an mp_int to a given value, the following functions are given:
mp_set(mp_int *mp, mp_digit d);
mp_set_int(mp_int *mp, long z);
The mp_set() function sets the mp_int to a single digit value, while
mp_set_int() sets the mp_int to a signed long integer value.
To set an mp_int to zero, use:
mp_zero(mp_int *mp);
Copying and Moving
------------------
If you have two initialized mp_int's, and you want to copy the value
of one into the other, use:
mp_copy(from, to)
This takes care of clearing the old value of 'to', and copies the new
value into it. If 'to' is not yet initialized, use mp_init_copy()
instead (see above).
Note: The library tries, whenever possible, to avoid allocating
---- new memory. Thus, mp_copy() tries first to satisfy the needs
of the copy by re-using the memory already allocated to 'to'.
Only if this proves insufficient will mp_copy() actually
allocate new memory.
For this reason, if you know a priori that 'to' has enough
available space to hold 'from', you don't need to check the
return value of mp_copy() for memory failure. The USED()
macro tells you how many digits are used by an mp_int, and
the ALLOC() macro tells you how many are allocated.
If you have two initialized mp_int's, and you want to exchange their
values, use:
mp_exch(a, b)
This is better than using mp_copy() with a temporary, since it will
not (ever) touch the memory allocator -- it just swaps the exact
contents of the two structures. The mp_exch() function cannot fail;
if you pass it an invalid structure, it just ignores it, and does
nothing.
Basic Arithmetic
----------------
Once you have initialized your integers, you can operate on them. The
basic arithmetic functions on full mp_int values are:
mp_add(a, b, c) - computes c = a + b
mp_sub(a, b, c) - computes c = a - b
mp_mul(a, b, c) - computes c = a * b
mp_sqr(a, b) - computes b = a * a
mp_div(a, b, q, r) - computes q, r such that a = bq + r
mp_div_2d(a, d, q, r) - computes q = a / 2^d, r = a % 2^d
mp_expt(a, b, c) - computes c = a ** b
mp_2expt(a, k) - computes a = 2^k
The mp_div_2d() function efficiently computes division by powers of
two. Either the q or r parameter may be NULL, in which case that
portion of the computation will be discarded.
The algorithms used for some of the computations here are described in
the following files which are included with this distribution:
mul.txt Describes the multiplication algorithm
div.txt Describes the division algorithm
expt.txt Describes the exponentiation algorithm
sqrt.txt Describes the square-root algorithm
square.txt Describes the squaring algorithm
There are single-digit versions of most of these routines, as well.
In the following prototypes, 'd' is a single mp_digit:
mp_add_d(a, d, c) - computes c = a + d
mp_sub_d(a, d, c) - computes c = a - d
mp_mul_d(a, d, c) - computes c = a * d
mp_mul_2(a, c) - computes c = a * 2
mp_div_d(a, d, q, r) - computes q, r such that a = bq + r
mp_div_2(a, c) - computes c = a / 2
mp_expt_d(a, d, c) - computes c = a ** d
The mp_mul_2() and mp_div_2() functions take advantage of the internal
representation of an mp_int to do multiplication by two more quickly
than mp_mul_d() would. Other basic functions of an arithmetic variety
include:
mp_zero(a) - assign 0 to a
mp_neg(a, c) - negate a: c = -a
mp_abs(a, c) - absolute value: c = |a|
Comparisons
-----------
Several comparison functions are provided. Each of these, unless
otherwise specified, returns zero if the comparands are equal, < 0 if
the first is less than the second, and > 0 if the first is greater
than the second:
mp_cmp_z(a) - compare a <=> 0
mp_cmp_d(a, d) - compare a <=> d, d is a single digit
mp_cmp(a, b) - compare a <=> b
mp_cmp_mag(a, b) - compare |a| <=> |b|
mp_isodd(a) - return nonzero if odd, zero otherwise
mp_iseven(a) - return nonzero if even, zero otherwise
Modular Arithmetic
------------------
Modular variations of the basic arithmetic functions are also
supported. These are available if the MP_MODARITH parameter in
mpi-config.h is turned on (it is by default). The modular arithmetic
functions are:
mp_mod(a, m, c) - compute c = a (mod m), 0 <= c < m
mp_mod_d(a, d, c) - compute c = a (mod d), 0 <= c < d (see below)
mp_addmod(a, b, m, c) - compute c = (a + b) mod m
mp_submod(a, b, m, c) - compute c = (a - b) mod m
mp_mulmod(a, b, m, c) - compute c = (a * b) mod m
mp_sqrmod(a, m, c) - compute c = (a * a) mod m
mp_exptmod(a, b, m, c) - compute c = (a ** b) mod m
mp_exptmod_d(a, d, m, c)- compute c = (a ** d) mod m
The mp_sqr() function squares its input argument. A call to mp_sqr(a,
c) is identical in meaning to mp_mul(a, a, c); however, if the
MP_SQUARE variable is set true in mpi-config.h (see below), then it
will be implemented with a different algorithm, that is supposed to
take advantage of the redundant computation that takes place during
squaring. Unfortunately, some compilers result in worse performance
on this code, so you can change the behaviour at will. There is a
utility program "mulsqr.c" that lets you test which does better on
your system.
The mp_sqrmod() function is analogous to the mp_sqr() function; it
uses the mp_sqr() function rather than mp_mul(), and then performs the
modular reduction. This probably won't help much unless you are doing
a lot of them.
See the file 'square.txt' for a synopsis of the algorithm used.
Note: The mp_mod_d() function computes a modular reduction around
---- a single digit d. The result is a single digit c.
Because an inverse is defined for a (mod m) if and only if (a, m) = 1
(that is, if a and m are relatively prime), mp_invmod() may not be
able to compute an inverse for the arguments. In this case, it
returns the value MP_UNDEF, and does not modify c. If an inverse is
defined, however, it returns MP_OKAY, and sets c to the value of the
inverse (mod m).
See the file 'redux.txt' for a description of the modular reduction
algorithm used by mp_exptmod().
Greatest Common Divisor
-----------------------
If The greates common divisor of two values can be found using one of the
following functions:
mp_gcd(a, b, c) - compute c = (a, b) using binary algorithm
mp_lcm(a, b, c) - compute c = [a, b] = ab / (a, b)
mp_xgcd(a, b, g, x, y) - compute g, x, y so that ax + by = g = (a, b)
Also provided is a function to compute modular inverses, if they
exist:
mp_invmod(a, m, c) - compute c = a^-1 (mod m), if it exists
The function mp_xgcd() computes the greatest common divisor, and also
returns values of x and y satisfying Bezout's identity. This is used
by mp_invmod() to find modular inverses. However, if you do not need
these values, you will find that mp_gcd() is MUCH more efficient,
since it doesn't need all the intermediate values that mp_xgcd()
requires in order to compute x and y.
The mp_gcd() (and mp_xgcd()) functions use the binary (extended) GCD
algorithm due to Josef Stein.
Input & Output Functions
------------------------
The following basic I/O routines are provided. These are present at
all times:
mp_read_radix(mp, str, r) - convert a string in radix r to an mp_int
mp_read_raw(mp, s, len) - convert a string of bytes to an mp_int
mp_radix_size(mp, r) - return length of buffer needed by mp_toradix()
mp_raw_size(mp) - return length of buffer needed by mp_toraw()
mp_toradix(mp, str, r) - convert an mp_int to a string of radix r
digits
mp_toraw(mp, str) - convert an mp_int to a string of bytes
mp_tovalue(ch, r) - convert ch to its value when taken as
a radix r digit, or -1 if invalid
mp_strerror(err) - get a string describing mp_err value 'err'
If you compile the MPI library with MP_IOFUNC defined, you will also
have access to the following additional I/O function:
mp_print(mp, ofp) - print an mp_int as text to output stream ofp
Note that mp_radix_size() returns a size in bytes guaranteed to be AT
LEAST big enough for the digits output by mp_toradix(). Because it
uses an approximation technique to figure out how many digits will be
needed, it may return a figure which is larger than necessary. Thus,
the caller should not rely on the value to determine how many bytes
will actually be written by mp_toradix(). The string mp_toradix()
creates will be NUL terminated, so the standard C library function
strlen() should be able to ascertain this for you, if you need it.
The mp_read_radix() and mp_toradix() functions support bases from 2 to
64 inclusive. If you require more general radix conversion facilities
than this, you will need to write them yourself (that's why mp_div_d()
is provided, after all).
Note: mp_read_radix() will accept as digits either capital or
---- lower-case letters. However, the current implementation of
mp_toradix() only outputs upper-case letters, when writing
bases betwee 10 and 36. The underlying code supports using
lower-case letters, but the interface stub does not have a
selector for it. You can add one yourself if you think it
is worthwhile -- I do not. Bases from 36 to 64 use lower-
case letters as distinct from upper-case. Bases 63 and
64 use the characters '+' and '/' as digits.
Note also that compiling with MP_IOFUNC defined will cause
inclusion of <stdio.h>, so if you are trying to write code
which does not depend on the standard C library, you will
probably want to avoid this option. This is needed because
the mp_print() function takes a standard library FILE * as
one of its parameters, and uses the fprintf() function.
The mp_toraw() function converts the integer to a sequence of bytes,
in big-endian ordering (most-significant byte first). Assuming your
bytes are 8 bits wide, this corresponds to base 256. The sign is
encoded as a single leading byte, whose value is 0 for zero or
positive values, or 1 for negative values. The mp_read_raw() function
reverses this process -- it takes a buffer of bytes, interprets the
first as a sign indicator (0 = zero/positive, nonzero = negative), and
the rest as a sequence of 1-byte digits in big-endian ordering.
The mp_raw_size() function returns the exact number of bytes required
to store the given integer in "raw" format (as described in the
previous paragraph). Zero is returned in case of error; a valid
integer will require at least three bytes of storage.
In previous versions of the MPI library, an "external representation
format" was supported. This was removed, however, because I found I
was never using it, it was not as portable as I would have liked, and
I decided it was a waste of space.
Other Functions
---------------
The files 'mpprime.h' and 'mpprime.c' define some routines which are
useful for divisibility testing and probabilistic primality testing.
The routines defined are:
mpp_divis(a, b) - is a divisible by b?
mpp_divis_d(a, d) - is a divisible by digit d?
mpp_random(a) - set a to random value at current precision
mpp_random_size(a, prec) - set a to random value at given precision
Note: The mpp_random() and mpp_random_size() functions use the C
---- library's rand() function to generate random values. It is
up to the caller to seed this generator before it is called.
These functions are not suitable for generating quantities
requiring cryptographic-quality randomness; they are intended
primarily for use in primality testing.
Note too that the MPI library does not call srand(), so your
application should do this, if you ever want the sequence
to change.
mpp_divis_vector(a, v, s, w) - is a divisible by any of the s digits
in v? If so, let w be the index of
that digit
mpp_divis_primes(a, np) - is a divisible by any of the first np
primes? If so, set np to the prime
which divided a.
mpp_fermat(a, d) - test if w^a = w (mod a). If so,
returns MP_YES, otherwise MP_NO.
mpp_pprime(a, nt) - perform nt iterations of the Rabin-
Miller probabilistic primality test
on a. Returns MP_YES if all tests
passed, or MP_NO if any test fails.
The mpp_fermat() function works based on Fermat's little theorem, a
consequence of which is that if p is a prime, and (w, p) = 1, then:
w^p = w (mod p)
Put another way, if w^p != w (mod p), then p is not prime. The test
is expensive to compute, but it helps to quickly eliminate an enormous
class of composite numbers prior to Rabin-Miller testing.
Building the Library
--------------------
The MPI library is designed to be as self-contained as possible. You
should be able to compile it with your favourite ANSI C compiler, and
link it into your program directly. If you are on a Unix system using
the GNU C compiler (gcc), the following should work:
% gcc -ansi -pedantic -Wall -O2 -c mpi.c
The file 'mpi-config.h' defines several configurable parameters for
the library, which you can adjust to suit your application. At the
time of this writing, the available options are:
MP_IOFUNC - Define true to include the mp_print() function,
which is moderately useful for debugging. This
implicitly includes <stdio.h>.
MP_MODARITH - Define true to include the modular arithmetic
functions. If you don't need modular arithmetic
in your application, you can set this to zero to
leave out all the modular routines.
MP_NUMTH - Define true to include number theoretic functions
such as mp_gcd(), mp_lcm(), and mp_invmod().
MP_LOGTAB - If true, the file "logtab.h" is included, which
is basically a static table of base 2 logarithms.
These are used to compute how big the buffers for
radix conversion need to be. If you set this false,
the library includes <math.h> and uses log(). This
typically forces you to link against math libraries.
MP_MEMSET - If true, use memset() to zero buffers. If you run
into weird alignment related bugs, set this to zero
and an explicit loop will be used.
MP_MEMCPY - If true, use memcpy() to copy buffers. If you run
into weird alignment bugs, set this to zero and an
explicit loop will be used.
MP_ARGCHK - Set to 0, 1, or 2. This defines how the argument
checking macro, ARGCHK(), gets expanded. If this
is set to zero, ARGCHK() expands to nothing; no
argument checks are performed. If this is 1, the
ARGCHK() macro expands to code that returns MP_BADARG
or similar at runtime. If it is 2, ARGCHK() expands
to an assert() call that aborts the program on a
bad input.
MP_DEBUG - Turns on debugging output. This is probably not at
all useful unless you are debugging the library. It
tends to spit out a LOT of output.
MP_DEFPREC - The default precision of a newly-created mp_int, in
digits. The precision can be changed at runtime by
the mp_set_prec() function, but this is its initial
value.
MP_SQUARE - If this is set to a nonzero value, the mp_sqr()
function will use an alternate algorithm that takes
advantage of the redundant inner product computation
when both multiplicands are identical. Unfortunately,
with some compilers this is actually SLOWER than just
calling mp_mul() with the same argument twice. So
if you set MP_SQUARE to zero, mp_sqr() will be expan-
ded into a call to mp_mul(). This applies to all
the uses of mp_sqr(), including mp_sqrmod() and the
internal calls to s_mp_sqr() inside mpi.c
The program 'mulsqr' (mulsqr.c) can be used to test
which works best for your configuration. Set up the
CC and CFLAGS variables in the Makefile, then type:
make mulsqr
Invoke it with arguments similar to the following:
mulsqr 25000 1024
That is, 25000 products computed on 1024-bit values.
The output will compare the two timings, and recommend
a setting for MP_SQUARE. It is off by default.
If you would like to use the mp_print() function (see above), be sure
to define MP_IOFUNC in mpi-config.h. Many of the test drivers in the
'tests' subdirectory expect this to be defined (although the test
driver 'mpi-test' doesn't need it)
The Makefile which comes with the library should take care of building
the library for you, if you have set the CC and CFLAGS variables at
the top of the file appropriately. By default, they are set up to
use the GNU C compiler:
CC=gcc
CFLAGS=-ansi -pedantic -Wall -O2
If all goes well, the library should compile without warnings using
this combination. You should, of course, make whatever adjustments
you find necessary.
The MPI library distribution comes with several additional programs
which are intended to demonstrate the use of the library, and provide
a framework for testing it. There are a handful of test driver
programs, in the files named 'mptest-X.c', where X is a digit. Also,
there are some simple command-line utilities (in the 'utils'
directory) for manipulating large numbers. These include:
basecvt.c A radix-conversion program, supporting bases from
2 to 64 inclusive.
bbsrand.c A BBS (quadratic residue) pseudo-random number
generator. The file 'bbsrand.c' is just the driver
for the program; the real code lives in the files
'bbs_rand.h' and 'bbs_rand.c'
dec2hex.c Converts decimal to hexadecimal
gcd.c Computes the greatest common divisor of two values.
If invoked as 'xgcd', also computes constants x and
y such that (a, b) = ax + by, in accordance with
Bezout's identity.
hex2dec.c Converts hexadecimal to decimal
invmod.c Computes modular inverses
isprime.c Performs the Rabin-Miller probabilistic primality
test on a number. Values which fail this test are
definitely composite, and those which pass are very
likely to be prime (although there are no guarantees)
lap.c Computes the order (least annihilating power) of
a value v modulo m. Very dumb algorithm.
primegen.c Generates large (probable) primes.
prng.c A pseudo-random number generator based on the
BBS generator code in 'bbs_rand.c'
sieve.c Implements the Sieve of Eratosthenes, using a big
bitmap, to generate a list of prime numbers.
fact.c Computes the factorial of an arbitrary precision
integer (iterative).
exptmod.c Computes arbitrary precision modular exponentiation
from the command line (exptmod a b m -> a^b (mod m))
Most of these can be built from the Makefile that comes with the
library. Try 'make tools', if your environment supports it.
Testing the Library
-------------------
Automatic test vectors are included, in the form of a program called
'mpi-test'. To build this program and run all the tests, simply
invoke the shell script 'all-tests'. If all the tests pass, you
should see a message:
All tests passed
If something went wrong, you'll get:
One or more tests failed.
If this happens, scan back through the preceding lines, to see which
test failed. Any failure indicates a bug in the library, which needs
to be fixed before it will give accurate results. If you get any such
thing, please let me know, and I'll try to fix it. Please let me know
what platform and compiler you were using, as well as which test
failed. If a reason for failure was given, please send me that text
as well.
If you're on a system where the standard Unix build tools don't work,
you can build the 'mpi-test' program manually, and run it by hand.
This is tedious and obnoxious, sorry.
Further manual testing can be performed by building the manual testing
programs, whose source is found in the 'tests' subdirectory. Each
test is in a source file called 'mptest-X.c'. The Makefile contains a
target to build all of them at once:
make tests
Read the comments at the top of each source file to see what the
driver is supposed to test. You probably don't need to do this; these
programs were only written to help me as I was developing the library.
The relevant files are:
mpi-test.c The source for the test driver
make-test-arrays A Perl script to generate some of the internal
data structures used by mpi-test.c
test-arrays.txt The source file for make-test-arrays
all-tests A Bourne shell script which runs all the
tests in the mpi-test suite
Running 'make mpi-test' should build the mpi-test program. If you
cannot use make, here is what needs to be done:
(1) Use 'make-test-arrays' to generate the file 'test-info.c' from
the 'test-arrays.txt' file. Since Perl can be found everywhere,
this should be no trouble. Under Unix, this looks like:
make-test-arrays test-arrays.txt > test-info.c
(2) Build the MPI library:
gcc -ansi -pedantic -Wall -c mpi.c
(3) Build the mpi-test program:
gcc -ansi -pedantic -Wall -o mpi-test mpi.o mpi-test.c
When you've got mpi-test, you can use 'all-tests' to run all the tests
made available by mpi-test. If any of them fail, there should be a
diagnostic indicating what went wrong. These are fairly high-level
diagnostics, and won't really help you debug the problem; they're
simply intended to help you isolate which function caused the problem.
If you encounter a problem of this sort, feel free to e-mail me, and I
will certainly attempt to help you debug it.
Note: Several of the tests hard-wired into 'mpi-test' operate under
---- the assumption that you are using at least a 16-bit mp_digit
type. If that is not true, several tests might fail, because
of range problems with the maximum digit value.
If you are using an 8-bit digit, you will also need to
modify the code for mp_read_raw(), which assumes that
multiplication by 256 can be done with mp_mul_d(), a
fact that fails when DIGIT_MAX is 255. You can replace
the call with s_mp_lshd(), which will give you the same
effect, and without doing as much work. :)
Acknowledgements:
----------------
The algorithms used in this library were drawn primarily from Volume
2 of Donald Knuth's magnum opus, _The Art of Computer Programming_,
"Semi-Numerical Methods". Barrett's algorithm for modular reduction
came from Menezes, Oorschot, and Vanstone's _Handbook of Applied
Cryptography_, Chapter 14.
Thanks are due to Tom St. Denis, for finding an obnoxious sign-related
bug in mp_read_raw() that made things break on platforms which use
signed chars.
About the Author
----------------
This software was written by Michael J. Fromberger. You can contact
the author as follows:
E-mail: <sting@linguist.dartmouth.edu>
Postal: 8000 Cummings Hall, Thayer School of Engineering
Dartmouth College, Hanover, New Hampshire, USA
PGP key: http://linguist.dartmouth.edu/~sting/keys/mjf.html
9736 188B 5AFA 23D6 D6AA BE0D 5856 4525 289D 9907
Last updated: 16-Jan-2000

View file

@ -0,0 +1,83 @@
#!/bin/sh
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
ECHO=/bin/echo
MAKE=gmake
$ECHO "\n** Running unit tests for MPI library\n"
# Build the mpi-test program, which comprises all the unit tests for
# the MPI library...
$ECHO "Bringing mpi-test up to date ... "
if $MAKE mpi-test ; then
:
else
$ECHO " "
$ECHO "Make failed to build mpi-test."
$ECHO " "
exit 1
fi
if [ ! -x mpi-test ] ; then
$ECHO " "
$ECHO "Cannot find 'mpi-test' program, testing cannot continue."
$ECHO " "
exit 1
fi
# Get the list of available test suites...
tests=`./mpi-test list | awk '{print $1}'`
errs=0
# Run each test suite and check the result code of mpi-test
for test in $tests ; do
$ECHO "$test ... \c"
if ./mpi-test $test ; then
$ECHO "passed"
else
$ECHO "FAILED"
errs=1
fi
done
# If any tests failed, we'll stop at this point
if [ "$errs" = "0" ] ; then
$ECHO "All unit tests passed"
else
$ECHO "One or more tests failed"
exit 1
fi
# Now try to build the 'pi' program, and see if it can compute the
# first thousand digits of pi correctly
$ECHO "\n** Running other tests\n"
$ECHO "Bringing 'pi' up to date ... "
if $MAKE pi ; then
:
else
$ECHO "\nMake failed to build pi.\n"
exit 1
fi
if [ ! -x pi ] ; then
$ECHO "\nCannot find 'pi' program; testing cannot continue.\n"
exit 1
fi
./pi 2000 > /tmp/pi.tmp.$$
if cmp tests/pi2k.txt /tmp/pi.tmp.$$ ; then
$ECHO "Okay! The pi test passes."
else
$ECHO "Oops! The pi test failed. :("
exit 1
fi
rm -f /tmp/pi.tmp.$$
exit 0
# Here there be dragons

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