mirror of
https://repo.dactyloidae.xyz/Dactyloidae/UXP.git
synced 2026-09-26 10:27:32 +09:00
import FIREFOX_52_6_0esr_RELEASE from mozilla-esr52 hg repo
This commit is contained in:
commit
dcd9973243
150858 changed files with 23884658 additions and 0 deletions
764
security/nss/lib/freebl/Makefile
Normal file
764
security/nss/lib/freebl/Makefile
Normal 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
|
||||
389
security/nss/lib/freebl/aeskeywrap.c
Normal file
389
security/nss/lib/freebl/aeskeywrap.c
Normal 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
|
||||
509
security/nss/lib/freebl/alg2268.c
Normal file
509
security/nss/lib/freebl/alg2268.c
Normal 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;
|
||||
}
|
||||
165
security/nss/lib/freebl/alghmac.c
Normal file
165
security/nss/lib/freebl/alghmac.c
Normal 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;
|
||||
}
|
||||
64
security/nss/lib/freebl/alghmac.h
Normal file
64
security/nss/lib/freebl/alghmac.h
Normal 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
|
||||
87
security/nss/lib/freebl/arcfive.c
Normal file
87
security/nss/lib/freebl/arcfive.c
Normal 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;
|
||||
}
|
||||
88
security/nss/lib/freebl/arcfour-amd64-gas.s
Normal file
88
security/nss/lib/freebl/arcfour-amd64-gas.s
Normal 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
|
||||
107
security/nss/lib/freebl/arcfour-amd64-masm.asm
Normal file
107
security/nss/lib/freebl/arcfour-amd64-masm.asm
Normal 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
|
||||
84
security/nss/lib/freebl/arcfour-amd64-sun.s
Normal file
84
security/nss/lib/freebl/arcfour-amd64-sun.s
Normal 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
|
||||
594
security/nss/lib/freebl/arcfour.c
Normal file
594
security/nss/lib/freebl/arcfour.c
Normal 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
|
||||
1625
security/nss/lib/freebl/blapi.h
Normal file
1625
security/nss/lib/freebl/blapi.h
Normal file
File diff suppressed because it is too large
Load diff
61
security/nss/lib/freebl/blapii.h
Normal file
61
security/nss/lib/freebl/blapii.h
Normal 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_ */
|
||||
414
security/nss/lib/freebl/blapit.h
Normal file
414
security/nss/lib/freebl/blapit.h
Normal 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_ */
|
||||
100
security/nss/lib/freebl/blname.c
Normal file
100
security/nss/lib/freebl/blname.c
Normal 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
|
||||
1896
security/nss/lib/freebl/camellia.c
Normal file
1896
security/nss/lib/freebl/camellia.c
Normal file
File diff suppressed because it is too large
Load diff
42
security/nss/lib/freebl/camellia.h
Normal file
42
security/nss/lib/freebl/camellia.h
Normal 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_ */
|
||||
119
security/nss/lib/freebl/chacha20.c
Normal file
119
security/nss/lib/freebl/chacha20.c
Normal 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];
|
||||
}
|
||||
}
|
||||
}
|
||||
26
security/nss/lib/freebl/chacha20.h
Normal file
26
security/nss/lib/freebl/chacha20.h
Normal 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_ */
|
||||
327
security/nss/lib/freebl/chacha20_vec.c
Normal file
327
security/nss/lib/freebl/chacha20_vec.c
Normal 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];
|
||||
}
|
||||
}
|
||||
}
|
||||
198
security/nss/lib/freebl/chacha20poly1305.c
Normal file
198
security/nss/lib/freebl/chacha20poly1305.c
Normal 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
|
||||
}
|
||||
15
security/nss/lib/freebl/chacha20poly1305.h
Normal file
15
security/nss/lib/freebl/chacha20poly1305.h
Normal 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_ */
|
||||
97
security/nss/lib/freebl/config.mk
Normal file
97
security/nss/lib/freebl/config.mk
Normal 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
|
||||
246
security/nss/lib/freebl/ctr.c
Normal file
246
security/nss/lib/freebl/ctr.c
Normal 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
|
||||
53
security/nss/lib/freebl/ctr.h
Normal file
53
security/nss/lib/freebl/ctr.h
Normal 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
|
||||
307
security/nss/lib/freebl/cts.c
Normal file
307
security/nss/lib/freebl/cts.c
Normal 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;
|
||||
}
|
||||
33
security/nss/lib/freebl/cts.h
Normal file
33
security/nss/lib/freebl/cts.h
Normal 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
|
||||
676
security/nss/lib/freebl/des.c
Normal file
676
security/nss/lib/freebl/des.c
Normal 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.
|
||||
*/
|
||||
43
security/nss/lib/freebl/des.h
Normal file
43
security/nss/lib/freebl/des.h
Normal 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
|
||||
256
security/nss/lib/freebl/desblapi.c
Normal file
256
security/nss/lib/freebl/desblapi.c
Normal 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;
|
||||
}
|
||||
67
security/nss/lib/freebl/det_rng.c
Normal file
67
security/nss/lib/freebl/det_rng.c
Normal 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;
|
||||
}
|
||||
12
security/nss/lib/freebl/det_rng.h
Normal file
12
security/nss/lib/freebl/det_rng.h
Normal 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_ */
|
||||
452
security/nss/lib/freebl/dh.c
Normal file
452
security/nss/lib/freebl/dh.c
Normal 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, ¶ms->prime));
|
||||
SECITEM_TO_MPINT(key->prime, &p);
|
||||
/* Set private key's g */
|
||||
CHECK_SEC_OK(SECITEM_CopyItem(arena, &key->base, ¶ms->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;
|
||||
}
|
||||
968
security/nss/lib/freebl/drbg.c
Normal file
968
security/nss/lib/freebl/drbg.c
Normal 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;
|
||||
}
|
||||
647
security/nss/lib/freebl/dsa.c
Normal file
647
security/nss/lib/freebl/dsa.c
Normal 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,
|
||||
¶ms->prime));
|
||||
CHECK_MPI_OK(SECITEM_CopyItem(arena, &key->params.subPrime,
|
||||
¶ms->subPrime));
|
||||
CHECK_MPI_OK(SECITEM_CopyItem(arena, &key->params.base, ¶ms->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, ¶ms->subPrime, &seed);
|
||||
if (rv == SECSuccess) {
|
||||
if (seed.len != PQG_GetLength(¶ms->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(¶ms->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
1159
security/nss/lib/freebl/ec.c
Normal file
File diff suppressed because it is too large
Load diff
21
security/nss/lib/freebl/ec.h
Normal file
21
security/nss/lib/freebl/ec.h
Normal 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_ */
|
||||
311
security/nss/lib/freebl/ecdecode.c
Normal file
311
security/nss/lib/freebl/ecdecode.c
Normal 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, ¶ms->fieldID.u.prime,
|
||||
curveParams->irr));
|
||||
} else {
|
||||
CHECK_OK(hexString2SECItem(params->arena, ¶ms->fieldID.u.poly,
|
||||
curveParams->irr));
|
||||
}
|
||||
CHECK_OK(hexString2SECItem(params->arena, ¶ms->curve.a,
|
||||
curveParams->curvea));
|
||||
CHECK_OK(hexString2SECItem(params->arena, ¶ms->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, ¶ms->base, genenc));
|
||||
CHECK_OK(hexString2SECItem(params->arena, ¶ms->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 */
|
||||
267
security/nss/lib/freebl/ecl/README
Normal file
267
security/nss/lib/freebl/ecl/README
Normal 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.
|
||||
390
security/nss/lib/freebl/ecl/curve25519_32.c
Normal file
390
security/nss/lib/freebl/ecl/curve25519_32.c
Normal 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;
|
||||
}
|
||||
514
security/nss/lib/freebl/ecl/curve25519_64.c
Normal file
514
security/nss/lib/freebl/ecl/curve25519_64.c
Normal 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;
|
||||
}
|
||||
68
security/nss/lib/freebl/ecl/ec_naf.c
Normal file
68
security/nss/lib/freebl/ecl/ec_naf.c
Normal 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;
|
||||
}
|
||||
123
security/nss/lib/freebl/ecl/ecl-curve.h
Normal file
123
security/nss/lib/freebl/ecl/ecl-curve.h
Normal 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
|
||||
167
security/nss/lib/freebl/ecl/ecl-exp.h
Normal file
167
security/nss/lib/freebl/ecl/ecl-exp.h
Normal 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_ */
|
||||
257
security/nss/lib/freebl/ecl/ecl-priv.h
Normal file
257
security/nss/lib/freebl/ecl/ecl-priv.h
Normal 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_ */
|
||||
301
security/nss/lib/freebl/ecl/ecl.c
Normal file
301
security/nss/lib/freebl/ecl/ecl.c
Normal 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);
|
||||
}
|
||||
60
security/nss/lib/freebl/ecl/ecl.h
Normal file
60
security/nss/lib/freebl/ecl/ecl.h
Normal 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_ */
|
||||
93
security/nss/lib/freebl/ecl/ecl_curve.c
Normal file
93
security/nss/lib/freebl/ecl/ecl_curve.c
Normal 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);
|
||||
}
|
||||
958
security/nss/lib/freebl/ecl/ecl_gf.c
Normal file
958
security/nss/lib/freebl/ecl/ecl_gf.c
Normal 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);
|
||||
}
|
||||
}
|
||||
305
security/nss/lib/freebl/ecl/ecl_mult.c
Normal file
305
security/nss/lib/freebl/ecl/ecl_mult.c
Normal 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;
|
||||
}
|
||||
106
security/nss/lib/freebl/ecl/ecp.h
Normal file
106
security/nss/lib/freebl/ecl/ecp.h
Normal 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_ */
|
||||
120
security/nss/lib/freebl/ecl/ecp_25519.c
Normal file
120
security/nss/lib/freebl/ecl/ecp_25519.c
Normal 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);
|
||||
}
|
||||
401
security/nss/lib/freebl/ecl/ecp_256.c
Normal file
401
security/nss/lib/freebl/ecl/ecp_256.c
Normal 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;
|
||||
}
|
||||
1535
security/nss/lib/freebl/ecl/ecp_256_32.c
Normal file
1535
security/nss/lib/freebl/ecl/ecp_256_32.c
Normal file
File diff suppressed because it is too large
Load diff
258
security/nss/lib/freebl/ecl/ecp_384.c
Normal file
258
security/nss/lib/freebl/ecl/ecp_384.c
Normal 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;
|
||||
}
|
||||
137
security/nss/lib/freebl/ecl/ecp_521.c
Normal file
137
security/nss/lib/freebl/ecl/ecp_521.c
Normal 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;
|
||||
}
|
||||
308
security/nss/lib/freebl/ecl/ecp_aff.c
Normal file
308
security/nss/lib/freebl/ecl/ecp_aff.c
Normal 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;
|
||||
}
|
||||
513
security/nss/lib/freebl/ecl/ecp_jac.c
Normal file
513
security/nss/lib/freebl/ecl/ecp_jac.c
Normal 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;
|
||||
}
|
||||
283
security/nss/lib/freebl/ecl/ecp_jm.c
Normal file
283
security/nss/lib/freebl/ecl/ecp_jm.c
Normal 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;
|
||||
}
|
||||
154
security/nss/lib/freebl/ecl/ecp_mont.c
Normal file
154
security/nss/lib/freebl/ecl/ecp_mont.c
Normal 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;
|
||||
}
|
||||
}
|
||||
121
security/nss/lib/freebl/ecl/tests/ec_naft.c
Normal file
121
security/nss/lib/freebl/ecl/tests/ec_naft.c
Normal 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;
|
||||
}
|
||||
409
security/nss/lib/freebl/ecl/tests/ecp_test.c
Normal file
409
security/nss/lib/freebl/ecl/tests/ecp_test.c
Normal 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;
|
||||
}
|
||||
87
security/nss/lib/freebl/ecl/uint128.c
Normal file
87
security/nss/lib/freebl/ecl/uint128.c
Normal 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;
|
||||
}
|
||||
35
security/nss/lib/freebl/ecl/uint128.h
Normal file
35
security/nss/lib/freebl/ecl/uint128.h
Normal 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
|
||||
48
security/nss/lib/freebl/exports.gyp
Normal file
48
security/nss/lib/freebl/exports.gyp
Normal 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'
|
||||
}
|
||||
}
|
||||
1715
security/nss/lib/freebl/fipsfreebl.c
Normal file
1715
security/nss/lib/freebl/fipsfreebl.c
Normal file
File diff suppressed because it is too large
Load diff
26
security/nss/lib/freebl/freebl.def
Normal file
26
security/nss/lib/freebl/freebl.def
Normal 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:
|
||||
;+ *;
|
||||
;+};
|
||||
408
security/nss/lib/freebl/freebl.gyp
Normal file
408
security/nss/lib/freebl/freebl.gyp
Normal 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',
|
||||
}
|
||||
}
|
||||
68
security/nss/lib/freebl/freebl.rc
Normal file
68
security/nss/lib/freebl/freebl.rc
Normal 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
|
||||
39
security/nss/lib/freebl/freebl_hash.def
Normal file
39
security/nss/lib/freebl/freebl_hash.def
Normal 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:
|
||||
;+ *;
|
||||
;+};
|
||||
34
security/nss/lib/freebl/freebl_hash_vector.def
Normal file
34
security/nss/lib/freebl/freebl_hash_vector.def
Normal 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:
|
||||
;+ *;
|
||||
;+};
|
||||
18
security/nss/lib/freebl/freeblver.c
Normal file
18
security/nss/lib/freebl/freeblver.c
Normal 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;
|
||||
860
security/nss/lib/freebl/gcm.c
Normal file
860
security/nss/lib/freebl/gcm.c
Normal 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);
|
||||
}
|
||||
31
security/nss/lib/freebl/gcm.h
Normal file
31
security/nss/lib/freebl/gcm.h
Normal 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
|
||||
167
security/nss/lib/freebl/genload.c
Normal file
167
security/nss/lib/freebl/genload.c
Normal 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;
|
||||
}
|
||||
335
security/nss/lib/freebl/hmacct.c
Normal file
335
security/nss/lib/freebl/hmacct.c
Normal 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 */);
|
||||
}
|
||||
38
security/nss/lib/freebl/hmacct.h
Normal file
38
security/nss/lib/freebl/hmacct.h
Normal 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
|
||||
971
security/nss/lib/freebl/intel-aes-x64-masm.asm
Normal file
971
security/nss/lib/freebl/intel-aes-x64-masm.asm
Normal 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
|
||||
949
security/nss/lib/freebl/intel-aes-x86-masm.asm
Normal file
949
security/nss/lib/freebl/intel-aes-x86-masm.asm
Normal 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
|
||||
143
security/nss/lib/freebl/intel-aes.h
Normal file
143
security/nss/lib/freebl/intel-aes.h
Normal 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)
|
||||
2514
security/nss/lib/freebl/intel-aes.s
Normal file
2514
security/nss/lib/freebl/intel-aes.s
Normal file
File diff suppressed because it is too large
Load diff
254
security/nss/lib/freebl/intel-gcm-wrap.c
Normal file
254
security/nss/lib/freebl/intel-gcm-wrap.c
Normal 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
|
||||
1295
security/nss/lib/freebl/intel-gcm-x64-masm.asm
Normal file
1295
security/nss/lib/freebl/intel-gcm-x64-masm.asm
Normal file
File diff suppressed because it is too large
Load diff
1209
security/nss/lib/freebl/intel-gcm-x86-masm.asm
Normal file
1209
security/nss/lib/freebl/intel-gcm-x86-masm.asm
Normal file
File diff suppressed because it is too large
Load diff
83
security/nss/lib/freebl/intel-gcm.h
Normal file
83
security/nss/lib/freebl/intel-gcm.h
Normal 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
|
||||
1340
security/nss/lib/freebl/intel-gcm.s
Normal file
1340
security/nss/lib/freebl/intel-gcm.s
Normal file
File diff suppressed because it is too large
Load diff
495
security/nss/lib/freebl/jpake.c
Normal file
495
security/nss/lib/freebl/jpake.c
Normal 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;
|
||||
}
|
||||
353
security/nss/lib/freebl/ldvector.c
Normal file
353
security/nss/lib/freebl/ldvector.c
Normal 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
|
||||
2126
security/nss/lib/freebl/loader.c
Normal file
2126
security/nss/lib/freebl/loader.c
Normal file
File diff suppressed because it is too large
Load diff
788
security/nss/lib/freebl/loader.h
Normal file
788
security/nss/lib/freebl/loader.h
Normal 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
|
||||
217
security/nss/lib/freebl/lowhash_vector.c
Normal file
217
security/nss/lib/freebl/lowhash_vector.c
Normal 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);
|
||||
}
|
||||
195
security/nss/lib/freebl/manifest.mn
Normal file
195
security/nss/lib/freebl/manifest.mn
Normal 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
|
||||
269
security/nss/lib/freebl/md2.c
Normal file
269
security/nss/lib/freebl/md2.c
Normal 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);
|
||||
}
|
||||
598
security/nss/lib/freebl/md5.c
Normal file
598
security/nss/lib/freebl/md5.c
Normal 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);
|
||||
}
|
||||
208
security/nss/lib/freebl/mknewpc2.c
Normal file
208
security/nss/lib/freebl/mknewpc2.c
Normal 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;
|
||||
}
|
||||
119
security/nss/lib/freebl/mksp.c
Normal file
119
security/nss/lib/freebl/mksp.c
Normal 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;
|
||||
}
|
||||
244
security/nss/lib/freebl/mpi/Makefile
Normal file
244
security/nss/lib/freebl/mpi/Makefile
Normal 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
|
||||
243
security/nss/lib/freebl/mpi/Makefile.os2
Normal file
243
security/nss/lib/freebl/mpi/Makefile.os2
Normal 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
|
||||
254
security/nss/lib/freebl/mpi/Makefile.win
Normal file
254
security/nss/lib/freebl/mpi/Makefile.win
Normal 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
|
||||
749
security/nss/lib/freebl/mpi/README
Normal file
749
security/nss/lib/freebl/mpi/README
Normal 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
|
||||
83
security/nss/lib/freebl/mpi/all-tests
Normal file
83
security/nss/lib/freebl/mpi/all-tests
Normal 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
Loading…
Add table
Add a link
Reference in a new issue