pax_global_header00006660000000000000000000000064136375134650014527gustar00rootroot0000000000000052 comment=3a83a4f4ed2302ff6e68ab569c88793b50c22d28 libsignal-protocol-c-2.3.3/000077500000000000000000000000001363751346500155575ustar00rootroot00000000000000libsignal-protocol-c-2.3.3/.gitattributes000066400000000000000000000003721363751346500204540ustar00rootroot00000000000000# Set default behaviour, in case users don't have core.autocrlf set. * text=auto # Explicitly declare text files we want to always be normalized and converted # to native line endings on checkout. *.txt text *.c text *.cpp text *.h text *.hpp text libsignal-protocol-c-2.3.3/.gitignore000066400000000000000000000002231363751346500175440ustar00rootroot00000000000000# Compiled source build/ *.o *.so *.so.* *.a # IDE-related files # OS generated files .DS_Store* Thumbs.db # Other *~ .* *.swp core *.log *.zip libsignal-protocol-c-2.3.3/CMakeLists.txt000066400000000000000000000060041363751346500203170ustar00rootroot00000000000000cmake_minimum_required(VERSION 2.8.4) set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_SOURCE_DIR}/CMakeModules/") project(signal-protocol-c) if(POLICY CMP0042) cmake_policy(SET CMP0042 NEW) endif() SET(SIGNAL_PROTOCOL_C_VERSION_MAJOR 2) SET(SIGNAL_PROTOCOL_C_VERSION_MINOR 3) SET(SIGNAL_PROTOCOL_C_VERSION_PATCH 3) SET(SIGNAL_PROTOCOL_C_VERSION ${SIGNAL_PROTOCOL_C_VERSION_MAJOR}.${SIGNAL_PROTOCOL_C_VERSION_MINOR}.${SIGNAL_PROTOCOL_C_VERSION_PATCH}) SET(LIB_SUFFIX "" CACHE STRING "Define suffix of directory name (32/64)") SET(BIN_INSTALL_DIR "${CMAKE_INSTALL_PREFIX}/bin" CACHE STRING "The directory the binaries are installed in") SET(LIB_INSTALL_DIR "${CMAKE_INSTALL_PREFIX}/lib${LIB_SUFFIX}" CACHE STRING "The directory the libraries are installed in") SET(INCLUDE_INSTALL_DIR "${CMAKE_INSTALL_PREFIX}/include" CACHE PATH "The directory the headers are installed in") SET(INSTALL_PKGCONFIG_DIR "${LIB_INSTALL_DIR}/pkgconfig" CACHE PATH "Installation directory for pkgconfig (.pc) files") INCLUDE(CheckSymbolExists) INCLUDE(CheckCCompilerFlag) INCLUDE(TestBigEndian) CHECK_SYMBOL_EXISTS(memset_s "string.h" HAVE_MEMSET_S) IF(CMAKE_SYSTEM_NAME MATCHES "Windows") CHECK_SYMBOL_EXISTS(SecureZeroMemory "Windows.h;WinBase.h" HAVE_SECUREZEROMEMORY) ENDIF(CMAKE_SYSTEM_NAME MATCHES "Windows") IF(BUILD_TESTING) enable_testing() ENDIF(BUILD_TESTING) IF(CMAKE_COMPILER_IS_GNUCC OR CMAKE_C_COMPILER_ID MATCHES "Clang") SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fmessage-length=0 -Wall -Wmissing-field-initializers -Wno-missing-braces -Wparentheses") ENDIF(CMAKE_COMPILER_IS_GNUCC OR CMAKE_C_COMPILER_ID MATCHES "Clang") IF(CMAKE_COMPILER_IS_GNUCC) CHECK_C_COMPILER_FLAG("-Wsign-conversion" GCC_WARN_SIGN_CONVERSION) SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wsign-compare") IF(GCC_WARN_SIGN_CONVERSION) SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wsign-conversion") ENDIF(GCC_WARN_SIGN_CONVERSION) ENDIF(CMAKE_COMPILER_IS_GNUCC) IF(CMAKE_C_COMPILER_ID MATCHES "Clang") SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wswitch -Wunused-variable -Wunused-value -Wshadow -Wint-conversion -Wpointer-sign -Wprotocol -Wshorten-64-to-32") ENDIF(CMAKE_C_COMPILER_ID MATCHES "Clang") IF(HAVE_MEMSET_S) SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -DHAVE_MEMSET_S=1") ENDIF(HAVE_MEMSET_S) TEST_BIG_ENDIAN(WORDS_BIGENDIAN) IF(WORDS_BIGENDIAN) ADD_DEFINITIONS(-DWORDS_BIGENDIAN) ENDIF(WORDS_BIGENDIAN) IF(COVERAGE) SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fprofile-arcs -ftest-coverage") SET(LINK_FLAGS "${LINK_FLAGS} -fprofile-arcs -ftest-coverage") add_custom_command(OUTPUT run_coverage COMMAND ctest COMMAND lcov -q --capture --directory src --output-file coverage.info.total COMMAND lcov -q --remove coverage.info.total 'vpool.*' 'ut*.h' '*.pb-c.*' 'protobuf-c/*' 'curve25519/*' --output-file coverage.info COMMAND genhtml -q coverage.info --output-directory coverage COMMENT Collecting and creating coverage information ) add_custom_target( coverage DEPENDS run_coverage ) ENDIF(COVERAGE) add_subdirectory(src) IF(BUILD_TESTING) add_subdirectory(tests) ENDIF(BUILD_TESTING) libsignal-protocol-c-2.3.3/CMakeModules/000077500000000000000000000000001363751346500200705ustar00rootroot00000000000000libsignal-protocol-c-2.3.3/CMakeModules/BlackBerry.toolchain.cmake000066400000000000000000000217321363751346500250760ustar00rootroot00000000000000# ------------------------------------------------------------------------------ # BlackBerry CMake toolchain file, for use with the BlackBerry 10 NDK # Requires cmake 2.6.3 or newer (2.8.3 or newer is recommended). # # Usage Linux: # $ source /absolute/path/to/the/bbndk/bbndk-env.sh # $ mkdir build # $ cd build # $ cmake .. -DCMAKE_TOOLCHAIN_FILE="../CMake/toolchain/blackberry.toolchain.cmake" -DTargetPlatform="BlackBerry" -DBLACKBERRY_ARCHITECTURE=arm -DOGRE_DEPENDENCIES_DIR="../BlackBerryDependencies" -DOGRE_BUILD_RENDERSYSTEM_GLES2=TRUE -DOGRE_STATIC=TRUE -DOGRE_BUILD_COMPONENT_PAGING=TRUE -DOGRE_BUILD_COMPONENT_TERRAIN=TRUE -DOGRE_BUILD_COMPONENT_RTSHADERSYSTEM=TRUE -DOGRE_BUILD_PLUGIN_BSP=FALSE -DOGRE_BUILD_PLUGIN_PCZ=FALSE -DOGRE_BUILD_RENDERSYSTEM_GLES=FALSE -DOGRE_BUILD_TESTS=FALSE -DOGRE_BUILD_TOOLS=FALSE -DCMAKE_VERBOSE_MAKEFILE=TRUE -G "Eclipse CDT4 - Unix Makefiles" # $ make -j8 # # Usage Mac: # Same as the steps on Linux # # Usage Windows: # > /absolute/path/to/the/bbndk/bbndk-env.bat # > mkdir build # > cd build # > cmake .. -DCMAKE_TOOLCHAIN_FILE="../CMake/toolchain/blackberry.toolchain.cmake" -DTargetPlatform="BlackBerry" -DBLACKBERRY_ARCHITECTURE=arm -DOGRE_DEPENDENCIES_DIR="../BlackBerryDependencies" -DOGRE_BUILD_RENDERSYSTEM_GLES2=TRUE -DOGRE_STATIC=TRUE -DOGRE_BUILD_COMPONENT_PAGING=TRUE -DOGRE_BUILD_COMPONENT_TERRAIN=TRUE -DOGRE_BUILD_COMPONENT_RTSHADERSYSTEM=TRUE -DOGRE_BUILD_PLUGIN_BSP=FALSE -DOGRE_BUILD_PLUGIN_PCZ=FALSE -DOGRE_BUILD_RENDERSYSTEM_GLES=FALSE -DOGRE_BUILD_TESTS=FALSE -DOGRE_BUILD_TOOLS=FALSE -DCMAKE_VERBOSE_MAKEFILE=TRUE -G "Eclipse CDT4 - Unix Makefiles" # > make -j8 # cmake_minimum_required( VERSION 2.6.3 ) if( DEFINED CMAKE_CROSSCOMPILING ) # Subsequent toolchain loading is not really needed return() endif() set( BLACKBERRY_TOOLCHAIN_ROOT "$ENV{QNX_HOST}" ) set( BLACKBERRY_TARGET_ROOT "$ENV{QNX_TARGET}" ) set( CMAKE_SYSTEM_NAME Linux ) set( CMAKE_SYSTEM_VERSION 1 ) # STL version: by default gnustl_static will be used set( BLACKBERRY_USE_STLPORT FALSE CACHE BOOL "Experimental: use stlport_static instead of gnustl_static") mark_as_advanced( BLACKBERRY_USE_STLPORT ) # Detect host platform set( TOOL_OS_SUFFIX "" ) if( CMAKE_HOST_APPLE ) set( BLACKBERRY_NDK_HOST_SYSTEM_NAME "darwin-x86" ) elseif( CMAKE_HOST_WIN32 ) set( BLACKBERRY_NDK_HOST_SYSTEM_NAME "windows" ) set( TOOL_OS_SUFFIX ".exe" ) elseif( CMAKE_HOST_UNIX ) set(BLACKBERRY_NDK_HOST_SYSTEM_NAME "linux-x86" ) else() message( FATAL_ERROR "Cross-compilation on your platform is not supported by this cmake toolchain" ) endif() # Specify the cross compiler set( CMAKE_C_COMPILER "$ENV{QNX_HOST}/usr/bin/qcc${TOOL_OS_SUFFIX}" CACHE PATH "gcc" ) set( CMAKE_CXX_COMPILER "$ENV{QNX_HOST}/usr/bin/qcc${TOOL_OS_SUFFIX}" CACHE PATH "g++" ) set( CMAKE_ASM_COMPILER "$ENV{QNX_HOST}/usr/bin/qcc${TOOL_OS_SUFFIX}" CACHE PATH "Assembler" ) if( CMAKE_VERSION VERSION_LESS 2.8.5 ) set( CMAKE_ASM_COMPILER_ARG1 "-c" ) endif() # There may be a way to make cmake reduce these TODO if( BLACKBERRY_ARCHITECTURE STREQUAL "arm" ) set( NEUTRINO_ARCH "v7" ) else() set( NEUTRINO_ARCH "" ) endif() set( CMAKE_STRIP "$ENV{QNX_HOST}/usr/bin/nto${BLACKBERRY_ARCHITECTURE}-strip${TOOL_OS_SUFFIX}" CACHE PATH "strip" ) set( CMAKE_AR "$ENV{QNX_HOST}/usr/bin/nto${BLACKBERRY_ARCHITECTURE}-ar${TOOL_OS_SUFFIX}" CACHE PATH "archive" ) set( CMAKE_LINKER "$ENV{QNX_HOST}/usr/bin/nto${BLACKBERRY_ARCHITECTURE}${NEUTRINO_ARCH}-ld${TOOL_OS_SUFFIX}" CACHE PATH "linker" ) set( CMAKE_NM "$ENV{QNX_HOST}/usr/bin/nto${BLACKBERRY_ARCHITECTURE}${NEUTRINO_ARCH}-nm${TOOL_OS_SUFFIX}" CACHE PATH "nm" ) set( CMAKE_OBJCOPY "$ENV{QNX_HOST}/usr/bin/nto${BLACKBERRY_ARCHITECTURE}${NEUTRINO_ARCH}-objcopy${TOOL_OS_SUFFIX}" CACHE PATH "objcopy" ) set( CMAKE_OBJDUMP "$ENV{QNX_HOST}/usr/bin/nto${BLACKBERRY_ARCHITECTURE}${NEUTRINO_ARCH}-objdump${TOOL_OS_SUFFIX}" CACHE PATH "objdump" ) set( CMAKE_RANLIB "$ENV{QNX_HOST}/usr/bin/nto${BLACKBERRY_ARCHITECTURE}-ranlib${TOOL_OS_SUFFIX}" CACHE PATH "ranlib" ) # Installer #if( APPLE ) # find_program( CMAKE_INSTALL_NAME_TOOL NAMES install_name_tool ) # if( NOT CMAKE_INSTALL_NAME_TOOL ) # message( FATAL_ERROR "Could not find install_name_tool, please check your #installation." ) # endif() # mark_as_advanced( CMAKE_INSTALL_NAME_TOOL ) # endif() # Setup output directories set( LIBRARY_OUTPUT_PATH_ROOT ${CMAKE_SOURCE_DIR} CACHE PATH "root for library output, set this to change where android libs are installed to" ) set( CMAKE_INSTALL_PREFIX "${BLACKBERRY_TOOLCHAIN_ROOT}/user" CACHE STRING "path for installing" ) if( EXISTS "${CMAKE_SOURCE_DIR}/jni/CMakeLists.txt" ) set( EXECUTABLE_OUTPUT_PATH "${LIBRARY_OUTPUT_PATH_ROOT}/bin/${ANDROID_NDK_ABI_NAME}" CACHE PATH "Output directory for applications" ) else() set( EXECUTABLE_OUTPUT_PATH "${LIBRARY_OUTPUT_PATH_ROOT}/bin" CACHE PATH "Output directory for applications" ) endif() # Includes list( APPEND BLACKBERRY_SYSTEM_INCLUDE_DIRS "${BLACKBERRY_TARGET_ROOT}/qnx6/usr/include" ) # Flags and preprocessor definitions if( BLACKBERRY_ARCHITECTURE STREQUAL "arm" ) set( BLACKBERRY_CC_FLAGS " -V4.6.3,gcc_ntoarmv7le -D__QNX__" ) set( BLACKBERRY_CXX_FLAGS " -V4.6.3,gcc_ntoarmv7le -Y_gpp -D__QNX__" ) else() set( BLACKBERRY_CC_FLAGS " -V4.6.3,gcc_ntox86 -D__QNX__" ) set( BLACKBERRY_CXX_FLAGS " -V4.6.3,gcc_ntox86 -Y_gpp -D__QNX__" ) endif() set( BLACKBERRY 1 ) # NDK flags set( CMAKE_CXX_FLAGS "${BLACKBERRY_CXX_FLAGS}" ) set( CMAKE_C_FLAGS "${BLACKBERRY_CC_FLAGS}" ) set( CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fexceptions" ) set( CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fexceptions" ) # Release and Debug flags if( BLACKBERRY_ARCHITECTURE STREQUAL "arm" ) set( CMAKE_CXX_FLAGS_RELEASE "-mthumb -O3" ) set( CMAKE_C_FLAGS_RELEASE "-mthumb -O3" ) set( CMAKE_CXX_FLAGS_DEBUG "-g -marm -Os -finline-limit=64" ) set( CMAKE_C_FLAGS_DEBUG "-g -marm -Os -finline-limit=64" ) else() set( CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -march=i486" ) set( CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -march=i486" ) endif() # Cache flags set( CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}" CACHE STRING "c++ flags" ) set( CMAKE_C_FLAGS "${CMAKE_C_FLAGS}" CACHE STRING "c flags" ) set( CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE}" CACHE STRING "c++ Release flags" ) set( CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE}" CACHE STRING "c Release flags" ) set( CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG}" CACHE STRING "c++ Debug flags" ) set( CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG}" CACHE STRING "c Debug flags" ) set( CMAKE_SHARED_LINKER_FLAGS "" CACHE STRING "linker flags" ) SET( CMAKE_SHARED_LIBRARY_LINK_CXX_FLAGS "" CACHE STRING "linker flags") SET( CMAKE_SHARED_LIBRARY_LINK_C_FLAGS "" CACHE STRING "linker flags") set( CMAKE_MODULE_LINKER_FLAGS "" CACHE STRING "linker flags" ) set( CMAKE_EXE_LINKER_FLAGS "-lstdc++ -lm -lEGL -lGLESv2 -lbps -lscreen" CACHE STRING "linker flags" ) # Finish flags set( BLACKBERRY_CXX_FLAGS "${BLACKBERRY_CXX_FLAGS}" CACHE INTERNAL "Extra BlackBerry compiler flags") set( BLACKBERRY_LINKER_FLAGS "${BLACKBERRY_LINKER_FLAGS}" CACHE INTERNAL "Extra BlackBerry linker flags") set( CMAKE_CXX_FLAGS "${BLACKBERRY_CXX_FLAGS} ${CMAKE_CXX_FLAGS}" ) set( CMAKE_C_FLAGS "${BLACKBERRY_CXX_FLAGS} ${CMAKE_C_FLAGS}" ) # Global flags for cmake client scripts to change behavior set( BLACKBERRY True ) # Find the Target environment set( CMAKE_FIND_ROOT_PATH "${CMAKE_SOURCE_DIR}" "${BLACKBERRY_TARGET_ROOT}" "${CMAKE_INSTALL_PREFIX}" "${CMAKE_INSTALL_PREFIX}/share" ) # Search for libraries and includes in the ndk toolchain set( CMAKE_FIND_ROOT_PATH_MODE_PROGRAM ONLY ) set( CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY ) set( CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY ) # Macro to find packages on the host OS macro( find_host_package ) set( CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER ) set( CMAKE_FIND_ROOT_PATH_MODE_LIBRARY NEVER ) set( CMAKE_FIND_ROOT_PATH_MODE_INCLUDE NEVER ) if( CMAKE_HOST_WIN32 ) SET( WIN32 1 ) SET( UNIX ) elseif( CMAKE_HOST_APPLE ) SET( APPLE 1 ) SET( UNIX ) endif() find_package( ${ARGN} ) SET( WIN32 ) SET( APPLE ) SET( UNIX 1 ) set( CMAKE_FIND_ROOT_PATH_MODE_PROGRAM ONLY ) set( CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY ) set( CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY ) endmacro() # Macro to find programs on the host OS macro( find_host_program ) set( CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER ) set( CMAKE_FIND_ROOT_PATH_MODE_LIBRARY NEVER ) set( CMAKE_FIND_ROOT_PATH_MODE_INCLUDE NEVER ) if( CMAKE_HOST_WIN32 ) SET( WIN32 1 ) SET( UNIX ) elseif( CMAKE_HOST_APPLE ) SET( APPLE 1 ) SET( UNIX ) endif() find_program( ${ARGN} ) SET( WIN32 ) SET( APPLE ) SET( UNIX 1 ) set( CMAKE_FIND_ROOT_PATH_MODE_PROGRAM ONLY ) set( CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY ) set( CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY ) endmacro() # We are doing cross compiling, reset the OS information of the Building system UNSET( APPLE ) UNSET( WIN32 ) UNSET( UNIX ) libsignal-protocol-c-2.3.3/CMakeModules/FindCheck.cmake000066400000000000000000000033211363751346500227070ustar00rootroot00000000000000# - Try to find the CHECK libraries # Once done this will define # # CHECK_FOUND - system has check # CHECK_INCLUDE_DIRS - the check include directory # CHECK_LIBRARIES - check library # # Copyright (c) 2007 Daniel Gollub # Copyright (c) 2007-2009 Bjoern Ricks # # Redistribution and use is allowed according to the terms of the New # BSD license. # For details see the accompanying COPYING-CMAKE-SCRIPTS file. INCLUDE( FindPkgConfig ) IF ( Check_FIND_REQUIRED ) SET( _pkgconfig_REQUIRED "REQUIRED" ) ELSE( Check_FIND_REQUIRED ) SET( _pkgconfig_REQUIRED "" ) ENDIF ( Check_FIND_REQUIRED ) IF ( CHECK_MIN_VERSION ) PKG_SEARCH_MODULE( CHECK ${_pkgconfig_REQUIRED} check>=${CHECK_MIN_VERSION} ) ELSE ( CHECK_MIN_VERSION ) PKG_SEARCH_MODULE( CHECK ${_pkgconfig_REQUIRED} check ) ENDIF ( CHECK_MIN_VERSION ) # Look for CHECK include dir and libraries IF( NOT CHECK_FOUND AND NOT PKG_CONFIG_FOUND ) FIND_PATH( CHECK_INCLUDE_DIRS check.h ) FIND_LIBRARY( CHECK_LIBRARIES NAMES check ) IF ( CHECK_INCLUDE_DIRS AND CHECK_LIBRARIES ) SET( CHECK_FOUND 1 ) IF ( NOT Check_FIND_QUIETLY ) MESSAGE ( STATUS "Found CHECK: ${CHECK_LIBRARIES}" ) ENDIF ( NOT Check_FIND_QUIETLY ) ELSE ( CHECK_INCLUDE_DIRS AND CHECK_LIBRARIES ) IF ( Check_FIND_REQUIRED ) MESSAGE( FATAL_ERROR "Could NOT find CHECK" ) ELSE ( Check_FIND_REQUIRED ) IF ( NOT Check_FIND_QUIETLY ) MESSAGE( STATUS "Could NOT find CHECK" ) ENDIF ( NOT Check_FIND_QUIETLY ) ENDIF ( Check_FIND_REQUIRED ) ENDIF ( CHECK_INCLUDE_DIRS AND CHECK_LIBRARIES ) ENDIF( NOT CHECK_FOUND AND NOT PKG_CONFIG_FOUND ) # Hide advanced variables from CMake GUIs MARK_AS_ADVANCED( CHECK_INCLUDE_DIRS CHECK_LIBRARIES ) libsignal-protocol-c-2.3.3/CMakeModules/iOS.toolchain.cmake000066400000000000000000000210231363751346500235410ustar00rootroot00000000000000# This file is based off of the Platform/Darwin.cmake and Platform/UnixPaths.cmake # files which are included with CMake 2.8.4 # It has been altered for iOS development # Options: # # IOS_PLATFORM = OS (default) or SIMULATOR # This decides if SDKS will be selected from the iPhoneOS.platform or iPhoneSimulator.platform folders # OS - the default, used to build for iPhone and iPad physical devices, which have an arm arch. # SIMULATOR - used to build for the Simulator platforms, which have an x86 arch. # # CMAKE_IOS_DEVELOPER_ROOT = automatic(default) or /path/to/platform/Developer folder # By default this location is automatcially chosen based on the IOS_PLATFORM value above. # If set manually, it will override the default location and force the user of a particular Developer Platform # # CMAKE_IOS_SDK_ROOT = automatic(default) or /path/to/platform/Developer/SDKs/SDK folder # By default this location is automatcially chosen based on the CMAKE_IOS_DEVELOPER_ROOT value. # In this case it will always be the most up-to-date SDK found in the CMAKE_IOS_DEVELOPER_ROOT path. # If set manually, this will force the use of a specific SDK version # Macros: # # set_xcode_property (TARGET XCODE_PROPERTY XCODE_VALUE) # A convenience macro for setting xcode specific properties on targets # example: set_xcode_property (myioslib IPHONEOS_DEPLOYMENT_TARGET "3.1") # # find_host_package (PROGRAM ARGS) # A macro used to find executable programs on the host system, not within the iOS environment. # Thanks to the android-cmake project for providing the command # Standard settings set (CMAKE_SYSTEM_NAME Darwin) set (CMAKE_SYSTEM_VERSION 1) set (UNIX True) set (APPLE True) set (IOS True) # Required as of cmake 2.8.10 set (CMAKE_OSX_DEPLOYMENT_TARGET "" CACHE STRING "Force unset of the deployment target for iOS" FORCE) # Determine the cmake host system version so we know where to find the iOS SDKs find_program (CMAKE_UNAME uname /bin /usr/bin /usr/local/bin) if (CMAKE_UNAME) exec_program(uname ARGS -r OUTPUT_VARIABLE CMAKE_HOST_SYSTEM_VERSION) string (REGEX REPLACE "^([0-9]+)\\.([0-9]+).*$" "\\1" DARWIN_MAJOR_VERSION "${CMAKE_HOST_SYSTEM_VERSION}") endif (CMAKE_UNAME) # Force the compilers to clang for iOS include (CMakeForceCompiler) CMAKE_FORCE_C_COMPILER (/usr/bin/clang Apple) CMAKE_FORCE_CXX_COMPILER (/usr/bin/clang++ Apple) set(CMAKE_AR ar CACHE FILEPATH "" FORCE) # Skip the platform compiler checks for cross compiling set (CMAKE_CXX_COMPILER_WORKS TRUE) set (CMAKE_C_COMPILER_WORKS TRUE) # All iOS/Darwin specific settings - some may be redundant set (CMAKE_SHARED_LIBRARY_PREFIX "lib") set (CMAKE_SHARED_LIBRARY_SUFFIX ".dylib") set (CMAKE_SHARED_MODULE_PREFIX "lib") set (CMAKE_SHARED_MODULE_SUFFIX ".so") set (CMAKE_MODULE_EXISTS 1) set (CMAKE_DL_LIBS "") set (CMAKE_C_OSX_COMPATIBILITY_VERSION_FLAG "-compatibility_version ") set (CMAKE_C_OSX_CURRENT_VERSION_FLAG "-current_version ") set (CMAKE_CXX_OSX_COMPATIBILITY_VERSION_FLAG "${CMAKE_C_OSX_COMPATIBILITY_VERSION_FLAG}") set (CMAKE_CXX_OSX_CURRENT_VERSION_FLAG "${CMAKE_C_OSX_CURRENT_VERSION_FLAG}") # Hidden visibilty is required for cxx on iOS set (CMAKE_C_FLAGS_INIT "") set (CMAKE_CXX_FLAGS_INIT "-fvisibility=hidden -fvisibility-inlines-hidden -isysroot ${CMAKE_OSX_SYSROOT}") set (CMAKE_C_LINK_FLAGS "-Wl,-search_paths_first ${CMAKE_C_LINK_FLAGS}") set (CMAKE_CXX_LINK_FLAGS "-Wl,-search_paths_first ${CMAKE_CXX_LINK_FLAGS}") set (CMAKE_PLATFORM_HAS_INSTALLNAME 1) set (CMAKE_SHARED_LIBRARY_CREATE_C_FLAGS "-dynamiclib -headerpad_max_install_names") set (CMAKE_SHARED_MODULE_CREATE_C_FLAGS "-bundle -headerpad_max_install_names") set (CMAKE_SHARED_MODULE_LOADER_C_FLAG "-Wl,-bundle_loader,") set (CMAKE_SHARED_MODULE_LOADER_CXX_FLAG "-Wl,-bundle_loader,") set (CMAKE_FIND_LIBRARY_SUFFIXES ".dylib" ".so" ".a") # hack: if a new cmake (which uses CMAKE_INSTALL_NAME_TOOL) runs on an old build tree # (where install_name_tool was hardcoded) and where CMAKE_INSTALL_NAME_TOOL isn't in the cache # and still cmake didn't fail in CMakeFindBinUtils.cmake (because it isn't rerun) # hardcode CMAKE_INSTALL_NAME_TOOL here to install_name_tool, so it behaves as it did before, Alex if (NOT DEFINED CMAKE_INSTALL_NAME_TOOL) find_program(CMAKE_INSTALL_NAME_TOOL install_name_tool) endif (NOT DEFINED CMAKE_INSTALL_NAME_TOOL) # Setup iOS platform unless specified manually with IOS_PLATFORM if (NOT DEFINED IOS_PLATFORM) set (IOS_PLATFORM "OS") endif (NOT DEFINED IOS_PLATFORM) set (IOS_PLATFORM ${IOS_PLATFORM} CACHE STRING "Type of iOS Platform") # Check the platform selection and setup for developer root if (${IOS_PLATFORM} STREQUAL "OS") set (IOS_PLATFORM_LOCATION "iPhoneOS.platform") # This causes the installers to properly locate the output libraries set (CMAKE_XCODE_EFFECTIVE_PLATFORMS "-iphoneos") elseif (${IOS_PLATFORM} STREQUAL "SIMULATOR") set (IOS_PLATFORM_LOCATION "iPhoneSimulator.platform") # This causes the installers to properly locate the output libraries set (CMAKE_XCODE_EFFECTIVE_PLATFORMS "-iphonesimulator") else (${IOS_PLATFORM} STREQUAL "OS") message (FATAL_ERROR "Unsupported IOS_PLATFORM value selected. Please choose OS or SIMULATOR") endif (${IOS_PLATFORM} STREQUAL "OS") # Setup iOS developer location unless specified manually with CMAKE_IOS_DEVELOPER_ROOT # Note Xcode 4.3 changed the installation location, choose the most recent one available set (XCODE_POST_43_ROOT "/Applications/Xcode.app/Contents/Developer/Platforms/${IOS_PLATFORM_LOCATION}/Developer") set (XCODE_PRE_43_ROOT "/Developer/Platforms/${IOS_PLATFORM_LOCATION}/Developer") if (NOT DEFINED CMAKE_IOS_DEVELOPER_ROOT) if (EXISTS ${XCODE_POST_43_ROOT}) set (CMAKE_IOS_DEVELOPER_ROOT ${XCODE_POST_43_ROOT}) elseif(EXISTS ${XCODE_PRE_43_ROOT}) set (CMAKE_IOS_DEVELOPER_ROOT ${XCODE_PRE_43_ROOT}) endif (EXISTS ${XCODE_POST_43_ROOT}) endif (NOT DEFINED CMAKE_IOS_DEVELOPER_ROOT) set (CMAKE_IOS_DEVELOPER_ROOT ${CMAKE_IOS_DEVELOPER_ROOT} CACHE PATH "Location of iOS Platform") # Find and use the most recent iOS sdk unless specified manually with CMAKE_IOS_SDK_ROOT if (NOT DEFINED CMAKE_IOS_SDK_ROOT) file (GLOB _CMAKE_IOS_SDKS "${CMAKE_IOS_DEVELOPER_ROOT}/SDKs/*") if (_CMAKE_IOS_SDKS) list (SORT _CMAKE_IOS_SDKS) list (REVERSE _CMAKE_IOS_SDKS) list (GET _CMAKE_IOS_SDKS 0 CMAKE_IOS_SDK_ROOT) else (_CMAKE_IOS_SDKS) message (FATAL_ERROR "No iOS SDK's found in default search path ${CMAKE_IOS_DEVELOPER_ROOT}. Manually set CMAKE_IOS_SDK_ROOT or install the iOS SDK.") endif (_CMAKE_IOS_SDKS) message (STATUS "Toolchain using default iOS SDK: ${CMAKE_IOS_SDK_ROOT}") endif (NOT DEFINED CMAKE_IOS_SDK_ROOT) set (CMAKE_IOS_SDK_ROOT ${CMAKE_IOS_SDK_ROOT} CACHE PATH "Location of the selected iOS SDK") # Set the sysroot default to the most recent SDK set (CMAKE_OSX_SYSROOT ${CMAKE_IOS_SDK_ROOT} CACHE PATH "Sysroot used for iOS support") # set the architecture for iOS # NOTE: Currently both ARCHS_STANDARD_32_BIT and ARCHS_UNIVERSAL_IPHONE_OS set armv7 only, so set both manually if (${IOS_PLATFORM} STREQUAL "OS") set (IOS_ARCH armv6 armv7) else (${IOS_PLATFORM} STREQUAL "OS") set (IOS_ARCH i386) endif (${IOS_PLATFORM} STREQUAL "OS") set (CMAKE_OSX_ARCHITECTURES ${IOS_ARCH} CACHE string "Build architecture for iOS") # Set the find root to the iOS developer roots and to user defined paths set (CMAKE_FIND_ROOT_PATH ${CMAKE_IOS_DEVELOPER_ROOT} ${CMAKE_IOS_SDK_ROOT} ${CMAKE_PREFIX_PATH} CACHE string "iOS find search path root") # default to searching for frameworks first set (CMAKE_FIND_FRAMEWORK FIRST) # set up the default search directories for frameworks set (CMAKE_SYSTEM_FRAMEWORK_PATH ${CMAKE_IOS_SDK_ROOT}/System/Library/Frameworks ${CMAKE_IOS_SDK_ROOT}/System/Library/PrivateFrameworks ${CMAKE_IOS_SDK_ROOT}/Developer/Library/Frameworks ) # only search the iOS sdks, not the remainder of the host filesystem set (CMAKE_FIND_ROOT_PATH_MODE_PROGRAM ONLY) set (CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY) set (CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY) # This little macro lets you set any XCode specific property macro (set_xcode_property TARGET XCODE_PROPERTY XCODE_VALUE) set_property (TARGET ${TARGET} PROPERTY XCODE_ATTRIBUTE_${XCODE_PROPERTY} ${XCODE_VALUE}) endmacro (set_xcode_property) # This macro lets you find executable programs on the host system macro (find_host_package) set (CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER) set (CMAKE_FIND_ROOT_PATH_MODE_LIBRARY NEVER) set (CMAKE_FIND_ROOT_PATH_MODE_INCLUDE NEVER) set (IOS FALSE) find_package(${ARGN}) set (IOS TRUE) set (CMAKE_FIND_ROOT_PATH_MODE_PROGRAM ONLY) set (CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY) set (CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY) endmacro (find_host_package) libsignal-protocol-c-2.3.3/ISSUE_TEMPLATE.md000066400000000000000000000027541363751346500202740ustar00rootroot00000000000000 I have: - [ ] searched open and closed issues for duplicates ---------------------------------------- ### Bug description Describe here the issue that you are experiencing. ### Steps to reproduce - using hyphens as bullet points - list the steps - that reproduce the bug **Actual result:** Describe here what happens after you run the steps above (i.e. the buggy behaviour) **Expected result:** Describe here what should happen after you run the steps above (i.e. what would be the correct behaviour) ### Device info **Device:** Manufacturer Model XVI **Android version:** 0.0.0 **Signal version:** 0.0.0 ### Link to logs libsignal-protocol-c-2.3.3/LICENSE000066400000000000000000000773301363751346500165760ustar00rootroot00000000000000 GNU GENERAL PUBLIC LICENSE Version 3, 29 June 2007 Copyright (C) 2007 Free Software Foundation, Inc. Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble The GNU General Public License is a free, copyleft license for software and other kinds of works. The licenses for most software and other practical works are designed to take away your freedom to share and change the works. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change all versions of a program--to make sure it remains free software for all its users. We, the Free Software Foundation, use the GNU General Public License for most of our software; it applies also to any other work released this way by its authors. You can apply it to your programs, too. When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for them if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs, and that you know you can do these things. To protect your rights, we need to prevent others from denying you these rights or asking you to surrender the rights. Therefore, you have certain responsibilities if you distribute copies of the software, or if you modify it: responsibilities to respect the freedom of others. For example, if you distribute copies of such a program, whether gratis or for a fee, you must pass on to the recipients the same freedoms that you received. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights. Developers that use the GNU GPL protect your rights with two steps: (1) assert copyright on the software, and (2) offer you this License giving you legal permission to copy, distribute and/or modify it. For the developers' and authors' protection, the GPL clearly explains that there is no warranty for this free software. For both users' and authors' sake, the GPL requires that modified versions be marked as changed, so that their problems will not be attributed erroneously to authors of previous versions. Some devices are designed to deny users access to install or run modified versions of the software inside them, although the manufacturer can do so. This is fundamentally incompatible with the aim of protecting users' freedom to change the software. The systematic pattern of such abuse occurs in the area of products for individuals to use, which is precisely where it is most unacceptable. Therefore, we have designed this version of the GPL to prohibit the practice for those products. If such problems arise substantially in other domains, we stand ready to extend this provision to those domains in future versions of the GPL, as needed to protect the freedom of users. Finally, every program is threatened constantly by software patents. States should not allow patents to restrict development and use of software on general-purpose computers, but in those that do, we wish to avoid the special danger that patents applied to a free program could make it effectively proprietary. To prevent this, the GPL assures that patents cannot be used to render the program non-free. The precise terms and conditions for copying, distribution and modification follow. TERMS AND CONDITIONS 0. Definitions. "This License" refers to version 3 of the GNU General Public License. "Copyright" also means copyright-like laws that apply to other kinds of works, such as semiconductor masks. "The Program" refers to any copyrightable work licensed under this License. Each licensee is addressed as "you". "Licensees" and "recipients" may be individuals or organizations. To "modify" a work means to copy from or adapt all or part of the work in a fashion requiring copyright permission, other than the making of an exact copy. The resulting work is called a "modified version" of the earlier work or a work "based on" the earlier work. A "covered work" means either the unmodified Program or a work based on the Program. To "propagate" a work means to do anything with it that, without permission, would make you directly or secondarily liable for infringement under applicable copyright law, except executing it on a computer or modifying a private copy. Propagation includes copying, distribution (with or without modification), making available to the public, and in some countries other activities as well. To "convey" a work means any kind of propagation that enables other parties to make or receive copies. Mere interaction with a user through a computer network, with no transfer of a copy, is not conveying. An interactive user interface displays "Appropriate Legal Notices" to the extent that it includes a convenient and prominently visible feature that (1) displays an appropriate copyright notice, and (2) tells the user that there is no warranty for the work (except to the extent that warranties are provided), that licensees may convey the work under this License, and how to view a copy of this License. If the interface presents a list of user commands or options, such as a menu, a prominent item in the list meets this criterion. 1. Source Code. The "source code" for a work means the preferred form of the work for making modifications to it. "Object code" means any non-source form of a work. A "Standard Interface" means an interface that either is an official standard defined by a recognized standards body, or, in the case of interfaces specified for a particular programming language, one that is widely used among developers working in that language. The "System Libraries" of an executable work include anything, other than the work as a whole, that (a) is included in the normal form of packaging a Major Component, but which is not part of that Major Component, and (b) serves only to enable use of the work with that Major Component, or to implement a Standard Interface for which an implementation is available to the public in source code form. A "Major Component", in this context, means a major essential component (kernel, window system, and so on) of the specific operating system (if any) on which the executable work runs, or a compiler used to produce the work, or an object code interpreter used to run it. The "Corresponding Source" for a work in object code form means all the source code needed to generate, install, and (for an executable work) run the object code and to modify the work, including scripts to control those activities. However, it does not include the work's System Libraries, or general-purpose tools or generally available free programs which are used unmodified in performing those activities but which are not part of the work. For example, Corresponding Source includes interface definition files associated with source files for the work, and the source code for shared libraries and dynamically linked subprograms that the work is specifically designed to require, such as by intimate data communication or control flow between those subprograms and other parts of the work. The Corresponding Source need not include anything that users can regenerate automatically from other parts of the Corresponding Source. The Corresponding Source for a work in source code form is that same work. 2. Basic Permissions. All rights granted under this License are granted for the term of copyright on the Program, and are irrevocable provided the stated conditions are met. This License explicitly affirms your unlimited permission to run the unmodified Program. The output from running a covered work is covered by this License only if the output, given its content, constitutes a covered work. This License acknowledges your rights of fair use or other equivalent, as provided by copyright law. You may make, run and propagate covered works that you do not convey, without conditions so long as your license otherwise remains in force. You may convey covered works to others for the sole purpose of having them make modifications exclusively for you, or provide you with facilities for running those works, provided that you comply with the terms of this License in conveying all material for which you do not control copyright. Those thus making or running the covered works for you must do so exclusively on your behalf, under your direction and control, on terms that prohibit them from making any copies of your copyrighted material outside their relationship with you. Conveying under any other circumstances is permitted solely under the conditions stated below. Sublicensing is not allowed; section 10 makes it unnecessary. 3. Protecting Users' Legal Rights From Anti-Circumvention Law. No covered work shall be deemed part of an effective technological measure under any applicable law fulfilling obligations under article 11 of the WIPO copyright treaty adopted on 20 December 1996, or similar laws prohibiting or restricting circumvention of such measures. When you convey a covered work, you waive any legal power to forbid circumvention of technological measures to the extent such circumvention is effected by exercising rights under this License with respect to the covered work, and you disclaim any intention to limit operation or modification of the work as a means of enforcing, against the work's users, your or third parties' legal rights to forbid circumvention of technological measures. 4. Conveying Verbatim Copies. You may convey verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice; keep intact all notices stating that this License and any non-permissive terms added in accord with section 7 apply to the code; keep intact all notices of the absence of any warranty; and give all recipients a copy of this License along with the Program. You may charge any price or no price for each copy that you convey, and you may offer support or warranty protection for a fee. 5. Conveying Modified Source Versions. You may convey a work based on the Program, or the modifications to produce it from the Program, in the form of source code under the terms of section 4, provided that you also meet all of these conditions: a) The work must carry prominent notices stating that you modified it, and giving a relevant date. b) The work must carry prominent notices stating that it is released under this License and any conditions added under section 7. This requirement modifies the requirement in section 4 to "keep intact all notices". c) You must license the entire work, as a whole, under this License to anyone who comes into possession of a copy. This License will therefore apply, along with any applicable section 7 additional terms, to the whole of the work, and all its parts, regardless of how they are packaged. This License gives no permission to license the work in any other way, but it does not invalidate such permission if you have separately received it. d) If the work has interactive user interfaces, each must display Appropriate Legal Notices; however, if the Program has interactive interfaces that do not display Appropriate Legal Notices, your work need not make them do so. A compilation of a covered work with other separate and independent works, which are not by their nature extensions of the covered work, and which are not combined with it such as to form a larger program, in or on a volume of a storage or distribution medium, is called an "aggregate" if the compilation and its resulting copyright are not used to limit the access or legal rights of the compilation's users beyond what the individual works permit. Inclusion of a covered work in an aggregate does not cause this License to apply to the other parts of the aggregate. 6. Conveying Non-Source Forms. You may convey a covered work in object code form under the terms of sections 4 and 5, provided that you also convey the machine-readable Corresponding Source under the terms of this License, in one of these ways: a) Convey the object code in, or embodied in, a physical product (including a physical distribution medium), accompanied by the Corresponding Source fixed on a durable physical medium customarily used for software interchange. b) Convey the object code in, or embodied in, a physical product (including a physical distribution medium), accompanied by a written offer, valid for at least three years and valid for as long as you offer spare parts or customer support for that product model, to give anyone who possesses the object code either (1) a copy of the Corresponding Source for all the software in the product that is covered by this License, on a durable physical medium customarily used for software interchange, for a price no more than your reasonable cost of physically performing this conveying of source, or (2) access to copy the Corresponding Source from a network server at no charge. c) Convey individual copies of the object code with a copy of the written offer to provide the Corresponding Source. This alternative is allowed only occasionally and noncommercially, and only if you received the object code with such an offer, in accord with subsection 6b. d) Convey the object code by offering access from a designated place (gratis or for a charge), and offer equivalent access to the Corresponding Source in the same way through the same place at no further charge. You need not require recipients to copy the Corresponding Source along with the object code. If the place to copy the object code is a network server, the Corresponding Source may be on a different server (operated by you or a third party) that supports equivalent copying facilities, provided you maintain clear directions next to the object code saying where to find the Corresponding Source. Regardless of what server hosts the Corresponding Source, you remain obligated to ensure that it is available for as long as needed to satisfy these requirements. e) Convey the object code using peer-to-peer transmission, provided you inform other peers where the object code and Corresponding Source of the work are being offered to the general public at no charge under subsection 6d. A separable portion of the object code, whose source code is excluded from the Corresponding Source as a System Library, need not be included in conveying the object code work. A "User Product" is either (1) a "consumer product", which means any tangible personal property which is normally used for personal, family, or household purposes, or (2) anything designed or sold for incorporation into a dwelling. In determining whether a product is a consumer product, doubtful cases shall be resolved in favor of coverage. For a particular product received by a particular user, "normally used" refers to a typical or common use of that class of product, regardless of the status of the particular user or of the way in which the particular user actually uses, or expects or is expected to use, the product. A product is a consumer product regardless of whether the product has substantial commercial, industrial or non-consumer uses, unless such uses represent the only significant mode of use of the product. "Installation Information" for a User Product means any methods, procedures, authorization keys, or other information required to install and execute modified versions of a covered work in that User Product from a modified version of its Corresponding Source. The information must suffice to ensure that the continued functioning of the modified object code is in no case prevented or interfered with solely because modification has been made. If you convey an object code work under this section in, or with, or specifically for use in, a User Product, and the conveying occurs as part of a transaction in which the right of possession and use of the User Product is transferred to the recipient in perpetuity or for a fixed term (regardless of how the transaction is characterized), the Corresponding Source conveyed under this section must be accompanied by the Installation Information. But this requirement does not apply if neither you nor any third party retains the ability to install modified object code on the User Product (for example, the work has been installed in ROM). The requirement to provide Installation Information does not include a requirement to continue to provide support service, warranty, or updates for a work that has been modified or installed by the recipient, or for the User Product in which it has been modified or installed. Access to a network may be denied when the modification itself materially and adversely affects the operation of the network or violates the rules and protocols for communication across the network. Corresponding Source conveyed, and Installation Information provided, in accord with this section must be in a format that is publicly documented (and with an implementation available to the public in source code form), and must require no special password or key for unpacking, reading or copying. 7. Additional Terms. "Additional permissions" are terms that supplement the terms of this License by making exceptions from one or more of its conditions. Additional permissions that are applicable to the entire Program shall be treated as though they were included in this License, to the extent that they are valid under applicable law. If additional permissions apply only to part of the Program, that part may be used separately under those permissions, but the entire Program remains governed by this License without regard to the additional permissions. When you convey a copy of a covered work, you may at your option remove any additional permissions from that copy, or from any part of it. (Additional permissions may be written to require their own removal in certain cases when you modify the work.) You may place additional permissions on material, added by you to a covered work, for which you have or can give appropriate copyright permission. Notwithstanding any other provision of this License, for material you add to a covered work, you may (if authorized by the copyright holders of that material) supplement the terms of this License with terms: a) Disclaiming warranty or limiting liability differently from the terms of sections 15 and 16 of this License; or b) Requiring preservation of specified reasonable legal notices or author attributions in that material or in the Appropriate Legal Notices displayed by works containing it; or c) Prohibiting misrepresentation of the origin of that material, or requiring that modified versions of such material be marked in reasonable ways as different from the original version; or d) Limiting the use for publicity purposes of names of licensors or authors of the material; or e) Declining to grant rights under trademark law for use of some trade names, trademarks, or service marks; or f) Requiring indemnification of licensors and authors of that material by anyone who conveys the material (or modified versions of it) with contractual assumptions of liability to the recipient, for any liability that these contractual assumptions directly impose on those licensors and authors. All other non-permissive additional terms are considered "further restrictions" within the meaning of section 10. If the Program as you received it, or any part of it, contains a notice stating that it is governed by this License along with a term that is a further restriction, you may remove that term. If a license document contains a further restriction but permits relicensing or conveying under this License, you may add to a covered work material governed by the terms of that license document, provided that the further restriction does not survive such relicensing or conveying. If you add terms to a covered work in accord with this section, you must place, in the relevant source files, a statement of the additional terms that apply to those files, or a notice indicating where to find the applicable terms. Additional terms, permissive or non-permissive, may be stated in the form of a separately written license, or stated as exceptions; the above requirements apply either way. 8. Termination. You may not propagate or modify a covered work except as expressly provided under this License. Any attempt otherwise to propagate or modify it is void, and will automatically terminate your rights under this License (including any patent licenses granted under the third paragraph of section 11). However, if you cease all violation of this License, then your license from a particular copyright holder is reinstated (a) provisionally, unless and until the copyright holder explicitly and finally terminates your license, and (b) permanently, if the copyright holder fails to notify you of the violation by some reasonable means prior to 60 days after the cessation. Moreover, your license from a particular copyright holder is reinstated permanently if the copyright holder notifies you of the violation by some reasonable means, this is the first time you have received notice of violation of this License (for any work) from that copyright holder, and you cure the violation prior to 30 days after your receipt of the notice. Termination of your rights under this section does not terminate the licenses of parties who have received copies or rights from you under this License. If your rights have been terminated and not permanently reinstated, you do not qualify to receive new licenses for the same material under section 10. 9. Acceptance Not Required for Having Copies. You are not required to accept this License in order to receive or run a copy of the Program. Ancillary propagation of a covered work occurring solely as a consequence of using peer-to-peer transmission to receive a copy likewise does not require acceptance. However, nothing other than this License grants you permission to propagate or modify any covered work. These actions infringe copyright if you do not accept this License. Therefore, by modifying or propagating a covered work, you indicate your acceptance of this License to do so. 10. Automatic Licensing of Downstream Recipients. Each time you convey a covered work, the recipient automatically receives a license from the original licensors, to run, modify and propagate that work, subject to this License. You are not responsible for enforcing compliance by third parties with this License. An "entity transaction" is a transaction transferring control of an organization, or substantially all assets of one, or subdividing an organization, or merging organizations. If propagation of a covered work results from an entity transaction, each party to that transaction who receives a copy of the work also receives whatever licenses to the work the party's predecessor in interest had or could give under the previous paragraph, plus a right to possession of the Corresponding Source of the work from the predecessor in interest, if the predecessor has it or can get it with reasonable efforts. You may not impose any further restrictions on the exercise of the rights granted or affirmed under this License. For example, you may not impose a license fee, royalty, or other charge for exercise of rights granted under this License, and you may not initiate litigation (including a cross-claim or counterclaim in a lawsuit) alleging that any patent claim is infringed by making, using, selling, offering for sale, or importing the Program or any portion of it. 11. Patents. A "contributor" is a copyright holder who authorizes use under this License of the Program or a work on which the Program is based. The work thus licensed is called the contributor's "contributor version". A contributor's "essential patent claims" are all patent claims owned or controlled by the contributor, whether already acquired or hereafter acquired, that would be infringed by some manner, permitted by this License, of making, using, or selling its contributor version, but do not include claims that would be infringed only as a consequence of further modification of the contributor version. For purposes of this definition, "control" includes the right to grant patent sublicenses in a manner consistent with the requirements of this License. Each contributor grants you a non-exclusive, worldwide, royalty-free patent license under the contributor's essential patent claims, to make, use, sell, offer for sale, import and otherwise run, modify and propagate the contents of its contributor version. In the following three paragraphs, a "patent license" is any express agreement or commitment, however denominated, not to enforce a patent (such as an express permission to practice a patent or covenant not to sue for patent infringement). To "grant" such a patent license to a party means to make such an agreement or commitment not to enforce a patent against the party. If you convey a covered work, knowingly relying on a patent license, and the Corresponding Source of the work is not available for anyone to copy, free of charge and under the terms of this License, through a publicly available network server or other readily accessible means, then you must either (1) cause the Corresponding Source to be so available, or (2) arrange to deprive yourself of the benefit of the patent license for this particular work, or (3) arrange, in a manner consistent with the requirements of this License, to extend the patent license to downstream recipients. "Knowingly relying" means you have actual knowledge that, but for the patent license, your conveying the covered work in a country, or your recipient's use of the covered work in a country, would infringe one or more identifiable patents in that country that you have reason to believe are valid. If, pursuant to or in connection with a single transaction or arrangement, you convey, or propagate by procuring conveyance of, a covered work, and grant a patent license to some of the parties receiving the covered work authorizing them to use, propagate, modify or convey a specific copy of the covered work, then the patent license you grant is automatically extended to all recipients of the covered work and works based on it. A patent license is "discriminatory" if it does not include within the scope of its coverage, prohibits the exercise of, or is conditioned on the non-exercise of one or more of the rights that are specifically granted under this License. You may not convey a covered work if you are a party to an arrangement with a third party that is in the business of distributing software, under which you make payment to the third party based on the extent of your activity of conveying the work, and under which the third party grants, to any of the parties who would receive the covered work from you, a discriminatory patent license (a) in connection with copies of the covered work conveyed by you (or copies made from those copies), or (b) primarily for and in connection with specific products or compilations that contain the covered work, unless you entered into that arrangement, or that patent license was granted, prior to 28 March 2007. Nothing in this License shall be construed as excluding or limiting any implied license or other defenses to infringement that may otherwise be available to you under applicable patent law. 12. No Surrender of Others' Freedom. If conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot convey a covered work so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not convey it at all. For example, if you agree to terms that obligate you to collect a royalty for further conveying from those to whom you convey the Program, the only way you could satisfy both those terms and this License would be to refrain entirely from conveying the Program. 13. Use with the GNU Affero General Public License. Notwithstanding any other provision of this License, you have permission to link or combine any covered work with a work licensed under version 3 of the GNU Affero General Public License into a single combined work, and to convey the resulting work. The terms of this License will continue to apply to the part which is the covered work, but the special requirements of the GNU Affero General Public License, section 13, concerning interaction through a network will apply to the combination as such. 14. Revised Versions of this License. The Free Software Foundation may publish revised and/or new versions of the GNU General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Program specifies that a certain numbered version of the GNU General Public License "or any later version" applies to it, you have the option of following the terms and conditions either of that numbered version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of the GNU General Public License, you may choose any version ever published by the Free Software Foundation. If the Program specifies that a proxy can decide which future versions of the GNU General Public License can be used, that proxy's public statement of acceptance of a version permanently authorizes you to choose that version for the Program. Later license versions may give you additional or different permissions. However, no additional obligations are imposed on any author or copyright holder as a result of your choosing to follow a later version. 15. Disclaimer of Warranty. THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 16. Limitation of Liability. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. 17. Interpretation of Sections 15 and 16. If the disclaimer of warranty and limitation of liability provided above cannot be given local legal effect according to their terms, reviewing courts shall apply local law that most closely approximates an absolute waiver of all civil liability in connection with the Program, unless a warranty or assumption of liability accompanies a copy of the Program in return for a fee. END OF TERMS AND CONDITIONS libsignal-protocol-c-2.3.3/README.md000066400000000000000000000233651363751346500170470ustar00rootroot00000000000000# Overview This is a ratcheting forward secrecy protocol that works in synchronous and asynchronous messaging environments. See the [Java library](https://github.com/whispersystems/libsignal-protocol-java) for more details. # Building libsignal-protocol-c ## Development host setup ### Build dependencies * [CMake](https://cmake.org/) 2.8.4 or higher * [Check *1](https://libcheck.github.io/check/) * [OpenSSL *1](https://www.openssl.org/) 1.0 or higher * On MacOS X, [Common Crypto](https://developer.apple.com/library/content/documentation/Security/Conceptual/cryptoservices/GeneralPurposeCrypto/GeneralPurposeCrypto.html) is used instead of OpenSSL * [LCOV *2](http://ltp.sourceforge.net/coverage/lcov.php) Most of these dependencies are required just for the unit test suite and development of the library itself. When integrating into actual applications, you should not need anything beyond CMake. Alternatively, you may integrate the code using a build system of your choice. Items marked with *1 are required for tests, with *2 are additionally required for code coverage. ### Setting up a fresh source tree $ cd /path/to/libsignal-protocol-c $ mkdir build $ cd build $ cmake -DCMAKE_BUILD_TYPE=Debug .. $ make ### Running the unit tests $ cd /path/to/libsignal-protocol-c/build $ cmake -DCMAKE_BUILD_TYPE=Debug -DBUILD_TESTING=1 .. $ cd tests $ make $ cd .. $ ctest ### Creating the code coverage report $ cd /path/to/libsignal-protocol-c/build $ cmake -DCMAKE_BUILD_TYPE=Debug -DBUILD_TESTING=1 -DCOVERAGE=1 .. $ make coverage The generated code coverage report can be found in: `/path/to/libsignal-protocol-c/build/coverage` ### Eclipse project setup CMake provides a tutorial on Eclipse project setup here: https://cmake.org/Wiki/CMake:Eclipse_UNIX_Tutorial It is recommended to follow the more manual "Option 2," since the Eclipse project generator built into CMake tends to be outdated and leads you toward a very awkward and occasionally broken project configuration. ### Protocol Buffers compiler This project uses serialization code based on [Protocol Buffers](https://github.com/google/protobuf). Since the official library does not support C, the [protobuf-c](https://github.com/protobuf-c/protobuf-c) generator is used instead. For the sake of convenience, the generated code and its dependencies are included in the source tree. The generated code can be regenerated at any time by installing the two mentioned packages and running "make" in the "protobuf/" subdirectory. ## Target platforms CMake toolchain files have been included from the following sources: * [iOS](https://code.google.com/archive/p/ios-cmake) * [BlackBerry 10](https://github.com/blackberry/OGRE/blob/master/src/CMake/toolchain/blackberry.toolchain.cmake) # Using libsignal-protocol-c ## Library initialization Before using the library, a libsignal-protocol-c client needs to initialize a global context. This global context is used to provide callbacks for implementations of functions used across the library that need client-specific implementations. Refer to "signal_protocol.h" for detailed documentation on these functions, and the unit tests for example implementations. ```c signal_context *global_context; signal_context_create(&global_context, user_data); signal_context_set_crypto_provider(global_context, &provider); signal_context_set_locking_functions(global_context, lock_function, unlock_function); ``` ## Client install time At install time, a libsignal-protocol-c client needs to generate its identity keys, registration id, and prekeys. ```c ratchet_identity_key_pair *identity_key_pair; uint32_t registration_id; signal_protocol_key_helper_pre_key_list_node *pre_keys_head; session_signed_pre_key *signed_pre_key; signal_protocol_key_helper_generate_identity_key_pair(&identity_key_pair, global_context); signal_protocol_key_helper_generate_registration_id(®istration_id, 0, global_context); signal_protocol_key_helper_generate_pre_keys(&pre_keys_head, start_id, 100, global_context); signal_protocol_key_helper_generate_signed_pre_key(&signed_pre_key, identity_key_pair, 5, timestamp, global_context); /* Store identity_key_pair somewhere durable and safe. */ /* Store registration_id somewhere durable and safe. */ /* Store pre keys in the pre key store. */ /* Store signed pre key in the signed pre key store. */ ``` The above example is simplified for the sake of clarity. All of these functions return errors on failure, and those errors should be checked for in real usage. There are also iteration and serialization methods for the above types that should be used as appropriate. ## Building a session A libsignal-protocol-c client needs to implement four data store callback interfaces: `signal_protocol_identity_key_store`, `signal_protocol_pre_key_store`, `signal_protocol_signed_pre_key_store`, and `signal_protocol_session_store`. These will manage loading and storing of identity, prekeys, signed prekeys, and session state. These callback interfaces are designed such that implementations should treat all data flowing through them as opaque binary blobs. Anything necessary for referencing that data will be provided as separate function arguments to those callbacks. If it is ever necessary for clients to directly access stored data in terms of library data structures, they should use the accessor functions declared in "signal_protocol.h" for these data stores. Once the callbacks for these data stores are implemented, building a session is fairly straightforward: ```c /* Create the data store context, and add all the callbacks to it */ signal_protocol_store_context *store_context; signal_protocol_store_context_create(&store_context, context); signal_protocol_store_context_set_session_store(store_context, &session_store); signal_protocol_store_context_set_pre_key_store(store_context, &pre_key_store); signal_protocol_store_context_set_signed_pre_key_store(store_context, &signed_pre_key_store); signal_protocol_store_context_set_identity_key_store(store_context, &identity_key_store); /* Instantiate a session_builder for a recipient address. */ signal_protocol_address address = { "+14159998888", 12, 1 }; session_builder *builder; session_builder_create(&builder, store_context, &address, global_context); /* Build a session with a pre key retrieved from the server. */ session_builder_process_pre_key_bundle(builder, retrieved_pre_key); /* Create the session cipher and encrypt the message */ session_cipher *cipher; session_cipher_create(&cipher, store_context, &address, global_context); ciphertext_message *encrypted_message; session_cipher_encrypt(cipher, message, message_len, &encrypted_message); /* Get the serialized content and deliver it */ signal_buffer *serialized = ciphertext_message_get_serialized(encrypted_message); deliver(signal_buffer_data(serialized), signal_buffer_len(serialized)); /* Cleanup */ SIGNAL_UNREF(encrypted_message); session_cipher_free(cipher); session_builder_free(builder); signal_protocol_store_context_destroy(store_context); ``` The above example is simplified for the sake of clarity. All of these functions return errors on failure, and those errors should be checked for in real usage. ## Memory management notes For every custom data type that the libsignal-protocol-c library can allocate and return, a corresponding way of deallocating an instance of that data type is provided. The more basic and higher level data types provide a type-specific free or destroy function. These types include `signal_context`, `signal_protocol_store_context`, `signal_buffer`, `signal_buffer_list`, `signal_int_list`, `signal_protocol_key_helper_pre_key_list_node`, `session_builder`, `session_cipher`, `group_session_builder`, `group_cipher`, and `fingerprint_generator`. Most of the other data types, including everything internal, use a reference counting mechanism. If you are going to hold onto a reference to one of these types, use the `SIGNAL_REF(x)` macro to increment its count. If you are done with a reference, use `SIGNAL_UNREF(x)` to decrement its count. When the count reaches 0, the type's destructor function is called. # Legal things ## Cryptography Notice This distribution includes cryptographic software. The country in which you currently reside may have restrictions on the import, possession, use, and/or re-export to another country, of encryption software. BEFORE using any encryption software, please check your country's laws, regulations and policies concerning the import, possession, or use, and re-export of encryption software, to see if this is permitted. See for more information. The U.S. Government Department of Commerce, Bureau of Industry and Security (BIS), has classified this software as Export Commodity Control Number (ECCN) 5D002.C.1, which includes information security software using or performing cryptographic functions with asymmetric algorithms. The form and manner of this distribution makes it eligible for export under the License Exception ENC Technology Software Unrestricted (TSU) exception (see the BIS Export Administration Regulations, Section 740.13) for both object code and source code. ## License Copyright 2015-2016 Open Whisper Systems Licensed under the GPLv3: http://www.gnu.org/licenses/gpl-3.0.html Additional Permissions For Submission to Apple App Store: Provided that you are otherwise in compliance with the GPLv3 for each covered work you convey (including without limitation making the Corresponding Source available in compliance with Section 6 of the GPLv3), Open Whisper Systems also grants you the additional permission to convey through the Apple App Store non-source executable versions of the Program as incorporated into each applicable covered work as Executable Versions only under the Mozilla Public License version 2.0 (https://www.mozilla.org/en-US/MPL/2.0/). libsignal-protocol-c-2.3.3/protobuf/000077500000000000000000000000001363751346500174175ustar00rootroot00000000000000libsignal-protocol-c-2.3.3/protobuf/FingerprintProtocol.proto000066400000000000000000000006671363751346500245260ustar00rootroot00000000000000package textsecure; option java_package = "org.whispersystems.libsignal.fingerprint"; option java_outer_classname = "FingerprintProtos"; message LogicalFingerprint { optional bytes content = 1; optional bytes identifier = 2; // Version 0 } message CombinedFingerprints { optional uint32 version = 1; optional LogicalFingerprint localFingerprint = 2; optional LogicalFingerprint remoteFingerprint = 3; } libsignal-protocol-c-2.3.3/protobuf/LocalStorageProtocol.proto000066400000000000000000000061471363751346500246150ustar00rootroot00000000000000package textsecure; option java_package = "org.whispersystems.libsignal.state"; option java_outer_classname = "StorageProtos"; message SessionStructure { message Chain { optional bytes senderRatchetKey = 1; optional bytes senderRatchetKeyPrivate = 2; message ChainKey { optional uint32 index = 1; optional bytes key = 2; } optional ChainKey chainKey = 3; message MessageKey { optional uint32 index = 1; optional bytes cipherKey = 2; optional bytes macKey = 3; optional bytes iv = 4; } repeated MessageKey messageKeys = 4; } message PendingKeyExchange { optional uint32 sequence = 1; optional bytes localBaseKey = 2; optional bytes localBaseKeyPrivate = 3; optional bytes localRatchetKey = 4; optional bytes localRatchetKeyPrivate = 5; optional bytes localIdentityKey = 7; optional bytes localIdentityKeyPrivate = 8; } message PendingPreKey { optional uint32 preKeyId = 1; optional int32 signedPreKeyId = 3; optional bytes baseKey = 2; } optional uint32 sessionVersion = 1; optional bytes localIdentityPublic = 2; optional bytes remoteIdentityPublic = 3; optional bytes rootKey = 4; optional uint32 previousCounter = 5; optional Chain senderChain = 6; repeated Chain receiverChains = 7; optional PendingKeyExchange pendingKeyExchange = 8; optional PendingPreKey pendingPreKey = 9; optional uint32 remoteRegistrationId = 10; optional uint32 localRegistrationId = 11; optional bool needsRefresh = 12; optional bytes aliceBaseKey = 13; } message RecordStructure { optional SessionStructure currentSession = 1; repeated SessionStructure previousSessions = 2; } message PreKeyRecordStructure { optional uint32 id = 1; optional bytes publicKey = 2; optional bytes privateKey = 3; } message SignedPreKeyRecordStructure { optional uint32 id = 1; optional bytes publicKey = 2; optional bytes privateKey = 3; optional bytes signature = 4; optional fixed64 timestamp = 5; } message IdentityKeyPairStructure { optional bytes publicKey = 1; optional bytes privateKey = 2; } message SenderKeyStateStructure { message SenderChainKey { optional uint32 iteration = 1; optional bytes seed = 2; } message SenderMessageKey { optional uint32 iteration = 1; optional bytes seed = 2; } message SenderSigningKey { optional bytes public = 1; optional bytes private = 2; } optional uint32 senderKeyId = 1; optional SenderChainKey senderChainKey = 2; optional SenderSigningKey senderSigningKey = 3; repeated SenderMessageKey senderMessageKeys = 4; } message SenderKeyRecordStructure { repeated SenderKeyStateStructure senderKeyStates = 1; }libsignal-protocol-c-2.3.3/protobuf/Makefile000066400000000000000000000001571363751346500210620ustar00rootroot00000000000000 all: protoc-c --c_out=../src/ WhisperTextProtocol.proto LocalStorageProtocol.proto FingerprintProtocol.proto libsignal-protocol-c-2.3.3/protobuf/WhisperTextProtocol.proto000066400000000000000000000023321363751346500245140ustar00rootroot00000000000000package textsecure; option java_package = "org.whispersystems.libsignal.protocol"; option java_outer_classname = "SignalProtos"; message SignalMessage { optional bytes ratchetKey = 1; optional uint32 counter = 2; optional uint32 previousCounter = 3; optional bytes ciphertext = 4; } message PreKeySignalMessage { optional uint32 registrationId = 5; optional uint32 preKeyId = 1; optional uint32 signedPreKeyId = 6; optional bytes baseKey = 2; optional bytes identityKey = 3; optional bytes message = 4; // SignalMessage } message KeyExchangeMessage { optional uint32 id = 1; optional bytes baseKey = 2; optional bytes ratchetKey = 3; optional bytes identityKey = 4; optional bytes baseKeySignature = 5; } message SenderKeyMessage { optional uint32 id = 1; optional uint32 iteration = 2; optional bytes ciphertext = 3; } message SenderKeyDistributionMessage { optional uint32 id = 1; optional uint32 iteration = 2; optional bytes chainKey = 3; optional bytes signingKey = 4; } message DeviceConsistencyCodeMessage { optional uint32 generation = 1; optional bytes signature = 2; }libsignal-protocol-c-2.3.3/src/000077500000000000000000000000001363751346500163465ustar00rootroot00000000000000libsignal-protocol-c-2.3.3/src/CMakeLists.txt000066400000000000000000000042651363751346500211150ustar00rootroot00000000000000if(BUILD_SHARED_LIBS) find_library(M_LIB m) endif() include_directories( . curve25519/ed25519/nacl_includes curve25519/ed25519/additions curve25519/ed25519/sha512 curve25519/ed25519 curve25519 ) set(protobuf_SRCS LocalStorageProtocol.pb-c.c WhisperTextProtocol.pb-c.c FingerprintProtocol.pb-c.c ) set(signal_protocol_SRCS vpool.c vpool.h signal_protocol.c signal_protocol.h signal_protocol_types.h signal_protocol_internal.h curve.c curve.h hkdf.c hkdf.h ratchet.c ratchet.h protocol.c protocol.h session_state.c session_state.h session_record.c session_record.h session_pre_key.c session_pre_key.h session_builder.c session_builder.h session_builder_internal.h session_cipher.c session_cipher.h key_helper.c key_helper.h sender_key.c sender_key.h sender_key_state.c sender_key_state.h sender_key_record.c sender_key_record.h group_session_builder.c group_session_builder.h group_cipher.c group_cipher.h fingerprint.c fingerprint.h device_consistency.c device_consistency.h ) add_subdirectory(curve25519) add_subdirectory(protobuf-c) add_library(signal-protocol-c ${protobuf_SRCS} ${signal_protocol_SRCS} $ $ ) if(BUILD_SHARED_LIBS) target_link_libraries(signal-protocol-c ${M_LIB}) set_target_properties(signal-protocol-c PROPERTIES VERSION ${SIGNAL_PROTOCOL_C_VERSION} SOVERSION ${SIGNAL_PROTOCOL_C_VERSION_MAJOR} ) endif() INSTALL( FILES signal_protocol.h signal_protocol_types.h curve.h hkdf.h ratchet.h protocol.h session_state.h session_record.h session_pre_key.h session_builder.h session_cipher.h key_helper.h sender_key.h sender_key_state.h sender_key_record.h group_session_builder.h group_cipher.h fingerprint.h device_consistency.h DESTINATION ${INCLUDE_INSTALL_DIR}/signal ) INSTALL(TARGETS signal-protocol-c LIBRARY DESTINATION ${LIB_INSTALL_DIR} RUNTIME DESTINATION ${BIN_INSTALL_DIR} ARCHIVE DESTINATION ${LIB_INSTALL_DIR} ) configure_file( ${CMAKE_CURRENT_SOURCE_DIR}/libsignal-protocol-c.pc.in ${CMAKE_CURRENT_BINARY_DIR}/libsignal-protocol-c.pc @ONLY) INSTALL(FILES ${CMAKE_CURRENT_BINARY_DIR}/libsignal-protocol-c.pc DESTINATION "${INSTALL_PKGCONFIG_DIR}") libsignal-protocol-c-2.3.3/src/FingerprintProtocol.pb-c.c000066400000000000000000000170471363751346500233540ustar00rootroot00000000000000/* Generated by the protocol buffer compiler. DO NOT EDIT! */ /* Generated from: FingerprintProtocol.proto */ /* Do not generate deprecated warnings for self */ #ifndef PROTOBUF_C__NO_DEPRECATED #define PROTOBUF_C__NO_DEPRECATED #endif #include "FingerprintProtocol.pb-c.h" void textsecure__logical_fingerprint__init (Textsecure__LogicalFingerprint *message) { static Textsecure__LogicalFingerprint init_value = TEXTSECURE__LOGICAL_FINGERPRINT__INIT; *message = init_value; } size_t textsecure__logical_fingerprint__get_packed_size (const Textsecure__LogicalFingerprint *message) { assert(message->base.descriptor == &textsecure__logical_fingerprint__descriptor); return protobuf_c_message_get_packed_size ((const ProtobufCMessage*)(message)); } size_t textsecure__logical_fingerprint__pack (const Textsecure__LogicalFingerprint *message, uint8_t *out) { assert(message->base.descriptor == &textsecure__logical_fingerprint__descriptor); return protobuf_c_message_pack ((const ProtobufCMessage*)message, out); } size_t textsecure__logical_fingerprint__pack_to_buffer (const Textsecure__LogicalFingerprint *message, ProtobufCBuffer *buffer) { assert(message->base.descriptor == &textsecure__logical_fingerprint__descriptor); return protobuf_c_message_pack_to_buffer ((const ProtobufCMessage*)message, buffer); } Textsecure__LogicalFingerprint * textsecure__logical_fingerprint__unpack (ProtobufCAllocator *allocator, size_t len, const uint8_t *data) { return (Textsecure__LogicalFingerprint *) protobuf_c_message_unpack (&textsecure__logical_fingerprint__descriptor, allocator, len, data); } void textsecure__logical_fingerprint__free_unpacked (Textsecure__LogicalFingerprint *message, ProtobufCAllocator *allocator) { assert(message->base.descriptor == &textsecure__logical_fingerprint__descriptor); protobuf_c_message_free_unpacked ((ProtobufCMessage*)message, allocator); } void textsecure__combined_fingerprints__init (Textsecure__CombinedFingerprints *message) { static Textsecure__CombinedFingerprints init_value = TEXTSECURE__COMBINED_FINGERPRINTS__INIT; *message = init_value; } size_t textsecure__combined_fingerprints__get_packed_size (const Textsecure__CombinedFingerprints *message) { assert(message->base.descriptor == &textsecure__combined_fingerprints__descriptor); return protobuf_c_message_get_packed_size ((const ProtobufCMessage*)(message)); } size_t textsecure__combined_fingerprints__pack (const Textsecure__CombinedFingerprints *message, uint8_t *out) { assert(message->base.descriptor == &textsecure__combined_fingerprints__descriptor); return protobuf_c_message_pack ((const ProtobufCMessage*)message, out); } size_t textsecure__combined_fingerprints__pack_to_buffer (const Textsecure__CombinedFingerprints *message, ProtobufCBuffer *buffer) { assert(message->base.descriptor == &textsecure__combined_fingerprints__descriptor); return protobuf_c_message_pack_to_buffer ((const ProtobufCMessage*)message, buffer); } Textsecure__CombinedFingerprints * textsecure__combined_fingerprints__unpack (ProtobufCAllocator *allocator, size_t len, const uint8_t *data) { return (Textsecure__CombinedFingerprints *) protobuf_c_message_unpack (&textsecure__combined_fingerprints__descriptor, allocator, len, data); } void textsecure__combined_fingerprints__free_unpacked (Textsecure__CombinedFingerprints *message, ProtobufCAllocator *allocator) { assert(message->base.descriptor == &textsecure__combined_fingerprints__descriptor); protobuf_c_message_free_unpacked ((ProtobufCMessage*)message, allocator); } static const ProtobufCFieldDescriptor textsecure__logical_fingerprint__field_descriptors[2] = { { "content", 1, PROTOBUF_C_LABEL_OPTIONAL, PROTOBUF_C_TYPE_BYTES, offsetof(Textsecure__LogicalFingerprint, has_content), offsetof(Textsecure__LogicalFingerprint, content), NULL, NULL, 0, /* flags */ 0,NULL,NULL /* reserved1,reserved2, etc */ }, { "identifier", 2, PROTOBUF_C_LABEL_OPTIONAL, PROTOBUF_C_TYPE_BYTES, offsetof(Textsecure__LogicalFingerprint, has_identifier), offsetof(Textsecure__LogicalFingerprint, identifier), NULL, NULL, 0, /* flags */ 0,NULL,NULL /* reserved1,reserved2, etc */ }, }; static const unsigned textsecure__logical_fingerprint__field_indices_by_name[] = { 0, /* field[0] = content */ 1, /* field[1] = identifier */ }; static const ProtobufCIntRange textsecure__logical_fingerprint__number_ranges[1 + 1] = { { 1, 0 }, { 0, 2 } }; const ProtobufCMessageDescriptor textsecure__logical_fingerprint__descriptor = { PROTOBUF_C__MESSAGE_DESCRIPTOR_MAGIC, "textsecure.LogicalFingerprint", "LogicalFingerprint", "Textsecure__LogicalFingerprint", "textsecure", sizeof(Textsecure__LogicalFingerprint), 2, textsecure__logical_fingerprint__field_descriptors, textsecure__logical_fingerprint__field_indices_by_name, 1, textsecure__logical_fingerprint__number_ranges, (ProtobufCMessageInit) textsecure__logical_fingerprint__init, NULL,NULL,NULL /* reserved[123] */ }; static const ProtobufCFieldDescriptor textsecure__combined_fingerprints__field_descriptors[3] = { { "version", 1, PROTOBUF_C_LABEL_OPTIONAL, PROTOBUF_C_TYPE_UINT32, offsetof(Textsecure__CombinedFingerprints, has_version), offsetof(Textsecure__CombinedFingerprints, version), NULL, NULL, 0, /* flags */ 0,NULL,NULL /* reserved1,reserved2, etc */ }, { "localFingerprint", 2, PROTOBUF_C_LABEL_OPTIONAL, PROTOBUF_C_TYPE_MESSAGE, 0, /* quantifier_offset */ offsetof(Textsecure__CombinedFingerprints, localfingerprint), &textsecure__logical_fingerprint__descriptor, NULL, 0, /* flags */ 0,NULL,NULL /* reserved1,reserved2, etc */ }, { "remoteFingerprint", 3, PROTOBUF_C_LABEL_OPTIONAL, PROTOBUF_C_TYPE_MESSAGE, 0, /* quantifier_offset */ offsetof(Textsecure__CombinedFingerprints, remotefingerprint), &textsecure__logical_fingerprint__descriptor, NULL, 0, /* flags */ 0,NULL,NULL /* reserved1,reserved2, etc */ }, }; static const unsigned textsecure__combined_fingerprints__field_indices_by_name[] = { 1, /* field[1] = localFingerprint */ 2, /* field[2] = remoteFingerprint */ 0, /* field[0] = version */ }; static const ProtobufCIntRange textsecure__combined_fingerprints__number_ranges[1 + 1] = { { 1, 0 }, { 0, 3 } }; const ProtobufCMessageDescriptor textsecure__combined_fingerprints__descriptor = { PROTOBUF_C__MESSAGE_DESCRIPTOR_MAGIC, "textsecure.CombinedFingerprints", "CombinedFingerprints", "Textsecure__CombinedFingerprints", "textsecure", sizeof(Textsecure__CombinedFingerprints), 3, textsecure__combined_fingerprints__field_descriptors, textsecure__combined_fingerprints__field_indices_by_name, 1, textsecure__combined_fingerprints__number_ranges, (ProtobufCMessageInit) textsecure__combined_fingerprints__init, NULL,NULL,NULL /* reserved[123] */ }; libsignal-protocol-c-2.3.3/src/FingerprintProtocol.pb-c.h000066400000000000000000000105611363751346500233530ustar00rootroot00000000000000/* Generated by the protocol buffer compiler. DO NOT EDIT! */ /* Generated from: FingerprintProtocol.proto */ #ifndef PROTOBUF_C_FingerprintProtocol_2eproto__INCLUDED #define PROTOBUF_C_FingerprintProtocol_2eproto__INCLUDED #include PROTOBUF_C__BEGIN_DECLS #if PROTOBUF_C_VERSION_NUMBER < 1000000 # error This file was generated by a newer version of protoc-c which is incompatible with your libprotobuf-c headers. Please update your headers. #elif 1002001 < PROTOBUF_C_MIN_COMPILER_VERSION # error This file was generated by an older version of protoc-c which is incompatible with your libprotobuf-c headers. Please regenerate this file with a newer version of protoc-c. #endif typedef struct _Textsecure__LogicalFingerprint Textsecure__LogicalFingerprint; typedef struct _Textsecure__CombinedFingerprints Textsecure__CombinedFingerprints; /* --- enums --- */ /* --- messages --- */ struct _Textsecure__LogicalFingerprint { ProtobufCMessage base; protobuf_c_boolean has_content; ProtobufCBinaryData content; /* * Version 0 */ protobuf_c_boolean has_identifier; ProtobufCBinaryData identifier; }; #define TEXTSECURE__LOGICAL_FINGERPRINT__INIT \ { PROTOBUF_C_MESSAGE_INIT (&textsecure__logical_fingerprint__descriptor) \ , 0,{0,NULL}, 0,{0,NULL} } struct _Textsecure__CombinedFingerprints { ProtobufCMessage base; protobuf_c_boolean has_version; uint32_t version; Textsecure__LogicalFingerprint *localfingerprint; Textsecure__LogicalFingerprint *remotefingerprint; }; #define TEXTSECURE__COMBINED_FINGERPRINTS__INIT \ { PROTOBUF_C_MESSAGE_INIT (&textsecure__combined_fingerprints__descriptor) \ , 0,0, NULL, NULL } /* Textsecure__LogicalFingerprint methods */ void textsecure__logical_fingerprint__init (Textsecure__LogicalFingerprint *message); size_t textsecure__logical_fingerprint__get_packed_size (const Textsecure__LogicalFingerprint *message); size_t textsecure__logical_fingerprint__pack (const Textsecure__LogicalFingerprint *message, uint8_t *out); size_t textsecure__logical_fingerprint__pack_to_buffer (const Textsecure__LogicalFingerprint *message, ProtobufCBuffer *buffer); Textsecure__LogicalFingerprint * textsecure__logical_fingerprint__unpack (ProtobufCAllocator *allocator, size_t len, const uint8_t *data); void textsecure__logical_fingerprint__free_unpacked (Textsecure__LogicalFingerprint *message, ProtobufCAllocator *allocator); /* Textsecure__CombinedFingerprints methods */ void textsecure__combined_fingerprints__init (Textsecure__CombinedFingerprints *message); size_t textsecure__combined_fingerprints__get_packed_size (const Textsecure__CombinedFingerprints *message); size_t textsecure__combined_fingerprints__pack (const Textsecure__CombinedFingerprints *message, uint8_t *out); size_t textsecure__combined_fingerprints__pack_to_buffer (const Textsecure__CombinedFingerprints *message, ProtobufCBuffer *buffer); Textsecure__CombinedFingerprints * textsecure__combined_fingerprints__unpack (ProtobufCAllocator *allocator, size_t len, const uint8_t *data); void textsecure__combined_fingerprints__free_unpacked (Textsecure__CombinedFingerprints *message, ProtobufCAllocator *allocator); /* --- per-message closures --- */ typedef void (*Textsecure__LogicalFingerprint_Closure) (const Textsecure__LogicalFingerprint *message, void *closure_data); typedef void (*Textsecure__CombinedFingerprints_Closure) (const Textsecure__CombinedFingerprints *message, void *closure_data); /* --- services --- */ /* --- descriptors --- */ extern const ProtobufCMessageDescriptor textsecure__logical_fingerprint__descriptor; extern const ProtobufCMessageDescriptor textsecure__combined_fingerprints__descriptor; PROTOBUF_C__END_DECLS #endif /* PROTOBUF_C_FingerprintProtocol_2eproto__INCLUDED */ libsignal-protocol-c-2.3.3/src/LocalStorageProtocol.pb-c.c000066400000000000000000001473171363751346500234500ustar00rootroot00000000000000/* Generated by the protocol buffer compiler. DO NOT EDIT! */ /* Generated from: LocalStorageProtocol.proto */ /* Do not generate deprecated warnings for self */ #ifndef PROTOBUF_C__NO_DEPRECATED #define PROTOBUF_C__NO_DEPRECATED #endif #include "LocalStorageProtocol.pb-c.h" void textsecure__session_structure__chain__chain_key__init (Textsecure__SessionStructure__Chain__ChainKey *message) { static Textsecure__SessionStructure__Chain__ChainKey init_value = TEXTSECURE__SESSION_STRUCTURE__CHAIN__CHAIN_KEY__INIT; *message = init_value; } void textsecure__session_structure__chain__message_key__init (Textsecure__SessionStructure__Chain__MessageKey *message) { static Textsecure__SessionStructure__Chain__MessageKey init_value = TEXTSECURE__SESSION_STRUCTURE__CHAIN__MESSAGE_KEY__INIT; *message = init_value; } void textsecure__session_structure__chain__init (Textsecure__SessionStructure__Chain *message) { static Textsecure__SessionStructure__Chain init_value = TEXTSECURE__SESSION_STRUCTURE__CHAIN__INIT; *message = init_value; } void textsecure__session_structure__pending_key_exchange__init (Textsecure__SessionStructure__PendingKeyExchange *message) { static Textsecure__SessionStructure__PendingKeyExchange init_value = TEXTSECURE__SESSION_STRUCTURE__PENDING_KEY_EXCHANGE__INIT; *message = init_value; } void textsecure__session_structure__pending_pre_key__init (Textsecure__SessionStructure__PendingPreKey *message) { static Textsecure__SessionStructure__PendingPreKey init_value = TEXTSECURE__SESSION_STRUCTURE__PENDING_PRE_KEY__INIT; *message = init_value; } void textsecure__session_structure__init (Textsecure__SessionStructure *message) { static Textsecure__SessionStructure init_value = TEXTSECURE__SESSION_STRUCTURE__INIT; *message = init_value; } size_t textsecure__session_structure__get_packed_size (const Textsecure__SessionStructure *message) { assert(message->base.descriptor == &textsecure__session_structure__descriptor); return protobuf_c_message_get_packed_size ((const ProtobufCMessage*)(message)); } size_t textsecure__session_structure__pack (const Textsecure__SessionStructure *message, uint8_t *out) { assert(message->base.descriptor == &textsecure__session_structure__descriptor); return protobuf_c_message_pack ((const ProtobufCMessage*)message, out); } size_t textsecure__session_structure__pack_to_buffer (const Textsecure__SessionStructure *message, ProtobufCBuffer *buffer) { assert(message->base.descriptor == &textsecure__session_structure__descriptor); return protobuf_c_message_pack_to_buffer ((const ProtobufCMessage*)message, buffer); } Textsecure__SessionStructure * textsecure__session_structure__unpack (ProtobufCAllocator *allocator, size_t len, const uint8_t *data) { return (Textsecure__SessionStructure *) protobuf_c_message_unpack (&textsecure__session_structure__descriptor, allocator, len, data); } void textsecure__session_structure__free_unpacked (Textsecure__SessionStructure *message, ProtobufCAllocator *allocator) { assert(message->base.descriptor == &textsecure__session_structure__descriptor); protobuf_c_message_free_unpacked ((ProtobufCMessage*)message, allocator); } void textsecure__record_structure__init (Textsecure__RecordStructure *message) { static Textsecure__RecordStructure init_value = TEXTSECURE__RECORD_STRUCTURE__INIT; *message = init_value; } size_t textsecure__record_structure__get_packed_size (const Textsecure__RecordStructure *message) { assert(message->base.descriptor == &textsecure__record_structure__descriptor); return protobuf_c_message_get_packed_size ((const ProtobufCMessage*)(message)); } size_t textsecure__record_structure__pack (const Textsecure__RecordStructure *message, uint8_t *out) { assert(message->base.descriptor == &textsecure__record_structure__descriptor); return protobuf_c_message_pack ((const ProtobufCMessage*)message, out); } size_t textsecure__record_structure__pack_to_buffer (const Textsecure__RecordStructure *message, ProtobufCBuffer *buffer) { assert(message->base.descriptor == &textsecure__record_structure__descriptor); return protobuf_c_message_pack_to_buffer ((const ProtobufCMessage*)message, buffer); } Textsecure__RecordStructure * textsecure__record_structure__unpack (ProtobufCAllocator *allocator, size_t len, const uint8_t *data) { return (Textsecure__RecordStructure *) protobuf_c_message_unpack (&textsecure__record_structure__descriptor, allocator, len, data); } void textsecure__record_structure__free_unpacked (Textsecure__RecordStructure *message, ProtobufCAllocator *allocator) { assert(message->base.descriptor == &textsecure__record_structure__descriptor); protobuf_c_message_free_unpacked ((ProtobufCMessage*)message, allocator); } void textsecure__pre_key_record_structure__init (Textsecure__PreKeyRecordStructure *message) { static Textsecure__PreKeyRecordStructure init_value = TEXTSECURE__PRE_KEY_RECORD_STRUCTURE__INIT; *message = init_value; } size_t textsecure__pre_key_record_structure__get_packed_size (const Textsecure__PreKeyRecordStructure *message) { assert(message->base.descriptor == &textsecure__pre_key_record_structure__descriptor); return protobuf_c_message_get_packed_size ((const ProtobufCMessage*)(message)); } size_t textsecure__pre_key_record_structure__pack (const Textsecure__PreKeyRecordStructure *message, uint8_t *out) { assert(message->base.descriptor == &textsecure__pre_key_record_structure__descriptor); return protobuf_c_message_pack ((const ProtobufCMessage*)message, out); } size_t textsecure__pre_key_record_structure__pack_to_buffer (const Textsecure__PreKeyRecordStructure *message, ProtobufCBuffer *buffer) { assert(message->base.descriptor == &textsecure__pre_key_record_structure__descriptor); return protobuf_c_message_pack_to_buffer ((const ProtobufCMessage*)message, buffer); } Textsecure__PreKeyRecordStructure * textsecure__pre_key_record_structure__unpack (ProtobufCAllocator *allocator, size_t len, const uint8_t *data) { return (Textsecure__PreKeyRecordStructure *) protobuf_c_message_unpack (&textsecure__pre_key_record_structure__descriptor, allocator, len, data); } void textsecure__pre_key_record_structure__free_unpacked (Textsecure__PreKeyRecordStructure *message, ProtobufCAllocator *allocator) { assert(message->base.descriptor == &textsecure__pre_key_record_structure__descriptor); protobuf_c_message_free_unpacked ((ProtobufCMessage*)message, allocator); } void textsecure__signed_pre_key_record_structure__init (Textsecure__SignedPreKeyRecordStructure *message) { static Textsecure__SignedPreKeyRecordStructure init_value = TEXTSECURE__SIGNED_PRE_KEY_RECORD_STRUCTURE__INIT; *message = init_value; } size_t textsecure__signed_pre_key_record_structure__get_packed_size (const Textsecure__SignedPreKeyRecordStructure *message) { assert(message->base.descriptor == &textsecure__signed_pre_key_record_structure__descriptor); return protobuf_c_message_get_packed_size ((const ProtobufCMessage*)(message)); } size_t textsecure__signed_pre_key_record_structure__pack (const Textsecure__SignedPreKeyRecordStructure *message, uint8_t *out) { assert(message->base.descriptor == &textsecure__signed_pre_key_record_structure__descriptor); return protobuf_c_message_pack ((const ProtobufCMessage*)message, out); } size_t textsecure__signed_pre_key_record_structure__pack_to_buffer (const Textsecure__SignedPreKeyRecordStructure *message, ProtobufCBuffer *buffer) { assert(message->base.descriptor == &textsecure__signed_pre_key_record_structure__descriptor); return protobuf_c_message_pack_to_buffer ((const ProtobufCMessage*)message, buffer); } Textsecure__SignedPreKeyRecordStructure * textsecure__signed_pre_key_record_structure__unpack (ProtobufCAllocator *allocator, size_t len, const uint8_t *data) { return (Textsecure__SignedPreKeyRecordStructure *) protobuf_c_message_unpack (&textsecure__signed_pre_key_record_structure__descriptor, allocator, len, data); } void textsecure__signed_pre_key_record_structure__free_unpacked (Textsecure__SignedPreKeyRecordStructure *message, ProtobufCAllocator *allocator) { assert(message->base.descriptor == &textsecure__signed_pre_key_record_structure__descriptor); protobuf_c_message_free_unpacked ((ProtobufCMessage*)message, allocator); } void textsecure__identity_key_pair_structure__init (Textsecure__IdentityKeyPairStructure *message) { static Textsecure__IdentityKeyPairStructure init_value = TEXTSECURE__IDENTITY_KEY_PAIR_STRUCTURE__INIT; *message = init_value; } size_t textsecure__identity_key_pair_structure__get_packed_size (const Textsecure__IdentityKeyPairStructure *message) { assert(message->base.descriptor == &textsecure__identity_key_pair_structure__descriptor); return protobuf_c_message_get_packed_size ((const ProtobufCMessage*)(message)); } size_t textsecure__identity_key_pair_structure__pack (const Textsecure__IdentityKeyPairStructure *message, uint8_t *out) { assert(message->base.descriptor == &textsecure__identity_key_pair_structure__descriptor); return protobuf_c_message_pack ((const ProtobufCMessage*)message, out); } size_t textsecure__identity_key_pair_structure__pack_to_buffer (const Textsecure__IdentityKeyPairStructure *message, ProtobufCBuffer *buffer) { assert(message->base.descriptor == &textsecure__identity_key_pair_structure__descriptor); return protobuf_c_message_pack_to_buffer ((const ProtobufCMessage*)message, buffer); } Textsecure__IdentityKeyPairStructure * textsecure__identity_key_pair_structure__unpack (ProtobufCAllocator *allocator, size_t len, const uint8_t *data) { return (Textsecure__IdentityKeyPairStructure *) protobuf_c_message_unpack (&textsecure__identity_key_pair_structure__descriptor, allocator, len, data); } void textsecure__identity_key_pair_structure__free_unpacked (Textsecure__IdentityKeyPairStructure *message, ProtobufCAllocator *allocator) { assert(message->base.descriptor == &textsecure__identity_key_pair_structure__descriptor); protobuf_c_message_free_unpacked ((ProtobufCMessage*)message, allocator); } void textsecure__sender_key_state_structure__sender_chain_key__init (Textsecure__SenderKeyStateStructure__SenderChainKey *message) { static Textsecure__SenderKeyStateStructure__SenderChainKey init_value = TEXTSECURE__SENDER_KEY_STATE_STRUCTURE__SENDER_CHAIN_KEY__INIT; *message = init_value; } void textsecure__sender_key_state_structure__sender_message_key__init (Textsecure__SenderKeyStateStructure__SenderMessageKey *message) { static Textsecure__SenderKeyStateStructure__SenderMessageKey init_value = TEXTSECURE__SENDER_KEY_STATE_STRUCTURE__SENDER_MESSAGE_KEY__INIT; *message = init_value; } void textsecure__sender_key_state_structure__sender_signing_key__init (Textsecure__SenderKeyStateStructure__SenderSigningKey *message) { static Textsecure__SenderKeyStateStructure__SenderSigningKey init_value = TEXTSECURE__SENDER_KEY_STATE_STRUCTURE__SENDER_SIGNING_KEY__INIT; *message = init_value; } void textsecure__sender_key_state_structure__init (Textsecure__SenderKeyStateStructure *message) { static Textsecure__SenderKeyStateStructure init_value = TEXTSECURE__SENDER_KEY_STATE_STRUCTURE__INIT; *message = init_value; } size_t textsecure__sender_key_state_structure__get_packed_size (const Textsecure__SenderKeyStateStructure *message) { assert(message->base.descriptor == &textsecure__sender_key_state_structure__descriptor); return protobuf_c_message_get_packed_size ((const ProtobufCMessage*)(message)); } size_t textsecure__sender_key_state_structure__pack (const Textsecure__SenderKeyStateStructure *message, uint8_t *out) { assert(message->base.descriptor == &textsecure__sender_key_state_structure__descriptor); return protobuf_c_message_pack ((const ProtobufCMessage*)message, out); } size_t textsecure__sender_key_state_structure__pack_to_buffer (const Textsecure__SenderKeyStateStructure *message, ProtobufCBuffer *buffer) { assert(message->base.descriptor == &textsecure__sender_key_state_structure__descriptor); return protobuf_c_message_pack_to_buffer ((const ProtobufCMessage*)message, buffer); } Textsecure__SenderKeyStateStructure * textsecure__sender_key_state_structure__unpack (ProtobufCAllocator *allocator, size_t len, const uint8_t *data) { return (Textsecure__SenderKeyStateStructure *) protobuf_c_message_unpack (&textsecure__sender_key_state_structure__descriptor, allocator, len, data); } void textsecure__sender_key_state_structure__free_unpacked (Textsecure__SenderKeyStateStructure *message, ProtobufCAllocator *allocator) { assert(message->base.descriptor == &textsecure__sender_key_state_structure__descriptor); protobuf_c_message_free_unpacked ((ProtobufCMessage*)message, allocator); } void textsecure__sender_key_record_structure__init (Textsecure__SenderKeyRecordStructure *message) { static Textsecure__SenderKeyRecordStructure init_value = TEXTSECURE__SENDER_KEY_RECORD_STRUCTURE__INIT; *message = init_value; } size_t textsecure__sender_key_record_structure__get_packed_size (const Textsecure__SenderKeyRecordStructure *message) { assert(message->base.descriptor == &textsecure__sender_key_record_structure__descriptor); return protobuf_c_message_get_packed_size ((const ProtobufCMessage*)(message)); } size_t textsecure__sender_key_record_structure__pack (const Textsecure__SenderKeyRecordStructure *message, uint8_t *out) { assert(message->base.descriptor == &textsecure__sender_key_record_structure__descriptor); return protobuf_c_message_pack ((const ProtobufCMessage*)message, out); } size_t textsecure__sender_key_record_structure__pack_to_buffer (const Textsecure__SenderKeyRecordStructure *message, ProtobufCBuffer *buffer) { assert(message->base.descriptor == &textsecure__sender_key_record_structure__descriptor); return protobuf_c_message_pack_to_buffer ((const ProtobufCMessage*)message, buffer); } Textsecure__SenderKeyRecordStructure * textsecure__sender_key_record_structure__unpack (ProtobufCAllocator *allocator, size_t len, const uint8_t *data) { return (Textsecure__SenderKeyRecordStructure *) protobuf_c_message_unpack (&textsecure__sender_key_record_structure__descriptor, allocator, len, data); } void textsecure__sender_key_record_structure__free_unpacked (Textsecure__SenderKeyRecordStructure *message, ProtobufCAllocator *allocator) { assert(message->base.descriptor == &textsecure__sender_key_record_structure__descriptor); protobuf_c_message_free_unpacked ((ProtobufCMessage*)message, allocator); } static const ProtobufCFieldDescriptor textsecure__session_structure__chain__chain_key__field_descriptors[2] = { { "index", 1, PROTOBUF_C_LABEL_OPTIONAL, PROTOBUF_C_TYPE_UINT32, offsetof(Textsecure__SessionStructure__Chain__ChainKey, has_index), offsetof(Textsecure__SessionStructure__Chain__ChainKey, index), NULL, NULL, 0, /* flags */ 0,NULL,NULL /* reserved1,reserved2, etc */ }, { "key", 2, PROTOBUF_C_LABEL_OPTIONAL, PROTOBUF_C_TYPE_BYTES, offsetof(Textsecure__SessionStructure__Chain__ChainKey, has_key), offsetof(Textsecure__SessionStructure__Chain__ChainKey, key), NULL, NULL, 0, /* flags */ 0,NULL,NULL /* reserved1,reserved2, etc */ }, }; static const unsigned textsecure__session_structure__chain__chain_key__field_indices_by_name[] = { 0, /* field[0] = index */ 1, /* field[1] = key */ }; static const ProtobufCIntRange textsecure__session_structure__chain__chain_key__number_ranges[1 + 1] = { { 1, 0 }, { 0, 2 } }; const ProtobufCMessageDescriptor textsecure__session_structure__chain__chain_key__descriptor = { PROTOBUF_C__MESSAGE_DESCRIPTOR_MAGIC, "textsecure.SessionStructure.Chain.ChainKey", "ChainKey", "Textsecure__SessionStructure__Chain__ChainKey", "textsecure", sizeof(Textsecure__SessionStructure__Chain__ChainKey), 2, textsecure__session_structure__chain__chain_key__field_descriptors, textsecure__session_structure__chain__chain_key__field_indices_by_name, 1, textsecure__session_structure__chain__chain_key__number_ranges, (ProtobufCMessageInit) textsecure__session_structure__chain__chain_key__init, NULL,NULL,NULL /* reserved[123] */ }; static const ProtobufCFieldDescriptor textsecure__session_structure__chain__message_key__field_descriptors[4] = { { "index", 1, PROTOBUF_C_LABEL_OPTIONAL, PROTOBUF_C_TYPE_UINT32, offsetof(Textsecure__SessionStructure__Chain__MessageKey, has_index), offsetof(Textsecure__SessionStructure__Chain__MessageKey, index), NULL, NULL, 0, /* flags */ 0,NULL,NULL /* reserved1,reserved2, etc */ }, { "cipherKey", 2, PROTOBUF_C_LABEL_OPTIONAL, PROTOBUF_C_TYPE_BYTES, offsetof(Textsecure__SessionStructure__Chain__MessageKey, has_cipherkey), offsetof(Textsecure__SessionStructure__Chain__MessageKey, cipherkey), NULL, NULL, 0, /* flags */ 0,NULL,NULL /* reserved1,reserved2, etc */ }, { "macKey", 3, PROTOBUF_C_LABEL_OPTIONAL, PROTOBUF_C_TYPE_BYTES, offsetof(Textsecure__SessionStructure__Chain__MessageKey, has_mackey), offsetof(Textsecure__SessionStructure__Chain__MessageKey, mackey), NULL, NULL, 0, /* flags */ 0,NULL,NULL /* reserved1,reserved2, etc */ }, { "iv", 4, PROTOBUF_C_LABEL_OPTIONAL, PROTOBUF_C_TYPE_BYTES, offsetof(Textsecure__SessionStructure__Chain__MessageKey, has_iv), offsetof(Textsecure__SessionStructure__Chain__MessageKey, iv), NULL, NULL, 0, /* flags */ 0,NULL,NULL /* reserved1,reserved2, etc */ }, }; static const unsigned textsecure__session_structure__chain__message_key__field_indices_by_name[] = { 1, /* field[1] = cipherKey */ 0, /* field[0] = index */ 3, /* field[3] = iv */ 2, /* field[2] = macKey */ }; static const ProtobufCIntRange textsecure__session_structure__chain__message_key__number_ranges[1 + 1] = { { 1, 0 }, { 0, 4 } }; const ProtobufCMessageDescriptor textsecure__session_structure__chain__message_key__descriptor = { PROTOBUF_C__MESSAGE_DESCRIPTOR_MAGIC, "textsecure.SessionStructure.Chain.MessageKey", "MessageKey", "Textsecure__SessionStructure__Chain__MessageKey", "textsecure", sizeof(Textsecure__SessionStructure__Chain__MessageKey), 4, textsecure__session_structure__chain__message_key__field_descriptors, textsecure__session_structure__chain__message_key__field_indices_by_name, 1, textsecure__session_structure__chain__message_key__number_ranges, (ProtobufCMessageInit) textsecure__session_structure__chain__message_key__init, NULL,NULL,NULL /* reserved[123] */ }; static const ProtobufCFieldDescriptor textsecure__session_structure__chain__field_descriptors[4] = { { "senderRatchetKey", 1, PROTOBUF_C_LABEL_OPTIONAL, PROTOBUF_C_TYPE_BYTES, offsetof(Textsecure__SessionStructure__Chain, has_senderratchetkey), offsetof(Textsecure__SessionStructure__Chain, senderratchetkey), NULL, NULL, 0, /* flags */ 0,NULL,NULL /* reserved1,reserved2, etc */ }, { "senderRatchetKeyPrivate", 2, PROTOBUF_C_LABEL_OPTIONAL, PROTOBUF_C_TYPE_BYTES, offsetof(Textsecure__SessionStructure__Chain, has_senderratchetkeyprivate), offsetof(Textsecure__SessionStructure__Chain, senderratchetkeyprivate), NULL, NULL, 0, /* flags */ 0,NULL,NULL /* reserved1,reserved2, etc */ }, { "chainKey", 3, PROTOBUF_C_LABEL_OPTIONAL, PROTOBUF_C_TYPE_MESSAGE, 0, /* quantifier_offset */ offsetof(Textsecure__SessionStructure__Chain, chainkey), &textsecure__session_structure__chain__chain_key__descriptor, NULL, 0, /* flags */ 0,NULL,NULL /* reserved1,reserved2, etc */ }, { "messageKeys", 4, PROTOBUF_C_LABEL_REPEATED, PROTOBUF_C_TYPE_MESSAGE, offsetof(Textsecure__SessionStructure__Chain, n_messagekeys), offsetof(Textsecure__SessionStructure__Chain, messagekeys), &textsecure__session_structure__chain__message_key__descriptor, NULL, 0, /* flags */ 0,NULL,NULL /* reserved1,reserved2, etc */ }, }; static const unsigned textsecure__session_structure__chain__field_indices_by_name[] = { 2, /* field[2] = chainKey */ 3, /* field[3] = messageKeys */ 0, /* field[0] = senderRatchetKey */ 1, /* field[1] = senderRatchetKeyPrivate */ }; static const ProtobufCIntRange textsecure__session_structure__chain__number_ranges[1 + 1] = { { 1, 0 }, { 0, 4 } }; const ProtobufCMessageDescriptor textsecure__session_structure__chain__descriptor = { PROTOBUF_C__MESSAGE_DESCRIPTOR_MAGIC, "textsecure.SessionStructure.Chain", "Chain", "Textsecure__SessionStructure__Chain", "textsecure", sizeof(Textsecure__SessionStructure__Chain), 4, textsecure__session_structure__chain__field_descriptors, textsecure__session_structure__chain__field_indices_by_name, 1, textsecure__session_structure__chain__number_ranges, (ProtobufCMessageInit) textsecure__session_structure__chain__init, NULL,NULL,NULL /* reserved[123] */ }; static const ProtobufCFieldDescriptor textsecure__session_structure__pending_key_exchange__field_descriptors[7] = { { "sequence", 1, PROTOBUF_C_LABEL_OPTIONAL, PROTOBUF_C_TYPE_UINT32, offsetof(Textsecure__SessionStructure__PendingKeyExchange, has_sequence), offsetof(Textsecure__SessionStructure__PendingKeyExchange, sequence), NULL, NULL, 0, /* flags */ 0,NULL,NULL /* reserved1,reserved2, etc */ }, { "localBaseKey", 2, PROTOBUF_C_LABEL_OPTIONAL, PROTOBUF_C_TYPE_BYTES, offsetof(Textsecure__SessionStructure__PendingKeyExchange, has_localbasekey), offsetof(Textsecure__SessionStructure__PendingKeyExchange, localbasekey), NULL, NULL, 0, /* flags */ 0,NULL,NULL /* reserved1,reserved2, etc */ }, { "localBaseKeyPrivate", 3, PROTOBUF_C_LABEL_OPTIONAL, PROTOBUF_C_TYPE_BYTES, offsetof(Textsecure__SessionStructure__PendingKeyExchange, has_localbasekeyprivate), offsetof(Textsecure__SessionStructure__PendingKeyExchange, localbasekeyprivate), NULL, NULL, 0, /* flags */ 0,NULL,NULL /* reserved1,reserved2, etc */ }, { "localRatchetKey", 4, PROTOBUF_C_LABEL_OPTIONAL, PROTOBUF_C_TYPE_BYTES, offsetof(Textsecure__SessionStructure__PendingKeyExchange, has_localratchetkey), offsetof(Textsecure__SessionStructure__PendingKeyExchange, localratchetkey), NULL, NULL, 0, /* flags */ 0,NULL,NULL /* reserved1,reserved2, etc */ }, { "localRatchetKeyPrivate", 5, PROTOBUF_C_LABEL_OPTIONAL, PROTOBUF_C_TYPE_BYTES, offsetof(Textsecure__SessionStructure__PendingKeyExchange, has_localratchetkeyprivate), offsetof(Textsecure__SessionStructure__PendingKeyExchange, localratchetkeyprivate), NULL, NULL, 0, /* flags */ 0,NULL,NULL /* reserved1,reserved2, etc */ }, { "localIdentityKey", 7, PROTOBUF_C_LABEL_OPTIONAL, PROTOBUF_C_TYPE_BYTES, offsetof(Textsecure__SessionStructure__PendingKeyExchange, has_localidentitykey), offsetof(Textsecure__SessionStructure__PendingKeyExchange, localidentitykey), NULL, NULL, 0, /* flags */ 0,NULL,NULL /* reserved1,reserved2, etc */ }, { "localIdentityKeyPrivate", 8, PROTOBUF_C_LABEL_OPTIONAL, PROTOBUF_C_TYPE_BYTES, offsetof(Textsecure__SessionStructure__PendingKeyExchange, has_localidentitykeyprivate), offsetof(Textsecure__SessionStructure__PendingKeyExchange, localidentitykeyprivate), NULL, NULL, 0, /* flags */ 0,NULL,NULL /* reserved1,reserved2, etc */ }, }; static const unsigned textsecure__session_structure__pending_key_exchange__field_indices_by_name[] = { 1, /* field[1] = localBaseKey */ 2, /* field[2] = localBaseKeyPrivate */ 5, /* field[5] = localIdentityKey */ 6, /* field[6] = localIdentityKeyPrivate */ 3, /* field[3] = localRatchetKey */ 4, /* field[4] = localRatchetKeyPrivate */ 0, /* field[0] = sequence */ }; static const ProtobufCIntRange textsecure__session_structure__pending_key_exchange__number_ranges[2 + 1] = { { 1, 0 }, { 7, 5 }, { 0, 7 } }; const ProtobufCMessageDescriptor textsecure__session_structure__pending_key_exchange__descriptor = { PROTOBUF_C__MESSAGE_DESCRIPTOR_MAGIC, "textsecure.SessionStructure.PendingKeyExchange", "PendingKeyExchange", "Textsecure__SessionStructure__PendingKeyExchange", "textsecure", sizeof(Textsecure__SessionStructure__PendingKeyExchange), 7, textsecure__session_structure__pending_key_exchange__field_descriptors, textsecure__session_structure__pending_key_exchange__field_indices_by_name, 2, textsecure__session_structure__pending_key_exchange__number_ranges, (ProtobufCMessageInit) textsecure__session_structure__pending_key_exchange__init, NULL,NULL,NULL /* reserved[123] */ }; static const ProtobufCFieldDescriptor textsecure__session_structure__pending_pre_key__field_descriptors[3] = { { "preKeyId", 1, PROTOBUF_C_LABEL_OPTIONAL, PROTOBUF_C_TYPE_UINT32, offsetof(Textsecure__SessionStructure__PendingPreKey, has_prekeyid), offsetof(Textsecure__SessionStructure__PendingPreKey, prekeyid), NULL, NULL, 0, /* flags */ 0,NULL,NULL /* reserved1,reserved2, etc */ }, { "baseKey", 2, PROTOBUF_C_LABEL_OPTIONAL, PROTOBUF_C_TYPE_BYTES, offsetof(Textsecure__SessionStructure__PendingPreKey, has_basekey), offsetof(Textsecure__SessionStructure__PendingPreKey, basekey), NULL, NULL, 0, /* flags */ 0,NULL,NULL /* reserved1,reserved2, etc */ }, { "signedPreKeyId", 3, PROTOBUF_C_LABEL_OPTIONAL, PROTOBUF_C_TYPE_INT32, offsetof(Textsecure__SessionStructure__PendingPreKey, has_signedprekeyid), offsetof(Textsecure__SessionStructure__PendingPreKey, signedprekeyid), NULL, NULL, 0, /* flags */ 0,NULL,NULL /* reserved1,reserved2, etc */ }, }; static const unsigned textsecure__session_structure__pending_pre_key__field_indices_by_name[] = { 1, /* field[1] = baseKey */ 0, /* field[0] = preKeyId */ 2, /* field[2] = signedPreKeyId */ }; static const ProtobufCIntRange textsecure__session_structure__pending_pre_key__number_ranges[1 + 1] = { { 1, 0 }, { 0, 3 } }; const ProtobufCMessageDescriptor textsecure__session_structure__pending_pre_key__descriptor = { PROTOBUF_C__MESSAGE_DESCRIPTOR_MAGIC, "textsecure.SessionStructure.PendingPreKey", "PendingPreKey", "Textsecure__SessionStructure__PendingPreKey", "textsecure", sizeof(Textsecure__SessionStructure__PendingPreKey), 3, textsecure__session_structure__pending_pre_key__field_descriptors, textsecure__session_structure__pending_pre_key__field_indices_by_name, 1, textsecure__session_structure__pending_pre_key__number_ranges, (ProtobufCMessageInit) textsecure__session_structure__pending_pre_key__init, NULL,NULL,NULL /* reserved[123] */ }; static const ProtobufCFieldDescriptor textsecure__session_structure__field_descriptors[13] = { { "sessionVersion", 1, PROTOBUF_C_LABEL_OPTIONAL, PROTOBUF_C_TYPE_UINT32, offsetof(Textsecure__SessionStructure, has_sessionversion), offsetof(Textsecure__SessionStructure, sessionversion), NULL, NULL, 0, /* flags */ 0,NULL,NULL /* reserved1,reserved2, etc */ }, { "localIdentityPublic", 2, PROTOBUF_C_LABEL_OPTIONAL, PROTOBUF_C_TYPE_BYTES, offsetof(Textsecure__SessionStructure, has_localidentitypublic), offsetof(Textsecure__SessionStructure, localidentitypublic), NULL, NULL, 0, /* flags */ 0,NULL,NULL /* reserved1,reserved2, etc */ }, { "remoteIdentityPublic", 3, PROTOBUF_C_LABEL_OPTIONAL, PROTOBUF_C_TYPE_BYTES, offsetof(Textsecure__SessionStructure, has_remoteidentitypublic), offsetof(Textsecure__SessionStructure, remoteidentitypublic), NULL, NULL, 0, /* flags */ 0,NULL,NULL /* reserved1,reserved2, etc */ }, { "rootKey", 4, PROTOBUF_C_LABEL_OPTIONAL, PROTOBUF_C_TYPE_BYTES, offsetof(Textsecure__SessionStructure, has_rootkey), offsetof(Textsecure__SessionStructure, rootkey), NULL, NULL, 0, /* flags */ 0,NULL,NULL /* reserved1,reserved2, etc */ }, { "previousCounter", 5, PROTOBUF_C_LABEL_OPTIONAL, PROTOBUF_C_TYPE_UINT32, offsetof(Textsecure__SessionStructure, has_previouscounter), offsetof(Textsecure__SessionStructure, previouscounter), NULL, NULL, 0, /* flags */ 0,NULL,NULL /* reserved1,reserved2, etc */ }, { "senderChain", 6, PROTOBUF_C_LABEL_OPTIONAL, PROTOBUF_C_TYPE_MESSAGE, 0, /* quantifier_offset */ offsetof(Textsecure__SessionStructure, senderchain), &textsecure__session_structure__chain__descriptor, NULL, 0, /* flags */ 0,NULL,NULL /* reserved1,reserved2, etc */ }, { "receiverChains", 7, PROTOBUF_C_LABEL_REPEATED, PROTOBUF_C_TYPE_MESSAGE, offsetof(Textsecure__SessionStructure, n_receiverchains), offsetof(Textsecure__SessionStructure, receiverchains), &textsecure__session_structure__chain__descriptor, NULL, 0, /* flags */ 0,NULL,NULL /* reserved1,reserved2, etc */ }, { "pendingKeyExchange", 8, PROTOBUF_C_LABEL_OPTIONAL, PROTOBUF_C_TYPE_MESSAGE, 0, /* quantifier_offset */ offsetof(Textsecure__SessionStructure, pendingkeyexchange), &textsecure__session_structure__pending_key_exchange__descriptor, NULL, 0, /* flags */ 0,NULL,NULL /* reserved1,reserved2, etc */ }, { "pendingPreKey", 9, PROTOBUF_C_LABEL_OPTIONAL, PROTOBUF_C_TYPE_MESSAGE, 0, /* quantifier_offset */ offsetof(Textsecure__SessionStructure, pendingprekey), &textsecure__session_structure__pending_pre_key__descriptor, NULL, 0, /* flags */ 0,NULL,NULL /* reserved1,reserved2, etc */ }, { "remoteRegistrationId", 10, PROTOBUF_C_LABEL_OPTIONAL, PROTOBUF_C_TYPE_UINT32, offsetof(Textsecure__SessionStructure, has_remoteregistrationid), offsetof(Textsecure__SessionStructure, remoteregistrationid), NULL, NULL, 0, /* flags */ 0,NULL,NULL /* reserved1,reserved2, etc */ }, { "localRegistrationId", 11, PROTOBUF_C_LABEL_OPTIONAL, PROTOBUF_C_TYPE_UINT32, offsetof(Textsecure__SessionStructure, has_localregistrationid), offsetof(Textsecure__SessionStructure, localregistrationid), NULL, NULL, 0, /* flags */ 0,NULL,NULL /* reserved1,reserved2, etc */ }, { "needsRefresh", 12, PROTOBUF_C_LABEL_OPTIONAL, PROTOBUF_C_TYPE_BOOL, offsetof(Textsecure__SessionStructure, has_needsrefresh), offsetof(Textsecure__SessionStructure, needsrefresh), NULL, NULL, 0, /* flags */ 0,NULL,NULL /* reserved1,reserved2, etc */ }, { "aliceBaseKey", 13, PROTOBUF_C_LABEL_OPTIONAL, PROTOBUF_C_TYPE_BYTES, offsetof(Textsecure__SessionStructure, has_alicebasekey), offsetof(Textsecure__SessionStructure, alicebasekey), NULL, NULL, 0, /* flags */ 0,NULL,NULL /* reserved1,reserved2, etc */ }, }; static const unsigned textsecure__session_structure__field_indices_by_name[] = { 12, /* field[12] = aliceBaseKey */ 1, /* field[1] = localIdentityPublic */ 10, /* field[10] = localRegistrationId */ 11, /* field[11] = needsRefresh */ 7, /* field[7] = pendingKeyExchange */ 8, /* field[8] = pendingPreKey */ 4, /* field[4] = previousCounter */ 6, /* field[6] = receiverChains */ 2, /* field[2] = remoteIdentityPublic */ 9, /* field[9] = remoteRegistrationId */ 3, /* field[3] = rootKey */ 5, /* field[5] = senderChain */ 0, /* field[0] = sessionVersion */ }; static const ProtobufCIntRange textsecure__session_structure__number_ranges[1 + 1] = { { 1, 0 }, { 0, 13 } }; const ProtobufCMessageDescriptor textsecure__session_structure__descriptor = { PROTOBUF_C__MESSAGE_DESCRIPTOR_MAGIC, "textsecure.SessionStructure", "SessionStructure", "Textsecure__SessionStructure", "textsecure", sizeof(Textsecure__SessionStructure), 13, textsecure__session_structure__field_descriptors, textsecure__session_structure__field_indices_by_name, 1, textsecure__session_structure__number_ranges, (ProtobufCMessageInit) textsecure__session_structure__init, NULL,NULL,NULL /* reserved[123] */ }; static const ProtobufCFieldDescriptor textsecure__record_structure__field_descriptors[2] = { { "currentSession", 1, PROTOBUF_C_LABEL_OPTIONAL, PROTOBUF_C_TYPE_MESSAGE, 0, /* quantifier_offset */ offsetof(Textsecure__RecordStructure, currentsession), &textsecure__session_structure__descriptor, NULL, 0, /* flags */ 0,NULL,NULL /* reserved1,reserved2, etc */ }, { "previousSessions", 2, PROTOBUF_C_LABEL_REPEATED, PROTOBUF_C_TYPE_MESSAGE, offsetof(Textsecure__RecordStructure, n_previoussessions), offsetof(Textsecure__RecordStructure, previoussessions), &textsecure__session_structure__descriptor, NULL, 0, /* flags */ 0,NULL,NULL /* reserved1,reserved2, etc */ }, }; static const unsigned textsecure__record_structure__field_indices_by_name[] = { 0, /* field[0] = currentSession */ 1, /* field[1] = previousSessions */ }; static const ProtobufCIntRange textsecure__record_structure__number_ranges[1 + 1] = { { 1, 0 }, { 0, 2 } }; const ProtobufCMessageDescriptor textsecure__record_structure__descriptor = { PROTOBUF_C__MESSAGE_DESCRIPTOR_MAGIC, "textsecure.RecordStructure", "RecordStructure", "Textsecure__RecordStructure", "textsecure", sizeof(Textsecure__RecordStructure), 2, textsecure__record_structure__field_descriptors, textsecure__record_structure__field_indices_by_name, 1, textsecure__record_structure__number_ranges, (ProtobufCMessageInit) textsecure__record_structure__init, NULL,NULL,NULL /* reserved[123] */ }; static const ProtobufCFieldDescriptor textsecure__pre_key_record_structure__field_descriptors[3] = { { "id", 1, PROTOBUF_C_LABEL_OPTIONAL, PROTOBUF_C_TYPE_UINT32, offsetof(Textsecure__PreKeyRecordStructure, has_id), offsetof(Textsecure__PreKeyRecordStructure, id), NULL, NULL, 0, /* flags */ 0,NULL,NULL /* reserved1,reserved2, etc */ }, { "publicKey", 2, PROTOBUF_C_LABEL_OPTIONAL, PROTOBUF_C_TYPE_BYTES, offsetof(Textsecure__PreKeyRecordStructure, has_publickey), offsetof(Textsecure__PreKeyRecordStructure, publickey), NULL, NULL, 0, /* flags */ 0,NULL,NULL /* reserved1,reserved2, etc */ }, { "privateKey", 3, PROTOBUF_C_LABEL_OPTIONAL, PROTOBUF_C_TYPE_BYTES, offsetof(Textsecure__PreKeyRecordStructure, has_privatekey), offsetof(Textsecure__PreKeyRecordStructure, privatekey), NULL, NULL, 0, /* flags */ 0,NULL,NULL /* reserved1,reserved2, etc */ }, }; static const unsigned textsecure__pre_key_record_structure__field_indices_by_name[] = { 0, /* field[0] = id */ 2, /* field[2] = privateKey */ 1, /* field[1] = publicKey */ }; static const ProtobufCIntRange textsecure__pre_key_record_structure__number_ranges[1 + 1] = { { 1, 0 }, { 0, 3 } }; const ProtobufCMessageDescriptor textsecure__pre_key_record_structure__descriptor = { PROTOBUF_C__MESSAGE_DESCRIPTOR_MAGIC, "textsecure.PreKeyRecordStructure", "PreKeyRecordStructure", "Textsecure__PreKeyRecordStructure", "textsecure", sizeof(Textsecure__PreKeyRecordStructure), 3, textsecure__pre_key_record_structure__field_descriptors, textsecure__pre_key_record_structure__field_indices_by_name, 1, textsecure__pre_key_record_structure__number_ranges, (ProtobufCMessageInit) textsecure__pre_key_record_structure__init, NULL,NULL,NULL /* reserved[123] */ }; static const ProtobufCFieldDescriptor textsecure__signed_pre_key_record_structure__field_descriptors[5] = { { "id", 1, PROTOBUF_C_LABEL_OPTIONAL, PROTOBUF_C_TYPE_UINT32, offsetof(Textsecure__SignedPreKeyRecordStructure, has_id), offsetof(Textsecure__SignedPreKeyRecordStructure, id), NULL, NULL, 0, /* flags */ 0,NULL,NULL /* reserved1,reserved2, etc */ }, { "publicKey", 2, PROTOBUF_C_LABEL_OPTIONAL, PROTOBUF_C_TYPE_BYTES, offsetof(Textsecure__SignedPreKeyRecordStructure, has_publickey), offsetof(Textsecure__SignedPreKeyRecordStructure, publickey), NULL, NULL, 0, /* flags */ 0,NULL,NULL /* reserved1,reserved2, etc */ }, { "privateKey", 3, PROTOBUF_C_LABEL_OPTIONAL, PROTOBUF_C_TYPE_BYTES, offsetof(Textsecure__SignedPreKeyRecordStructure, has_privatekey), offsetof(Textsecure__SignedPreKeyRecordStructure, privatekey), NULL, NULL, 0, /* flags */ 0,NULL,NULL /* reserved1,reserved2, etc */ }, { "signature", 4, PROTOBUF_C_LABEL_OPTIONAL, PROTOBUF_C_TYPE_BYTES, offsetof(Textsecure__SignedPreKeyRecordStructure, has_signature), offsetof(Textsecure__SignedPreKeyRecordStructure, signature), NULL, NULL, 0, /* flags */ 0,NULL,NULL /* reserved1,reserved2, etc */ }, { "timestamp", 5, PROTOBUF_C_LABEL_OPTIONAL, PROTOBUF_C_TYPE_FIXED64, offsetof(Textsecure__SignedPreKeyRecordStructure, has_timestamp), offsetof(Textsecure__SignedPreKeyRecordStructure, timestamp), NULL, NULL, 0, /* flags */ 0,NULL,NULL /* reserved1,reserved2, etc */ }, }; static const unsigned textsecure__signed_pre_key_record_structure__field_indices_by_name[] = { 0, /* field[0] = id */ 2, /* field[2] = privateKey */ 1, /* field[1] = publicKey */ 3, /* field[3] = signature */ 4, /* field[4] = timestamp */ }; static const ProtobufCIntRange textsecure__signed_pre_key_record_structure__number_ranges[1 + 1] = { { 1, 0 }, { 0, 5 } }; const ProtobufCMessageDescriptor textsecure__signed_pre_key_record_structure__descriptor = { PROTOBUF_C__MESSAGE_DESCRIPTOR_MAGIC, "textsecure.SignedPreKeyRecordStructure", "SignedPreKeyRecordStructure", "Textsecure__SignedPreKeyRecordStructure", "textsecure", sizeof(Textsecure__SignedPreKeyRecordStructure), 5, textsecure__signed_pre_key_record_structure__field_descriptors, textsecure__signed_pre_key_record_structure__field_indices_by_name, 1, textsecure__signed_pre_key_record_structure__number_ranges, (ProtobufCMessageInit) textsecure__signed_pre_key_record_structure__init, NULL,NULL,NULL /* reserved[123] */ }; static const ProtobufCFieldDescriptor textsecure__identity_key_pair_structure__field_descriptors[2] = { { "publicKey", 1, PROTOBUF_C_LABEL_OPTIONAL, PROTOBUF_C_TYPE_BYTES, offsetof(Textsecure__IdentityKeyPairStructure, has_publickey), offsetof(Textsecure__IdentityKeyPairStructure, publickey), NULL, NULL, 0, /* flags */ 0,NULL,NULL /* reserved1,reserved2, etc */ }, { "privateKey", 2, PROTOBUF_C_LABEL_OPTIONAL, PROTOBUF_C_TYPE_BYTES, offsetof(Textsecure__IdentityKeyPairStructure, has_privatekey), offsetof(Textsecure__IdentityKeyPairStructure, privatekey), NULL, NULL, 0, /* flags */ 0,NULL,NULL /* reserved1,reserved2, etc */ }, }; static const unsigned textsecure__identity_key_pair_structure__field_indices_by_name[] = { 1, /* field[1] = privateKey */ 0, /* field[0] = publicKey */ }; static const ProtobufCIntRange textsecure__identity_key_pair_structure__number_ranges[1 + 1] = { { 1, 0 }, { 0, 2 } }; const ProtobufCMessageDescriptor textsecure__identity_key_pair_structure__descriptor = { PROTOBUF_C__MESSAGE_DESCRIPTOR_MAGIC, "textsecure.IdentityKeyPairStructure", "IdentityKeyPairStructure", "Textsecure__IdentityKeyPairStructure", "textsecure", sizeof(Textsecure__IdentityKeyPairStructure), 2, textsecure__identity_key_pair_structure__field_descriptors, textsecure__identity_key_pair_structure__field_indices_by_name, 1, textsecure__identity_key_pair_structure__number_ranges, (ProtobufCMessageInit) textsecure__identity_key_pair_structure__init, NULL,NULL,NULL /* reserved[123] */ }; static const ProtobufCFieldDescriptor textsecure__sender_key_state_structure__sender_chain_key__field_descriptors[2] = { { "iteration", 1, PROTOBUF_C_LABEL_OPTIONAL, PROTOBUF_C_TYPE_UINT32, offsetof(Textsecure__SenderKeyStateStructure__SenderChainKey, has_iteration), offsetof(Textsecure__SenderKeyStateStructure__SenderChainKey, iteration), NULL, NULL, 0, /* flags */ 0,NULL,NULL /* reserved1,reserved2, etc */ }, { "seed", 2, PROTOBUF_C_LABEL_OPTIONAL, PROTOBUF_C_TYPE_BYTES, offsetof(Textsecure__SenderKeyStateStructure__SenderChainKey, has_seed), offsetof(Textsecure__SenderKeyStateStructure__SenderChainKey, seed), NULL, NULL, 0, /* flags */ 0,NULL,NULL /* reserved1,reserved2, etc */ }, }; static const unsigned textsecure__sender_key_state_structure__sender_chain_key__field_indices_by_name[] = { 0, /* field[0] = iteration */ 1, /* field[1] = seed */ }; static const ProtobufCIntRange textsecure__sender_key_state_structure__sender_chain_key__number_ranges[1 + 1] = { { 1, 0 }, { 0, 2 } }; const ProtobufCMessageDescriptor textsecure__sender_key_state_structure__sender_chain_key__descriptor = { PROTOBUF_C__MESSAGE_DESCRIPTOR_MAGIC, "textsecure.SenderKeyStateStructure.SenderChainKey", "SenderChainKey", "Textsecure__SenderKeyStateStructure__SenderChainKey", "textsecure", sizeof(Textsecure__SenderKeyStateStructure__SenderChainKey), 2, textsecure__sender_key_state_structure__sender_chain_key__field_descriptors, textsecure__sender_key_state_structure__sender_chain_key__field_indices_by_name, 1, textsecure__sender_key_state_structure__sender_chain_key__number_ranges, (ProtobufCMessageInit) textsecure__sender_key_state_structure__sender_chain_key__init, NULL,NULL,NULL /* reserved[123] */ }; static const ProtobufCFieldDescriptor textsecure__sender_key_state_structure__sender_message_key__field_descriptors[2] = { { "iteration", 1, PROTOBUF_C_LABEL_OPTIONAL, PROTOBUF_C_TYPE_UINT32, offsetof(Textsecure__SenderKeyStateStructure__SenderMessageKey, has_iteration), offsetof(Textsecure__SenderKeyStateStructure__SenderMessageKey, iteration), NULL, NULL, 0, /* flags */ 0,NULL,NULL /* reserved1,reserved2, etc */ }, { "seed", 2, PROTOBUF_C_LABEL_OPTIONAL, PROTOBUF_C_TYPE_BYTES, offsetof(Textsecure__SenderKeyStateStructure__SenderMessageKey, has_seed), offsetof(Textsecure__SenderKeyStateStructure__SenderMessageKey, seed), NULL, NULL, 0, /* flags */ 0,NULL,NULL /* reserved1,reserved2, etc */ }, }; static const unsigned textsecure__sender_key_state_structure__sender_message_key__field_indices_by_name[] = { 0, /* field[0] = iteration */ 1, /* field[1] = seed */ }; static const ProtobufCIntRange textsecure__sender_key_state_structure__sender_message_key__number_ranges[1 + 1] = { { 1, 0 }, { 0, 2 } }; const ProtobufCMessageDescriptor textsecure__sender_key_state_structure__sender_message_key__descriptor = { PROTOBUF_C__MESSAGE_DESCRIPTOR_MAGIC, "textsecure.SenderKeyStateStructure.SenderMessageKey", "SenderMessageKey", "Textsecure__SenderKeyStateStructure__SenderMessageKey", "textsecure", sizeof(Textsecure__SenderKeyStateStructure__SenderMessageKey), 2, textsecure__sender_key_state_structure__sender_message_key__field_descriptors, textsecure__sender_key_state_structure__sender_message_key__field_indices_by_name, 1, textsecure__sender_key_state_structure__sender_message_key__number_ranges, (ProtobufCMessageInit) textsecure__sender_key_state_structure__sender_message_key__init, NULL,NULL,NULL /* reserved[123] */ }; static const ProtobufCFieldDescriptor textsecure__sender_key_state_structure__sender_signing_key__field_descriptors[2] = { { "public", 1, PROTOBUF_C_LABEL_OPTIONAL, PROTOBUF_C_TYPE_BYTES, offsetof(Textsecure__SenderKeyStateStructure__SenderSigningKey, has_public_), offsetof(Textsecure__SenderKeyStateStructure__SenderSigningKey, public_), NULL, NULL, 0, /* flags */ 0,NULL,NULL /* reserved1,reserved2, etc */ }, { "private", 2, PROTOBUF_C_LABEL_OPTIONAL, PROTOBUF_C_TYPE_BYTES, offsetof(Textsecure__SenderKeyStateStructure__SenderSigningKey, has_private_), offsetof(Textsecure__SenderKeyStateStructure__SenderSigningKey, private_), NULL, NULL, 0, /* flags */ 0,NULL,NULL /* reserved1,reserved2, etc */ }, }; static const unsigned textsecure__sender_key_state_structure__sender_signing_key__field_indices_by_name[] = { 1, /* field[1] = private */ 0, /* field[0] = public */ }; static const ProtobufCIntRange textsecure__sender_key_state_structure__sender_signing_key__number_ranges[1 + 1] = { { 1, 0 }, { 0, 2 } }; const ProtobufCMessageDescriptor textsecure__sender_key_state_structure__sender_signing_key__descriptor = { PROTOBUF_C__MESSAGE_DESCRIPTOR_MAGIC, "textsecure.SenderKeyStateStructure.SenderSigningKey", "SenderSigningKey", "Textsecure__SenderKeyStateStructure__SenderSigningKey", "textsecure", sizeof(Textsecure__SenderKeyStateStructure__SenderSigningKey), 2, textsecure__sender_key_state_structure__sender_signing_key__field_descriptors, textsecure__sender_key_state_structure__sender_signing_key__field_indices_by_name, 1, textsecure__sender_key_state_structure__sender_signing_key__number_ranges, (ProtobufCMessageInit) textsecure__sender_key_state_structure__sender_signing_key__init, NULL,NULL,NULL /* reserved[123] */ }; static const ProtobufCFieldDescriptor textsecure__sender_key_state_structure__field_descriptors[4] = { { "senderKeyId", 1, PROTOBUF_C_LABEL_OPTIONAL, PROTOBUF_C_TYPE_UINT32, offsetof(Textsecure__SenderKeyStateStructure, has_senderkeyid), offsetof(Textsecure__SenderKeyStateStructure, senderkeyid), NULL, NULL, 0, /* flags */ 0,NULL,NULL /* reserved1,reserved2, etc */ }, { "senderChainKey", 2, PROTOBUF_C_LABEL_OPTIONAL, PROTOBUF_C_TYPE_MESSAGE, 0, /* quantifier_offset */ offsetof(Textsecure__SenderKeyStateStructure, senderchainkey), &textsecure__sender_key_state_structure__sender_chain_key__descriptor, NULL, 0, /* flags */ 0,NULL,NULL /* reserved1,reserved2, etc */ }, { "senderSigningKey", 3, PROTOBUF_C_LABEL_OPTIONAL, PROTOBUF_C_TYPE_MESSAGE, 0, /* quantifier_offset */ offsetof(Textsecure__SenderKeyStateStructure, sendersigningkey), &textsecure__sender_key_state_structure__sender_signing_key__descriptor, NULL, 0, /* flags */ 0,NULL,NULL /* reserved1,reserved2, etc */ }, { "senderMessageKeys", 4, PROTOBUF_C_LABEL_REPEATED, PROTOBUF_C_TYPE_MESSAGE, offsetof(Textsecure__SenderKeyStateStructure, n_sendermessagekeys), offsetof(Textsecure__SenderKeyStateStructure, sendermessagekeys), &textsecure__sender_key_state_structure__sender_message_key__descriptor, NULL, 0, /* flags */ 0,NULL,NULL /* reserved1,reserved2, etc */ }, }; static const unsigned textsecure__sender_key_state_structure__field_indices_by_name[] = { 1, /* field[1] = senderChainKey */ 0, /* field[0] = senderKeyId */ 3, /* field[3] = senderMessageKeys */ 2, /* field[2] = senderSigningKey */ }; static const ProtobufCIntRange textsecure__sender_key_state_structure__number_ranges[1 + 1] = { { 1, 0 }, { 0, 4 } }; const ProtobufCMessageDescriptor textsecure__sender_key_state_structure__descriptor = { PROTOBUF_C__MESSAGE_DESCRIPTOR_MAGIC, "textsecure.SenderKeyStateStructure", "SenderKeyStateStructure", "Textsecure__SenderKeyStateStructure", "textsecure", sizeof(Textsecure__SenderKeyStateStructure), 4, textsecure__sender_key_state_structure__field_descriptors, textsecure__sender_key_state_structure__field_indices_by_name, 1, textsecure__sender_key_state_structure__number_ranges, (ProtobufCMessageInit) textsecure__sender_key_state_structure__init, NULL,NULL,NULL /* reserved[123] */ }; static const ProtobufCFieldDescriptor textsecure__sender_key_record_structure__field_descriptors[1] = { { "senderKeyStates", 1, PROTOBUF_C_LABEL_REPEATED, PROTOBUF_C_TYPE_MESSAGE, offsetof(Textsecure__SenderKeyRecordStructure, n_senderkeystates), offsetof(Textsecure__SenderKeyRecordStructure, senderkeystates), &textsecure__sender_key_state_structure__descriptor, NULL, 0, /* flags */ 0,NULL,NULL /* reserved1,reserved2, etc */ }, }; static const unsigned textsecure__sender_key_record_structure__field_indices_by_name[] = { 0, /* field[0] = senderKeyStates */ }; static const ProtobufCIntRange textsecure__sender_key_record_structure__number_ranges[1 + 1] = { { 1, 0 }, { 0, 1 } }; const ProtobufCMessageDescriptor textsecure__sender_key_record_structure__descriptor = { PROTOBUF_C__MESSAGE_DESCRIPTOR_MAGIC, "textsecure.SenderKeyRecordStructure", "SenderKeyRecordStructure", "Textsecure__SenderKeyRecordStructure", "textsecure", sizeof(Textsecure__SenderKeyRecordStructure), 1, textsecure__sender_key_record_structure__field_descriptors, textsecure__sender_key_record_structure__field_indices_by_name, 1, textsecure__sender_key_record_structure__number_ranges, (ProtobufCMessageInit) textsecure__sender_key_record_structure__init, NULL,NULL,NULL /* reserved[123] */ }; libsignal-protocol-c-2.3.3/src/LocalStorageProtocol.pb-c.h000066400000000000000000000566311363751346500234530ustar00rootroot00000000000000/* Generated by the protocol buffer compiler. DO NOT EDIT! */ /* Generated from: LocalStorageProtocol.proto */ #ifndef PROTOBUF_C_LocalStorageProtocol_2eproto__INCLUDED #define PROTOBUF_C_LocalStorageProtocol_2eproto__INCLUDED #include PROTOBUF_C__BEGIN_DECLS #if PROTOBUF_C_VERSION_NUMBER < 1000000 # error This file was generated by a newer version of protoc-c which is incompatible with your libprotobuf-c headers. Please update your headers. #elif 1002001 < PROTOBUF_C_MIN_COMPILER_VERSION # error This file was generated by an older version of protoc-c which is incompatible with your libprotobuf-c headers. Please regenerate this file with a newer version of protoc-c. #endif typedef struct _Textsecure__SessionStructure Textsecure__SessionStructure; typedef struct _Textsecure__SessionStructure__Chain Textsecure__SessionStructure__Chain; typedef struct _Textsecure__SessionStructure__Chain__ChainKey Textsecure__SessionStructure__Chain__ChainKey; typedef struct _Textsecure__SessionStructure__Chain__MessageKey Textsecure__SessionStructure__Chain__MessageKey; typedef struct _Textsecure__SessionStructure__PendingKeyExchange Textsecure__SessionStructure__PendingKeyExchange; typedef struct _Textsecure__SessionStructure__PendingPreKey Textsecure__SessionStructure__PendingPreKey; typedef struct _Textsecure__RecordStructure Textsecure__RecordStructure; typedef struct _Textsecure__PreKeyRecordStructure Textsecure__PreKeyRecordStructure; typedef struct _Textsecure__SignedPreKeyRecordStructure Textsecure__SignedPreKeyRecordStructure; typedef struct _Textsecure__IdentityKeyPairStructure Textsecure__IdentityKeyPairStructure; typedef struct _Textsecure__SenderKeyStateStructure Textsecure__SenderKeyStateStructure; typedef struct _Textsecure__SenderKeyStateStructure__SenderChainKey Textsecure__SenderKeyStateStructure__SenderChainKey; typedef struct _Textsecure__SenderKeyStateStructure__SenderMessageKey Textsecure__SenderKeyStateStructure__SenderMessageKey; typedef struct _Textsecure__SenderKeyStateStructure__SenderSigningKey Textsecure__SenderKeyStateStructure__SenderSigningKey; typedef struct _Textsecure__SenderKeyRecordStructure Textsecure__SenderKeyRecordStructure; /* --- enums --- */ /* --- messages --- */ struct _Textsecure__SessionStructure__Chain__ChainKey { ProtobufCMessage base; protobuf_c_boolean has_index; uint32_t index; protobuf_c_boolean has_key; ProtobufCBinaryData key; }; #define TEXTSECURE__SESSION_STRUCTURE__CHAIN__CHAIN_KEY__INIT \ { PROTOBUF_C_MESSAGE_INIT (&textsecure__session_structure__chain__chain_key__descriptor) \ , 0,0, 0,{0,NULL} } struct _Textsecure__SessionStructure__Chain__MessageKey { ProtobufCMessage base; protobuf_c_boolean has_index; uint32_t index; protobuf_c_boolean has_cipherkey; ProtobufCBinaryData cipherkey; protobuf_c_boolean has_mackey; ProtobufCBinaryData mackey; protobuf_c_boolean has_iv; ProtobufCBinaryData iv; }; #define TEXTSECURE__SESSION_STRUCTURE__CHAIN__MESSAGE_KEY__INIT \ { PROTOBUF_C_MESSAGE_INIT (&textsecure__session_structure__chain__message_key__descriptor) \ , 0,0, 0,{0,NULL}, 0,{0,NULL}, 0,{0,NULL} } struct _Textsecure__SessionStructure__Chain { ProtobufCMessage base; protobuf_c_boolean has_senderratchetkey; ProtobufCBinaryData senderratchetkey; protobuf_c_boolean has_senderratchetkeyprivate; ProtobufCBinaryData senderratchetkeyprivate; Textsecure__SessionStructure__Chain__ChainKey *chainkey; size_t n_messagekeys; Textsecure__SessionStructure__Chain__MessageKey **messagekeys; }; #define TEXTSECURE__SESSION_STRUCTURE__CHAIN__INIT \ { PROTOBUF_C_MESSAGE_INIT (&textsecure__session_structure__chain__descriptor) \ , 0,{0,NULL}, 0,{0,NULL}, NULL, 0,NULL } struct _Textsecure__SessionStructure__PendingKeyExchange { ProtobufCMessage base; protobuf_c_boolean has_sequence; uint32_t sequence; protobuf_c_boolean has_localbasekey; ProtobufCBinaryData localbasekey; protobuf_c_boolean has_localbasekeyprivate; ProtobufCBinaryData localbasekeyprivate; protobuf_c_boolean has_localratchetkey; ProtobufCBinaryData localratchetkey; protobuf_c_boolean has_localratchetkeyprivate; ProtobufCBinaryData localratchetkeyprivate; protobuf_c_boolean has_localidentitykey; ProtobufCBinaryData localidentitykey; protobuf_c_boolean has_localidentitykeyprivate; ProtobufCBinaryData localidentitykeyprivate; }; #define TEXTSECURE__SESSION_STRUCTURE__PENDING_KEY_EXCHANGE__INIT \ { PROTOBUF_C_MESSAGE_INIT (&textsecure__session_structure__pending_key_exchange__descriptor) \ , 0,0, 0,{0,NULL}, 0,{0,NULL}, 0,{0,NULL}, 0,{0,NULL}, 0,{0,NULL}, 0,{0,NULL} } struct _Textsecure__SessionStructure__PendingPreKey { ProtobufCMessage base; protobuf_c_boolean has_prekeyid; uint32_t prekeyid; protobuf_c_boolean has_signedprekeyid; int32_t signedprekeyid; protobuf_c_boolean has_basekey; ProtobufCBinaryData basekey; }; #define TEXTSECURE__SESSION_STRUCTURE__PENDING_PRE_KEY__INIT \ { PROTOBUF_C_MESSAGE_INIT (&textsecure__session_structure__pending_pre_key__descriptor) \ , 0,0, 0,0, 0,{0,NULL} } struct _Textsecure__SessionStructure { ProtobufCMessage base; protobuf_c_boolean has_sessionversion; uint32_t sessionversion; protobuf_c_boolean has_localidentitypublic; ProtobufCBinaryData localidentitypublic; protobuf_c_boolean has_remoteidentitypublic; ProtobufCBinaryData remoteidentitypublic; protobuf_c_boolean has_rootkey; ProtobufCBinaryData rootkey; protobuf_c_boolean has_previouscounter; uint32_t previouscounter; Textsecure__SessionStructure__Chain *senderchain; size_t n_receiverchains; Textsecure__SessionStructure__Chain **receiverchains; Textsecure__SessionStructure__PendingKeyExchange *pendingkeyexchange; Textsecure__SessionStructure__PendingPreKey *pendingprekey; protobuf_c_boolean has_remoteregistrationid; uint32_t remoteregistrationid; protobuf_c_boolean has_localregistrationid; uint32_t localregistrationid; protobuf_c_boolean has_needsrefresh; protobuf_c_boolean needsrefresh; protobuf_c_boolean has_alicebasekey; ProtobufCBinaryData alicebasekey; }; #define TEXTSECURE__SESSION_STRUCTURE__INIT \ { PROTOBUF_C_MESSAGE_INIT (&textsecure__session_structure__descriptor) \ , 0,0, 0,{0,NULL}, 0,{0,NULL}, 0,{0,NULL}, 0,0, NULL, 0,NULL, NULL, NULL, 0,0, 0,0, 0,0, 0,{0,NULL} } struct _Textsecure__RecordStructure { ProtobufCMessage base; Textsecure__SessionStructure *currentsession; size_t n_previoussessions; Textsecure__SessionStructure **previoussessions; }; #define TEXTSECURE__RECORD_STRUCTURE__INIT \ { PROTOBUF_C_MESSAGE_INIT (&textsecure__record_structure__descriptor) \ , NULL, 0,NULL } struct _Textsecure__PreKeyRecordStructure { ProtobufCMessage base; protobuf_c_boolean has_id; uint32_t id; protobuf_c_boolean has_publickey; ProtobufCBinaryData publickey; protobuf_c_boolean has_privatekey; ProtobufCBinaryData privatekey; }; #define TEXTSECURE__PRE_KEY_RECORD_STRUCTURE__INIT \ { PROTOBUF_C_MESSAGE_INIT (&textsecure__pre_key_record_structure__descriptor) \ , 0,0, 0,{0,NULL}, 0,{0,NULL} } struct _Textsecure__SignedPreKeyRecordStructure { ProtobufCMessage base; protobuf_c_boolean has_id; uint32_t id; protobuf_c_boolean has_publickey; ProtobufCBinaryData publickey; protobuf_c_boolean has_privatekey; ProtobufCBinaryData privatekey; protobuf_c_boolean has_signature; ProtobufCBinaryData signature; protobuf_c_boolean has_timestamp; uint64_t timestamp; }; #define TEXTSECURE__SIGNED_PRE_KEY_RECORD_STRUCTURE__INIT \ { PROTOBUF_C_MESSAGE_INIT (&textsecure__signed_pre_key_record_structure__descriptor) \ , 0,0, 0,{0,NULL}, 0,{0,NULL}, 0,{0,NULL}, 0,0 } struct _Textsecure__IdentityKeyPairStructure { ProtobufCMessage base; protobuf_c_boolean has_publickey; ProtobufCBinaryData publickey; protobuf_c_boolean has_privatekey; ProtobufCBinaryData privatekey; }; #define TEXTSECURE__IDENTITY_KEY_PAIR_STRUCTURE__INIT \ { PROTOBUF_C_MESSAGE_INIT (&textsecure__identity_key_pair_structure__descriptor) \ , 0,{0,NULL}, 0,{0,NULL} } struct _Textsecure__SenderKeyStateStructure__SenderChainKey { ProtobufCMessage base; protobuf_c_boolean has_iteration; uint32_t iteration; protobuf_c_boolean has_seed; ProtobufCBinaryData seed; }; #define TEXTSECURE__SENDER_KEY_STATE_STRUCTURE__SENDER_CHAIN_KEY__INIT \ { PROTOBUF_C_MESSAGE_INIT (&textsecure__sender_key_state_structure__sender_chain_key__descriptor) \ , 0,0, 0,{0,NULL} } struct _Textsecure__SenderKeyStateStructure__SenderMessageKey { ProtobufCMessage base; protobuf_c_boolean has_iteration; uint32_t iteration; protobuf_c_boolean has_seed; ProtobufCBinaryData seed; }; #define TEXTSECURE__SENDER_KEY_STATE_STRUCTURE__SENDER_MESSAGE_KEY__INIT \ { PROTOBUF_C_MESSAGE_INIT (&textsecure__sender_key_state_structure__sender_message_key__descriptor) \ , 0,0, 0,{0,NULL} } struct _Textsecure__SenderKeyStateStructure__SenderSigningKey { ProtobufCMessage base; protobuf_c_boolean has_public_; ProtobufCBinaryData public_; protobuf_c_boolean has_private_; ProtobufCBinaryData private_; }; #define TEXTSECURE__SENDER_KEY_STATE_STRUCTURE__SENDER_SIGNING_KEY__INIT \ { PROTOBUF_C_MESSAGE_INIT (&textsecure__sender_key_state_structure__sender_signing_key__descriptor) \ , 0,{0,NULL}, 0,{0,NULL} } struct _Textsecure__SenderKeyStateStructure { ProtobufCMessage base; protobuf_c_boolean has_senderkeyid; uint32_t senderkeyid; Textsecure__SenderKeyStateStructure__SenderChainKey *senderchainkey; Textsecure__SenderKeyStateStructure__SenderSigningKey *sendersigningkey; size_t n_sendermessagekeys; Textsecure__SenderKeyStateStructure__SenderMessageKey **sendermessagekeys; }; #define TEXTSECURE__SENDER_KEY_STATE_STRUCTURE__INIT \ { PROTOBUF_C_MESSAGE_INIT (&textsecure__sender_key_state_structure__descriptor) \ , 0,0, NULL, NULL, 0,NULL } struct _Textsecure__SenderKeyRecordStructure { ProtobufCMessage base; size_t n_senderkeystates; Textsecure__SenderKeyStateStructure **senderkeystates; }; #define TEXTSECURE__SENDER_KEY_RECORD_STRUCTURE__INIT \ { PROTOBUF_C_MESSAGE_INIT (&textsecure__sender_key_record_structure__descriptor) \ , 0,NULL } /* Textsecure__SessionStructure__Chain__ChainKey methods */ void textsecure__session_structure__chain__chain_key__init (Textsecure__SessionStructure__Chain__ChainKey *message); /* Textsecure__SessionStructure__Chain__MessageKey methods */ void textsecure__session_structure__chain__message_key__init (Textsecure__SessionStructure__Chain__MessageKey *message); /* Textsecure__SessionStructure__Chain methods */ void textsecure__session_structure__chain__init (Textsecure__SessionStructure__Chain *message); /* Textsecure__SessionStructure__PendingKeyExchange methods */ void textsecure__session_structure__pending_key_exchange__init (Textsecure__SessionStructure__PendingKeyExchange *message); /* Textsecure__SessionStructure__PendingPreKey methods */ void textsecure__session_structure__pending_pre_key__init (Textsecure__SessionStructure__PendingPreKey *message); /* Textsecure__SessionStructure methods */ void textsecure__session_structure__init (Textsecure__SessionStructure *message); size_t textsecure__session_structure__get_packed_size (const Textsecure__SessionStructure *message); size_t textsecure__session_structure__pack (const Textsecure__SessionStructure *message, uint8_t *out); size_t textsecure__session_structure__pack_to_buffer (const Textsecure__SessionStructure *message, ProtobufCBuffer *buffer); Textsecure__SessionStructure * textsecure__session_structure__unpack (ProtobufCAllocator *allocator, size_t len, const uint8_t *data); void textsecure__session_structure__free_unpacked (Textsecure__SessionStructure *message, ProtobufCAllocator *allocator); /* Textsecure__RecordStructure methods */ void textsecure__record_structure__init (Textsecure__RecordStructure *message); size_t textsecure__record_structure__get_packed_size (const Textsecure__RecordStructure *message); size_t textsecure__record_structure__pack (const Textsecure__RecordStructure *message, uint8_t *out); size_t textsecure__record_structure__pack_to_buffer (const Textsecure__RecordStructure *message, ProtobufCBuffer *buffer); Textsecure__RecordStructure * textsecure__record_structure__unpack (ProtobufCAllocator *allocator, size_t len, const uint8_t *data); void textsecure__record_structure__free_unpacked (Textsecure__RecordStructure *message, ProtobufCAllocator *allocator); /* Textsecure__PreKeyRecordStructure methods */ void textsecure__pre_key_record_structure__init (Textsecure__PreKeyRecordStructure *message); size_t textsecure__pre_key_record_structure__get_packed_size (const Textsecure__PreKeyRecordStructure *message); size_t textsecure__pre_key_record_structure__pack (const Textsecure__PreKeyRecordStructure *message, uint8_t *out); size_t textsecure__pre_key_record_structure__pack_to_buffer (const Textsecure__PreKeyRecordStructure *message, ProtobufCBuffer *buffer); Textsecure__PreKeyRecordStructure * textsecure__pre_key_record_structure__unpack (ProtobufCAllocator *allocator, size_t len, const uint8_t *data); void textsecure__pre_key_record_structure__free_unpacked (Textsecure__PreKeyRecordStructure *message, ProtobufCAllocator *allocator); /* Textsecure__SignedPreKeyRecordStructure methods */ void textsecure__signed_pre_key_record_structure__init (Textsecure__SignedPreKeyRecordStructure *message); size_t textsecure__signed_pre_key_record_structure__get_packed_size (const Textsecure__SignedPreKeyRecordStructure *message); size_t textsecure__signed_pre_key_record_structure__pack (const Textsecure__SignedPreKeyRecordStructure *message, uint8_t *out); size_t textsecure__signed_pre_key_record_structure__pack_to_buffer (const Textsecure__SignedPreKeyRecordStructure *message, ProtobufCBuffer *buffer); Textsecure__SignedPreKeyRecordStructure * textsecure__signed_pre_key_record_structure__unpack (ProtobufCAllocator *allocator, size_t len, const uint8_t *data); void textsecure__signed_pre_key_record_structure__free_unpacked (Textsecure__SignedPreKeyRecordStructure *message, ProtobufCAllocator *allocator); /* Textsecure__IdentityKeyPairStructure methods */ void textsecure__identity_key_pair_structure__init (Textsecure__IdentityKeyPairStructure *message); size_t textsecure__identity_key_pair_structure__get_packed_size (const Textsecure__IdentityKeyPairStructure *message); size_t textsecure__identity_key_pair_structure__pack (const Textsecure__IdentityKeyPairStructure *message, uint8_t *out); size_t textsecure__identity_key_pair_structure__pack_to_buffer (const Textsecure__IdentityKeyPairStructure *message, ProtobufCBuffer *buffer); Textsecure__IdentityKeyPairStructure * textsecure__identity_key_pair_structure__unpack (ProtobufCAllocator *allocator, size_t len, const uint8_t *data); void textsecure__identity_key_pair_structure__free_unpacked (Textsecure__IdentityKeyPairStructure *message, ProtobufCAllocator *allocator); /* Textsecure__SenderKeyStateStructure__SenderChainKey methods */ void textsecure__sender_key_state_structure__sender_chain_key__init (Textsecure__SenderKeyStateStructure__SenderChainKey *message); /* Textsecure__SenderKeyStateStructure__SenderMessageKey methods */ void textsecure__sender_key_state_structure__sender_message_key__init (Textsecure__SenderKeyStateStructure__SenderMessageKey *message); /* Textsecure__SenderKeyStateStructure__SenderSigningKey methods */ void textsecure__sender_key_state_structure__sender_signing_key__init (Textsecure__SenderKeyStateStructure__SenderSigningKey *message); /* Textsecure__SenderKeyStateStructure methods */ void textsecure__sender_key_state_structure__init (Textsecure__SenderKeyStateStructure *message); size_t textsecure__sender_key_state_structure__get_packed_size (const Textsecure__SenderKeyStateStructure *message); size_t textsecure__sender_key_state_structure__pack (const Textsecure__SenderKeyStateStructure *message, uint8_t *out); size_t textsecure__sender_key_state_structure__pack_to_buffer (const Textsecure__SenderKeyStateStructure *message, ProtobufCBuffer *buffer); Textsecure__SenderKeyStateStructure * textsecure__sender_key_state_structure__unpack (ProtobufCAllocator *allocator, size_t len, const uint8_t *data); void textsecure__sender_key_state_structure__free_unpacked (Textsecure__SenderKeyStateStructure *message, ProtobufCAllocator *allocator); /* Textsecure__SenderKeyRecordStructure methods */ void textsecure__sender_key_record_structure__init (Textsecure__SenderKeyRecordStructure *message); size_t textsecure__sender_key_record_structure__get_packed_size (const Textsecure__SenderKeyRecordStructure *message); size_t textsecure__sender_key_record_structure__pack (const Textsecure__SenderKeyRecordStructure *message, uint8_t *out); size_t textsecure__sender_key_record_structure__pack_to_buffer (const Textsecure__SenderKeyRecordStructure *message, ProtobufCBuffer *buffer); Textsecure__SenderKeyRecordStructure * textsecure__sender_key_record_structure__unpack (ProtobufCAllocator *allocator, size_t len, const uint8_t *data); void textsecure__sender_key_record_structure__free_unpacked (Textsecure__SenderKeyRecordStructure *message, ProtobufCAllocator *allocator); /* --- per-message closures --- */ typedef void (*Textsecure__SessionStructure__Chain__ChainKey_Closure) (const Textsecure__SessionStructure__Chain__ChainKey *message, void *closure_data); typedef void (*Textsecure__SessionStructure__Chain__MessageKey_Closure) (const Textsecure__SessionStructure__Chain__MessageKey *message, void *closure_data); typedef void (*Textsecure__SessionStructure__Chain_Closure) (const Textsecure__SessionStructure__Chain *message, void *closure_data); typedef void (*Textsecure__SessionStructure__PendingKeyExchange_Closure) (const Textsecure__SessionStructure__PendingKeyExchange *message, void *closure_data); typedef void (*Textsecure__SessionStructure__PendingPreKey_Closure) (const Textsecure__SessionStructure__PendingPreKey *message, void *closure_data); typedef void (*Textsecure__SessionStructure_Closure) (const Textsecure__SessionStructure *message, void *closure_data); typedef void (*Textsecure__RecordStructure_Closure) (const Textsecure__RecordStructure *message, void *closure_data); typedef void (*Textsecure__PreKeyRecordStructure_Closure) (const Textsecure__PreKeyRecordStructure *message, void *closure_data); typedef void (*Textsecure__SignedPreKeyRecordStructure_Closure) (const Textsecure__SignedPreKeyRecordStructure *message, void *closure_data); typedef void (*Textsecure__IdentityKeyPairStructure_Closure) (const Textsecure__IdentityKeyPairStructure *message, void *closure_data); typedef void (*Textsecure__SenderKeyStateStructure__SenderChainKey_Closure) (const Textsecure__SenderKeyStateStructure__SenderChainKey *message, void *closure_data); typedef void (*Textsecure__SenderKeyStateStructure__SenderMessageKey_Closure) (const Textsecure__SenderKeyStateStructure__SenderMessageKey *message, void *closure_data); typedef void (*Textsecure__SenderKeyStateStructure__SenderSigningKey_Closure) (const Textsecure__SenderKeyStateStructure__SenderSigningKey *message, void *closure_data); typedef void (*Textsecure__SenderKeyStateStructure_Closure) (const Textsecure__SenderKeyStateStructure *message, void *closure_data); typedef void (*Textsecure__SenderKeyRecordStructure_Closure) (const Textsecure__SenderKeyRecordStructure *message, void *closure_data); /* --- services --- */ /* --- descriptors --- */ extern const ProtobufCMessageDescriptor textsecure__session_structure__descriptor; extern const ProtobufCMessageDescriptor textsecure__session_structure__chain__descriptor; extern const ProtobufCMessageDescriptor textsecure__session_structure__chain__chain_key__descriptor; extern const ProtobufCMessageDescriptor textsecure__session_structure__chain__message_key__descriptor; extern const ProtobufCMessageDescriptor textsecure__session_structure__pending_key_exchange__descriptor; extern const ProtobufCMessageDescriptor textsecure__session_structure__pending_pre_key__descriptor; extern const ProtobufCMessageDescriptor textsecure__record_structure__descriptor; extern const ProtobufCMessageDescriptor textsecure__pre_key_record_structure__descriptor; extern const ProtobufCMessageDescriptor textsecure__signed_pre_key_record_structure__descriptor; extern const ProtobufCMessageDescriptor textsecure__identity_key_pair_structure__descriptor; extern const ProtobufCMessageDescriptor textsecure__sender_key_state_structure__descriptor; extern const ProtobufCMessageDescriptor textsecure__sender_key_state_structure__sender_chain_key__descriptor; extern const ProtobufCMessageDescriptor textsecure__sender_key_state_structure__sender_message_key__descriptor; extern const ProtobufCMessageDescriptor textsecure__sender_key_state_structure__sender_signing_key__descriptor; extern const ProtobufCMessageDescriptor textsecure__sender_key_record_structure__descriptor; PROTOBUF_C__END_DECLS #endif /* PROTOBUF_C_LocalStorageProtocol_2eproto__INCLUDED */ libsignal-protocol-c-2.3.3/src/WhisperTextProtocol.pb-c.c000066400000000000000000000626241363751346500233540ustar00rootroot00000000000000/* Generated by the protocol buffer compiler. DO NOT EDIT! */ /* Generated from: WhisperTextProtocol.proto */ /* Do not generate deprecated warnings for self */ #ifndef PROTOBUF_C__NO_DEPRECATED #define PROTOBUF_C__NO_DEPRECATED #endif #include "WhisperTextProtocol.pb-c.h" void textsecure__signal_message__init (Textsecure__SignalMessage *message) { static Textsecure__SignalMessage init_value = TEXTSECURE__SIGNAL_MESSAGE__INIT; *message = init_value; } size_t textsecure__signal_message__get_packed_size (const Textsecure__SignalMessage *message) { assert(message->base.descriptor == &textsecure__signal_message__descriptor); return protobuf_c_message_get_packed_size ((const ProtobufCMessage*)(message)); } size_t textsecure__signal_message__pack (const Textsecure__SignalMessage *message, uint8_t *out) { assert(message->base.descriptor == &textsecure__signal_message__descriptor); return protobuf_c_message_pack ((const ProtobufCMessage*)message, out); } size_t textsecure__signal_message__pack_to_buffer (const Textsecure__SignalMessage *message, ProtobufCBuffer *buffer) { assert(message->base.descriptor == &textsecure__signal_message__descriptor); return protobuf_c_message_pack_to_buffer ((const ProtobufCMessage*)message, buffer); } Textsecure__SignalMessage * textsecure__signal_message__unpack (ProtobufCAllocator *allocator, size_t len, const uint8_t *data) { return (Textsecure__SignalMessage *) protobuf_c_message_unpack (&textsecure__signal_message__descriptor, allocator, len, data); } void textsecure__signal_message__free_unpacked (Textsecure__SignalMessage *message, ProtobufCAllocator *allocator) { assert(message->base.descriptor == &textsecure__signal_message__descriptor); protobuf_c_message_free_unpacked ((ProtobufCMessage*)message, allocator); } void textsecure__pre_key_signal_message__init (Textsecure__PreKeySignalMessage *message) { static Textsecure__PreKeySignalMessage init_value = TEXTSECURE__PRE_KEY_SIGNAL_MESSAGE__INIT; *message = init_value; } size_t textsecure__pre_key_signal_message__get_packed_size (const Textsecure__PreKeySignalMessage *message) { assert(message->base.descriptor == &textsecure__pre_key_signal_message__descriptor); return protobuf_c_message_get_packed_size ((const ProtobufCMessage*)(message)); } size_t textsecure__pre_key_signal_message__pack (const Textsecure__PreKeySignalMessage *message, uint8_t *out) { assert(message->base.descriptor == &textsecure__pre_key_signal_message__descriptor); return protobuf_c_message_pack ((const ProtobufCMessage*)message, out); } size_t textsecure__pre_key_signal_message__pack_to_buffer (const Textsecure__PreKeySignalMessage *message, ProtobufCBuffer *buffer) { assert(message->base.descriptor == &textsecure__pre_key_signal_message__descriptor); return protobuf_c_message_pack_to_buffer ((const ProtobufCMessage*)message, buffer); } Textsecure__PreKeySignalMessage * textsecure__pre_key_signal_message__unpack (ProtobufCAllocator *allocator, size_t len, const uint8_t *data) { return (Textsecure__PreKeySignalMessage *) protobuf_c_message_unpack (&textsecure__pre_key_signal_message__descriptor, allocator, len, data); } void textsecure__pre_key_signal_message__free_unpacked (Textsecure__PreKeySignalMessage *message, ProtobufCAllocator *allocator) { assert(message->base.descriptor == &textsecure__pre_key_signal_message__descriptor); protobuf_c_message_free_unpacked ((ProtobufCMessage*)message, allocator); } void textsecure__key_exchange_message__init (Textsecure__KeyExchangeMessage *message) { static Textsecure__KeyExchangeMessage init_value = TEXTSECURE__KEY_EXCHANGE_MESSAGE__INIT; *message = init_value; } size_t textsecure__key_exchange_message__get_packed_size (const Textsecure__KeyExchangeMessage *message) { assert(message->base.descriptor == &textsecure__key_exchange_message__descriptor); return protobuf_c_message_get_packed_size ((const ProtobufCMessage*)(message)); } size_t textsecure__key_exchange_message__pack (const Textsecure__KeyExchangeMessage *message, uint8_t *out) { assert(message->base.descriptor == &textsecure__key_exchange_message__descriptor); return protobuf_c_message_pack ((const ProtobufCMessage*)message, out); } size_t textsecure__key_exchange_message__pack_to_buffer (const Textsecure__KeyExchangeMessage *message, ProtobufCBuffer *buffer) { assert(message->base.descriptor == &textsecure__key_exchange_message__descriptor); return protobuf_c_message_pack_to_buffer ((const ProtobufCMessage*)message, buffer); } Textsecure__KeyExchangeMessage * textsecure__key_exchange_message__unpack (ProtobufCAllocator *allocator, size_t len, const uint8_t *data) { return (Textsecure__KeyExchangeMessage *) protobuf_c_message_unpack (&textsecure__key_exchange_message__descriptor, allocator, len, data); } void textsecure__key_exchange_message__free_unpacked (Textsecure__KeyExchangeMessage *message, ProtobufCAllocator *allocator) { assert(message->base.descriptor == &textsecure__key_exchange_message__descriptor); protobuf_c_message_free_unpacked ((ProtobufCMessage*)message, allocator); } void textsecure__sender_key_message__init (Textsecure__SenderKeyMessage *message) { static Textsecure__SenderKeyMessage init_value = TEXTSECURE__SENDER_KEY_MESSAGE__INIT; *message = init_value; } size_t textsecure__sender_key_message__get_packed_size (const Textsecure__SenderKeyMessage *message) { assert(message->base.descriptor == &textsecure__sender_key_message__descriptor); return protobuf_c_message_get_packed_size ((const ProtobufCMessage*)(message)); } size_t textsecure__sender_key_message__pack (const Textsecure__SenderKeyMessage *message, uint8_t *out) { assert(message->base.descriptor == &textsecure__sender_key_message__descriptor); return protobuf_c_message_pack ((const ProtobufCMessage*)message, out); } size_t textsecure__sender_key_message__pack_to_buffer (const Textsecure__SenderKeyMessage *message, ProtobufCBuffer *buffer) { assert(message->base.descriptor == &textsecure__sender_key_message__descriptor); return protobuf_c_message_pack_to_buffer ((const ProtobufCMessage*)message, buffer); } Textsecure__SenderKeyMessage * textsecure__sender_key_message__unpack (ProtobufCAllocator *allocator, size_t len, const uint8_t *data) { return (Textsecure__SenderKeyMessage *) protobuf_c_message_unpack (&textsecure__sender_key_message__descriptor, allocator, len, data); } void textsecure__sender_key_message__free_unpacked (Textsecure__SenderKeyMessage *message, ProtobufCAllocator *allocator) { assert(message->base.descriptor == &textsecure__sender_key_message__descriptor); protobuf_c_message_free_unpacked ((ProtobufCMessage*)message, allocator); } void textsecure__sender_key_distribution_message__init (Textsecure__SenderKeyDistributionMessage *message) { static Textsecure__SenderKeyDistributionMessage init_value = TEXTSECURE__SENDER_KEY_DISTRIBUTION_MESSAGE__INIT; *message = init_value; } size_t textsecure__sender_key_distribution_message__get_packed_size (const Textsecure__SenderKeyDistributionMessage *message) { assert(message->base.descriptor == &textsecure__sender_key_distribution_message__descriptor); return protobuf_c_message_get_packed_size ((const ProtobufCMessage*)(message)); } size_t textsecure__sender_key_distribution_message__pack (const Textsecure__SenderKeyDistributionMessage *message, uint8_t *out) { assert(message->base.descriptor == &textsecure__sender_key_distribution_message__descriptor); return protobuf_c_message_pack ((const ProtobufCMessage*)message, out); } size_t textsecure__sender_key_distribution_message__pack_to_buffer (const Textsecure__SenderKeyDistributionMessage *message, ProtobufCBuffer *buffer) { assert(message->base.descriptor == &textsecure__sender_key_distribution_message__descriptor); return protobuf_c_message_pack_to_buffer ((const ProtobufCMessage*)message, buffer); } Textsecure__SenderKeyDistributionMessage * textsecure__sender_key_distribution_message__unpack (ProtobufCAllocator *allocator, size_t len, const uint8_t *data) { return (Textsecure__SenderKeyDistributionMessage *) protobuf_c_message_unpack (&textsecure__sender_key_distribution_message__descriptor, allocator, len, data); } void textsecure__sender_key_distribution_message__free_unpacked (Textsecure__SenderKeyDistributionMessage *message, ProtobufCAllocator *allocator) { assert(message->base.descriptor == &textsecure__sender_key_distribution_message__descriptor); protobuf_c_message_free_unpacked ((ProtobufCMessage*)message, allocator); } void textsecure__device_consistency_code_message__init (Textsecure__DeviceConsistencyCodeMessage *message) { static Textsecure__DeviceConsistencyCodeMessage init_value = TEXTSECURE__DEVICE_CONSISTENCY_CODE_MESSAGE__INIT; *message = init_value; } size_t textsecure__device_consistency_code_message__get_packed_size (const Textsecure__DeviceConsistencyCodeMessage *message) { assert(message->base.descriptor == &textsecure__device_consistency_code_message__descriptor); return protobuf_c_message_get_packed_size ((const ProtobufCMessage*)(message)); } size_t textsecure__device_consistency_code_message__pack (const Textsecure__DeviceConsistencyCodeMessage *message, uint8_t *out) { assert(message->base.descriptor == &textsecure__device_consistency_code_message__descriptor); return protobuf_c_message_pack ((const ProtobufCMessage*)message, out); } size_t textsecure__device_consistency_code_message__pack_to_buffer (const Textsecure__DeviceConsistencyCodeMessage *message, ProtobufCBuffer *buffer) { assert(message->base.descriptor == &textsecure__device_consistency_code_message__descriptor); return protobuf_c_message_pack_to_buffer ((const ProtobufCMessage*)message, buffer); } Textsecure__DeviceConsistencyCodeMessage * textsecure__device_consistency_code_message__unpack (ProtobufCAllocator *allocator, size_t len, const uint8_t *data) { return (Textsecure__DeviceConsistencyCodeMessage *) protobuf_c_message_unpack (&textsecure__device_consistency_code_message__descriptor, allocator, len, data); } void textsecure__device_consistency_code_message__free_unpacked (Textsecure__DeviceConsistencyCodeMessage *message, ProtobufCAllocator *allocator) { assert(message->base.descriptor == &textsecure__device_consistency_code_message__descriptor); protobuf_c_message_free_unpacked ((ProtobufCMessage*)message, allocator); } static const ProtobufCFieldDescriptor textsecure__signal_message__field_descriptors[4] = { { "ratchetKey", 1, PROTOBUF_C_LABEL_OPTIONAL, PROTOBUF_C_TYPE_BYTES, offsetof(Textsecure__SignalMessage, has_ratchetkey), offsetof(Textsecure__SignalMessage, ratchetkey), NULL, NULL, 0, /* flags */ 0,NULL,NULL /* reserved1,reserved2, etc */ }, { "counter", 2, PROTOBUF_C_LABEL_OPTIONAL, PROTOBUF_C_TYPE_UINT32, offsetof(Textsecure__SignalMessage, has_counter), offsetof(Textsecure__SignalMessage, counter), NULL, NULL, 0, /* flags */ 0,NULL,NULL /* reserved1,reserved2, etc */ }, { "previousCounter", 3, PROTOBUF_C_LABEL_OPTIONAL, PROTOBUF_C_TYPE_UINT32, offsetof(Textsecure__SignalMessage, has_previouscounter), offsetof(Textsecure__SignalMessage, previouscounter), NULL, NULL, 0, /* flags */ 0,NULL,NULL /* reserved1,reserved2, etc */ }, { "ciphertext", 4, PROTOBUF_C_LABEL_OPTIONAL, PROTOBUF_C_TYPE_BYTES, offsetof(Textsecure__SignalMessage, has_ciphertext), offsetof(Textsecure__SignalMessage, ciphertext), NULL, NULL, 0, /* flags */ 0,NULL,NULL /* reserved1,reserved2, etc */ }, }; static const unsigned textsecure__signal_message__field_indices_by_name[] = { 3, /* field[3] = ciphertext */ 1, /* field[1] = counter */ 2, /* field[2] = previousCounter */ 0, /* field[0] = ratchetKey */ }; static const ProtobufCIntRange textsecure__signal_message__number_ranges[1 + 1] = { { 1, 0 }, { 0, 4 } }; const ProtobufCMessageDescriptor textsecure__signal_message__descriptor = { PROTOBUF_C__MESSAGE_DESCRIPTOR_MAGIC, "textsecure.SignalMessage", "SignalMessage", "Textsecure__SignalMessage", "textsecure", sizeof(Textsecure__SignalMessage), 4, textsecure__signal_message__field_descriptors, textsecure__signal_message__field_indices_by_name, 1, textsecure__signal_message__number_ranges, (ProtobufCMessageInit) textsecure__signal_message__init, NULL,NULL,NULL /* reserved[123] */ }; static const ProtobufCFieldDescriptor textsecure__pre_key_signal_message__field_descriptors[6] = { { "preKeyId", 1, PROTOBUF_C_LABEL_OPTIONAL, PROTOBUF_C_TYPE_UINT32, offsetof(Textsecure__PreKeySignalMessage, has_prekeyid), offsetof(Textsecure__PreKeySignalMessage, prekeyid), NULL, NULL, 0, /* flags */ 0,NULL,NULL /* reserved1,reserved2, etc */ }, { "baseKey", 2, PROTOBUF_C_LABEL_OPTIONAL, PROTOBUF_C_TYPE_BYTES, offsetof(Textsecure__PreKeySignalMessage, has_basekey), offsetof(Textsecure__PreKeySignalMessage, basekey), NULL, NULL, 0, /* flags */ 0,NULL,NULL /* reserved1,reserved2, etc */ }, { "identityKey", 3, PROTOBUF_C_LABEL_OPTIONAL, PROTOBUF_C_TYPE_BYTES, offsetof(Textsecure__PreKeySignalMessage, has_identitykey), offsetof(Textsecure__PreKeySignalMessage, identitykey), NULL, NULL, 0, /* flags */ 0,NULL,NULL /* reserved1,reserved2, etc */ }, { "message", 4, PROTOBUF_C_LABEL_OPTIONAL, PROTOBUF_C_TYPE_BYTES, offsetof(Textsecure__PreKeySignalMessage, has_message), offsetof(Textsecure__PreKeySignalMessage, message), NULL, NULL, 0, /* flags */ 0,NULL,NULL /* reserved1,reserved2, etc */ }, { "registrationId", 5, PROTOBUF_C_LABEL_OPTIONAL, PROTOBUF_C_TYPE_UINT32, offsetof(Textsecure__PreKeySignalMessage, has_registrationid), offsetof(Textsecure__PreKeySignalMessage, registrationid), NULL, NULL, 0, /* flags */ 0,NULL,NULL /* reserved1,reserved2, etc */ }, { "signedPreKeyId", 6, PROTOBUF_C_LABEL_OPTIONAL, PROTOBUF_C_TYPE_UINT32, offsetof(Textsecure__PreKeySignalMessage, has_signedprekeyid), offsetof(Textsecure__PreKeySignalMessage, signedprekeyid), NULL, NULL, 0, /* flags */ 0,NULL,NULL /* reserved1,reserved2, etc */ }, }; static const unsigned textsecure__pre_key_signal_message__field_indices_by_name[] = { 1, /* field[1] = baseKey */ 2, /* field[2] = identityKey */ 3, /* field[3] = message */ 0, /* field[0] = preKeyId */ 4, /* field[4] = registrationId */ 5, /* field[5] = signedPreKeyId */ }; static const ProtobufCIntRange textsecure__pre_key_signal_message__number_ranges[1 + 1] = { { 1, 0 }, { 0, 6 } }; const ProtobufCMessageDescriptor textsecure__pre_key_signal_message__descriptor = { PROTOBUF_C__MESSAGE_DESCRIPTOR_MAGIC, "textsecure.PreKeySignalMessage", "PreKeySignalMessage", "Textsecure__PreKeySignalMessage", "textsecure", sizeof(Textsecure__PreKeySignalMessage), 6, textsecure__pre_key_signal_message__field_descriptors, textsecure__pre_key_signal_message__field_indices_by_name, 1, textsecure__pre_key_signal_message__number_ranges, (ProtobufCMessageInit) textsecure__pre_key_signal_message__init, NULL,NULL,NULL /* reserved[123] */ }; static const ProtobufCFieldDescriptor textsecure__key_exchange_message__field_descriptors[5] = { { "id", 1, PROTOBUF_C_LABEL_OPTIONAL, PROTOBUF_C_TYPE_UINT32, offsetof(Textsecure__KeyExchangeMessage, has_id), offsetof(Textsecure__KeyExchangeMessage, id), NULL, NULL, 0, /* flags */ 0,NULL,NULL /* reserved1,reserved2, etc */ }, { "baseKey", 2, PROTOBUF_C_LABEL_OPTIONAL, PROTOBUF_C_TYPE_BYTES, offsetof(Textsecure__KeyExchangeMessage, has_basekey), offsetof(Textsecure__KeyExchangeMessage, basekey), NULL, NULL, 0, /* flags */ 0,NULL,NULL /* reserved1,reserved2, etc */ }, { "ratchetKey", 3, PROTOBUF_C_LABEL_OPTIONAL, PROTOBUF_C_TYPE_BYTES, offsetof(Textsecure__KeyExchangeMessage, has_ratchetkey), offsetof(Textsecure__KeyExchangeMessage, ratchetkey), NULL, NULL, 0, /* flags */ 0,NULL,NULL /* reserved1,reserved2, etc */ }, { "identityKey", 4, PROTOBUF_C_LABEL_OPTIONAL, PROTOBUF_C_TYPE_BYTES, offsetof(Textsecure__KeyExchangeMessage, has_identitykey), offsetof(Textsecure__KeyExchangeMessage, identitykey), NULL, NULL, 0, /* flags */ 0,NULL,NULL /* reserved1,reserved2, etc */ }, { "baseKeySignature", 5, PROTOBUF_C_LABEL_OPTIONAL, PROTOBUF_C_TYPE_BYTES, offsetof(Textsecure__KeyExchangeMessage, has_basekeysignature), offsetof(Textsecure__KeyExchangeMessage, basekeysignature), NULL, NULL, 0, /* flags */ 0,NULL,NULL /* reserved1,reserved2, etc */ }, }; static const unsigned textsecure__key_exchange_message__field_indices_by_name[] = { 1, /* field[1] = baseKey */ 4, /* field[4] = baseKeySignature */ 0, /* field[0] = id */ 3, /* field[3] = identityKey */ 2, /* field[2] = ratchetKey */ }; static const ProtobufCIntRange textsecure__key_exchange_message__number_ranges[1 + 1] = { { 1, 0 }, { 0, 5 } }; const ProtobufCMessageDescriptor textsecure__key_exchange_message__descriptor = { PROTOBUF_C__MESSAGE_DESCRIPTOR_MAGIC, "textsecure.KeyExchangeMessage", "KeyExchangeMessage", "Textsecure__KeyExchangeMessage", "textsecure", sizeof(Textsecure__KeyExchangeMessage), 5, textsecure__key_exchange_message__field_descriptors, textsecure__key_exchange_message__field_indices_by_name, 1, textsecure__key_exchange_message__number_ranges, (ProtobufCMessageInit) textsecure__key_exchange_message__init, NULL,NULL,NULL /* reserved[123] */ }; static const ProtobufCFieldDescriptor textsecure__sender_key_message__field_descriptors[3] = { { "id", 1, PROTOBUF_C_LABEL_OPTIONAL, PROTOBUF_C_TYPE_UINT32, offsetof(Textsecure__SenderKeyMessage, has_id), offsetof(Textsecure__SenderKeyMessage, id), NULL, NULL, 0, /* flags */ 0,NULL,NULL /* reserved1,reserved2, etc */ }, { "iteration", 2, PROTOBUF_C_LABEL_OPTIONAL, PROTOBUF_C_TYPE_UINT32, offsetof(Textsecure__SenderKeyMessage, has_iteration), offsetof(Textsecure__SenderKeyMessage, iteration), NULL, NULL, 0, /* flags */ 0,NULL,NULL /* reserved1,reserved2, etc */ }, { "ciphertext", 3, PROTOBUF_C_LABEL_OPTIONAL, PROTOBUF_C_TYPE_BYTES, offsetof(Textsecure__SenderKeyMessage, has_ciphertext), offsetof(Textsecure__SenderKeyMessage, ciphertext), NULL, NULL, 0, /* flags */ 0,NULL,NULL /* reserved1,reserved2, etc */ }, }; static const unsigned textsecure__sender_key_message__field_indices_by_name[] = { 2, /* field[2] = ciphertext */ 0, /* field[0] = id */ 1, /* field[1] = iteration */ }; static const ProtobufCIntRange textsecure__sender_key_message__number_ranges[1 + 1] = { { 1, 0 }, { 0, 3 } }; const ProtobufCMessageDescriptor textsecure__sender_key_message__descriptor = { PROTOBUF_C__MESSAGE_DESCRIPTOR_MAGIC, "textsecure.SenderKeyMessage", "SenderKeyMessage", "Textsecure__SenderKeyMessage", "textsecure", sizeof(Textsecure__SenderKeyMessage), 3, textsecure__sender_key_message__field_descriptors, textsecure__sender_key_message__field_indices_by_name, 1, textsecure__sender_key_message__number_ranges, (ProtobufCMessageInit) textsecure__sender_key_message__init, NULL,NULL,NULL /* reserved[123] */ }; static const ProtobufCFieldDescriptor textsecure__sender_key_distribution_message__field_descriptors[4] = { { "id", 1, PROTOBUF_C_LABEL_OPTIONAL, PROTOBUF_C_TYPE_UINT32, offsetof(Textsecure__SenderKeyDistributionMessage, has_id), offsetof(Textsecure__SenderKeyDistributionMessage, id), NULL, NULL, 0, /* flags */ 0,NULL,NULL /* reserved1,reserved2, etc */ }, { "iteration", 2, PROTOBUF_C_LABEL_OPTIONAL, PROTOBUF_C_TYPE_UINT32, offsetof(Textsecure__SenderKeyDistributionMessage, has_iteration), offsetof(Textsecure__SenderKeyDistributionMessage, iteration), NULL, NULL, 0, /* flags */ 0,NULL,NULL /* reserved1,reserved2, etc */ }, { "chainKey", 3, PROTOBUF_C_LABEL_OPTIONAL, PROTOBUF_C_TYPE_BYTES, offsetof(Textsecure__SenderKeyDistributionMessage, has_chainkey), offsetof(Textsecure__SenderKeyDistributionMessage, chainkey), NULL, NULL, 0, /* flags */ 0,NULL,NULL /* reserved1,reserved2, etc */ }, { "signingKey", 4, PROTOBUF_C_LABEL_OPTIONAL, PROTOBUF_C_TYPE_BYTES, offsetof(Textsecure__SenderKeyDistributionMessage, has_signingkey), offsetof(Textsecure__SenderKeyDistributionMessage, signingkey), NULL, NULL, 0, /* flags */ 0,NULL,NULL /* reserved1,reserved2, etc */ }, }; static const unsigned textsecure__sender_key_distribution_message__field_indices_by_name[] = { 2, /* field[2] = chainKey */ 0, /* field[0] = id */ 1, /* field[1] = iteration */ 3, /* field[3] = signingKey */ }; static const ProtobufCIntRange textsecure__sender_key_distribution_message__number_ranges[1 + 1] = { { 1, 0 }, { 0, 4 } }; const ProtobufCMessageDescriptor textsecure__sender_key_distribution_message__descriptor = { PROTOBUF_C__MESSAGE_DESCRIPTOR_MAGIC, "textsecure.SenderKeyDistributionMessage", "SenderKeyDistributionMessage", "Textsecure__SenderKeyDistributionMessage", "textsecure", sizeof(Textsecure__SenderKeyDistributionMessage), 4, textsecure__sender_key_distribution_message__field_descriptors, textsecure__sender_key_distribution_message__field_indices_by_name, 1, textsecure__sender_key_distribution_message__number_ranges, (ProtobufCMessageInit) textsecure__sender_key_distribution_message__init, NULL,NULL,NULL /* reserved[123] */ }; static const ProtobufCFieldDescriptor textsecure__device_consistency_code_message__field_descriptors[2] = { { "generation", 1, PROTOBUF_C_LABEL_OPTIONAL, PROTOBUF_C_TYPE_UINT32, offsetof(Textsecure__DeviceConsistencyCodeMessage, has_generation), offsetof(Textsecure__DeviceConsistencyCodeMessage, generation), NULL, NULL, 0, /* flags */ 0,NULL,NULL /* reserved1,reserved2, etc */ }, { "signature", 2, PROTOBUF_C_LABEL_OPTIONAL, PROTOBUF_C_TYPE_BYTES, offsetof(Textsecure__DeviceConsistencyCodeMessage, has_signature), offsetof(Textsecure__DeviceConsistencyCodeMessage, signature), NULL, NULL, 0, /* flags */ 0,NULL,NULL /* reserved1,reserved2, etc */ }, }; static const unsigned textsecure__device_consistency_code_message__field_indices_by_name[] = { 0, /* field[0] = generation */ 1, /* field[1] = signature */ }; static const ProtobufCIntRange textsecure__device_consistency_code_message__number_ranges[1 + 1] = { { 1, 0 }, { 0, 2 } }; const ProtobufCMessageDescriptor textsecure__device_consistency_code_message__descriptor = { PROTOBUF_C__MESSAGE_DESCRIPTOR_MAGIC, "textsecure.DeviceConsistencyCodeMessage", "DeviceConsistencyCodeMessage", "Textsecure__DeviceConsistencyCodeMessage", "textsecure", sizeof(Textsecure__DeviceConsistencyCodeMessage), 2, textsecure__device_consistency_code_message__field_descriptors, textsecure__device_consistency_code_message__field_indices_by_name, 1, textsecure__device_consistency_code_message__number_ranges, (ProtobufCMessageInit) textsecure__device_consistency_code_message__init, NULL,NULL,NULL /* reserved[123] */ }; libsignal-protocol-c-2.3.3/src/WhisperTextProtocol.pb-c.h000066400000000000000000000302471363751346500233550ustar00rootroot00000000000000/* Generated by the protocol buffer compiler. DO NOT EDIT! */ /* Generated from: WhisperTextProtocol.proto */ #ifndef PROTOBUF_C_WhisperTextProtocol_2eproto__INCLUDED #define PROTOBUF_C_WhisperTextProtocol_2eproto__INCLUDED #include PROTOBUF_C__BEGIN_DECLS #if PROTOBUF_C_VERSION_NUMBER < 1000000 # error This file was generated by a newer version of protoc-c which is incompatible with your libprotobuf-c headers. Please update your headers. #elif 1002001 < PROTOBUF_C_MIN_COMPILER_VERSION # error This file was generated by an older version of protoc-c which is incompatible with your libprotobuf-c headers. Please regenerate this file with a newer version of protoc-c. #endif typedef struct _Textsecure__SignalMessage Textsecure__SignalMessage; typedef struct _Textsecure__PreKeySignalMessage Textsecure__PreKeySignalMessage; typedef struct _Textsecure__KeyExchangeMessage Textsecure__KeyExchangeMessage; typedef struct _Textsecure__SenderKeyMessage Textsecure__SenderKeyMessage; typedef struct _Textsecure__SenderKeyDistributionMessage Textsecure__SenderKeyDistributionMessage; typedef struct _Textsecure__DeviceConsistencyCodeMessage Textsecure__DeviceConsistencyCodeMessage; /* --- enums --- */ /* --- messages --- */ struct _Textsecure__SignalMessage { ProtobufCMessage base; protobuf_c_boolean has_ratchetkey; ProtobufCBinaryData ratchetkey; protobuf_c_boolean has_counter; uint32_t counter; protobuf_c_boolean has_previouscounter; uint32_t previouscounter; protobuf_c_boolean has_ciphertext; ProtobufCBinaryData ciphertext; }; #define TEXTSECURE__SIGNAL_MESSAGE__INIT \ { PROTOBUF_C_MESSAGE_INIT (&textsecure__signal_message__descriptor) \ , 0,{0,NULL}, 0,0, 0,0, 0,{0,NULL} } struct _Textsecure__PreKeySignalMessage { ProtobufCMessage base; protobuf_c_boolean has_registrationid; uint32_t registrationid; protobuf_c_boolean has_prekeyid; uint32_t prekeyid; protobuf_c_boolean has_signedprekeyid; uint32_t signedprekeyid; protobuf_c_boolean has_basekey; ProtobufCBinaryData basekey; protobuf_c_boolean has_identitykey; ProtobufCBinaryData identitykey; /* * SignalMessage */ protobuf_c_boolean has_message; ProtobufCBinaryData message; }; #define TEXTSECURE__PRE_KEY_SIGNAL_MESSAGE__INIT \ { PROTOBUF_C_MESSAGE_INIT (&textsecure__pre_key_signal_message__descriptor) \ , 0,0, 0,0, 0,0, 0,{0,NULL}, 0,{0,NULL}, 0,{0,NULL} } struct _Textsecure__KeyExchangeMessage { ProtobufCMessage base; protobuf_c_boolean has_id; uint32_t id; protobuf_c_boolean has_basekey; ProtobufCBinaryData basekey; protobuf_c_boolean has_ratchetkey; ProtobufCBinaryData ratchetkey; protobuf_c_boolean has_identitykey; ProtobufCBinaryData identitykey; protobuf_c_boolean has_basekeysignature; ProtobufCBinaryData basekeysignature; }; #define TEXTSECURE__KEY_EXCHANGE_MESSAGE__INIT \ { PROTOBUF_C_MESSAGE_INIT (&textsecure__key_exchange_message__descriptor) \ , 0,0, 0,{0,NULL}, 0,{0,NULL}, 0,{0,NULL}, 0,{0,NULL} } struct _Textsecure__SenderKeyMessage { ProtobufCMessage base; protobuf_c_boolean has_id; uint32_t id; protobuf_c_boolean has_iteration; uint32_t iteration; protobuf_c_boolean has_ciphertext; ProtobufCBinaryData ciphertext; }; #define TEXTSECURE__SENDER_KEY_MESSAGE__INIT \ { PROTOBUF_C_MESSAGE_INIT (&textsecure__sender_key_message__descriptor) \ , 0,0, 0,0, 0,{0,NULL} } struct _Textsecure__SenderKeyDistributionMessage { ProtobufCMessage base; protobuf_c_boolean has_id; uint32_t id; protobuf_c_boolean has_iteration; uint32_t iteration; protobuf_c_boolean has_chainkey; ProtobufCBinaryData chainkey; protobuf_c_boolean has_signingkey; ProtobufCBinaryData signingkey; }; #define TEXTSECURE__SENDER_KEY_DISTRIBUTION_MESSAGE__INIT \ { PROTOBUF_C_MESSAGE_INIT (&textsecure__sender_key_distribution_message__descriptor) \ , 0,0, 0,0, 0,{0,NULL}, 0,{0,NULL} } struct _Textsecure__DeviceConsistencyCodeMessage { ProtobufCMessage base; protobuf_c_boolean has_generation; uint32_t generation; protobuf_c_boolean has_signature; ProtobufCBinaryData signature; }; #define TEXTSECURE__DEVICE_CONSISTENCY_CODE_MESSAGE__INIT \ { PROTOBUF_C_MESSAGE_INIT (&textsecure__device_consistency_code_message__descriptor) \ , 0,0, 0,{0,NULL} } /* Textsecure__SignalMessage methods */ void textsecure__signal_message__init (Textsecure__SignalMessage *message); size_t textsecure__signal_message__get_packed_size (const Textsecure__SignalMessage *message); size_t textsecure__signal_message__pack (const Textsecure__SignalMessage *message, uint8_t *out); size_t textsecure__signal_message__pack_to_buffer (const Textsecure__SignalMessage *message, ProtobufCBuffer *buffer); Textsecure__SignalMessage * textsecure__signal_message__unpack (ProtobufCAllocator *allocator, size_t len, const uint8_t *data); void textsecure__signal_message__free_unpacked (Textsecure__SignalMessage *message, ProtobufCAllocator *allocator); /* Textsecure__PreKeySignalMessage methods */ void textsecure__pre_key_signal_message__init (Textsecure__PreKeySignalMessage *message); size_t textsecure__pre_key_signal_message__get_packed_size (const Textsecure__PreKeySignalMessage *message); size_t textsecure__pre_key_signal_message__pack (const Textsecure__PreKeySignalMessage *message, uint8_t *out); size_t textsecure__pre_key_signal_message__pack_to_buffer (const Textsecure__PreKeySignalMessage *message, ProtobufCBuffer *buffer); Textsecure__PreKeySignalMessage * textsecure__pre_key_signal_message__unpack (ProtobufCAllocator *allocator, size_t len, const uint8_t *data); void textsecure__pre_key_signal_message__free_unpacked (Textsecure__PreKeySignalMessage *message, ProtobufCAllocator *allocator); /* Textsecure__KeyExchangeMessage methods */ void textsecure__key_exchange_message__init (Textsecure__KeyExchangeMessage *message); size_t textsecure__key_exchange_message__get_packed_size (const Textsecure__KeyExchangeMessage *message); size_t textsecure__key_exchange_message__pack (const Textsecure__KeyExchangeMessage *message, uint8_t *out); size_t textsecure__key_exchange_message__pack_to_buffer (const Textsecure__KeyExchangeMessage *message, ProtobufCBuffer *buffer); Textsecure__KeyExchangeMessage * textsecure__key_exchange_message__unpack (ProtobufCAllocator *allocator, size_t len, const uint8_t *data); void textsecure__key_exchange_message__free_unpacked (Textsecure__KeyExchangeMessage *message, ProtobufCAllocator *allocator); /* Textsecure__SenderKeyMessage methods */ void textsecure__sender_key_message__init (Textsecure__SenderKeyMessage *message); size_t textsecure__sender_key_message__get_packed_size (const Textsecure__SenderKeyMessage *message); size_t textsecure__sender_key_message__pack (const Textsecure__SenderKeyMessage *message, uint8_t *out); size_t textsecure__sender_key_message__pack_to_buffer (const Textsecure__SenderKeyMessage *message, ProtobufCBuffer *buffer); Textsecure__SenderKeyMessage * textsecure__sender_key_message__unpack (ProtobufCAllocator *allocator, size_t len, const uint8_t *data); void textsecure__sender_key_message__free_unpacked (Textsecure__SenderKeyMessage *message, ProtobufCAllocator *allocator); /* Textsecure__SenderKeyDistributionMessage methods */ void textsecure__sender_key_distribution_message__init (Textsecure__SenderKeyDistributionMessage *message); size_t textsecure__sender_key_distribution_message__get_packed_size (const Textsecure__SenderKeyDistributionMessage *message); size_t textsecure__sender_key_distribution_message__pack (const Textsecure__SenderKeyDistributionMessage *message, uint8_t *out); size_t textsecure__sender_key_distribution_message__pack_to_buffer (const Textsecure__SenderKeyDistributionMessage *message, ProtobufCBuffer *buffer); Textsecure__SenderKeyDistributionMessage * textsecure__sender_key_distribution_message__unpack (ProtobufCAllocator *allocator, size_t len, const uint8_t *data); void textsecure__sender_key_distribution_message__free_unpacked (Textsecure__SenderKeyDistributionMessage *message, ProtobufCAllocator *allocator); /* Textsecure__DeviceConsistencyCodeMessage methods */ void textsecure__device_consistency_code_message__init (Textsecure__DeviceConsistencyCodeMessage *message); size_t textsecure__device_consistency_code_message__get_packed_size (const Textsecure__DeviceConsistencyCodeMessage *message); size_t textsecure__device_consistency_code_message__pack (const Textsecure__DeviceConsistencyCodeMessage *message, uint8_t *out); size_t textsecure__device_consistency_code_message__pack_to_buffer (const Textsecure__DeviceConsistencyCodeMessage *message, ProtobufCBuffer *buffer); Textsecure__DeviceConsistencyCodeMessage * textsecure__device_consistency_code_message__unpack (ProtobufCAllocator *allocator, size_t len, const uint8_t *data); void textsecure__device_consistency_code_message__free_unpacked (Textsecure__DeviceConsistencyCodeMessage *message, ProtobufCAllocator *allocator); /* --- per-message closures --- */ typedef void (*Textsecure__SignalMessage_Closure) (const Textsecure__SignalMessage *message, void *closure_data); typedef void (*Textsecure__PreKeySignalMessage_Closure) (const Textsecure__PreKeySignalMessage *message, void *closure_data); typedef void (*Textsecure__KeyExchangeMessage_Closure) (const Textsecure__KeyExchangeMessage *message, void *closure_data); typedef void (*Textsecure__SenderKeyMessage_Closure) (const Textsecure__SenderKeyMessage *message, void *closure_data); typedef void (*Textsecure__SenderKeyDistributionMessage_Closure) (const Textsecure__SenderKeyDistributionMessage *message, void *closure_data); typedef void (*Textsecure__DeviceConsistencyCodeMessage_Closure) (const Textsecure__DeviceConsistencyCodeMessage *message, void *closure_data); /* --- services --- */ /* --- descriptors --- */ extern const ProtobufCMessageDescriptor textsecure__signal_message__descriptor; extern const ProtobufCMessageDescriptor textsecure__pre_key_signal_message__descriptor; extern const ProtobufCMessageDescriptor textsecure__key_exchange_message__descriptor; extern const ProtobufCMessageDescriptor textsecure__sender_key_message__descriptor; extern const ProtobufCMessageDescriptor textsecure__sender_key_distribution_message__descriptor; extern const ProtobufCMessageDescriptor textsecure__device_consistency_code_message__descriptor; PROTOBUF_C__END_DECLS #endif /* PROTOBUF_C_WhisperTextProtocol_2eproto__INCLUDED */ libsignal-protocol-c-2.3.3/src/curve.c000066400000000000000000000351171363751346500176450ustar00rootroot00000000000000#include "curve.h" #include #include #include #include #include "curve25519/curve25519-donna.h" #include "curve25519/ed25519/additions/curve_sigs.h" #include "curve25519/ed25519/additions/generalized/gen_x.h" #include "curve25519/ed25519/tests/internal_fast_tests.h" #include "signal_protocol_internal.h" #include "signal_utarray.h" #define DJB_TYPE 0x05 #define DJB_KEY_LEN 32 #define VRF_VERIFY_LEN 32 struct ec_public_key { signal_type_base base; uint8_t data[DJB_KEY_LEN]; }; struct ec_private_key { signal_type_base base; uint8_t data[DJB_KEY_LEN]; }; struct ec_key_pair { signal_type_base base; ec_public_key *public_key; ec_private_key *private_key; }; struct ec_public_key_list { UT_array *values; }; int curve_internal_fast_tests(int silent) { if (all_fast_tests(silent) != 0) return SG_ERR_UNKNOWN; return 0; } int curve_decode_point(ec_public_key **public_key, const uint8_t *key_data, size_t key_len, signal_context *global_context) { ec_public_key *key = 0; if(key_len > 0 && key_data[0] != DJB_TYPE) { signal_log(global_context, SG_LOG_ERROR, "Invalid key type: %d", key_data[0]); return SG_ERR_INVALID_KEY; } if(key_len != DJB_KEY_LEN + 1) { signal_log(global_context, SG_LOG_ERROR, "Invalid key length: %d", key_len); return SG_ERR_INVALID_KEY; } key = malloc(sizeof(ec_public_key)); if(!key) { return SG_ERR_NOMEM; } SIGNAL_INIT(key, ec_public_key_destroy); memcpy(key->data, key_data + 1, DJB_KEY_LEN); *public_key = key; return 0; } int ec_public_key_compare(const ec_public_key *key1, const ec_public_key *key2) { if(key1 == key2) { return 0; } else if(key1 == 0 && key2 != 0) { return -1; } else if(key1 != 0 && key2 == 0) { return 1; } else { return signal_constant_memcmp(key1->data, key2->data, DJB_KEY_LEN); } } int ec_public_key_memcmp(const ec_public_key *key1, const ec_public_key *key2) { if(key1 == key2) { return 0; } else if(key1 == 0 && key2 != 0) { return -1; } else if(key1 != 0 && key2 == 0) { return 1; } else { return memcmp(key1->data, key2->data, DJB_KEY_LEN); } } int ec_public_key_serialize(signal_buffer **buffer, const ec_public_key *key) { signal_buffer *buf = 0; uint8_t *data = 0; if(!key) { return SG_ERR_INVAL; } buf = signal_buffer_alloc(sizeof(uint8_t) * (DJB_KEY_LEN + 1)); if(!buf) { return SG_ERR_NOMEM; } data = signal_buffer_data(buf); data[0] = DJB_TYPE; memcpy(data + 1, key->data, DJB_KEY_LEN); *buffer = buf; return 0; } int ec_public_key_serialize_protobuf(ProtobufCBinaryData *buffer, const ec_public_key *key) { size_t len = 0; uint8_t *data = 0; assert(buffer); assert(key); len = sizeof(uint8_t) * (DJB_KEY_LEN + 1); data = malloc(len); if(!data) { return SG_ERR_NOMEM; } data[0] = DJB_TYPE; memcpy(data + 1, key->data, DJB_KEY_LEN); buffer->data = data; buffer->len = len; return 0; } void ec_public_key_destroy(signal_type_base *type) { ec_public_key *public_key = (ec_public_key *)type; free(public_key); } int curve_decode_private_point(ec_private_key **private_key, const uint8_t *key_data, size_t key_len, signal_context *global_context) { ec_private_key *key = 0; if(key_len != DJB_KEY_LEN) { signal_log(global_context, SG_LOG_ERROR, "Invalid key length: %d", key_len); return SG_ERR_INVALID_KEY; } key = malloc(sizeof(ec_private_key)); if(!key) { return SG_ERR_NOMEM; } SIGNAL_INIT(key, ec_private_key_destroy); memcpy(key->data, key_data, DJB_KEY_LEN); *private_key = key; return 0; } int ec_private_key_compare(const ec_private_key *key1, const ec_private_key *key2) { if(key1 == key2) { return 0; } else if(key1 == 0 && key2 != 0) { return -1; } else if(key1 != 0 && key2 == 0) { return 1; } else { return signal_constant_memcmp(key1->data, key2->data, DJB_KEY_LEN); } } int ec_private_key_serialize(signal_buffer **buffer, const ec_private_key *key) { signal_buffer *buf = 0; uint8_t *data = 0 ; buf = signal_buffer_alloc(sizeof(uint8_t) * DJB_KEY_LEN); if(!buf) { return SG_ERR_NOMEM; } data = signal_buffer_data(buf); memcpy(data, key->data, DJB_KEY_LEN); *buffer = buf; return 0; } int ec_private_key_serialize_protobuf(ProtobufCBinaryData *buffer, const ec_private_key *key) { size_t len = 0; uint8_t *data = 0; assert(buffer); assert(key); len = sizeof(uint8_t) * DJB_KEY_LEN; data = malloc(len); if(!data) { return SG_ERR_NOMEM; } memcpy(data, key->data, DJB_KEY_LEN); buffer->data = data; buffer->len = len; return 0; } void ec_private_key_destroy(signal_type_base *type) { ec_private_key *private_key = (ec_private_key *)type; signal_explicit_bzero(private_key, sizeof(ec_private_key)); free(private_key); } int ec_key_pair_create(ec_key_pair **key_pair, ec_public_key *public_key, ec_private_key *private_key) { ec_key_pair *result = malloc(sizeof(ec_key_pair)); if(!result) { return SG_ERR_NOMEM; } SIGNAL_INIT(result, ec_key_pair_destroy); result->public_key = public_key; SIGNAL_REF(public_key); result->private_key = private_key; SIGNAL_REF(private_key); *key_pair = result; return 0; } ec_public_key *ec_key_pair_get_public(const ec_key_pair *key_pair) { return key_pair->public_key; } ec_private_key *ec_key_pair_get_private(const ec_key_pair *key_pair) { return key_pair->private_key; } void ec_key_pair_destroy(signal_type_base *type) { ec_key_pair *key_pair = (ec_key_pair *)type; SIGNAL_UNREF(key_pair->public_key); SIGNAL_UNREF(key_pair->private_key); free(key_pair); } int curve_generate_private_key(signal_context *context, ec_private_key **private_key) { int result = 0; ec_private_key *key = 0; assert(context); key = malloc(sizeof(ec_private_key)); if(!key) { result = SG_ERR_NOMEM; goto complete; } SIGNAL_INIT(key, ec_private_key_destroy); result = signal_crypto_random(context, key->data, DJB_KEY_LEN); if(result < 0) { goto complete; } key->data[0] &= 248; key->data[31] &= 127; key->data[31] |= 64; complete: if(result < 0) { if(key) { SIGNAL_UNREF(key); } } else { *private_key = key; } return result; } int curve_generate_public_key(ec_public_key **public_key, const ec_private_key *private_key) { static const uint8_t basepoint[32] = {9}; int result = 0; ec_public_key *key = malloc(sizeof(ec_public_key)); if(!key) { return SG_ERR_NOMEM; } SIGNAL_INIT(key, ec_public_key_destroy); result = curve25519_donna(key->data, private_key->data, basepoint); if(result == 0) { *public_key = key; return 0; } else { if(key) { SIGNAL_UNREF(key); } return SG_ERR_UNKNOWN; } } int curve_generate_key_pair(signal_context *context, ec_key_pair **key_pair) { int result = 0; ec_key_pair *pair_result = 0; ec_private_key *key_private = 0; ec_public_key *key_public = 0; assert(context); result = curve_generate_private_key(context, &key_private); if(result < 0) { goto complete; } result = curve_generate_public_key(&key_public, key_private); if(result < 0) { goto complete; } result = ec_key_pair_create(&pair_result, key_public, key_private); if(result < 0) { goto complete; } complete: if(key_public) { SIGNAL_UNREF(key_public); } if(key_private) { SIGNAL_UNREF(key_private); } if(result < 0) { if(pair_result) { SIGNAL_UNREF(pair_result); } } else { *key_pair = pair_result; } return result; } ec_public_key_list *ec_public_key_list_alloc() { int result = 0; ec_public_key_list *list = malloc(sizeof(ec_public_key_list)); if(!list) { result = SG_ERR_NOMEM; goto complete; } memset(list, 0, sizeof(ec_public_key_list)); utarray_new(list->values, &ut_ptr_icd); complete: if(result < 0) { if(list) { free(list); } return 0; } else { return list; } } ec_public_key_list *ec_public_key_list_copy(const ec_public_key_list *list) { int result = 0; ec_public_key_list *result_list = 0; unsigned int size; unsigned int i; ec_public_key **p; result_list = ec_public_key_list_alloc(); if(!result_list) { result = SG_ERR_NOMEM; goto complete; } size = utarray_len(list->values); utarray_reserve(result_list->values, size); for (i = 0; i < size; i++) { p = (ec_public_key **)utarray_eltptr(list->values, i); result = ec_public_key_list_push_back(result_list, *p); if(result < 0) { goto complete; } } complete: if(result < 0) { if(result_list) { ec_public_key_list_free(result_list); } return 0; } else { return result_list; } } int ec_public_key_list_push_back(ec_public_key_list *list, ec_public_key *value) { int result = 0; assert(list); assert(value); utarray_push_back(list->values, &value); SIGNAL_REF(value); complete: return result; } unsigned int ec_public_key_list_size(const ec_public_key_list *list) { assert(list); return utarray_len(list->values); } ec_public_key *ec_public_key_list_at(const ec_public_key_list *list, unsigned int index) { ec_public_key **value = 0; assert(list); assert(index < utarray_len(list->values)); value = (ec_public_key **)utarray_eltptr(list->values, index); assert(*value); return *value; } int ec_public_key_list_sort_comparator(const void *a, const void *b) { const ec_public_key *key1 = *((const ec_public_key **)a); const ec_public_key *key2 = *((const ec_public_key **)b); return ec_public_key_memcmp(key1, key2); } void ec_public_key_list_sort(ec_public_key_list *list) { assert(list); utarray_sort(list->values, ec_public_key_list_sort_comparator); } void ec_public_key_list_free(ec_public_key_list *list) { unsigned int size; unsigned int i; ec_public_key **p; if(list) { size = utarray_len(list->values); for (i = 0; i < size; i++) { p = (ec_public_key **)utarray_eltptr(list->values, i); SIGNAL_UNREF(*p); } utarray_free(list->values); free(list); } } int curve_calculate_agreement(uint8_t **shared_key_data, const ec_public_key *public_key, const ec_private_key *private_key) { uint8_t *key = 0; int result = 0; if(!public_key || !private_key) { return SG_ERR_INVALID_KEY; } key = malloc(DJB_KEY_LEN); if(!key) { return SG_ERR_NOMEM; } result = curve25519_donna(key, private_key->data, public_key->data); if(result == 0) { *shared_key_data = key; return DJB_KEY_LEN; } else { if(key) { free(key); } return SG_ERR_UNKNOWN; } } int curve_verify_signature(const ec_public_key *signing_key, const uint8_t *message_data, size_t message_len, const uint8_t *signature_data, size_t signature_len) { if(signature_len != CURVE_SIGNATURE_LEN) { return SG_ERR_INVAL; } return curve25519_verify(signature_data, signing_key->data, message_data, message_len) == 0; } int curve_calculate_signature(signal_context *context, signal_buffer **signature, const ec_private_key *signing_key, const uint8_t *message_data, size_t message_len) { int result = 0; uint8_t random_data[CURVE_SIGNATURE_LEN]; signal_buffer *buffer = 0; result = signal_crypto_random(context, random_data, sizeof(random_data)); if(result < 0) { goto complete; } buffer = signal_buffer_alloc(CURVE_SIGNATURE_LEN); if(!buffer) { result = SG_ERR_NOMEM; goto complete; } result = curve25519_sign(signal_buffer_data(buffer), signing_key->data, message_data, message_len, random_data); complete: if(result < 0) { if(buffer) { signal_buffer_free(buffer); } } else { *signature = buffer; } return result; } int curve_verify_vrf_signature(signal_context *context, signal_buffer **vrf_output, const ec_public_key *signing_key, const uint8_t *message_data, size_t message_len, const uint8_t *signature_data, size_t signature_len) { int result = 0; signal_buffer *buffer = 0; if(!signing_key) { return SG_ERR_INVAL; } if(!message_data || !signature_data || signature_len != VRF_SIGNATURE_LEN) { signal_log(context, SG_LOG_ERROR, "Invalid message or signature format"); return SG_ERR_VRF_SIG_VERIF_FAILED; } buffer = signal_buffer_alloc(VRF_VERIFY_LEN); if(!buffer) { result = SG_ERR_NOMEM; goto complete; } result = generalized_xveddsa_25519_verify(signal_buffer_data(buffer), signature_data, signing_key->data, message_data, message_len, NULL, 0); if(result != 0) { signal_log(context, SG_LOG_ERROR, "Invalid signature"); result = SG_ERR_VRF_SIG_VERIF_FAILED; } complete: if(result < 0) { signal_buffer_free(buffer); } else { *vrf_output = buffer; } return result; } int curve_calculate_vrf_signature(signal_context *context, signal_buffer **signature, const ec_private_key *signing_key, const uint8_t *message_data, size_t message_len) { int result = 0; uint8_t random_data[64]; signal_buffer *buffer = 0; result = signal_crypto_random(context, random_data, sizeof(random_data)); if(result < 0) { goto complete; } buffer = signal_buffer_alloc(VRF_SIGNATURE_LEN); if(!buffer) { result = SG_ERR_NOMEM; goto complete; } result = generalized_xveddsa_25519_sign(signal_buffer_data(buffer), signing_key->data, message_data, message_len, random_data, NULL, 0); if(result != 0) { signal_log(context, SG_LOG_ERROR, "Signature failed!"); result = SG_ERR_UNKNOWN; } complete: if(result < 0) { signal_buffer_free(buffer); } else { *signature = buffer; } return result; } libsignal-protocol-c-2.3.3/src/curve.h000066400000000000000000000152411363751346500176460ustar00rootroot00000000000000#ifndef CURVE_H #define CURVE_H #include #include #include "signal_protocol_types.h" #ifdef __cplusplus extern "C" { #endif #define CURVE_SIGNATURE_LEN 64 #define VRF_SIGNATURE_LEN 96 int curve_internal_fast_tests(int silent); int curve_decode_point(ec_public_key **public_key, const uint8_t *key_data, size_t key_len, signal_context *global_context); int ec_public_key_compare(const ec_public_key *key1, const ec_public_key *key2); int ec_public_key_memcmp(const ec_public_key *key1, const ec_public_key *key2); /** * Serialize the public key into a buffer that can be stored. * The format of this data is compatible with the input format of * curve_decode_point(). * * @param buffer Pointer to a buffer that will be allocated by this function * and filled with the contents of the key. The caller is responsible for * freeing this buffer with signal_buffer_free(). * @param key Key to serialize * @return 0 on success, negative on failure */ int ec_public_key_serialize(signal_buffer **buffer, const ec_public_key *key); void ec_public_key_destroy(signal_type_base *type); int curve_decode_private_point(ec_private_key **private_key, const uint8_t *key_data, size_t key_len, signal_context *global_context); int ec_private_key_compare(const ec_private_key *key1, const ec_private_key *key2); /** * Serialize the private key into a buffer that can be stored. * The format of this data is compatible with the input format of * curve_decode_private_point(). * * @param buffer Pointer to a buffer that will be allocated by this function * and filled with the contents of the key. The caller is responsible for * freeing this buffer with signal_buffer_free(). * @param key Key to serialize * @return 0 on success, negative on failure */ int ec_private_key_serialize(signal_buffer **buffer, const ec_private_key *key); void ec_private_key_destroy(signal_type_base *type); int ec_key_pair_create(ec_key_pair **key_pair, ec_public_key *public_key, ec_private_key *private_key); ec_public_key *ec_key_pair_get_public(const ec_key_pair *key_pair); ec_private_key *ec_key_pair_get_private(const ec_key_pair *key_pair); void ec_key_pair_destroy(signal_type_base *type); int curve_generate_private_key(signal_context *context, ec_private_key **private_key); int curve_generate_public_key(ec_public_key **public_key, const ec_private_key *private_key); /** * Generates a Curve25519 keypair. * * @param key_pair Set to a randomly generated Curve25519 keypair on success. * @return 0 on success, negative on failure */ int curve_generate_key_pair(signal_context *context, ec_key_pair **key_pair); /** * Allocate a new ec_public_key list * * @return pointer to the allocated list, or 0 on failure */ ec_public_key_list *ec_public_key_list_alloc(void); /** * Copy an ec_public_key list * * @return pointer to the copy of the list, or 0 on failure */ ec_public_key_list *ec_public_key_list_copy(const ec_public_key_list *list); /** * Push a new value onto the end of the list * * @param list the list * @param value the value to push * @return 0 on success, negative on failure */ int ec_public_key_list_push_back(ec_public_key_list *list, ec_public_key *value); /** * Gets the size of the list. * * @param list the list * @return the size of the list */ unsigned int ec_public_key_list_size(const ec_public_key_list *list); /** * Gets the value of the element at a particular index in the list * * @param list the list * @param index the index within the list * @return the value */ ec_public_key *ec_public_key_list_at(const ec_public_key_list *list, unsigned int index); /** * Sorts the list based on a comparison of the key data. * * @param list the list */ void ec_public_key_list_sort(ec_public_key_list *list); /** * Free the ec_public_key list * @param list the list to free */ void ec_public_key_list_free(ec_public_key_list *list); /** * Calculates an ECDH agreement. * * @param shared_key_data Set to a 32-byte shared secret on success. * @param public_key The Curve25519 (typically remote party's) public key. * @param private_key The Curve25519 (typically yours) private key. * @return length of the shared secret on success, negative on failure */ int curve_calculate_agreement(uint8_t **shared_key_data, const ec_public_key *public_key, const ec_private_key *private_key); /** * Verify a Curve25519 signature. * * @param signing_key The Curve25519 public key the signature belongs to. * @param message_data The message that was signed. * @param message_len The length of the message that was signed. * @param signature_data The signature to verify. * @param signature_len The length of the signature to verify. * @return 1 if valid, 0 if invalid, negative on failure */ int curve_verify_signature(const ec_public_key *signing_key, const uint8_t *message_data, size_t message_len, const uint8_t *signature_data, size_t signature_len); /** * Calculates a Curve25519 signature. * * @param signature Set to a 64-byte signature on success. * @param signing_key The private Curve25519 key to create the signature with. * @param message_data The message to sign. * @param message_len The length of the message to sign. * @return 0 on success, negative on failure */ int curve_calculate_signature(signal_context *context, signal_buffer **signature, const ec_private_key *signing_key, const uint8_t *message_data, size_t message_len); /** * Verify a Unique Curve25519 signature. * * @param vrf_output Set to VRF output on success * @param signing_key The Curve25519 public key the unique signature belongs to. * @param message_data The message that was signed. * @param message_len The length of the message that was signed. * @param signature_data The signature to verify. * @param signature_len The length of the signature to verify. * @return 1 if valid, 0 if invalid, negative on failure */ int curve_verify_vrf_signature(signal_context *context, signal_buffer **vrf_output, const ec_public_key *signing_key, const uint8_t *message_data, size_t message_len, const uint8_t *signature_data, size_t signature_len); /** * Calculates a Unique Curve25519 signature. * * @param signature Set to a 96-byte signature on success. * @param signing_key The private Curve25519 key to create the signature with. * @param message_data The message to sign. * @param message_len The length of the message to sign. * @return 0 on success, negative on failure */ int curve_calculate_vrf_signature(signal_context *context, signal_buffer **signature, const ec_private_key *signing_key, const uint8_t *message_data, size_t message_len); #ifdef __cplusplus } #endif #endif /* CURVE_H */ libsignal-protocol-c-2.3.3/src/curve25519/000077500000000000000000000000001363751346500201005ustar00rootroot00000000000000libsignal-protocol-c-2.3.3/src/curve25519/CMakeLists.txt000066400000000000000000000062071363751346500226450ustar00rootroot00000000000000IF(CMAKE_COMPILER_IS_GNUCC OR CMAKE_C_COMPILER_ID MATCHES "Clang") SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wno-unused-variable -Wno-unused-function -Wno-shadow") ENDIF(CMAKE_COMPILER_IS_GNUCC OR CMAKE_C_COMPILER_ID MATCHES "Clang") IF(CMAKE_COMPILER_IS_GNUCC) SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wno-sign-compare") IF(GCC_WARN_SIGN_CONVERSION) SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wno-sign-conversion") ENDIF(GCC_WARN_SIGN_CONVERSION) ENDIF(CMAKE_COMPILER_IS_GNUCC) IF(CMAKE_C_COMPILER_ID MATCHES "Clang") SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wno-shorten-64-to-32") ENDIF(CMAKE_C_COMPILER_ID MATCHES "Clang") include_directories( ed25519/nacl_includes ed25519/additions ed25519/additions/generalized ed25519/sha512 ed25519/tests ed25519 ) set(curve25519_SRCS curve25519-donna.c ) set(ed25519_SRCS ed25519/fe_0.c ed25519/fe_1.c ed25519/fe_add.c ed25519/fe_cmov.c ed25519/fe_copy.c ed25519/fe_frombytes.c ed25519/fe_invert.c ed25519/fe_isnegative.c ed25519/fe_isnonzero.c ed25519/fe_mul.c ed25519/fe_neg.c ed25519/fe_pow22523.c ed25519/fe_sq.c ed25519/fe_sq2.c ed25519/fe_sub.c ed25519/fe_tobytes.c ed25519/ge_add.c ed25519/ge_double_scalarmult.c ed25519/ge_frombytes.c ed25519/ge_madd.c ed25519/ge_msub.c ed25519/ge_p1p1_to_p2.c ed25519/ge_p1p1_to_p3.c ed25519/ge_p2_0.c ed25519/ge_p2_dbl.c ed25519/ge_p3_0.c ed25519/ge_p3_dbl.c ed25519/ge_p3_to_cached.c ed25519/ge_p3_to_p2.c ed25519/ge_p3_tobytes.c ed25519/ge_precomp_0.c ed25519/ge_scalarmult_base.c ed25519/ge_sub.c ed25519/ge_tobytes.c ed25519/open.c ed25519/sc_muladd.c ed25519/sc_reduce.c ed25519/sign.c ed25519/additions/compare.c ed25519/additions/curve_sigs.c ed25519/additions/elligator.c ed25519/additions/fe_isequal.c ed25519/additions/fe_isreduced.c ed25519/additions/fe_mont_rhs.c ed25519/additions/fe_montx_to_edy.c ed25519/additions/fe_sqrt.c ed25519/additions/ge_isneutral.c ed25519/additions/ge_montx_to_p3.c ed25519/additions/ge_neg.c ed25519/additions/ge_p3_to_montx.c ed25519/additions/ge_scalarmult.c ed25519/additions/ge_scalarmult_cofactor.c ed25519/additions/keygen.c ed25519/additions/open_modified.c ed25519/additions/sc_clamp.c ed25519/additions/sc_cmov.c ed25519/additions/sc_neg.c ed25519/additions/sign_modified.c ed25519/additions/utility.c ed25519/additions/generalized/ge_p3_add.c ed25519/additions/generalized/gen_eddsa.c ed25519/additions/generalized/gen_labelset.c ed25519/additions/generalized/gen_veddsa.c ed25519/additions/generalized/gen_x.c ed25519/additions/generalized/point_isreduced.c ed25519/additions/generalized/sc_isreduced.c ed25519/additions/xeddsa.c ed25519/additions/zeroize.c ed25519/nacl_sha512/blocks.c ed25519/nacl_sha512/hash.c ed25519/tests/internal_fast_tests.c ) add_library(curve25519 OBJECT ${curve25519_SRCS} ${ed25519_SRCS}) # Add -fPIC flag if(BUILD_SHARED_LIBS) set_property(TARGET curve25519 PROPERTY POSITION_INDEPENDENT_CODE ON) endif() libsignal-protocol-c-2.3.3/src/curve25519/curve25519-donna.c000066400000000000000000000762741363751346500231130ustar00rootroot00000000000000/* Copyright 2008, Google Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are * met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the following disclaimer * in the documentation and/or other materials provided with the * distribution. * * Neither the name of Google Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * curve25519-donna: Curve25519 elliptic curve, public key function * * http://code.google.com/p/curve25519-donna/ * * Adam Langley * * Derived from public domain C code by Daniel J. Bernstein * * More information about curve25519 can be found here * http://cr.yp.to/ecdh.html * * djb's sample implementation of curve25519 is written in a special assembly * language called qhasm and uses the floating point registers. * * This is, almost, a clean room reimplementation from the curve25519 paper. It * uses many of the tricks described therein. Only the crecip function is taken * from the sample implementation. */ #include #include #ifdef _MSC_VER #define inline __inline #endif typedef uint8_t u8; typedef int32_t s32; typedef int64_t limb; /* Field element representation: * * Field elements are written as an array of signed, 64-bit limbs, least * significant first. The value of the field element is: * x[0] + 2^26·x[1] + x^51·x[2] + 2^102·x[3] + ... * * i.e. the limbs are 26, 25, 26, 25, ... bits wide. */ /* Sum two numbers: output += in */ static void fsum(limb *output, const limb *in) { unsigned i; for (i = 0; i < 10; i += 2) { output[0+i] = output[0+i] + in[0+i]; output[1+i] = output[1+i] + in[1+i]; } } /* Find the difference of two numbers: output = in - output * (note the order of the arguments!). */ static void fdifference(limb *output, const limb *in) { unsigned i; for (i = 0; i < 10; ++i) { output[i] = in[i] - output[i]; } } /* Multiply a number by a scalar: output = in * scalar */ static void fscalar_product(limb *output, const limb *in, const limb scalar) { unsigned i; for (i = 0; i < 10; ++i) { output[i] = in[i] * scalar; } } /* Multiply two numbers: output = in2 * in * * output must be distinct to both inputs. The inputs are reduced coefficient * form, the output is not. * * output[x] <= 14 * the largest product of the input limbs. */ static void fproduct(limb *output, const limb *in2, const limb *in) { output[0] = ((limb) ((s32) in2[0])) * ((s32) in[0]); output[1] = ((limb) ((s32) in2[0])) * ((s32) in[1]) + ((limb) ((s32) in2[1])) * ((s32) in[0]); output[2] = 2 * ((limb) ((s32) in2[1])) * ((s32) in[1]) + ((limb) ((s32) in2[0])) * ((s32) in[2]) + ((limb) ((s32) in2[2])) * ((s32) in[0]); output[3] = ((limb) ((s32) in2[1])) * ((s32) in[2]) + ((limb) ((s32) in2[2])) * ((s32) in[1]) + ((limb) ((s32) in2[0])) * ((s32) in[3]) + ((limb) ((s32) in2[3])) * ((s32) in[0]); output[4] = ((limb) ((s32) in2[2])) * ((s32) in[2]) + 2 * (((limb) ((s32) in2[1])) * ((s32) in[3]) + ((limb) ((s32) in2[3])) * ((s32) in[1])) + ((limb) ((s32) in2[0])) * ((s32) in[4]) + ((limb) ((s32) in2[4])) * ((s32) in[0]); output[5] = ((limb) ((s32) in2[2])) * ((s32) in[3]) + ((limb) ((s32) in2[3])) * ((s32) in[2]) + ((limb) ((s32) in2[1])) * ((s32) in[4]) + ((limb) ((s32) in2[4])) * ((s32) in[1]) + ((limb) ((s32) in2[0])) * ((s32) in[5]) + ((limb) ((s32) in2[5])) * ((s32) in[0]); output[6] = 2 * (((limb) ((s32) in2[3])) * ((s32) in[3]) + ((limb) ((s32) in2[1])) * ((s32) in[5]) + ((limb) ((s32) in2[5])) * ((s32) in[1])) + ((limb) ((s32) in2[2])) * ((s32) in[4]) + ((limb) ((s32) in2[4])) * ((s32) in[2]) + ((limb) ((s32) in2[0])) * ((s32) in[6]) + ((limb) ((s32) in2[6])) * ((s32) in[0]); output[7] = ((limb) ((s32) in2[3])) * ((s32) in[4]) + ((limb) ((s32) in2[4])) * ((s32) in[3]) + ((limb) ((s32) in2[2])) * ((s32) in[5]) + ((limb) ((s32) in2[5])) * ((s32) in[2]) + ((limb) ((s32) in2[1])) * ((s32) in[6]) + ((limb) ((s32) in2[6])) * ((s32) in[1]) + ((limb) ((s32) in2[0])) * ((s32) in[7]) + ((limb) ((s32) in2[7])) * ((s32) in[0]); output[8] = ((limb) ((s32) in2[4])) * ((s32) in[4]) + 2 * (((limb) ((s32) in2[3])) * ((s32) in[5]) + ((limb) ((s32) in2[5])) * ((s32) in[3]) + ((limb) ((s32) in2[1])) * ((s32) in[7]) + ((limb) ((s32) in2[7])) * ((s32) in[1])) + ((limb) ((s32) in2[2])) * ((s32) in[6]) + ((limb) ((s32) in2[6])) * ((s32) in[2]) + ((limb) ((s32) in2[0])) * ((s32) in[8]) + ((limb) ((s32) in2[8])) * ((s32) in[0]); output[9] = ((limb) ((s32) in2[4])) * ((s32) in[5]) + ((limb) ((s32) in2[5])) * ((s32) in[4]) + ((limb) ((s32) in2[3])) * ((s32) in[6]) + ((limb) ((s32) in2[6])) * ((s32) in[3]) + ((limb) ((s32) in2[2])) * ((s32) in[7]) + ((limb) ((s32) in2[7])) * ((s32) in[2]) + ((limb) ((s32) in2[1])) * ((s32) in[8]) + ((limb) ((s32) in2[8])) * ((s32) in[1]) + ((limb) ((s32) in2[0])) * ((s32) in[9]) + ((limb) ((s32) in2[9])) * ((s32) in[0]); output[10] = 2 * (((limb) ((s32) in2[5])) * ((s32) in[5]) + ((limb) ((s32) in2[3])) * ((s32) in[7]) + ((limb) ((s32) in2[7])) * ((s32) in[3]) + ((limb) ((s32) in2[1])) * ((s32) in[9]) + ((limb) ((s32) in2[9])) * ((s32) in[1])) + ((limb) ((s32) in2[4])) * ((s32) in[6]) + ((limb) ((s32) in2[6])) * ((s32) in[4]) + ((limb) ((s32) in2[2])) * ((s32) in[8]) + ((limb) ((s32) in2[8])) * ((s32) in[2]); output[11] = ((limb) ((s32) in2[5])) * ((s32) in[6]) + ((limb) ((s32) in2[6])) * ((s32) in[5]) + ((limb) ((s32) in2[4])) * ((s32) in[7]) + ((limb) ((s32) in2[7])) * ((s32) in[4]) + ((limb) ((s32) in2[3])) * ((s32) in[8]) + ((limb) ((s32) in2[8])) * ((s32) in[3]) + ((limb) ((s32) in2[2])) * ((s32) in[9]) + ((limb) ((s32) in2[9])) * ((s32) in[2]); output[12] = ((limb) ((s32) in2[6])) * ((s32) in[6]) + 2 * (((limb) ((s32) in2[5])) * ((s32) in[7]) + ((limb) ((s32) in2[7])) * ((s32) in[5]) + ((limb) ((s32) in2[3])) * ((s32) in[9]) + ((limb) ((s32) in2[9])) * ((s32) in[3])) + ((limb) ((s32) in2[4])) * ((s32) in[8]) + ((limb) ((s32) in2[8])) * ((s32) in[4]); output[13] = ((limb) ((s32) in2[6])) * ((s32) in[7]) + ((limb) ((s32) in2[7])) * ((s32) in[6]) + ((limb) ((s32) in2[5])) * ((s32) in[8]) + ((limb) ((s32) in2[8])) * ((s32) in[5]) + ((limb) ((s32) in2[4])) * ((s32) in[9]) + ((limb) ((s32) in2[9])) * ((s32) in[4]); output[14] = 2 * (((limb) ((s32) in2[7])) * ((s32) in[7]) + ((limb) ((s32) in2[5])) * ((s32) in[9]) + ((limb) ((s32) in2[9])) * ((s32) in[5])) + ((limb) ((s32) in2[6])) * ((s32) in[8]) + ((limb) ((s32) in2[8])) * ((s32) in[6]); output[15] = ((limb) ((s32) in2[7])) * ((s32) in[8]) + ((limb) ((s32) in2[8])) * ((s32) in[7]) + ((limb) ((s32) in2[6])) * ((s32) in[9]) + ((limb) ((s32) in2[9])) * ((s32) in[6]); output[16] = ((limb) ((s32) in2[8])) * ((s32) in[8]) + 2 * (((limb) ((s32) in2[7])) * ((s32) in[9]) + ((limb) ((s32) in2[9])) * ((s32) in[7])); output[17] = ((limb) ((s32) in2[8])) * ((s32) in[9]) + ((limb) ((s32) in2[9])) * ((s32) in[8]); output[18] = 2 * ((limb) ((s32) in2[9])) * ((s32) in[9]); } /* Reduce a long form to a short form by taking the input mod 2^255 - 19. * * On entry: |output[i]| < 14*2^54 * On exit: |output[0..8]| < 280*2^54 */ static void freduce_degree(limb *output) { /* Each of these shifts and adds ends up multiplying the value by 19. * * For output[0..8], the absolute entry value is < 14*2^54 and we add, at * most, 19*14*2^54 thus, on exit, |output[0..8]| < 280*2^54. */ output[8] += output[18] << 4; output[8] += output[18] << 1; output[8] += output[18]; output[7] += output[17] << 4; output[7] += output[17] << 1; output[7] += output[17]; output[6] += output[16] << 4; output[6] += output[16] << 1; output[6] += output[16]; output[5] += output[15] << 4; output[5] += output[15] << 1; output[5] += output[15]; output[4] += output[14] << 4; output[4] += output[14] << 1; output[4] += output[14]; output[3] += output[13] << 4; output[3] += output[13] << 1; output[3] += output[13]; output[2] += output[12] << 4; output[2] += output[12] << 1; output[2] += output[12]; output[1] += output[11] << 4; output[1] += output[11] << 1; output[1] += output[11]; output[0] += output[10] << 4; output[0] += output[10] << 1; output[0] += output[10]; } #if (-1 & 3) != 3 #error "This code only works on a two's complement system" #endif /* return v / 2^26, using only shifts and adds. * * On entry: v can take any value. */ static inline limb div_by_2_26(const limb v) { /* High word of v; no shift needed. */ const uint32_t highword = (uint32_t) (((uint64_t) v) >> 32); /* Set to all 1s if v was negative; else set to 0s. */ const int32_t sign = ((int32_t) highword) >> 31; /* Set to 0x3ffffff if v was negative; else set to 0. */ const int32_t roundoff = ((uint32_t) sign) >> 6; /* Should return v / (1<<26) */ return (v + roundoff) >> 26; } /* return v / (2^25), using only shifts and adds. * * On entry: v can take any value. */ static inline limb div_by_2_25(const limb v) { /* High word of v; no shift needed*/ const uint32_t highword = (uint32_t) (((uint64_t) v) >> 32); /* Set to all 1s if v was negative; else set to 0s. */ const int32_t sign = ((int32_t) highword) >> 31; /* Set to 0x1ffffff if v was negative; else set to 0. */ const int32_t roundoff = ((uint32_t) sign) >> 7; /* Should return v / (1<<25) */ return (v + roundoff) >> 25; } /* return v / (2^25), using only shifts and adds. * * On entry: v can take any value. */ static inline s32 div_s32_by_2_25(const s32 v) { const s32 roundoff = ((uint32_t)(v >> 31)) >> 7; return (v + roundoff) >> 25; } /* Reduce all coefficients of the short form input so that |x| < 2^26. * * On entry: |output[i]| < 280*2^54 */ static void freduce_coefficients(limb *output) { unsigned i; output[10] = 0; for (i = 0; i < 10; i += 2) { limb over = div_by_2_26(output[i]); /* The entry condition (that |output[i]| < 280*2^54) means that over is, at * most, 280*2^28 in the first iteration of this loop. This is added to the * next limb and we can approximate the resulting bound of that limb by * 281*2^54. */ output[i] -= over << 26; output[i+1] += over; /* For the first iteration, |output[i+1]| < 281*2^54, thus |over| < * 281*2^29. When this is added to the next limb, the resulting bound can * be approximated as 281*2^54. * * For subsequent iterations of the loop, 281*2^54 remains a conservative * bound and no overflow occurs. */ over = div_by_2_25(output[i+1]); output[i+1] -= over << 25; output[i+2] += over; } /* Now |output[10]| < 281*2^29 and all other coefficients are reduced. */ output[0] += output[10] << 4; output[0] += output[10] << 1; output[0] += output[10]; output[10] = 0; /* Now output[1..9] are reduced, and |output[0]| < 2^26 + 19*281*2^29 * So |over| will be no more than 2^16. */ { limb over = div_by_2_26(output[0]); output[0] -= over << 26; output[1] += over; } /* Now output[0,2..9] are reduced, and |output[1]| < 2^25 + 2^16 < 2^26. The * bound on |output[1]| is sufficient to meet our needs. */ } /* A helpful wrapper around fproduct: output = in * in2. * * On entry: |in[i]| < 2^27 and |in2[i]| < 2^27. * * output must be distinct to both inputs. The output is reduced degree * (indeed, one need only provide storage for 10 limbs) and |output[i]| < 2^26. */ static void fmul(limb *output, const limb *in, const limb *in2) { limb t[19]; fproduct(t, in, in2); /* |t[i]| < 14*2^54 */ freduce_degree(t); freduce_coefficients(t); /* |t[i]| < 2^26 */ memcpy(output, t, sizeof(limb) * 10); } /* Square a number: output = in**2 * * output must be distinct from the input. The inputs are reduced coefficient * form, the output is not. * * output[x] <= 14 * the largest product of the input limbs. */ static void fsquare_inner(limb *output, const limb *in) { output[0] = ((limb) ((s32) in[0])) * ((s32) in[0]); output[1] = 2 * ((limb) ((s32) in[0])) * ((s32) in[1]); output[2] = 2 * (((limb) ((s32) in[1])) * ((s32) in[1]) + ((limb) ((s32) in[0])) * ((s32) in[2])); output[3] = 2 * (((limb) ((s32) in[1])) * ((s32) in[2]) + ((limb) ((s32) in[0])) * ((s32) in[3])); output[4] = ((limb) ((s32) in[2])) * ((s32) in[2]) + 4 * ((limb) ((s32) in[1])) * ((s32) in[3]) + 2 * ((limb) ((s32) in[0])) * ((s32) in[4]); output[5] = 2 * (((limb) ((s32) in[2])) * ((s32) in[3]) + ((limb) ((s32) in[1])) * ((s32) in[4]) + ((limb) ((s32) in[0])) * ((s32) in[5])); output[6] = 2 * (((limb) ((s32) in[3])) * ((s32) in[3]) + ((limb) ((s32) in[2])) * ((s32) in[4]) + ((limb) ((s32) in[0])) * ((s32) in[6]) + 2 * ((limb) ((s32) in[1])) * ((s32) in[5])); output[7] = 2 * (((limb) ((s32) in[3])) * ((s32) in[4]) + ((limb) ((s32) in[2])) * ((s32) in[5]) + ((limb) ((s32) in[1])) * ((s32) in[6]) + ((limb) ((s32) in[0])) * ((s32) in[7])); output[8] = ((limb) ((s32) in[4])) * ((s32) in[4]) + 2 * (((limb) ((s32) in[2])) * ((s32) in[6]) + ((limb) ((s32) in[0])) * ((s32) in[8]) + 2 * (((limb) ((s32) in[1])) * ((s32) in[7]) + ((limb) ((s32) in[3])) * ((s32) in[5]))); output[9] = 2 * (((limb) ((s32) in[4])) * ((s32) in[5]) + ((limb) ((s32) in[3])) * ((s32) in[6]) + ((limb) ((s32) in[2])) * ((s32) in[7]) + ((limb) ((s32) in[1])) * ((s32) in[8]) + ((limb) ((s32) in[0])) * ((s32) in[9])); output[10] = 2 * (((limb) ((s32) in[5])) * ((s32) in[5]) + ((limb) ((s32) in[4])) * ((s32) in[6]) + ((limb) ((s32) in[2])) * ((s32) in[8]) + 2 * (((limb) ((s32) in[3])) * ((s32) in[7]) + ((limb) ((s32) in[1])) * ((s32) in[9]))); output[11] = 2 * (((limb) ((s32) in[5])) * ((s32) in[6]) + ((limb) ((s32) in[4])) * ((s32) in[7]) + ((limb) ((s32) in[3])) * ((s32) in[8]) + ((limb) ((s32) in[2])) * ((s32) in[9])); output[12] = ((limb) ((s32) in[6])) * ((s32) in[6]) + 2 * (((limb) ((s32) in[4])) * ((s32) in[8]) + 2 * (((limb) ((s32) in[5])) * ((s32) in[7]) + ((limb) ((s32) in[3])) * ((s32) in[9]))); output[13] = 2 * (((limb) ((s32) in[6])) * ((s32) in[7]) + ((limb) ((s32) in[5])) * ((s32) in[8]) + ((limb) ((s32) in[4])) * ((s32) in[9])); output[14] = 2 * (((limb) ((s32) in[7])) * ((s32) in[7]) + ((limb) ((s32) in[6])) * ((s32) in[8]) + 2 * ((limb) ((s32) in[5])) * ((s32) in[9])); output[15] = 2 * (((limb) ((s32) in[7])) * ((s32) in[8]) + ((limb) ((s32) in[6])) * ((s32) in[9])); output[16] = ((limb) ((s32) in[8])) * ((s32) in[8]) + 4 * ((limb) ((s32) in[7])) * ((s32) in[9]); output[17] = 2 * ((limb) ((s32) in[8])) * ((s32) in[9]); output[18] = 2 * ((limb) ((s32) in[9])) * ((s32) in[9]); } /* fsquare sets output = in^2. * * On entry: The |in| argument is in reduced coefficients form and |in[i]| < * 2^27. * * On exit: The |output| argument is in reduced coefficients form (indeed, one * need only provide storage for 10 limbs) and |out[i]| < 2^26. */ static void fsquare(limb *output, const limb *in) { limb t[19]; fsquare_inner(t, in); /* |t[i]| < 14*2^54 because the largest product of two limbs will be < * 2^(27+27) and fsquare_inner adds together, at most, 14 of those * products. */ freduce_degree(t); freduce_coefficients(t); /* |t[i]| < 2^26 */ memcpy(output, t, sizeof(limb) * 10); } /* Take a little-endian, 32-byte number and expand it into polynomial form */ static void fexpand(limb *output, const u8 *input) { #define F(n,start,shift,mask) \ output[n] = ((((limb) input[start + 0]) | \ ((limb) input[start + 1]) << 8 | \ ((limb) input[start + 2]) << 16 | \ ((limb) input[start + 3]) << 24) >> shift) & mask; F(0, 0, 0, 0x3ffffff); F(1, 3, 2, 0x1ffffff); F(2, 6, 3, 0x3ffffff); F(3, 9, 5, 0x1ffffff); F(4, 12, 6, 0x3ffffff); F(5, 16, 0, 0x1ffffff); F(6, 19, 1, 0x3ffffff); F(7, 22, 3, 0x1ffffff); F(8, 25, 4, 0x3ffffff); F(9, 28, 6, 0x1ffffff); #undef F } #if (-32 >> 1) != -16 #error "This code only works when >> does sign-extension on negative numbers" #endif /* s32_eq returns 0xffffffff iff a == b and zero otherwise. */ static s32 s32_eq(s32 a, s32 b) { a = ~(a ^ b); a &= a << 16; a &= a << 8; a &= a << 4; a &= a << 2; a &= a << 1; return a >> 31; } /* s32_gte returns 0xffffffff if a >= b and zero otherwise, where a and b are * both non-negative. */ static s32 s32_gte(s32 a, s32 b) { a -= b; /* a >= 0 iff a >= b. */ return ~(a >> 31); } /* Take a fully reduced polynomial form number and contract it into a * little-endian, 32-byte array. * * On entry: |input_limbs[i]| < 2^26 */ static void fcontract(u8 *output, limb *input_limbs) { int i; int j; s32 input[10]; s32 mask; /* |input_limbs[i]| < 2^26, so it's valid to convert to an s32. */ for (i = 0; i < 10; i++) { input[i] = input_limbs[i]; } for (j = 0; j < 2; ++j) { for (i = 0; i < 9; ++i) { if ((i & 1) == 1) { /* This calculation is a time-invariant way to make input[i] * non-negative by borrowing from the next-larger limb. */ const s32 mask = input[i] >> 31; const s32 carry = -((input[i] & mask) >> 25); input[i] = input[i] + (carry << 25); input[i+1] = input[i+1] - carry; } else { const s32 mask = input[i] >> 31; const s32 carry = -((input[i] & mask) >> 26); input[i] = input[i] + (carry << 26); input[i+1] = input[i+1] - carry; } } /* There's no greater limb for input[9] to borrow from, but we can multiply * by 19 and borrow from input[0], which is valid mod 2^255-19. */ { const s32 mask = input[9] >> 31; const s32 carry = -((input[9] & mask) >> 25); input[9] = input[9] + (carry << 25); input[0] = input[0] - (carry * 19); } /* After the first iteration, input[1..9] are non-negative and fit within * 25 or 26 bits, depending on position. However, input[0] may be * negative. */ } /* The first borrow-propagation pass above ended with every limb except (possibly) input[0] non-negative. If input[0] was negative after the first pass, then it was because of a carry from input[9]. On entry, input[9] < 2^26 so the carry was, at most, one, since (2**26-1) >> 25 = 1. Thus input[0] >= -19. In the second pass, each limb is decreased by at most one. Thus the second borrow-propagation pass could only have wrapped around to decrease input[0] again if the first pass left input[0] negative *and* input[1] through input[9] were all zero. In that case, input[1] is now 2^25 - 1, and this last borrow-propagation step will leave input[1] non-negative. */ { const s32 mask = input[0] >> 31; const s32 carry = -((input[0] & mask) >> 26); input[0] = input[0] + (carry << 26); input[1] = input[1] - carry; } /* All input[i] are now non-negative. However, there might be values between * 2^25 and 2^26 in a limb which is, nominally, 25 bits wide. */ for (j = 0; j < 2; j++) { for (i = 0; i < 9; i++) { if ((i & 1) == 1) { const s32 carry = input[i] >> 25; input[i] &= 0x1ffffff; input[i+1] += carry; } else { const s32 carry = input[i] >> 26; input[i] &= 0x3ffffff; input[i+1] += carry; } } { const s32 carry = input[9] >> 25; input[9] &= 0x1ffffff; input[0] += 19*carry; } } /* If the first carry-chain pass, just above, ended up with a carry from * input[9], and that caused input[0] to be out-of-bounds, then input[0] was * < 2^26 + 2*19, because the carry was, at most, two. * * If the second pass carried from input[9] again then input[0] is < 2*19 and * the input[9] -> input[0] carry didn't push input[0] out of bounds. */ /* It still remains the case that input might be between 2^255-19 and 2^255. * In this case, input[1..9] must take their maximum value and input[0] must * be >= (2^255-19) & 0x3ffffff, which is 0x3ffffed. */ mask = s32_gte(input[0], 0x3ffffed); for (i = 1; i < 10; i++) { if ((i & 1) == 1) { mask &= s32_eq(input[i], 0x1ffffff); } else { mask &= s32_eq(input[i], 0x3ffffff); } } /* mask is either 0xffffffff (if input >= 2^255-19) and zero otherwise. Thus * this conditionally subtracts 2^255-19. */ input[0] -= mask & 0x3ffffed; for (i = 1; i < 10; i++) { if ((i & 1) == 1) { input[i] -= mask & 0x1ffffff; } else { input[i] -= mask & 0x3ffffff; } } input[1] <<= 2; input[2] <<= 3; input[3] <<= 5; input[4] <<= 6; input[6] <<= 1; input[7] <<= 3; input[8] <<= 4; input[9] <<= 6; #define F(i, s) \ output[s+0] |= input[i] & 0xff; \ output[s+1] = (input[i] >> 8) & 0xff; \ output[s+2] = (input[i] >> 16) & 0xff; \ output[s+3] = (input[i] >> 24) & 0xff; output[0] = 0; output[16] = 0; F(0,0); F(1,3); F(2,6); F(3,9); F(4,12); F(5,16); F(6,19); F(7,22); F(8,25); F(9,28); #undef F } /* 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 * * On entry and exit, the absolute value of the limbs of all inputs and outputs * are < 2^26. */ static void fmonty(limb *x2, limb *z2, /* output 2Q */ limb *x3, limb *z3, /* output Q + Q' */ limb *x, limb *z, /* input Q */ limb *xprime, limb *zprime, /* input Q' */ const limb *qmqp /* input Q - Q' */) { limb origx[10], origxprime[10], zzz[19], xx[19], zz[19], xxprime[19], zzprime[19], zzzprime[19], xxxprime[19]; memcpy(origx, x, 10 * sizeof(limb)); fsum(x, z); /* |x[i]| < 2^27 */ fdifference(z, origx); /* does x - z */ /* |z[i]| < 2^27 */ memcpy(origxprime, xprime, sizeof(limb) * 10); fsum(xprime, zprime); /* |xprime[i]| < 2^27 */ fdifference(zprime, origxprime); /* |zprime[i]| < 2^27 */ fproduct(xxprime, xprime, z); /* |xxprime[i]| < 14*2^54: the largest product of two limbs will be < * 2^(27+27) and fproduct adds together, at most, 14 of those products. * (Approximating that to 2^58 doesn't work out.) */ fproduct(zzprime, x, zprime); /* |zzprime[i]| < 14*2^54 */ freduce_degree(xxprime); freduce_coefficients(xxprime); /* |xxprime[i]| < 2^26 */ freduce_degree(zzprime); freduce_coefficients(zzprime); /* |zzprime[i]| < 2^26 */ memcpy(origxprime, xxprime, sizeof(limb) * 10); fsum(xxprime, zzprime); /* |xxprime[i]| < 2^27 */ fdifference(zzprime, origxprime); /* |zzprime[i]| < 2^27 */ fsquare(xxxprime, xxprime); /* |xxxprime[i]| < 2^26 */ fsquare(zzzprime, zzprime); /* |zzzprime[i]| < 2^26 */ fproduct(zzprime, zzzprime, qmqp); /* |zzprime[i]| < 14*2^52 */ freduce_degree(zzprime); freduce_coefficients(zzprime); /* |zzprime[i]| < 2^26 */ memcpy(x3, xxxprime, sizeof(limb) * 10); memcpy(z3, zzprime, sizeof(limb) * 10); fsquare(xx, x); /* |xx[i]| < 2^26 */ fsquare(zz, z); /* |zz[i]| < 2^26 */ fproduct(x2, xx, zz); /* |x2[i]| < 14*2^52 */ freduce_degree(x2); freduce_coefficients(x2); /* |x2[i]| < 2^26 */ fdifference(zz, xx); // does zz = xx - zz /* |zz[i]| < 2^27 */ memset(zzz + 10, 0, sizeof(limb) * 9); fscalar_product(zzz, zz, 121665); /* |zzz[i]| < 2^(27+17) */ /* No need to call freduce_degree here: fscalar_product doesn't increase the degree of its input. */ freduce_coefficients(zzz); /* |zzz[i]| < 2^26 */ fsum(zzz, xx); /* |zzz[i]| < 2^27 */ fproduct(z2, zz, zzz); /* |z2[i]| < 14*2^(26+27) */ freduce_degree(z2); freduce_coefficients(z2); /* |z2|i| < 2^26 */ } /* Conditionally swap two reduced-form limb arrays if 'iswap' is 1, but leave * them unchanged if 'iswap' is 0. Runs in data-invariant time to avoid * side-channel attacks. * * NOTE that this function requires that 'iswap' be 1 or 0; other values give * wrong results. Also, the two limb arrays must be in reduced-coefficient, * reduced-degree form: the values in a[10..19] or b[10..19] aren't swapped, * and all all values in a[0..9],b[0..9] must have magnitude less than * INT32_MAX. */ static void swap_conditional(limb a[19], limb b[19], limb iswap) { unsigned i; const s32 swap = (s32) -iswap; for (i = 0; i < 10; ++i) { const s32 x = swap & ( ((s32)a[i]) ^ ((s32)b[i]) ); a[i] = ((s32)a[i]) ^ x; b[i] = ((s32)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 little endian, 32-byte number * q: a point of the curve (short form) */ static void cmult(limb *resultx, limb *resultz, const u8 *n, const limb *q) { limb a[19] = {0}, b[19] = {1}, c[19] = {1}, d[19] = {0}; limb *nqpqx = a, *nqpqz = b, *nqx = c, *nqz = d, *t; limb e[19] = {0}, f[19] = {1}, g[19] = {0}, h[19] = {1}; limb *nqpqx2 = e, *nqpqz2 = f, *nqx2 = g, *nqz2 = h; unsigned i, j; memcpy(nqpqx, q, sizeof(limb) * 10); for (i = 0; i < 32; ++i) { u8 byte = n[31 - i]; for (j = 0; j < 8; ++j) { const limb bit = byte >> 7; swap_conditional(nqx, nqpqx, bit); swap_conditional(nqz, nqpqz, bit); fmonty(nqx2, nqz2, nqpqx2, nqpqz2, nqx, nqz, nqpqx, nqpqz, q); swap_conditional(nqx2, nqpqx2, bit); swap_conditional(nqz2, nqpqz2, 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(limb) * 10); memcpy(resultz, nqz, sizeof(limb) * 10); } // ----------------------------------------------------------------------------- // Shamelessly copied from djb's code // ----------------------------------------------------------------------------- static void crecip(limb *out, const limb *z) { limb z2[10]; limb z9[10]; limb z11[10]; limb z2_5_0[10]; limb z2_10_0[10]; limb z2_20_0[10]; limb z2_50_0[10]; limb z2_100_0[10]; limb t0[10]; limb t1[10]; 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); } int curve25519_donna(u8 *mypublic, const u8 *secret, const u8 *basepoint) { limb bp[10], x[10], z[11], zmone[10]; 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; } libsignal-protocol-c-2.3.3/src/curve25519/curve25519-donna.h000066400000000000000000000002111363751346500230720ustar00rootroot00000000000000#ifndef CURVE25519_DONNA_H #define CURVE25519_DONNA_H extern int curve25519_donna(uint8_t *, const uint8_t *, const uint8_t *); #endif libsignal-protocol-c-2.3.3/src/curve25519/ed25519/000077500000000000000000000000001363751346500210765ustar00rootroot00000000000000libsignal-protocol-c-2.3.3/src/curve25519/ed25519/additions/000077500000000000000000000000001363751346500230545ustar00rootroot00000000000000libsignal-protocol-c-2.3.3/src/curve25519/ed25519/additions/compare.c000066400000000000000000000012271363751346500246500ustar00rootroot00000000000000#include #include "compare.h" /* Const-time comparison from SUPERCOP, but here it's only used for signature verification, so doesn't need to be const-time. But copied the nacl version anyways. */ int crypto_verify_32_ref(const unsigned char *x, const unsigned char *y) { unsigned int differentbits = 0; #define F(i) differentbits |= x[i] ^ y[i]; F(0) F(1) F(2) F(3) F(4) F(5) F(6) F(7) F(8) F(9) F(10) F(11) F(12) F(13) F(14) F(15) F(16) F(17) F(18) F(19) F(20) F(21) F(22) F(23) F(24) F(25) F(26) F(27) F(28) F(29) F(30) F(31) return (1 & ((differentbits - 1) >> 8)) - 1; } libsignal-protocol-c-2.3.3/src/curve25519/ed25519/additions/compare.h000066400000000000000000000002011363751346500246440ustar00rootroot00000000000000#ifndef __COMPARE_H__ #define __COMPARE_H__ int crypto_verify_32_ref(const unsigned char *b1, const unsigned char *b2); #endif libsignal-protocol-c-2.3.3/src/curve25519/ed25519/additions/crypto_additions.h000066400000000000000000000024631363751346500266100ustar00rootroot00000000000000 #ifndef __CRYPTO_ADDITIONS__ #define __CRYPTO_ADDITIONS__ #include "crypto_uint32.h" #include "fe.h" #include "ge.h" #define MAX_MSG_LEN 256 void sc_neg(unsigned char *b, const unsigned char *a); void sc_cmov(unsigned char* f, const unsigned char* g, unsigned char b); int fe_isequal(const fe f, const fe g); int fe_isreduced(const unsigned char* s); void fe_mont_rhs(fe v2, const fe u); void fe_montx_to_edy(fe y, const fe u); void fe_sqrt(fe b, const fe a); int ge_isneutral(const ge_p3* q); void ge_neg(ge_p3* r, const ge_p3 *p); void ge_montx_to_p3(ge_p3* p, const fe u, const unsigned char ed_sign_bit); void ge_p3_to_montx(fe u, const ge_p3 *p); void ge_scalarmult(ge_p3 *h, const unsigned char *a, const ge_p3 *A); void ge_scalarmult_cofactor(ge_p3 *q, const ge_p3 *p); void elligator(fe u, const fe r); void hash_to_point(ge_p3* p, const unsigned char* msg, const unsigned long in_len); int crypto_sign_modified( unsigned char *sm, const unsigned char *m,unsigned long long mlen, const unsigned char *sk, /* Curve/Ed25519 private key */ const unsigned char *pk, /* Ed25519 public key */ const unsigned char *random /* 64 bytes random to hash into nonce */ ); int crypto_sign_open_modified( unsigned char *m, const unsigned char *sm,unsigned long long smlen, const unsigned char *pk ); #endif libsignal-protocol-c-2.3.3/src/curve25519/ed25519/additions/crypto_hash_sha512.h000066400000000000000000000002341363751346500266320ustar00rootroot00000000000000#ifndef crypto_hash_sha512_H #define crypto_hash_sha512_H extern int crypto_hash_sha512(unsigned char *,const unsigned char *,unsigned long long); #endif libsignal-protocol-c-2.3.3/src/curve25519/ed25519/additions/curve_sigs.c000066400000000000000000000057461363751346500254050ustar00rootroot00000000000000#include #include #include "ge.h" #include "curve_sigs.h" #include "crypto_sign.h" #include "crypto_additions.h" int curve25519_sign(unsigned char* signature_out, const unsigned char* curve25519_privkey, const unsigned char* msg, const unsigned long msg_len, const unsigned char* random) { ge_p3 ed_pubkey_point; /* Ed25519 pubkey point */ unsigned char ed_pubkey[32]; /* Ed25519 encoded pubkey */ unsigned char *sigbuf; /* working buffer */ unsigned char sign_bit = 0; if ((sigbuf = malloc(msg_len + 128)) == 0) { memset(signature_out, 0, 64); return -1; } /* Convert the Curve25519 privkey to an Ed25519 public key */ ge_scalarmult_base(&ed_pubkey_point, curve25519_privkey); ge_p3_tobytes(ed_pubkey, &ed_pubkey_point); sign_bit = ed_pubkey[31] & 0x80; /* Perform an Ed25519 signature with explicit private key */ crypto_sign_modified(sigbuf, msg, msg_len, curve25519_privkey, ed_pubkey, random); memmove(signature_out, sigbuf, 64); /* Encode the sign bit into signature (in unused high bit of S) */ signature_out[63] &= 0x7F; /* bit should be zero already, but just in case */ signature_out[63] |= sign_bit; free(sigbuf); return 0; } int curve25519_verify(const unsigned char* signature, const unsigned char* curve25519_pubkey, const unsigned char* msg, const unsigned long msg_len) { fe u; fe y; unsigned char ed_pubkey[32]; unsigned char *verifybuf = NULL; /* working buffer */ unsigned char *verifybuf2 = NULL; /* working buffer #2 */ int result; if ((verifybuf = malloc(msg_len + 64)) == 0) { result = -1; goto err; } if ((verifybuf2 = malloc(msg_len + 64)) == 0) { result = -1; goto err; } /* Convert the Curve25519 public key into an Ed25519 public key. In particular, convert Curve25519's "montgomery" x-coordinate (u) into an Ed25519 "edwards" y-coordinate: y = (u - 1) / (u + 1) NOTE: u=-1 is converted to y=0 since fe_invert is mod-exp Then move the sign bit into the pubkey from the signature. */ fe_frombytes(u, curve25519_pubkey); fe_montx_to_edy(y, u); fe_tobytes(ed_pubkey, y); /* Copy the sign bit, and remove it from signature */ ed_pubkey[31] &= 0x7F; /* bit should be zero already, but just in case */ ed_pubkey[31] |= (signature[63] & 0x80); memmove(verifybuf, signature, 64); verifybuf[63] &= 0x7F; memmove(verifybuf+64, msg, msg_len); /* Then perform a normal Ed25519 verification, return 0 on success */ /* The below call has a strange API: */ /* verifybuf = R || S || message */ /* verifybuf2 = internal to next call gets a copy of verifybuf, S gets replaced with pubkey for hashing */ result = crypto_sign_open_modified(verifybuf2, verifybuf, 64 + msg_len, ed_pubkey); err: if (verifybuf != NULL) { free(verifybuf); } if (verifybuf2 != NULL) { free(verifybuf2); } return result; } libsignal-protocol-c-2.3.3/src/curve25519/ed25519/additions/curve_sigs.h000066400000000000000000000012261363751346500253770ustar00rootroot00000000000000 #ifndef __CURVE_SIGS_H__ #define __CURVE_SIGS_H__ /* returns 0 on success */ int curve25519_sign(unsigned char* signature_out, /* 64 bytes */ const unsigned char* curve25519_privkey, /* 32 bytes */ const unsigned char* msg, const unsigned long msg_len, /* <= 256 bytes */ const unsigned char* random); /* 64 bytes */ /* returns 0 on success */ int curve25519_verify(const unsigned char* signature, /* 64 bytes */ const unsigned char* curve25519_pubkey, /* 32 bytes */ const unsigned char* msg, const unsigned long msg_len); /* <= 256 bytes */ #endif libsignal-protocol-c-2.3.3/src/curve25519/ed25519/additions/elligator.c000066400000000000000000000042741363751346500252110ustar00rootroot00000000000000#include #include "fe.h" #include "ge.h" #include "crypto_uint32.h" #include "crypto_hash_sha512.h" #include "crypto_additions.h" unsigned int legendre_is_nonsquare(fe in) { fe temp; unsigned char bytes[32]; fe_pow22523(temp, in); /* temp = in^((q-5)/8) */ fe_sq(temp, temp); /* in^((q-5)/4) */ fe_sq(temp, temp); /* in^((q-5)/2) */ fe_mul(temp, temp, in); /* in^((q-3)/2) */ fe_mul(temp, temp, in); /* in^((q-1)/2) */ /* temp is now the Legendre symbol: * 1 = square * 0 = input is zero * -1 = nonsquare */ fe_tobytes(bytes, temp); return 1 & bytes[31]; } void elligator(fe u, const fe r) { /* r = input * x = -A/(1+2r^2) # 2 is nonsquare * e = (x^3 + Ax^2 + x)^((q-1)/2) # legendre symbol * if e == 1 (square) or e == 0 (because x == 0 and 2r^2 + 1 == 0) * u = x * if e == -1 (nonsquare) * u = -x - A */ fe A, one, twor2, twor2plus1, twor2plus1inv; fe x, e, Atemp, uneg; unsigned int nonsquare; fe_1(one); fe_0(A); A[0] = 486662; /* A = 486662 */ fe_sq2(twor2, r); /* 2r^2 */ fe_add(twor2plus1, twor2, one); /* 1+2r^2 */ fe_invert(twor2plus1inv, twor2plus1); /* 1/(1+2r^2) */ fe_mul(x, twor2plus1inv, A); /* A/(1+2r^2) */ fe_neg(x, x); /* x = -A/(1+2r^2) */ fe_mont_rhs(e, x); /* e = x^3 + Ax^2 + x */ nonsquare = legendre_is_nonsquare(e); fe_0(Atemp); fe_cmov(Atemp, A, nonsquare); /* 0, or A if nonsquare */ fe_add(u, x, Atemp); /* x, or x+A if nonsquare */ fe_neg(uneg, u); /* -x, or -x-A if nonsquare */ fe_cmov(u, uneg, nonsquare); /* x, or -x-A if nonsquare */ } void hash_to_point(ge_p3* p, const unsigned char* in, const unsigned long in_len) { unsigned char hash[64]; fe h, u; unsigned char sign_bit; ge_p3 p3; crypto_hash_sha512(hash, in, in_len); /* take the high bit as Edwards sign bit */ sign_bit = (hash[31] & 0x80) >> 7; hash[31] &= 0x7F; fe_frombytes(h, hash); elligator(u, h); ge_montx_to_p3(&p3, u, sign_bit); ge_scalarmult_cofactor(p, &p3); } libsignal-protocol-c-2.3.3/src/curve25519/ed25519/additions/fe_isequal.c000066400000000000000000000003151363751346500253340ustar00rootroot00000000000000#include "fe.h" #include "crypto_verify_32.h" /* return 1 if f == g return 0 if f != g */ int fe_isequal(const fe f, const fe g) { fe h; fe_sub(h, f, g); return 1 ^ (1 & (fe_isnonzero(h) >> 8)); } libsignal-protocol-c-2.3.3/src/curve25519/ed25519/additions/fe_isreduced.c000066400000000000000000000003621363751346500256420ustar00rootroot00000000000000#include "fe.h" #include "crypto_verify_32.h" int fe_isreduced(const unsigned char* s) { fe f; unsigned char strict[32]; fe_frombytes(f, s); fe_tobytes(strict, f); if (crypto_verify_32(strict, s) != 0) return 0; return 1; } libsignal-protocol-c-2.3.3/src/curve25519/ed25519/additions/fe_mont_rhs.c000066400000000000000000000006511363751346500255250ustar00rootroot00000000000000#include "fe.h" void fe_mont_rhs(fe v2, fe u) { fe A, one; fe u2, Au, inner; fe_1(one); fe_0(A); A[0] = 486662; /* A = 486662 */ fe_sq(u2, u); /* u^2 */ fe_mul(Au, A, u); /* Au */ fe_add(inner, u2, Au); /* u^2 + Au */ fe_add(inner, inner, one); /* u^2 + Au + 1 */ fe_mul(v2, u, inner); /* u(u^2 + Au + 1) */ } libsignal-protocol-c-2.3.3/src/curve25519/ed25519/additions/fe_montx_to_edy.c000066400000000000000000000004771363751346500264120ustar00rootroot00000000000000 #include "fe.h" #include "crypto_additions.h" void fe_montx_to_edy(fe y, const fe u) { /* y = (u - 1) / (u + 1) NOTE: u=-1 is converted to y=0 since fe_invert is mod-exp */ fe one, um1, up1; fe_1(one); fe_sub(um1, u, one); fe_add(up1, u, one); fe_invert(up1, up1); fe_mul(y, um1, up1); } libsignal-protocol-c-2.3.3/src/curve25519/ed25519/additions/fe_sqrt.c000066400000000000000000000025131363751346500246640ustar00rootroot00000000000000#include #include "fe.h" #include "crypto_additions.h" /* sqrt(-1) */ static unsigned char i_bytes[32] = { 0xb0, 0xa0, 0x0e, 0x4a, 0x27, 0x1b, 0xee, 0xc4, 0x78, 0xe4, 0x2f, 0xad, 0x06, 0x18, 0x43, 0x2f, 0xa7, 0xd7, 0xfb, 0x3d, 0x99, 0x00, 0x4d, 0x2b, 0x0b, 0xdf, 0xc1, 0x4f, 0x80, 0x24, 0x83, 0x2b }; /* Preconditions: a is square or zero */ void fe_sqrt(fe out, const fe a) { fe exp, b, b2, bi, i; #ifndef NDEBUG fe legendre, zero, one; #endif fe_frombytes(i, i_bytes); fe_pow22523(exp, a); /* b = a^(q-5)/8 */ /* PRECONDITION: legendre symbol == 1 (square) or 0 (a == zero) */ #ifndef NDEBUG fe_sq(legendre, exp); /* in^((q-5)/4) */ fe_sq(legendre, legendre); /* in^((q-5)/2) */ fe_mul(legendre, legendre, a); /* in^((q-3)/2) */ fe_mul(legendre, legendre, a); /* in^((q-1)/2) */ fe_0(zero); fe_1(one); assert(fe_isequal(legendre, zero) || fe_isequal(legendre, one)); #endif fe_mul(b, a, exp); /* b = a * a^(q-5)/8 */ fe_sq(b2, b); /* b^2 = a * a^(q-1)/4 */ /* note b^4 == a^2, so b^2 == a or -a * if b^2 != a, multiply it by sqrt(-1) */ fe_mul(bi, b, i); fe_cmov(b, bi, 1 ^ fe_isequal(b2, a)); fe_copy(out, b); /* PRECONDITION: out^2 == a */ #ifndef NDEBUG fe_sq(b2, out); assert(fe_isequal(a, b2)); #endif } libsignal-protocol-c-2.3.3/src/curve25519/ed25519/additions/ge_isneutral.c000066400000000000000000000004271363751346500257040ustar00rootroot00000000000000#include "crypto_additions.h" #include "ge.h" /* return 1 if p is the neutral point return 0 otherwise */ int ge_isneutral(const ge_p3 *p) { fe zero; fe_0(zero); /* Check if p == neutral element == (0, 1) */ return (fe_isequal(p->X, zero) & fe_isequal(p->Y, p->Z)); } libsignal-protocol-c-2.3.3/src/curve25519/ed25519/additions/ge_montx_to_p3.c000066400000000000000000000036561363751346500261560ustar00rootroot00000000000000#include "fe.h" #include "ge.h" #include "assert.h" #include "crypto_additions.h" #include "utility.h" /* sqrt(-(A+2)) */ static unsigned char A_bytes[32] = { 0x06, 0x7e, 0x45, 0xff, 0xaa, 0x04, 0x6e, 0xcc, 0x82, 0x1a, 0x7d, 0x4b, 0xd1, 0xd3, 0xa1, 0xc5, 0x7e, 0x4f, 0xfc, 0x03, 0xdc, 0x08, 0x7b, 0xd2, 0xbb, 0x06, 0xa0, 0x60, 0xf4, 0xed, 0x26, 0x0f }; void ge_montx_to_p3(ge_p3* p, const fe u, const unsigned char ed_sign_bit) { fe x, y, A, v, v2, iv, nx; fe_frombytes(A, A_bytes); /* given u, recover edwards y */ /* given u, recover v */ /* given u and v, recover edwards x */ fe_montx_to_edy(y, u); /* y = (u - 1) / (u + 1) */ fe_mont_rhs(v2, u); /* v^2 = u(u^2 + Au + 1) */ fe_sqrt(v, v2); /* v = sqrt(v^2) */ fe_mul(x, u, A); /* x = u * sqrt(-(A+2)) */ fe_invert(iv, v); /* 1/v */ fe_mul(x, x, iv); /* x = (u/v) * sqrt(-(A+2)) */ fe_neg(nx, x); /* negate x to match sign bit */ fe_cmov(x, nx, fe_isnegative(x) ^ ed_sign_bit); fe_copy(p->X, x); fe_copy(p->Y, y); fe_1(p->Z); fe_mul(p->T, p->X, p->Y); /* POSTCONDITION: check that p->X and p->Y satisfy the Ed curve equation */ /* -x^2 + y^2 = 1 + dx^2y^2 */ #ifndef NDEBUG { fe one, d, x2, y2, x2y2, dx2y2; unsigned char dbytes[32] = { 0xa3, 0x78, 0x59, 0x13, 0xca, 0x4d, 0xeb, 0x75, 0xab, 0xd8, 0x41, 0x41, 0x4d, 0x0a, 0x70, 0x00, 0x98, 0xe8, 0x79, 0x77, 0x79, 0x40, 0xc7, 0x8c, 0x73, 0xfe, 0x6f, 0x2b, 0xee, 0x6c, 0x03, 0x52 }; fe_frombytes(d, dbytes); fe_1(one); fe_sq(x2, p->X); /* x^2 */ fe_sq(y2, p->Y); /* y^2 */ fe_mul(dx2y2, x2, y2); /* x^2y^2 */ fe_mul(dx2y2, dx2y2, d); /* dx^2y^2 */ fe_add(dx2y2, dx2y2, one); /* dx^2y^2 + 1 */ fe_neg(x2y2, x2); /* -x^2 */ fe_add(x2y2, x2y2, y2); /* -x^2 + y^2 */ assert(fe_isequal(x2y2, dx2y2)); } #endif } libsignal-protocol-c-2.3.3/src/curve25519/ed25519/additions/ge_neg.c000066400000000000000000000003111363751346500244370ustar00rootroot00000000000000#include "crypto_additions.h" #include "ge.h" /* return r = -p */ void ge_neg(ge_p3* r, const ge_p3 *p) { fe_neg(r->X, p->X); fe_copy(r->Y, p->Y); fe_copy(r->Z, p->Z); fe_neg(r->T, p->T); } libsignal-protocol-c-2.3.3/src/curve25519/ed25519/additions/ge_p3_to_montx.c000066400000000000000000000006701363751346500261470ustar00rootroot00000000000000#include "fe.h" #include "crypto_additions.h" void ge_p3_to_montx(fe u, const ge_p3 *ed) { /* u = (y + 1) / (1 - y) or u = (y + z) / (z - y) NOTE: y=1 is converted to u=0 since fe_invert is mod-exp */ fe y_plus_one, one_minus_y, inv_one_minus_y; fe_add(y_plus_one, ed->Y, ed->Z); fe_sub(one_minus_y, ed->Z, ed->Y); fe_invert(inv_one_minus_y, one_minus_y); fe_mul(u, y_plus_one, inv_one_minus_y); } libsignal-protocol-c-2.3.3/src/curve25519/ed25519/additions/ge_scalarmult.c000066400000000000000000000061051363751346500260440ustar00rootroot00000000000000#include "crypto_uint32.h" #include "ge.h" #include "crypto_additions.h" static unsigned char equal(signed char b,signed char c) { unsigned char ub = b; unsigned char uc = c; unsigned char x = ub ^ uc; /* 0: yes; 1..255: no */ crypto_uint32 y = x; /* 0: yes; 1..255: no */ y -= 1; /* 4294967295: yes; 0..254: no */ y >>= 31; /* 1: yes; 0: no */ return y; } static unsigned char negative(signed char b) { unsigned long long x = b; /* 18446744073709551361..18446744073709551615: yes; 0..255: no */ x >>= 63; /* 1: yes; 0: no */ return x; } static void cmov(ge_cached *t,const ge_cached *u,unsigned char b) { fe_cmov(t->YplusX,u->YplusX,b); fe_cmov(t->YminusX,u->YminusX,b); fe_cmov(t->Z,u->Z,b); fe_cmov(t->T2d,u->T2d,b); } static void select(ge_cached *t,const ge_cached *pre, signed char b) { ge_cached minust; unsigned char bnegative = negative(b); unsigned char babs = b - (((-bnegative) & b) << 1); fe_1(t->YplusX); fe_1(t->YminusX); fe_1(t->Z); fe_0(t->T2d); cmov(t,pre+0,equal(babs,1)); cmov(t,pre+1,equal(babs,2)); cmov(t,pre+2,equal(babs,3)); cmov(t,pre+3,equal(babs,4)); cmov(t,pre+4,equal(babs,5)); cmov(t,pre+5,equal(babs,6)); cmov(t,pre+6,equal(babs,7)); cmov(t,pre+7,equal(babs,8)); fe_copy(minust.YplusX,t->YminusX); fe_copy(minust.YminusX,t->YplusX); fe_copy(minust.Z,t->Z); fe_neg(minust.T2d,t->T2d); cmov(t,&minust,bnegative); } /* h = a * B where a = a[0]+256*a[1]+...+256^31 a[31] B is the Ed25519 base point (x,4/5) with x positive. Preconditions: a[31] <= 127 */ void ge_scalarmult(ge_p3 *h, const unsigned char *a, const ge_p3 *A) { signed char e[64]; signed char carry; ge_p1p1 r; ge_p2 s; ge_p3 t0, t1, t2; ge_cached t, pre[8]; int i; for (i = 0;i < 32;++i) { e[2 * i + 0] = (a[i] >> 0) & 15; e[2 * i + 1] = (a[i] >> 4) & 15; } /* each e[i] is between 0 and 15 */ /* e[63] is between 0 and 7 */ carry = 0; for (i = 0;i < 63;++i) { e[i] += carry; carry = e[i] + 8; carry >>= 4; e[i] -= carry << 4; } e[63] += carry; /* each e[i] is between -8 and 8 */ // Precomputation: ge_p3_to_cached(pre+0, A); // A ge_p3_dbl(&r, A); ge_p1p1_to_p3(&t0, &r); ge_p3_to_cached(pre+1, &t0); // 2A ge_add(&r, A, pre+1); ge_p1p1_to_p3(&t1, &r); ge_p3_to_cached(pre+2, &t1); // 3A ge_p3_dbl(&r, &t0); ge_p1p1_to_p3(&t0, &r); ge_p3_to_cached(pre+3, &t0); // 4A ge_add(&r, A, pre+3); ge_p1p1_to_p3(&t2, &r); ge_p3_to_cached(pre+4, &t2); // 5A ge_p3_dbl(&r, &t1); ge_p1p1_to_p3(&t1, &r); ge_p3_to_cached(pre+5, &t1); // 6A ge_add(&r, A, pre+5); ge_p1p1_to_p3(&t1, &r); ge_p3_to_cached(pre+6, &t1); // 7A ge_p3_dbl(&r, &t0); ge_p1p1_to_p3(&t0, &r); ge_p3_to_cached(pre+7, &t0); // 8A ge_p3_0(h); for (i = 63;i > 0; i--) { select(&t,pre,e[i]); ge_add(&r, h, &t); ge_p1p1_to_p2(&s,&r); ge_p2_dbl(&r,&s); ge_p1p1_to_p2(&s,&r); ge_p2_dbl(&r,&s); ge_p1p1_to_p2(&s,&r); ge_p2_dbl(&r,&s); ge_p1p1_to_p2(&s,&r); ge_p2_dbl(&r,&s); ge_p1p1_to_p3(h,&r); } select(&t,pre,e[0]); ge_add(&r, h, &t); ge_p1p1_to_p3(h,&r); } libsignal-protocol-c-2.3.3/src/curve25519/ed25519/additions/ge_scalarmult_cofactor.c000066400000000000000000000004721363751346500277250ustar00rootroot00000000000000#include "crypto_additions.h" #include "ge.h" /* return 8 * p */ void ge_scalarmult_cofactor(ge_p3 *q, const ge_p3 *p) { ge_p1p1 p1p1; ge_p2 p2; ge_p3_dbl(&p1p1, p); ge_p1p1_to_p2(&p2, &p1p1); ge_p2_dbl(&p1p1, &p2); ge_p1p1_to_p2(&p2, &p1p1); ge_p2_dbl(&p1p1, &p2); ge_p1p1_to_p3(q, &p1p1); } libsignal-protocol-c-2.3.3/src/curve25519/ed25519/additions/generalized/000077500000000000000000000000001363751346500253455ustar00rootroot00000000000000libsignal-protocol-c-2.3.3/src/curve25519/ed25519/additions/generalized/ge_p3_add.c000066400000000000000000000003471363751346500273220ustar00rootroot00000000000000#include "ge.h" /* r = p + q */ void ge_p3_add(ge_p3 *r, const ge_p3 *p, const ge_p3 *q) { ge_cached p_cached; ge_p1p1 r_p1p1; ge_p3_to_cached(&p_cached, p); ge_add(&r_p1p1, q, &p_cached); ge_p1p1_to_p3(r, &r_p1p1); } libsignal-protocol-c-2.3.3/src/curve25519/ed25519/additions/generalized/gen_constants.h000066400000000000000000000006001363751346500303570ustar00rootroot00000000000000#ifndef _GEN_CONSTANTS_H__ #define _GEN_CONSTANTS_H__ #define LABELSETMAXLEN 512 #define LABELMAXLEN 128 #define BUFLEN 1024 #define BLOCKLEN 128 /* SHA512 */ #define HASHLEN 64 /* SHA512 */ #define POINTLEN 32 #define SCALARLEN 32 #define RANDLEN 32 #define SIGNATURELEN 64 #define VRFSIGNATURELEN 96 #define VRFOUTPUTLEN 32 #define MSTART 2048 #define MSGMAXLEN 1048576 #endif libsignal-protocol-c-2.3.3/src/curve25519/ed25519/additions/generalized/gen_crypto_additions.h000066400000000000000000000004341363751346500317260ustar00rootroot00000000000000 #ifndef __GEN_CRYPTO_ADDITIONS__ #define __GEN_CRYPTO_ADDITIONS__ #include "crypto_uint32.h" #include "fe.h" #include "ge.h" int sc_isreduced(const unsigned char* s); int point_isreduced(const unsigned char* p); void ge_p3_add(ge_p3 *r, const ge_p3 *p, const ge_p3 *q); #endif libsignal-protocol-c-2.3.3/src/curve25519/ed25519/additions/generalized/gen_eddsa.c000066400000000000000000000247061363751346500274330ustar00rootroot00000000000000#include #include "gen_eddsa.h" #include "gen_labelset.h" #include "gen_constants.h" #include "gen_crypto_additions.h" #include "crypto_hash_sha512.h" #include "crypto_verify_32.h" #include "zeroize.h" #include "ge.h" #include "sc.h" #include "crypto_additions.h" #include "utility.h" /* B: base point * R: commitment (point), r: private nonce (scalar) K: encoded public key k: private key (scalar) Z: 32-bytes random M: buffer containing message, message starts at M_start, continues for M_len r = hash(B || labelset || Z || pad1 || k || pad2 || labelset || K || extra || M) (mod q) */ int generalized_commit(unsigned char* R_bytes, unsigned char* r_scalar, const unsigned char* labelset, const unsigned long labelset_len, const unsigned char* extra, const unsigned long extra_len, const unsigned char* K_bytes, const unsigned char* k_scalar, const unsigned char* Z, unsigned char* M_buf, const unsigned long M_start, const unsigned long M_len) { ge_p3 R_point; unsigned char hash[HASHLEN]; unsigned char* bufstart = NULL; unsigned char* bufptr = NULL; unsigned char* bufend = NULL; unsigned long prefix_len = 0; if (labelset_validate(labelset, labelset_len) != 0) goto err; if (R_bytes == NULL || r_scalar == NULL || K_bytes == NULL || k_scalar == NULL || Z == NULL || M_buf == NULL) goto err; if (extra == NULL && extra_len != 0) goto err; if (extra != NULL && extra_len == 0) goto err; if (extra != NULL && labelset_is_empty(labelset, labelset_len)) goto err; if (HASHLEN != 64) goto err; prefix_len = 0; prefix_len += POINTLEN + labelset_len + RANDLEN; prefix_len += ((BLOCKLEN - (prefix_len % BLOCKLEN)) % BLOCKLEN); prefix_len += SCALARLEN; prefix_len += ((BLOCKLEN - (prefix_len % BLOCKLEN)) % BLOCKLEN); prefix_len += labelset_len + POINTLEN + extra_len; if (prefix_len > M_start) goto err; bufstart = M_buf + M_start - prefix_len; bufptr = bufstart; bufend = M_buf + M_start; bufptr = buffer_add(bufptr, bufend, B_bytes, POINTLEN); bufptr = buffer_add(bufptr, bufend, labelset, labelset_len); bufptr = buffer_add(bufptr, bufend, Z, RANDLEN); bufptr = buffer_pad(bufstart, bufptr, bufend); bufptr = buffer_add(bufptr, bufend, k_scalar, SCALARLEN); bufptr = buffer_pad(bufstart, bufptr, bufend); bufptr = buffer_add(bufptr, bufend, labelset, labelset_len); bufptr = buffer_add(bufptr, bufend, K_bytes, POINTLEN); bufptr = buffer_add(bufptr, bufend, extra, extra_len); if (bufptr != bufend || bufptr != M_buf + M_start || bufptr - bufstart != prefix_len) goto err; crypto_hash_sha512(hash, M_buf + M_start - prefix_len, prefix_len + M_len); sc_reduce(hash); ge_scalarmult_base(&R_point, hash); ge_p3_tobytes(R_bytes, &R_point); memcpy(r_scalar, hash, SCALARLEN); zeroize(hash, HASHLEN); zeroize(bufstart, prefix_len); return 0; err: zeroize(hash, HASHLEN); zeroize(M_buf, M_start); return -1; } /* if is_labelset_empty(labelset): return hash(R || K || M) (mod q) else: return hash(B || labelset || R || labelset || K || extra || M) (mod q) */ int generalized_challenge(unsigned char* h_scalar, const unsigned char* labelset, const unsigned long labelset_len, const unsigned char* extra, const unsigned long extra_len, const unsigned char* R_bytes, const unsigned char* K_bytes, unsigned char* M_buf, const unsigned long M_start, const unsigned long M_len) { unsigned char hash[HASHLEN]; unsigned char* bufstart = NULL; unsigned char* bufptr = NULL; unsigned char* bufend = NULL; unsigned long prefix_len = 0; if (h_scalar == NULL) goto err; memset(h_scalar, 0, SCALARLEN); if (labelset_validate(labelset, labelset_len) != 0) goto err; if (R_bytes == NULL || K_bytes == NULL || M_buf == NULL) goto err; if (extra == NULL && extra_len != 0) goto err; if (extra != NULL && extra_len == 0) goto err; if (extra != NULL && labelset_is_empty(labelset, labelset_len)) goto err; if (HASHLEN != 64) goto err; if (labelset_is_empty(labelset, labelset_len)) { if (2*POINTLEN > M_start) goto err; if (extra != NULL || extra_len != 0) goto err; memcpy(M_buf + M_start - (2*POINTLEN), R_bytes, POINTLEN); memcpy(M_buf + M_start - (1*POINTLEN), K_bytes, POINTLEN); prefix_len = 2*POINTLEN; } else { prefix_len = 3*POINTLEN + 2*labelset_len + extra_len; if (prefix_len > M_start) goto err; bufstart = M_buf + M_start - prefix_len; bufptr = bufstart; bufend = M_buf + M_start; bufptr = buffer_add(bufptr, bufend, B_bytes, POINTLEN); bufptr = buffer_add(bufptr, bufend, labelset, labelset_len); bufptr = buffer_add(bufptr, bufend, R_bytes, POINTLEN); bufptr = buffer_add(bufptr, bufend, labelset, labelset_len); bufptr = buffer_add(bufptr, bufend, K_bytes, POINTLEN); bufptr = buffer_add(bufptr, bufend, extra, extra_len); if (bufptr == NULL) goto err; if (bufptr != bufend || bufptr != M_buf + M_start || bufptr - bufstart != prefix_len) goto err; } crypto_hash_sha512(hash, M_buf + M_start - prefix_len, prefix_len + M_len); sc_reduce(hash); memcpy(h_scalar, hash, SCALARLEN); return 0; err: return -1; } /* return r + kh (mod q) */ int generalized_prove(unsigned char* out_scalar, const unsigned char* r_scalar, const unsigned char* k_scalar, const unsigned char* h_scalar) { sc_muladd(out_scalar, h_scalar, k_scalar, r_scalar); zeroize_stack(); return 0; } /* R = s*B - h*K */ int generalized_solve_commitment(unsigned char* R_bytes_out, ge_p3* K_point_out, const ge_p3* B_point, const unsigned char* s_scalar, const unsigned char* K_bytes, const unsigned char* h_scalar) { ge_p3 Kneg_point; ge_p2 R_calc_point_p2; ge_p3 sB; ge_p3 hK; ge_p3 R_calc_point_p3; if (ge_frombytes_negate_vartime(&Kneg_point, K_bytes) != 0) return -1; if (B_point == NULL) { ge_double_scalarmult_vartime(&R_calc_point_p2, h_scalar, &Kneg_point, s_scalar); ge_tobytes(R_bytes_out, &R_calc_point_p2); } else { // s * Bv ge_scalarmult(&sB, s_scalar, B_point); // h * -K ge_scalarmult(&hK, h_scalar, &Kneg_point); // R = sB - hK ge_p3_add(&R_calc_point_p3, &sB, &hK); ge_p3_tobytes(R_bytes_out, &R_calc_point_p3); } if (K_point_out) { ge_neg(K_point_out, &Kneg_point); } return 0; } int generalized_eddsa_25519_sign( unsigned char* signature_out, const unsigned char* eddsa_25519_pubkey_bytes, const unsigned char* eddsa_25519_privkey_scalar, const unsigned char* msg, const unsigned long msg_len, const unsigned char* random, const unsigned char* customization_label, const unsigned long customization_label_len) { unsigned char labelset[LABELSETMAXLEN]; unsigned long labelset_len = 0; unsigned char R_bytes[POINTLEN]; unsigned char r_scalar[SCALARLEN]; unsigned char h_scalar[SCALARLEN]; unsigned char s_scalar[SCALARLEN]; unsigned char* M_buf = NULL; if (signature_out == NULL) goto err; memset(signature_out, 0, SIGNATURELEN); if (eddsa_25519_pubkey_bytes == NULL) goto err; if (eddsa_25519_privkey_scalar == NULL) goto err; if (msg == NULL) goto err; if (customization_label == NULL && customization_label_len != 0) goto err; if (customization_label_len > LABELMAXLEN) goto err; if (msg_len > MSGMAXLEN) goto err; if ((M_buf = malloc(msg_len + MSTART)) == 0) goto err; memcpy(M_buf + MSTART, msg, msg_len); if (labelset_new(labelset, &labelset_len, LABELSETMAXLEN, NULL, 0, customization_label, customization_label_len) != 0) goto err; if (generalized_commit(R_bytes, r_scalar, labelset, labelset_len, NULL, 0, eddsa_25519_pubkey_bytes, eddsa_25519_privkey_scalar, random, M_buf, MSTART, msg_len) != 0) goto err; if (generalized_challenge(h_scalar, labelset, labelset_len, NULL, 0, R_bytes, eddsa_25519_pubkey_bytes, M_buf, MSTART, msg_len) != 0) goto err; if (generalized_prove(s_scalar, r_scalar, eddsa_25519_privkey_scalar, h_scalar) != 0) goto err; memcpy(signature_out, R_bytes, POINTLEN); memcpy(signature_out + POINTLEN, s_scalar, SCALARLEN); zeroize(r_scalar, SCALARLEN); zeroize_stack(); free(M_buf); return 0; err: zeroize(r_scalar, SCALARLEN); zeroize_stack(); free(M_buf); return -1; } int generalized_eddsa_25519_verify( const unsigned char* signature, const unsigned char* eddsa_25519_pubkey_bytes, const unsigned char* msg, const unsigned long msg_len, const unsigned char* customization_label, const unsigned long customization_label_len) { unsigned char labelset[LABELSETMAXLEN]; unsigned long labelset_len = 0; const unsigned char* R_bytes = NULL; const unsigned char* s_scalar = NULL; unsigned char h_scalar[SCALARLEN]; unsigned char* M_buf = NULL; unsigned char R_calc_bytes[POINTLEN]; if (signature == NULL) goto err; if (eddsa_25519_pubkey_bytes == NULL) goto err; if (msg == NULL) goto err; if (customization_label == NULL && customization_label_len != 0) goto err; if (customization_label_len > LABELMAXLEN) goto err; if (msg_len > MSGMAXLEN) goto err; if ((M_buf = malloc(msg_len + MSTART)) == 0) goto err; memcpy(M_buf + MSTART, msg, msg_len); if (labelset_new(labelset, &labelset_len, LABELSETMAXLEN, NULL, 0, customization_label, customization_label_len) != 0) goto err; R_bytes = signature; s_scalar = signature + POINTLEN; if (!point_isreduced(eddsa_25519_pubkey_bytes)) goto err; if (!point_isreduced(R_bytes)) goto err; if (!sc_isreduced(s_scalar)) goto err; if (generalized_challenge(h_scalar, labelset, labelset_len, NULL, 0, R_bytes, eddsa_25519_pubkey_bytes, M_buf, MSTART, msg_len) != 0) goto err; if (generalized_solve_commitment(R_calc_bytes, NULL, NULL, s_scalar, eddsa_25519_pubkey_bytes, h_scalar) != 0) goto err; if (crypto_verify_32(R_bytes, R_calc_bytes) != 0) goto err; free(M_buf); return 0; err: free(M_buf); return -1; } libsignal-protocol-c-2.3.3/src/curve25519/ed25519/additions/generalized/gen_eddsa.h000066400000000000000000000051441363751346500274330ustar00rootroot00000000000000#ifndef __GEN_EDDSA_H__ #define __GEN_EDDSA_H__ #include "ge.h" /* B: base point R: commitment (point), r: private nonce (scalar) K: encoded public key k: private key (scalar) Z: 32-bytes random M: buffer containing message, message starts at M_start, continues for M_len r = hash(B || labelset || Z || pad1 || k || pad2 || labelset || K || extra || M) (mod q) */ int generalized_commit(unsigned char* R_bytes, unsigned char* r_scalar, const unsigned char* labelset, const unsigned long labelset_len, const unsigned char* extra, const unsigned long extra_len, const unsigned char* K_bytes, const unsigned char* k_scalar, const unsigned char* Z, unsigned char* M_buf, const unsigned long M_start, const unsigned long M_len); /* if is_labelset_empty(labelset): return hash(R || K || M) (mod q) else: return hash(B || labelset || R || labelset || K || extra || M) (mod q) */ int generalized_challenge(unsigned char* h_scalar, const unsigned char* labelset, const unsigned long labelset_len, const unsigned char* extra, const unsigned long extra_len, const unsigned char* R_bytes, const unsigned char* K_bytes, unsigned char* M_buf, const unsigned long M_start, const unsigned long M_len); /* return r + kh (mod q) */ int generalized_prove(unsigned char* out_scalar, const unsigned char* r_scalar, const unsigned char* k_scalar, const unsigned char* h_scalar); /* R = B^s / K^h */ int generalized_solve_commitment(unsigned char* R_bytes_out, ge_p3* K_point_out, const ge_p3* B_point, const unsigned char* s_scalar, const unsigned char* K_bytes, const unsigned char* h_scalar); int generalized_eddsa_25519_sign( unsigned char* signature_out, const unsigned char* eddsa_25519_pubkey_bytes, const unsigned char* eddsa_25519_privkey_scalar, const unsigned char* msg, const unsigned long msg_len, const unsigned char* random, const unsigned char* customization_label, const unsigned long customization_label_len); int generalized_eddsa_25519_verify( const unsigned char* signature, const unsigned char* eddsa_25519_pubkey, const unsigned char* msg, const unsigned long msg_len, const unsigned char* customization_label, const unsigned long customization_label_len); #endif libsignal-protocol-c-2.3.3/src/curve25519/ed25519/additions/generalized/gen_labelset.c000066400000000000000000000106141363751346500301370ustar00rootroot00000000000000#include #include #include "gen_labelset.h" #include "gen_constants.h" const unsigned char B_bytes[] = { 0x58, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, }; unsigned char* buffer_add(unsigned char* bufptr, const unsigned char* bufend, const unsigned char* in, const unsigned long in_len) { unsigned long count = 0; if (bufptr == NULL || bufend == NULL || bufptr > bufend) return NULL; if (in == NULL && in_len != 0) return NULL; if (bufend - bufptr < in_len) return NULL; for (count=0; count < in_len; count++) { if (bufptr >= bufend) return NULL; *bufptr++ = *in++; } return bufptr; } unsigned char* buffer_pad(const unsigned char* buf, unsigned char* bufptr, const unsigned char* bufend) { unsigned long count = 0; unsigned long pad_len = 0; if (buf == NULL || bufptr == NULL || bufend == NULL || bufptr >= bufend || bufptr < buf) return NULL; pad_len = (BLOCKLEN - ((bufptr-buf) % BLOCKLEN)) % BLOCKLEN; if (bufend - bufptr < pad_len) return NULL; for (count=0; count < pad_len; count++) { if (bufptr >= bufend) return NULL; *bufptr++ = 0; } return bufptr; } int labelset_new(unsigned char* labelset, unsigned long* labelset_len, const unsigned long labelset_maxlen, const unsigned char* protocol_name, const unsigned char protocol_name_len, const unsigned char* customization_label, const unsigned char customization_label_len) { unsigned char* bufptr; *labelset_len = 0; if (labelset == NULL) return -1; if (labelset_len == NULL) return -1; if (labelset_maxlen > LABELSETMAXLEN) return -1; if (labelset_maxlen < 3 + protocol_name_len + customization_label_len) return -1; if (protocol_name == NULL && protocol_name_len != 0) return -1; if (customization_label == NULL && customization_label_len != 0) return -1; if (protocol_name_len > LABELMAXLEN) return -1; if (customization_label_len > LABELMAXLEN) return -1; bufptr = labelset; *bufptr++ = 2; *bufptr++ = protocol_name_len; bufptr = buffer_add(bufptr, labelset + labelset_maxlen, protocol_name, protocol_name_len); if (bufptr != NULL && bufptr < labelset + labelset_maxlen) *bufptr++ = customization_label_len; bufptr = buffer_add(bufptr, labelset + labelset_maxlen, customization_label, customization_label_len); if (bufptr != NULL && bufptr - labelset == 3 + protocol_name_len + customization_label_len) { *labelset_len = bufptr - labelset; return 0; } return -1; } int labelset_add(unsigned char* labelset, unsigned long* labelset_len, const unsigned long labelset_maxlen, const unsigned char* label, const unsigned char label_len) { unsigned char* bufptr; if (labelset_len == NULL) return -1; if (*labelset_len > LABELSETMAXLEN || labelset_maxlen > LABELSETMAXLEN) return -1; if (*labelset_len >= labelset_maxlen || *labelset_len + label_len + 1 > labelset_maxlen) return -1; if (*labelset_len < 3 || labelset_maxlen < 4) return -1; if (label_len > LABELMAXLEN) return -1; labelset[0]++; labelset[*labelset_len] = label_len; bufptr = labelset + *labelset_len + 1; bufptr = buffer_add(bufptr, labelset + labelset_maxlen, label, label_len); if (bufptr == NULL) return -1; if (bufptr - labelset >= labelset_maxlen) return -1; if (bufptr - labelset != *labelset_len + 1 + label_len) return -1; *labelset_len += (1 + label_len); return 0; } int labelset_validate(const unsigned char* labelset, const unsigned long labelset_len) { unsigned char num_labels = 0; unsigned char count = 0; unsigned long offset = 0; unsigned char label_len = 0; if (labelset == NULL) return -1; if (labelset_len < 3 || labelset_len > LABELSETMAXLEN) return -1; num_labels = labelset[0]; offset = 1; for (count = 0; count < num_labels; count++) { label_len = labelset[offset]; if (label_len > LABELMAXLEN) return -1; offset += 1 + label_len; if (offset > labelset_len) return -1; } if (offset != labelset_len) return -1; return 0; } int labelset_is_empty(const unsigned char* labelset, const unsigned long labelset_len) { if (labelset_len != 3) return 0; return 1; } libsignal-protocol-c-2.3.3/src/curve25519/ed25519/additions/generalized/gen_labelset.h000066400000000000000000000020121363751346500301350ustar00rootroot00000000000000#ifndef __GEN_LABELSET_H__ #define __GEN_LABELSET_H__ extern const unsigned char B_bytes[]; unsigned char* buffer_add(unsigned char* bufptr, const unsigned char* bufend, const unsigned char* in, const unsigned long in_len); unsigned char* buffer_pad(const unsigned char* buf, unsigned char* bufptr, const unsigned char* bufend); int labelset_new(unsigned char* labelset, unsigned long* labelset_len, const unsigned long labelset_maxlen, const unsigned char* protocol_name, const unsigned char protocol_name_len, const unsigned char* customization_label, const unsigned char customization_label_len); int labelset_add(unsigned char* labelset, unsigned long* labelset_len, const unsigned long labelset_maxlen, const unsigned char* label, const unsigned char label_len); int labelset_validate(const unsigned char* labelset, const unsigned long labelset_len); int labelset_is_empty(const unsigned char* labelset, const unsigned long labelset_len); #endif libsignal-protocol-c-2.3.3/src/curve25519/ed25519/additions/generalized/gen_veddsa.c000066400000000000000000000241451363751346500276160ustar00rootroot00000000000000#include #include "gen_eddsa.h" #include "gen_veddsa.h" #include "gen_constants.h" #include "gen_labelset.h" #include "gen_crypto_additions.h" #include "crypto_hash_sha512.h" #include "crypto_verify_32.h" #include "crypto_additions.h" #include "zeroize.h" #include "ge.h" #include "sc.h" #include "utility.h" static int generalized_calculate_Bv(ge_p3* Bv_point, const unsigned char* labelset, const unsigned long labelset_len, const unsigned char* K_bytes, unsigned char* M_buf, const unsigned long M_start, const unsigned long M_len) { unsigned char* bufptr; unsigned long prefix_len = 0; if (labelset_validate(labelset, labelset_len) != 0) return -1; if (Bv_point == NULL || K_bytes == NULL || M_buf == NULL) return -1; prefix_len = 2*POINTLEN + labelset_len; if (prefix_len > M_start) return -1; bufptr = M_buf + M_start - prefix_len; bufptr = buffer_add(bufptr, M_buf + M_start, B_bytes, POINTLEN); bufptr = buffer_add(bufptr, M_buf + M_start, labelset, labelset_len); bufptr = buffer_add(bufptr, M_buf + M_start, K_bytes, POINTLEN); if (bufptr == NULL || bufptr != M_buf + M_start) return -1; hash_to_point(Bv_point, M_buf + M_start - prefix_len, prefix_len + M_len); if (ge_isneutral(Bv_point)) return -1; return 0; } static int generalized_calculate_vrf_output(unsigned char* vrf_output, const unsigned char* labelset, const unsigned long labelset_len, const ge_p3* cKv_point) { unsigned char buf[BUFLEN]; unsigned char* bufptr = buf; unsigned char* bufend = buf + BUFLEN; unsigned char cKv_bytes[POINTLEN]; unsigned char hash[HASHLEN]; if (vrf_output == NULL) return -1; memset(vrf_output, 0, VRFOUTPUTLEN); if (labelset_len + 2*POINTLEN > BUFLEN) return -1; if (labelset_validate(labelset, labelset_len) != 0) return -1; if (cKv_point == NULL) return -1; if (VRFOUTPUTLEN > HASHLEN) return -1; ge_p3_tobytes(cKv_bytes, cKv_point); bufptr = buffer_add(bufptr, bufend, B_bytes, POINTLEN); bufptr = buffer_add(bufptr, bufend, labelset, labelset_len); bufptr = buffer_add(bufptr, bufend, cKv_bytes, POINTLEN); if (bufptr == NULL) return -1; if (bufptr - buf > BUFLEN) return -1; crypto_hash_sha512(hash, buf, bufptr - buf); memcpy(vrf_output, hash, VRFOUTPUTLEN); return 0; } int generalized_veddsa_25519_sign( unsigned char* signature_out, const unsigned char* eddsa_25519_pubkey_bytes, const unsigned char* eddsa_25519_privkey_scalar, const unsigned char* msg, const unsigned long msg_len, const unsigned char* random, const unsigned char* customization_label, const unsigned long customization_label_len) { unsigned char labelset[LABELSETMAXLEN]; unsigned long labelset_len = 0; ge_p3 Bv_point; ge_p3 Kv_point; ge_p3 Rv_point; unsigned char Bv_bytes[POINTLEN]; unsigned char Kv_bytes[POINTLEN]; unsigned char Rv_bytes[POINTLEN]; unsigned char R_bytes[POINTLEN]; unsigned char r_scalar[SCALARLEN]; unsigned char h_scalar[SCALARLEN]; unsigned char s_scalar[SCALARLEN]; unsigned char extra[3*POINTLEN]; unsigned char* M_buf = NULL; char* protocol_name = "VEdDSA_25519_SHA512_Elligator2"; if (signature_out == NULL) goto err; memset(signature_out, 0, VRFSIGNATURELEN); if (eddsa_25519_pubkey_bytes == NULL) goto err; if (eddsa_25519_privkey_scalar == NULL) goto err; if (msg == NULL) goto err; if (customization_label == NULL && customization_label_len != 0) goto err; if (customization_label_len > LABELMAXLEN) goto err; if (msg_len > MSGMAXLEN) goto err; if ((M_buf = malloc(msg_len + MSTART)) == 0) { goto err; } memcpy(M_buf + MSTART, msg, msg_len); // labelset = new_labelset(protocol_name, customization_label) if (labelset_new(labelset, &labelset_len, LABELSETMAXLEN, (unsigned char*)protocol_name, strlen(protocol_name), customization_label, customization_label_len) != 0) goto err; // labelset1 = add_label(labels, "1") // Bv = hash(hash(labelset1 || K) || M) // Kv = k * Bv labelset_add(labelset, &labelset_len, LABELSETMAXLEN, (unsigned char*)"1", 1); if (generalized_calculate_Bv(&Bv_point, labelset, labelset_len, eddsa_25519_pubkey_bytes, M_buf, MSTART, msg_len) != 0) goto err; ge_scalarmult(&Kv_point, eddsa_25519_privkey_scalar, &Bv_point); ge_p3_tobytes(Bv_bytes, &Bv_point); ge_p3_tobytes(Kv_bytes, &Kv_point); // labelset2 = add_label(labels, "2") // R, r = commit(labelset2, (Bv || Kv), (K,k), Z, M) labelset[labelset_len-1] = (unsigned char)'2'; memcpy(extra, Bv_bytes, POINTLEN); memcpy(extra + POINTLEN, Kv_bytes, POINTLEN); if (generalized_commit(R_bytes, r_scalar, labelset, labelset_len, extra, 2*POINTLEN, eddsa_25519_pubkey_bytes, eddsa_25519_privkey_scalar, random, M_buf, MSTART, msg_len) != 0) goto err; // Rv = r * Bv ge_scalarmult(&Rv_point, r_scalar, &Bv_point); ge_p3_tobytes(Rv_bytes, &Rv_point); // labelset3 = add_label(labels, "3") // h = challenge(labelset3, (Bv || Kv || Rv), R, K, M) labelset[labelset_len-1] = (unsigned char)'3'; memcpy(extra + 2*POINTLEN, Rv_bytes, POINTLEN); if (generalized_challenge(h_scalar, labelset, labelset_len, extra, 3*POINTLEN, R_bytes, eddsa_25519_pubkey_bytes, M_buf, MSTART, msg_len) != 0) goto err; // s = prove(r, k, h) if (generalized_prove(s_scalar, r_scalar, eddsa_25519_privkey_scalar, h_scalar) != 0) goto err; // return (Kv || h || s) memcpy(signature_out, Kv_bytes, POINTLEN); memcpy(signature_out + POINTLEN, h_scalar, SCALARLEN); memcpy(signature_out + POINTLEN + SCALARLEN, s_scalar, SCALARLEN); zeroize(r_scalar, SCALARLEN); zeroize_stack(); free(M_buf); return 0; err: zeroize(r_scalar, SCALARLEN); zeroize_stack(); free(M_buf); return -1; } int generalized_veddsa_25519_verify( unsigned char* vrf_out, const unsigned char* signature, const unsigned char* eddsa_25519_pubkey_bytes, const unsigned char* msg, const unsigned long msg_len, const unsigned char* customization_label, const unsigned long customization_label_len) { unsigned char labelset[LABELSETMAXLEN]; unsigned long labelset_len = 0; const unsigned char* Kv_bytes; const unsigned char* h_scalar; const unsigned char* s_scalar; ge_p3 Bv_point, K_point, Kv_point, cK_point, cKv_point; unsigned char Bv_bytes[POINTLEN]; unsigned char R_calc_bytes[POINTLEN]; unsigned char Rv_calc_bytes[POINTLEN]; unsigned char h_calc_scalar[SCALARLEN]; unsigned char extra[3*POINTLEN]; unsigned char* M_buf = NULL; char* protocol_name = "VEdDSA_25519_SHA512_Elligator2"; if (vrf_out == NULL) goto err; memset(vrf_out, 0, VRFOUTPUTLEN); if (signature == NULL) goto err; if (eddsa_25519_pubkey_bytes == NULL) goto err; if (msg == NULL) goto err; if (customization_label == NULL && customization_label_len != 0) goto err; if (customization_label_len > LABELMAXLEN) goto err; if (msg_len > MSGMAXLEN) goto err; if ((M_buf = malloc(msg_len + MSTART)) == 0) { goto err; } memcpy(M_buf + MSTART, msg, msg_len); Kv_bytes = signature; h_scalar = signature + POINTLEN; s_scalar = signature + POINTLEN + SCALARLEN; if (!point_isreduced(eddsa_25519_pubkey_bytes)) goto err; if (!point_isreduced(Kv_bytes)) goto err; if (!sc_isreduced(h_scalar)) goto err; if (!sc_isreduced(s_scalar)) goto err; // labelset = new_labelset(protocol_name, customization_label) if (labelset_new(labelset, &labelset_len, LABELSETMAXLEN, (unsigned char*)protocol_name, strlen(protocol_name), customization_label, customization_label_len) != 0) goto err; // labelset1 = add_label(labels, "1") // Bv = hash(hash(labelset1 || K) || M) labelset_add(labelset, &labelset_len, LABELSETMAXLEN, (unsigned char*)"1", 1); if (generalized_calculate_Bv(&Bv_point, labelset, labelset_len, eddsa_25519_pubkey_bytes, M_buf, MSTART, msg_len) != 0) goto err; ge_p3_tobytes(Bv_bytes, &Bv_point); // R = solve_commitment(B, s, K, h) if (generalized_solve_commitment(R_calc_bytes, &K_point, NULL, s_scalar, eddsa_25519_pubkey_bytes, h_scalar) != 0) goto err; // Rv = solve_commitment(Bv, s, Kv, h) if (generalized_solve_commitment(Rv_calc_bytes, &Kv_point, &Bv_point, s_scalar, Kv_bytes, h_scalar) != 0) goto err; ge_scalarmult_cofactor(&cK_point, &K_point); ge_scalarmult_cofactor(&cKv_point, &Kv_point); if (ge_isneutral(&cK_point) || ge_isneutral(&cKv_point) || ge_isneutral(&Bv_point)) goto err; // labelset3 = add_label(labels, "3") // h = challenge(labelset3, (Bv || Kv || Rv), R, K, M) labelset[labelset_len-1] = (unsigned char)'3'; memcpy(extra, Bv_bytes, POINTLEN); memcpy(extra + POINTLEN, Kv_bytes, POINTLEN); memcpy(extra + 2*POINTLEN, Rv_calc_bytes, POINTLEN); if (generalized_challenge(h_calc_scalar, labelset, labelset_len, extra, 3*POINTLEN, R_calc_bytes, eddsa_25519_pubkey_bytes, M_buf, MSTART, msg_len) != 0) goto err; // if bytes_equal(h, h') if (crypto_verify_32(h_scalar, h_calc_scalar) != 0) goto err; // labelset4 = add_label(labels, "4") // v = hash(labelset4 || c*Kv) labelset[labelset_len-1] = (unsigned char)'4'; if (generalized_calculate_vrf_output(vrf_out, labelset, labelset_len, &cKv_point) != 0) goto err; free(M_buf); return 0; err: free(M_buf); return -1; } libsignal-protocol-c-2.3.3/src/curve25519/ed25519/additions/generalized/gen_veddsa.h000066400000000000000000000016641363751346500276240ustar00rootroot00000000000000#ifndef __GEN_VEDDSA_H__ #define __GEN_VEDDSA_H__ int generalized_veddsa_25519_sign( unsigned char* signature_out, const unsigned char* eddsa_25519_pubkey_bytes, const unsigned char* eddsa_25519_privkey_scalar, const unsigned char* msg, const unsigned long msg_len, const unsigned char* random, const unsigned char* customization_label, const unsigned long customization_label_len); int generalized_veddsa_25519_verify( unsigned char* vrf_out, const unsigned char* signature, const unsigned char* eddsa_25519_pubkey_bytes, const unsigned char* msg, const unsigned long msg_len, const unsigned char* customization_label, const unsigned long customization_label_len); #endif libsignal-protocol-c-2.3.3/src/curve25519/ed25519/additions/generalized/gen_x.c000066400000000000000000000106601363751346500266140ustar00rootroot00000000000000#include #include "crypto_additions.h" #include "gen_x.h" #include "gen_constants.h" #include "gen_eddsa.h" #include "gen_veddsa.h" #include "gen_crypto_additions.h" #include "zeroize.h" static int convert_25519_pubkey(unsigned char* ed_pubkey_bytes, const unsigned char* x25519_pubkey_bytes) { fe u; fe y; /* Convert the X25519 public key into an Ed25519 public key. y = (u - 1) / (u + 1) NOTE: u=-1 is converted to y=0 since fe_invert is mod-exp */ if (!fe_isreduced(x25519_pubkey_bytes)) return -1; fe_frombytes(u, x25519_pubkey_bytes); fe_montx_to_edy(y, u); fe_tobytes(ed_pubkey_bytes, y); return 0; } static int calculate_25519_keypair(unsigned char* K_bytes, unsigned char* k_scalar, const unsigned char* x25519_privkey_scalar) { unsigned char kneg[SCALARLEN]; ge_p3 ed_pubkey_point; unsigned char sign_bit = 0; if (SCALARLEN != 32) return -1; /* Convert the Curve25519 privkey to an Ed25519 public key */ ge_scalarmult_base(&ed_pubkey_point, x25519_privkey_scalar); ge_p3_tobytes(K_bytes, &ed_pubkey_point); /* Force Edwards sign bit to zero */ sign_bit = (K_bytes[31] & 0x80) >> 7; memcpy(k_scalar, x25519_privkey_scalar, 32); sc_neg(kneg, k_scalar); sc_cmov(k_scalar, kneg, sign_bit); K_bytes[31] &= 0x7F; zeroize(kneg, SCALARLEN); return 0; } int generalized_xeddsa_25519_sign(unsigned char* signature_out, const unsigned char* x25519_privkey_scalar, const unsigned char* msg, const unsigned long msg_len, const unsigned char* random, const unsigned char* customization_label, const unsigned long customization_label_len) { unsigned char K_bytes[POINTLEN]; unsigned char k_scalar[SCALARLEN]; int retval = -1; if (calculate_25519_keypair(K_bytes, k_scalar, x25519_privkey_scalar) != 0) return -1; retval = generalized_eddsa_25519_sign(signature_out, K_bytes, k_scalar, msg, msg_len, random, customization_label, customization_label_len); zeroize(k_scalar, SCALARLEN); return retval; } int generalized_xveddsa_25519_sign( unsigned char* signature_out, const unsigned char* x25519_privkey_scalar, const unsigned char* msg, const unsigned long msg_len, const unsigned char* random, const unsigned char* customization_label, const unsigned long customization_label_len) { unsigned char K_bytes[POINTLEN]; unsigned char k_scalar[SCALARLEN]; int retval = -1; if (calculate_25519_keypair(K_bytes, k_scalar, x25519_privkey_scalar) != 0) return -1; retval = generalized_veddsa_25519_sign(signature_out, K_bytes, k_scalar, msg, msg_len, random, customization_label, customization_label_len); zeroize(k_scalar, SCALARLEN); return retval; } int generalized_xeddsa_25519_verify( const unsigned char* signature, const unsigned char* x25519_pubkey_bytes, const unsigned char* msg, const unsigned long msg_len, const unsigned char* customization_label, const unsigned long customization_label_len) { unsigned char K_bytes[POINTLEN]; if (convert_25519_pubkey(K_bytes, x25519_pubkey_bytes) != 0) return -1; return generalized_eddsa_25519_verify(signature, K_bytes, msg, msg_len, customization_label, customization_label_len); } int generalized_xveddsa_25519_verify( unsigned char* vrf_out, const unsigned char* signature, const unsigned char* x25519_pubkey_bytes, const unsigned char* msg, const unsigned long msg_len, const unsigned char* customization_label, const unsigned long customization_label_len) { unsigned char K_bytes[POINTLEN]; if (convert_25519_pubkey(K_bytes, x25519_pubkey_bytes) != 0) return -1; return generalized_veddsa_25519_verify(vrf_out, signature, K_bytes, msg, msg_len, customization_label, customization_label_len); } libsignal-protocol-c-2.3.3/src/curve25519/ed25519/additions/generalized/gen_x.h000066400000000000000000000034351363751346500266230ustar00rootroot00000000000000#ifndef __GEN_X_H #define __GEN_X_H int generalized_xeddsa_25519_sign(unsigned char* signature_out, /* 64 bytes */ const unsigned char* x25519_privkey_scalar, /* 32 bytes */ const unsigned char* msg, const unsigned long msg_len, const unsigned char* random, /* 32 bytes */ const unsigned char* customization_label, const unsigned long customization_label_len); int generalized_xeddsa_25519_verify( const unsigned char* signature, /* 64 bytes */ const unsigned char* x25519_pubkey_bytes, /* 32 bytes */ const unsigned char* msg, const unsigned long msg_len, const unsigned char* customization_label, const unsigned long customization_label_len); int generalized_xveddsa_25519_sign( unsigned char* signature_out, /* 96 bytes */ const unsigned char* x25519_privkey_scalar, /* 32 bytes */ const unsigned char* msg, const unsigned long msg_len, const unsigned char* random, /* 32 bytes */ const unsigned char* customization_label, const unsigned long customization_label_len); int generalized_xveddsa_25519_verify( unsigned char* vrf_out, /* 32 bytes */ const unsigned char* signature, /* 96 bytes */ const unsigned char* x25519_pubkey_bytes, /* 32 bytes */ const unsigned char* msg, const unsigned long msg_len, const unsigned char* customization_label, const unsigned long customization_label_len); #endif libsignal-protocol-c-2.3.3/src/curve25519/ed25519/additions/generalized/point_isreduced.c000066400000000000000000000003671363751346500306770ustar00rootroot00000000000000#include #include "fe.h" #include "crypto_additions.h" int point_isreduced(const unsigned char* p) { unsigned char strict[32]; memmove(strict, p, 32); strict[31] &= 0x7F; /* mask off sign bit */ return fe_isreduced(strict); } libsignal-protocol-c-2.3.3/src/curve25519/ed25519/additions/generalized/sc_isreduced.c000066400000000000000000000005051363751346500301450ustar00rootroot00000000000000#include #include "fe.h" #include "sc.h" #include "crypto_additions.h" #include "crypto_verify_32.h" int sc_isreduced(const unsigned char* s) { unsigned char strict[64]; memset(strict, 0, 64); memmove(strict, s, 32); sc_reduce(strict); if (crypto_verify_32(strict, s) != 0) return 0; return 1; } libsignal-protocol-c-2.3.3/src/curve25519/ed25519/additions/keygen.c000066400000000000000000000011551363751346500245040ustar00rootroot00000000000000#include "ge.h" #include "keygen.h" #include "crypto_additions.h" void curve25519_keygen(unsigned char* curve25519_pubkey_out, const unsigned char* curve25519_privkey_in) { /* Perform a fixed-base multiplication of the Edwards base point, (which is efficient due to precalculated tables), then convert to the Curve25519 montgomery-format public key. NOTE: y=1 is converted to u=0 since fe_invert is mod-exp */ ge_p3 ed; /* Ed25519 pubkey point */ fe u; ge_scalarmult_base(&ed, curve25519_privkey_in); ge_p3_to_montx(u, &ed); fe_tobytes(curve25519_pubkey_out, u); } libsignal-protocol-c-2.3.3/src/curve25519/ed25519/additions/keygen.h000066400000000000000000000006051363751346500245100ustar00rootroot00000000000000 #ifndef __KEYGEN_H__ #define __KEYGEN_H__ /* Sets and clears bits to make a random 32 bytes into a private key */ void sc_clamp(unsigned char* a); /* The private key should be 32 random bytes "clamped" by sc_clamp() */ void curve25519_keygen(unsigned char* curve25519_pubkey_out, /* 32 bytes */ const unsigned char* curve25519_privkey_in); /* 32 bytes */ #endif libsignal-protocol-c-2.3.3/src/curve25519/ed25519/additions/open_modified.c000066400000000000000000000016671363751346500260330ustar00rootroot00000000000000#include #include "crypto_sign.h" #include "crypto_hash_sha512.h" #include "crypto_verify_32.h" #include "ge.h" #include "sc.h" #include "crypto_additions.h" int crypto_sign_open_modified( unsigned char *m, const unsigned char *sm,unsigned long long smlen, const unsigned char *pk ) { unsigned char pkcopy[32]; unsigned char rcopy[32]; unsigned char scopy[32]; unsigned char h[64]; unsigned char rcheck[32]; ge_p3 A; ge_p2 R; if (smlen < 64) goto badsig; if (sm[63] & 224) goto badsig; /* strict parsing of s */ if (ge_frombytes_negate_vartime(&A,pk) != 0) goto badsig; memmove(pkcopy,pk,32); memmove(rcopy,sm,32); memmove(scopy,sm + 32,32); memmove(m,sm,smlen); memmove(m + 32,pkcopy,32); crypto_hash_sha512(h,m,smlen); sc_reduce(h); ge_double_scalarmult_vartime(&R,h,&A,scopy); ge_tobytes(rcheck,&R); if (crypto_verify_32(rcheck,rcopy) == 0) { return 0; } badsig: return -1; } libsignal-protocol-c-2.3.3/src/curve25519/ed25519/additions/sc_clamp.c000066400000000000000000000001611363751346500247770ustar00rootroot00000000000000#include "crypto_additions.h" void sc_clamp(unsigned char* a) { a[0] &= 248; a[31] &= 127; a[31] |= 64; } libsignal-protocol-c-2.3.3/src/curve25519/ed25519/additions/sc_cmov.c000066400000000000000000000007211363751346500246510ustar00rootroot00000000000000#include "crypto_additions.h" /* Replace (f,g) with (g,g) if b == 1; replace (f,g) with (f,g) if b == 0. Preconditions: b in {0,1}. */ void sc_cmov(unsigned char* f, const unsigned char* g, unsigned char b) { int count=32; unsigned char x[32]; for (count=0; count < 32; count++) x[count] = f[count] ^ g[count]; b = -b; for (count=0; count < 32; count++) x[count] &= b; for (count=0; count < 32; count++) f[count] = f[count] ^ x[count]; } libsignal-protocol-c-2.3.3/src/curve25519/ed25519/additions/sc_neg.c000066400000000000000000000017441363751346500244640ustar00rootroot00000000000000#include #include "crypto_additions.h" #include "sc.h" /* l = order of base point = 2^252 + 27742317777372353535851937790883648493 */ /* static unsigned char l[32] = {0xed, 0xd3, 0xf5, 0x5c, 0x1a, 0x63, 0x12, 0x58, 0xd6, 0x9c, 0xf7, 0xa2, 0xde, 0xf9, 0xde, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0, 0x10}; */ static unsigned char lminus1[32] = {0xec, 0xd3, 0xf5, 0x5c, 0x1a, 0x63, 0x12, 0x58, 0xd6, 0x9c, 0xf7, 0xa2, 0xde, 0xf9, 0xde, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10}; /* b = -a (mod l) */ void sc_neg(unsigned char *b, const unsigned char *a) { unsigned char zero[32]; memset(zero, 0, 32); sc_muladd(b, lminus1, a, zero); /* b = (-1)a + 0 (mod l) */ } libsignal-protocol-c-2.3.3/src/curve25519/ed25519/additions/sign_modified.c000066400000000000000000000024561363751346500260270ustar00rootroot00000000000000#include #include "crypto_sign.h" #include "crypto_hash_sha512.h" #include "ge.h" #include "sc.h" #include "zeroize.h" #include "crypto_additions.h" /* NEW: Compare to pristine crypto_sign() Uses explicit private key for nonce derivation and as scalar, instead of deriving both from a master key. */ int crypto_sign_modified( unsigned char *sm, const unsigned char *m,unsigned long long mlen, const unsigned char *sk, const unsigned char* pk, const unsigned char* random ) { unsigned char nonce[64]; unsigned char hram[64]; ge_p3 R; int count=0; memmove(sm + 64,m,mlen); memmove(sm + 32,sk,32); /* NEW: Use privkey directly for nonce derivation */ /* NEW : add prefix to separate hash uses - see .h */ sm[0] = 0xFE; for (count = 1; count < 32; count++) sm[count] = 0xFF; /* NEW: add suffix of random data */ memmove(sm + mlen + 64, random, 64); crypto_hash_sha512(nonce,sm,mlen + 128); memmove(sm + 32,pk,32); sc_reduce(nonce); ge_scalarmult_base(&R,nonce); ge_p3_tobytes(sm,&R); crypto_hash_sha512(hram,sm,mlen + 64); sc_reduce(hram); sc_muladd(sm + 32,hram,sk,nonce); /* NEW: Use privkey directly */ /* Erase any traces of private scalar or nonce left in the stack from sc_muladd */ zeroize_stack(); zeroize(nonce, 64); return 0; } libsignal-protocol-c-2.3.3/src/curve25519/ed25519/additions/utility.c000066400000000000000000000011221363751346500247170ustar00rootroot00000000000000#include #include #include "utility.h" void print_vector(const char* name, const unsigned char* v) { int count; printf("%s = \n", name); for (count = 0; count < 32; count++) printf("%02x ", v[count]); printf("\n"); } void print_bytes(const char* name, const unsigned char* v, int numbytes) { int count; printf("%s = \n", name); for (count = 0; count < numbytes; count++) printf("%02x ", v[count]); printf("\n"); } void print_fe(const char* name, const fe in) { unsigned char bytes[32]; fe_tobytes(bytes, in); print_vector(name, bytes); } libsignal-protocol-c-2.3.3/src/curve25519/ed25519/additions/utility.h000066400000000000000000000003741363751346500247340ustar00rootroot00000000000000 #ifndef __UTILITY_H__ #define __UTILITY_H__ #include "fe.h" void print_vector(const char* name, const unsigned char* v); void print_bytes(const char* name, const unsigned char* v, int numbytes); void print_fe(const char* name, const fe in); #endif libsignal-protocol-c-2.3.3/src/curve25519/ed25519/additions/xeddsa.c000066400000000000000000000044771363751346500245040ustar00rootroot00000000000000#include #include "ge.h" #include "crypto_additions.h" #include "zeroize.h" #include "xeddsa.h" #include "crypto_verify_32.h" int xed25519_sign(unsigned char* signature_out, const unsigned char* curve25519_privkey, const unsigned char* msg, const unsigned long msg_len, const unsigned char* random) { unsigned char a[32], aneg[32]; unsigned char A[32]; ge_p3 ed_pubkey_point; unsigned char *sigbuf; /* working buffer */ unsigned char sign_bit = 0; if ((sigbuf = malloc(msg_len + 128)) == 0) { memset(signature_out, 0, 64); return -1; } /* Convert the Curve25519 privkey to an Ed25519 public key */ ge_scalarmult_base(&ed_pubkey_point, curve25519_privkey); ge_p3_tobytes(A, &ed_pubkey_point); /* Force Edwards sign bit to zero */ sign_bit = (A[31] & 0x80) >> 7; memcpy(a, curve25519_privkey, 32); sc_neg(aneg, a); sc_cmov(a, aneg, sign_bit); A[31] &= 0x7F; /* Perform an Ed25519 signature with explicit private key */ crypto_sign_modified(sigbuf, msg, msg_len, a, A, random); memmove(signature_out, sigbuf, 64); zeroize(a, 32); zeroize(aneg, 32); free(sigbuf); return 0; } int xed25519_verify(const unsigned char* signature, const unsigned char* curve25519_pubkey, const unsigned char* msg, const unsigned long msg_len) { fe u; fe y; unsigned char ed_pubkey[32]; unsigned char verifybuf[MAX_MSG_LEN + 64]; /* working buffer */ unsigned char verifybuf2[MAX_MSG_LEN + 64]; /* working buffer #2 */ if (msg_len > MAX_MSG_LEN) { return -1; } /* Convert the Curve25519 public key into an Ed25519 public key. y = (u - 1) / (u + 1) NOTE: u=-1 is converted to y=0 since fe_invert is mod-exp */ if (!fe_isreduced(curve25519_pubkey)) return -1; fe_frombytes(u, curve25519_pubkey); fe_montx_to_edy(y, u); fe_tobytes(ed_pubkey, y); memmove(verifybuf, signature, 64); memmove(verifybuf+64, msg, msg_len); /* Then perform a normal Ed25519 verification, return 0 on success */ /* The below call has a strange API: */ /* verifybuf = R || S || message */ /* verifybuf2 = internal to next call gets a copy of verifybuf, S gets replaced with pubkey for hashing */ return crypto_sign_open_modified(verifybuf2, verifybuf, 64 + msg_len, ed_pubkey); } libsignal-protocol-c-2.3.3/src/curve25519/ed25519/additions/xeddsa.h000066400000000000000000000011741363751346500245000ustar00rootroot00000000000000 #ifndef __XEDDSA_H__ #define __XEDDSA_H__ /* returns 0 on success */ int xed25519_sign(unsigned char* signature_out, /* 64 bytes */ const unsigned char* curve25519_privkey, /* 32 bytes */ const unsigned char* msg, const unsigned long msg_len, /* <= 256 bytes */ const unsigned char* random); /* 64 bytes */ /* returns 0 on success */ int xed25519_verify(const unsigned char* signature, /* 64 bytes */ const unsigned char* curve25519_pubkey, /* 32 bytes */ const unsigned char* msg, const unsigned long msg_len); /* <= 256 bytes */ #endif libsignal-protocol-c-2.3.3/src/curve25519/ed25519/additions/zeroize.c000066400000000000000000000004301363751346500247040ustar00rootroot00000000000000#include "zeroize.h" void zeroize(unsigned char* b, size_t len) { size_t count = 0; volatile unsigned char *p = b; for (count = 0; count < len; count++) p[count] = 0; } void zeroize_stack() { unsigned char m[ZEROIZE_STACK_SIZE]; zeroize(m, ZEROIZE_STACK_SIZE); } libsignal-protocol-c-2.3.3/src/curve25519/ed25519/additions/zeroize.h000066400000000000000000000002561363751346500247170ustar00rootroot00000000000000#ifndef __ZEROIZE_H__ #define __ZEROIZE_H__ #include #define ZEROIZE_STACK_SIZE 1024 void zeroize(unsigned char* b, size_t len); void zeroize_stack(); #endif libsignal-protocol-c-2.3.3/src/curve25519/ed25519/base.h000066400000000000000000002252511363751346500221700ustar00rootroot00000000000000{ { { 25967493,-14356035,29566456,3660896,-12694345,4014787,27544626,-11754271,-6079156,2047605 }, { -12545711,934262,-2722910,3049990,-727428,9406986,12720692,5043384,19500929,-15469378 }, { -8738181,4489570,9688441,-14785194,10184609,-12363380,29287919,11864899,-24514362,-4438546 }, }, { { -12815894,-12976347,-21581243,11784320,-25355658,-2750717,-11717903,-3814571,-358445,-10211303 }, { -21703237,6903825,27185491,6451973,-29577724,-9554005,-15616551,11189268,-26829678,-5319081 }, { 26966642,11152617,32442495,15396054,14353839,-12752335,-3128826,-9541118,-15472047,-4166697 }, }, { { 15636291,-9688557,24204773,-7912398,616977,-16685262,27787600,-14772189,28944400,-1550024 }, { 16568933,4717097,-11556148,-1102322,15682896,-11807043,16354577,-11775962,7689662,11199574 }, { 30464156,-5976125,-11779434,-15670865,23220365,15915852,7512774,10017326,-17749093,-9920357 }, }, { { -17036878,13921892,10945806,-6033431,27105052,-16084379,-28926210,15006023,3284568,-6276540 }, { 23599295,-8306047,-11193664,-7687416,13236774,10506355,7464579,9656445,13059162,10374397 }, { 7798556,16710257,3033922,2874086,28997861,2835604,32406664,-3839045,-641708,-101325 }, }, { { 10861363,11473154,27284546,1981175,-30064349,12577861,32867885,14515107,-15438304,10819380 }, { 4708026,6336745,20377586,9066809,-11272109,6594696,-25653668,12483688,-12668491,5581306 }, { 19563160,16186464,-29386857,4097519,10237984,-4348115,28542350,13850243,-23678021,-15815942 }, }, { { -15371964,-12862754,32573250,4720197,-26436522,5875511,-19188627,-15224819,-9818940,-12085777 }, { -8549212,109983,15149363,2178705,22900618,4543417,3044240,-15689887,1762328,14866737 }, { -18199695,-15951423,-10473290,1707278,-17185920,3916101,-28236412,3959421,27914454,4383652 }, }, { { 5153746,9909285,1723747,-2777874,30523605,5516873,19480852,5230134,-23952439,-15175766 }, { -30269007,-3463509,7665486,10083793,28475525,1649722,20654025,16520125,30598449,7715701 }, { 28881845,14381568,9657904,3680757,-20181635,7843316,-31400660,1370708,29794553,-1409300 }, }, { { 14499471,-2729599,-33191113,-4254652,28494862,14271267,30290735,10876454,-33154098,2381726 }, { -7195431,-2655363,-14730155,462251,-27724326,3941372,-6236617,3696005,-32300832,15351955 }, { 27431194,8222322,16448760,-3907995,-18707002,11938355,-32961401,-2970515,29551813,10109425 }, }, }, { { { -13657040,-13155431,-31283750,11777098,21447386,6519384,-2378284,-1627556,10092783,-4764171 }, { 27939166,14210322,4677035,16277044,-22964462,-12398139,-32508754,12005538,-17810127,12803510 }, { 17228999,-15661624,-1233527,300140,-1224870,-11714777,30364213,-9038194,18016357,4397660 }, }, { { -10958843,-7690207,4776341,-14954238,27850028,-15602212,-26619106,14544525,-17477504,982639 }, { 29253598,15796703,-2863982,-9908884,10057023,3163536,7332899,-4120128,-21047696,9934963 }, { 5793303,16271923,-24131614,-10116404,29188560,1206517,-14747930,4559895,-30123922,-10897950 }, }, { { -27643952,-11493006,16282657,-11036493,28414021,-15012264,24191034,4541697,-13338309,5500568 }, { 12650548,-1497113,9052871,11355358,-17680037,-8400164,-17430592,12264343,10874051,13524335 }, { 25556948,-3045990,714651,2510400,23394682,-10415330,33119038,5080568,-22528059,5376628 }, }, { { -26088264,-4011052,-17013699,-3537628,-6726793,1920897,-22321305,-9447443,4535768,1569007 }, { -2255422,14606630,-21692440,-8039818,28430649,8775819,-30494562,3044290,31848280,12543772 }, { -22028579,2943893,-31857513,6777306,13784462,-4292203,-27377195,-2062731,7718482,14474653 }, }, { { 2385315,2454213,-22631320,46603,-4437935,-15680415,656965,-7236665,24316168,-5253567 }, { 13741529,10911568,-33233417,-8603737,-20177830,-1033297,33040651,-13424532,-20729456,8321686 }, { 21060490,-2212744,15712757,-4336099,1639040,10656336,23845965,-11874838,-9984458,608372 }, }, { { -13672732,-15087586,-10889693,-7557059,-6036909,11305547,1123968,-6780577,27229399,23887 }, { -23244140,-294205,-11744728,14712571,-29465699,-2029617,12797024,-6440308,-1633405,16678954 }, { -29500620,4770662,-16054387,14001338,7830047,9564805,-1508144,-4795045,-17169265,4904953 }, }, { { 24059557,14617003,19037157,-15039908,19766093,-14906429,5169211,16191880,2128236,-4326833 }, { -16981152,4124966,-8540610,-10653797,30336522,-14105247,-29806336,916033,-6882542,-2986532 }, { -22630907,12419372,-7134229,-7473371,-16478904,16739175,285431,2763829,15736322,4143876 }, }, { { 2379352,11839345,-4110402,-5988665,11274298,794957,212801,-14594663,23527084,-16458268 }, { 33431127,-11130478,-17838966,-15626900,8909499,8376530,-32625340,4087881,-15188911,-14416214 }, { 1767683,7197987,-13205226,-2022635,-13091350,448826,5799055,4357868,-4774191,-16323038 }, }, }, { { { 6721966,13833823,-23523388,-1551314,26354293,-11863321,23365147,-3949732,7390890,2759800 }, { 4409041,2052381,23373853,10530217,7676779,-12885954,21302353,-4264057,1244380,-12919645 }, { -4421239,7169619,4982368,-2957590,30256825,-2777540,14086413,9208236,15886429,16489664 }, }, { { 1996075,10375649,14346367,13311202,-6874135,-16438411,-13693198,398369,-30606455,-712933 }, { -25307465,9795880,-2777414,14878809,-33531835,14780363,13348553,12076947,-30836462,5113182 }, { -17770784,11797796,31950843,13929123,-25888302,12288344,-30341101,-7336386,13847711,5387222 }, }, { { -18582163,-3416217,17824843,-2340966,22744343,-10442611,8763061,3617786,-19600662,10370991 }, { 20246567,-14369378,22358229,-543712,18507283,-10413996,14554437,-8746092,32232924,16763880 }, { 9648505,10094563,26416693,14745928,-30374318,-6472621,11094161,15689506,3140038,-16510092 }, }, { { -16160072,5472695,31895588,4744994,8823515,10365685,-27224800,9448613,-28774454,366295 }, { 19153450,11523972,-11096490,-6503142,-24647631,5420647,28344573,8041113,719605,11671788 }, { 8678025,2694440,-6808014,2517372,4964326,11152271,-15432916,-15266516,27000813,-10195553 }, }, { { -15157904,7134312,8639287,-2814877,-7235688,10421742,564065,5336097,6750977,-14521026 }, { 11836410,-3979488,26297894,16080799,23455045,15735944,1695823,-8819122,8169720,16220347 }, { -18115838,8653647,17578566,-6092619,-8025777,-16012763,-11144307,-2627664,-5990708,-14166033 }, }, { { -23308498,-10968312,15213228,-10081214,-30853605,-11050004,27884329,2847284,2655861,1738395 }, { -27537433,-14253021,-25336301,-8002780,-9370762,8129821,21651608,-3239336,-19087449,-11005278 }, { 1533110,3437855,23735889,459276,29970501,11335377,26030092,5821408,10478196,8544890 }, }, { { 32173121,-16129311,24896207,3921497,22579056,-3410854,19270449,12217473,17789017,-3395995 }, { -30552961,-2228401,-15578829,-10147201,13243889,517024,15479401,-3853233,30460520,1052596 }, { -11614875,13323618,32618793,8175907,-15230173,12596687,27491595,-4612359,3179268,-9478891 }, }, { { 31947069,-14366651,-4640583,-15339921,-15125977,-6039709,-14756777,-16411740,19072640,-9511060 }, { 11685058,11822410,3158003,-13952594,33402194,-4165066,5977896,-5215017,473099,5040608 }, { -20290863,8198642,-27410132,11602123,1290375,-2799760,28326862,1721092,-19558642,-3131606 }, }, }, { { { 7881532,10687937,7578723,7738378,-18951012,-2553952,21820786,8076149,-27868496,11538389 }, { -19935666,3899861,18283497,-6801568,-15728660,-11249211,8754525,7446702,-5676054,5797016 }, { -11295600,-3793569,-15782110,-7964573,12708869,-8456199,2014099,-9050574,-2369172,-5877341 }, }, { { -22472376,-11568741,-27682020,1146375,18956691,16640559,1192730,-3714199,15123619,10811505 }, { 14352098,-3419715,-18942044,10822655,32750596,4699007,-70363,15776356,-28886779,-11974553 }, { -28241164,-8072475,-4978962,-5315317,29416931,1847569,-20654173,-16484855,4714547,-9600655 }, }, { { 15200332,8368572,19679101,15970074,-31872674,1959451,24611599,-4543832,-11745876,12340220 }, { 12876937,-10480056,33134381,6590940,-6307776,14872440,9613953,8241152,15370987,9608631 }, { -4143277,-12014408,8446281,-391603,4407738,13629032,-7724868,15866074,-28210621,-8814099 }, }, { { 26660628,-15677655,8393734,358047,-7401291,992988,-23904233,858697,20571223,8420556 }, { 14620715,13067227,-15447274,8264467,14106269,15080814,33531827,12516406,-21574435,-12476749 }, { 236881,10476226,57258,-14677024,6472998,2466984,17258519,7256740,8791136,15069930 }, }, { { 1276410,-9371918,22949635,-16322807,-23493039,-5702186,14711875,4874229,-30663140,-2331391 }, { 5855666,4990204,-13711848,7294284,-7804282,1924647,-1423175,-7912378,-33069337,9234253 }, { 20590503,-9018988,31529744,-7352666,-2706834,10650548,31559055,-11609587,18979186,13396066 }, }, { { 24474287,4968103,22267082,4407354,24063882,-8325180,-18816887,13594782,33514650,7021958 }, { -11566906,-6565505,-21365085,15928892,-26158305,4315421,-25948728,-3916677,-21480480,12868082 }, { -28635013,13504661,19988037,-2132761,21078225,6443208,-21446107,2244500,-12455797,-8089383 }, }, { { -30595528,13793479,-5852820,319136,-25723172,-6263899,33086546,8957937,-15233648,5540521 }, { -11630176,-11503902,-8119500,-7643073,2620056,1022908,-23710744,-1568984,-16128528,-14962807 }, { 23152971,775386,27395463,14006635,-9701118,4649512,1689819,892185,-11513277,-15205948 }, }, { { 9770129,9586738,26496094,4324120,1556511,-3550024,27453819,4763127,-19179614,5867134 }, { -32765025,1927590,31726409,-4753295,23962434,-16019500,27846559,5931263,-29749703,-16108455 }, { 27461885,-2977536,22380810,1815854,-23033753,-3031938,7283490,-15148073,-19526700,7734629 }, }, }, { { { -8010264,-9590817,-11120403,6196038,29344158,-13430885,7585295,-3176626,18549497,15302069 }, { -32658337,-6171222,-7672793,-11051681,6258878,13504381,10458790,-6418461,-8872242,8424746 }, { 24687205,8613276,-30667046,-3233545,1863892,-1830544,19206234,7134917,-11284482,-828919 }, }, { { 11334899,-9218022,8025293,12707519,17523892,-10476071,10243738,-14685461,-5066034,16498837 }, { 8911542,6887158,-9584260,-6958590,11145641,-9543680,17303925,-14124238,6536641,10543906 }, { -28946384,15479763,-17466835,568876,-1497683,11223454,-2669190,-16625574,-27235709,8876771 }, }, { { -25742899,-12566864,-15649966,-846607,-33026686,-796288,-33481822,15824474,-604426,-9039817 }, { 10330056,70051,7957388,-9002667,9764902,15609756,27698697,-4890037,1657394,3084098 }, { 10477963,-7470260,12119566,-13250805,29016247,-5365589,31280319,14396151,-30233575,15272409 }, }, { { -12288309,3169463,28813183,16658753,25116432,-5630466,-25173957,-12636138,-25014757,1950504 }, { -26180358,9489187,11053416,-14746161,-31053720,5825630,-8384306,-8767532,15341279,8373727 }, { 28685821,7759505,-14378516,-12002860,-31971820,4079242,298136,-10232602,-2878207,15190420 }, }, { { -32932876,13806336,-14337485,-15794431,-24004620,10940928,8669718,2742393,-26033313,-6875003 }, { -1580388,-11729417,-25979658,-11445023,-17411874,-10912854,9291594,-16247779,-12154742,6048605 }, { -30305315,14843444,1539301,11864366,20201677,1900163,13934231,5128323,11213262,9168384 }, }, { { -26280513,11007847,19408960,-940758,-18592965,-4328580,-5088060,-11105150,20470157,-16398701 }, { -23136053,9282192,14855179,-15390078,-7362815,-14408560,-22783952,14461608,14042978,5230683 }, { 29969567,-2741594,-16711867,-8552442,9175486,-2468974,21556951,3506042,-5933891,-12449708 }, }, { { -3144746,8744661,19704003,4581278,-20430686,6830683,-21284170,8971513,-28539189,15326563 }, { -19464629,10110288,-17262528,-3503892,-23500387,1355669,-15523050,15300988,-20514118,9168260 }, { -5353335,4488613,-23803248,16314347,7780487,-15638939,-28948358,9601605,33087103,-9011387 }, }, { { -19443170,-15512900,-20797467,-12445323,-29824447,10229461,-27444329,-15000531,-5996870,15664672 }, { 23294591,-16632613,-22650781,-8470978,27844204,11461195,13099750,-2460356,18151676,13417686 }, { -24722913,-4176517,-31150679,5988919,-26858785,6685065,1661597,-12551441,15271676,-15452665 }, }, }, { { { 11433042,-13228665,8239631,-5279517,-1985436,-725718,-18698764,2167544,-6921301,-13440182 }, { -31436171,15575146,30436815,12192228,-22463353,9395379,-9917708,-8638997,12215110,12028277 }, { 14098400,6555944,23007258,5757252,-15427832,-12950502,30123440,4617780,-16900089,-655628 }, }, { { -4026201,-15240835,11893168,13718664,-14809462,1847385,-15819999,10154009,23973261,-12684474 }, { -26531820,-3695990,-1908898,2534301,-31870557,-16550355,18341390,-11419951,32013174,-10103539 }, { -25479301,10876443,-11771086,-14625140,-12369567,1838104,21911214,6354752,4425632,-837822 }, }, { { -10433389,-14612966,22229858,-3091047,-13191166,776729,-17415375,-12020462,4725005,14044970 }, { 19268650,-7304421,1555349,8692754,-21474059,-9910664,6347390,-1411784,-19522291,-16109756 }, { -24864089,12986008,-10898878,-5558584,-11312371,-148526,19541418,8180106,9282262,10282508 }, }, { { -26205082,4428547,-8661196,-13194263,4098402,-14165257,15522535,8372215,5542595,-10702683 }, { -10562541,14895633,26814552,-16673850,-17480754,-2489360,-2781891,6993761,-18093885,10114655 }, { -20107055,-929418,31422704,10427861,-7110749,6150669,-29091755,-11529146,25953725,-106158 }, }, { { -4234397,-8039292,-9119125,3046000,2101609,-12607294,19390020,6094296,-3315279,12831125 }, { -15998678,7578152,5310217,14408357,-33548620,-224739,31575954,6326196,7381791,-2421839 }, { -20902779,3296811,24736065,-16328389,18374254,7318640,6295303,8082724,-15362489,12339664 }, }, { { 27724736,2291157,6088201,-14184798,1792727,5857634,13848414,15768922,25091167,14856294 }, { -18866652,8331043,24373479,8541013,-701998,-9269457,12927300,-12695493,-22182473,-9012899 }, { -11423429,-5421590,11632845,3405020,30536730,-11674039,-27260765,13866390,30146206,9142070 }, }, { { 3924129,-15307516,-13817122,-10054960,12291820,-668366,-27702774,9326384,-8237858,4171294 }, { -15921940,16037937,6713787,16606682,-21612135,2790944,26396185,3731949,345228,-5462949 }, { -21327538,13448259,25284571,1143661,20614966,-8849387,2031539,-12391231,-16253183,-13582083 }, }, { { 31016211,-16722429,26371392,-14451233,-5027349,14854137,17477601,3842657,28012650,-16405420 }, { -5075835,9368966,-8562079,-4600902,-15249953,6970560,-9189873,16292057,-8867157,3507940 }, { 29439664,3537914,23333589,6997794,-17555561,-11018068,-15209202,-15051267,-9164929,6580396 }, }, }, { { { -12185861,-7679788,16438269,10826160,-8696817,-6235611,17860444,-9273846,-2095802,9304567 }, { 20714564,-4336911,29088195,7406487,11426967,-5095705,14792667,-14608617,5289421,-477127 }, { -16665533,-10650790,-6160345,-13305760,9192020,-1802462,17271490,12349094,26939669,-3752294 }, }, { { -12889898,9373458,31595848,16374215,21471720,13221525,-27283495,-12348559,-3698806,117887 }, { 22263325,-6560050,3984570,-11174646,-15114008,-566785,28311253,5358056,-23319780,541964 }, { 16259219,3261970,2309254,-15534474,-16885711,-4581916,24134070,-16705829,-13337066,-13552195 }, }, { { 9378160,-13140186,-22845982,-12745264,28198281,-7244098,-2399684,-717351,690426,14876244 }, { 24977353,-314384,-8223969,-13465086,28432343,-1176353,-13068804,-12297348,-22380984,6618999 }, { -1538174,11685646,12944378,13682314,-24389511,-14413193,8044829,-13817328,32239829,-5652762 }, }, { { -18603066,4762990,-926250,8885304,-28412480,-3187315,9781647,-10350059,32779359,5095274 }, { -33008130,-5214506,-32264887,-3685216,9460461,-9327423,-24601656,14506724,21639561,-2630236 }, { -16400943,-13112215,25239338,15531969,3987758,-4499318,-1289502,-6863535,17874574,558605 }, }, { { -13600129,10240081,9171883,16131053,-20869254,9599700,33499487,5080151,2085892,5119761 }, { -22205145,-2519528,-16381601,414691,-25019550,2170430,30634760,-8363614,-31999993,-5759884 }, { -6845704,15791202,8550074,-1312654,29928809,-12092256,27534430,-7192145,-22351378,12961482 }, }, { { -24492060,-9570771,10368194,11582341,-23397293,-2245287,16533930,8206996,-30194652,-5159638 }, { -11121496,-3382234,2307366,6362031,-135455,8868177,-16835630,7031275,7589640,8945490 }, { -32152748,8917967,6661220,-11677616,-1192060,-15793393,7251489,-11182180,24099109,-14456170 }, }, { { 5019558,-7907470,4244127,-14714356,-26933272,6453165,-19118182,-13289025,-6231896,-10280736 }, { 10853594,10721687,26480089,5861829,-22995819,1972175,-1866647,-10557898,-3363451,-6441124 }, { -17002408,5906790,221599,-6563147,7828208,-13248918,24362661,-2008168,-13866408,7421392 }, }, { { 8139927,-6546497,32257646,-5890546,30375719,1886181,-21175108,15441252,28826358,-4123029 }, { 6267086,9695052,7709135,-16603597,-32869068,-1886135,14795160,-7840124,13746021,-1742048 }, { 28584902,7787108,-6732942,-15050729,22846041,-7571236,-3181936,-363524,4771362,-8419958 }, }, }, { { { 24949256,6376279,-27466481,-8174608,-18646154,-9930606,33543569,-12141695,3569627,11342593 }, { 26514989,4740088,27912651,3697550,19331575,-11472339,6809886,4608608,7325975,-14801071 }, { -11618399,-14554430,-24321212,7655128,-1369274,5214312,-27400540,10258390,-17646694,-8186692 }, }, { { 11431204,15823007,26570245,14329124,18029990,4796082,-31446179,15580664,9280358,-3973687 }, { -160783,-10326257,-22855316,-4304997,-20861367,-13621002,-32810901,-11181622,-15545091,4387441 }, { -20799378,12194512,3937617,-5805892,-27154820,9340370,-24513992,8548137,20617071,-7482001 }, }, { { -938825,-3930586,-8714311,16124718,24603125,-6225393,-13775352,-11875822,24345683,10325460 }, { -19855277,-1568885,-22202708,8714034,14007766,6928528,16318175,-1010689,4766743,3552007 }, { -21751364,-16730916,1351763,-803421,-4009670,3950935,3217514,14481909,10988822,-3994762 }, }, { { 15564307,-14311570,3101243,5684148,30446780,-8051356,12677127,-6505343,-8295852,13296005 }, { -9442290,6624296,-30298964,-11913677,-4670981,-2057379,31521204,9614054,-30000824,12074674 }, { 4771191,-135239,14290749,-13089852,27992298,14998318,-1413936,-1556716,29832613,-16391035 }, }, { { 7064884,-7541174,-19161962,-5067537,-18891269,-2912736,25825242,5293297,-27122660,13101590 }, { -2298563,2439670,-7466610,1719965,-27267541,-16328445,32512469,-5317593,-30356070,-4190957 }, { -30006540,10162316,-33180176,3981723,-16482138,-13070044,14413974,9515896,19568978,9628812 }, }, { { 33053803,199357,15894591,1583059,27380243,-4580435,-17838894,-6106839,-6291786,3437740 }, { -18978877,3884493,19469877,12726490,15913552,13614290,-22961733,70104,7463304,4176122 }, { -27124001,10659917,11482427,-16070381,12771467,-6635117,-32719404,-5322751,24216882,5944158 }, }, { { 8894125,7450974,-2664149,-9765752,-28080517,-12389115,19345746,14680796,11632993,5847885 }, { 26942781,-2315317,9129564,-4906607,26024105,11769399,-11518837,6367194,-9727230,4782140 }, { 19916461,-4828410,-22910704,-11414391,25606324,-5972441,33253853,8220911,6358847,-1873857 }, }, { { 801428,-2081702,16569428,11065167,29875704,96627,7908388,-4480480,-13538503,1387155 }, { 19646058,5720633,-11416706,12814209,11607948,12749789,14147075,15156355,-21866831,11835260 }, { 19299512,1155910,28703737,14890794,2925026,7269399,26121523,15467869,-26560550,5052483 }, }, }, { { { -3017432,10058206,1980837,3964243,22160966,12322533,-6431123,-12618185,12228557,-7003677 }, { 32944382,14922211,-22844894,5188528,21913450,-8719943,4001465,13238564,-6114803,8653815 }, { 22865569,-4652735,27603668,-12545395,14348958,8234005,24808405,5719875,28483275,2841751 }, }, { { -16420968,-1113305,-327719,-12107856,21886282,-15552774,-1887966,-315658,19932058,-12739203 }, { -11656086,10087521,-8864888,-5536143,-19278573,-3055912,3999228,13239134,-4777469,-13910208 }, { 1382174,-11694719,17266790,9194690,-13324356,9720081,20403944,11284705,-14013818,3093230 }, }, { { 16650921,-11037932,-1064178,1570629,-8329746,7352753,-302424,16271225,-24049421,-6691850 }, { -21911077,-5927941,-4611316,-5560156,-31744103,-10785293,24123614,15193618,-21652117,-16739389 }, { -9935934,-4289447,-25279823,4372842,2087473,10399484,31870908,14690798,17361620,11864968 }, }, { { -11307610,6210372,13206574,5806320,-29017692,-13967200,-12331205,-7486601,-25578460,-16240689 }, { 14668462,-12270235,26039039,15305210,25515617,4542480,10453892,6577524,9145645,-6443880 }, { 5974874,3053895,-9433049,-10385191,-31865124,3225009,-7972642,3936128,-5652273,-3050304 }, }, { { 30625386,-4729400,-25555961,-12792866,-20484575,7695099,17097188,-16303496,-27999779,1803632 }, { -3553091,9865099,-5228566,4272701,-5673832,-16689700,14911344,12196514,-21405489,7047412 }, { 20093277,9920966,-11138194,-5343857,13161587,12044805,-32856851,4124601,-32343828,-10257566 }, }, { { -20788824,14084654,-13531713,7842147,19119038,-13822605,4752377,-8714640,-21679658,2288038 }, { -26819236,-3283715,29965059,3039786,-14473765,2540457,29457502,14625692,-24819617,12570232 }, { -1063558,-11551823,16920318,12494842,1278292,-5869109,-21159943,-3498680,-11974704,4724943 }, }, { { 17960970,-11775534,-4140968,-9702530,-8876562,-1410617,-12907383,-8659932,-29576300,1903856 }, { 23134274,-14279132,-10681997,-1611936,20684485,15770816,-12989750,3190296,26955097,14109738 }, { 15308788,5320727,-30113809,-14318877,22902008,7767164,29425325,-11277562,31960942,11934971 }, }, { { -27395711,8435796,4109644,12222639,-24627868,14818669,20638173,4875028,10491392,1379718 }, { -13159415,9197841,3875503,-8936108,-1383712,-5879801,33518459,16176658,21432314,12180697 }, { -11787308,11500838,13787581,-13832590,-22430679,10140205,1465425,12689540,-10301319,-13872883 }, }, }, { { { 5414091,-15386041,-21007664,9643570,12834970,1186149,-2622916,-1342231,26128231,6032912 }, { -26337395,-13766162,32496025,-13653919,17847801,-12669156,3604025,8316894,-25875034,-10437358 }, { 3296484,6223048,24680646,-12246460,-23052020,5903205,-8862297,-4639164,12376617,3188849 }, }, { { 29190488,-14659046,27549113,-1183516,3520066,-10697301,32049515,-7309113,-16109234,-9852307 }, { -14744486,-9309156,735818,-598978,-20407687,-5057904,25246078,-15795669,18640741,-960977 }, { -6928835,-16430795,10361374,5642961,4910474,12345252,-31638386,-494430,10530747,1053335 }, }, { { -29265967,-14186805,-13538216,-12117373,-19457059,-10655384,-31462369,-2948985,24018831,15026644 }, { -22592535,-3145277,-2289276,5953843,-13440189,9425631,25310643,13003497,-2314791,-15145616 }, { -27419985,-603321,-8043984,-1669117,-26092265,13987819,-27297622,187899,-23166419,-2531735 }, }, { { -21744398,-13810475,1844840,5021428,-10434399,-15911473,9716667,16266922,-5070217,726099 }, { 29370922,-6053998,7334071,-15342259,9385287,2247707,-13661962,-4839461,30007388,-15823341 }, { -936379,16086691,23751945,-543318,-1167538,-5189036,9137109,730663,9835848,4555336 }, }, { { -23376435,1410446,-22253753,-12899614,30867635,15826977,17693930,544696,-11985298,12422646 }, { 31117226,-12215734,-13502838,6561947,-9876867,-12757670,-5118685,-4096706,29120153,13924425 }, { -17400879,-14233209,19675799,-2734756,-11006962,-5858820,-9383939,-11317700,7240931,-237388 }, }, { { -31361739,-11346780,-15007447,-5856218,-22453340,-12152771,1222336,4389483,3293637,-15551743 }, { -16684801,-14444245,11038544,11054958,-13801175,-3338533,-24319580,7733547,12796905,-6335822 }, { -8759414,-10817836,-25418864,10783769,-30615557,-9746811,-28253339,3647836,3222231,-11160462 }, }, { { 18606113,1693100,-25448386,-15170272,4112353,10045021,23603893,-2048234,-7550776,2484985 }, { 9255317,-3131197,-12156162,-1004256,13098013,-9214866,16377220,-2102812,-19802075,-3034702 }, { -22729289,7496160,-5742199,11329249,19991973,-3347502,-31718148,9936966,-30097688,-10618797 }, }, { { 21878590,-5001297,4338336,13643897,-3036865,13160960,19708896,5415497,-7360503,-4109293 }, { 27736861,10103576,12500508,8502413,-3413016,-9633558,10436918,-1550276,-23659143,-8132100 }, { 19492550,-12104365,-29681976,-852630,-3208171,12403437,30066266,8367329,13243957,8709688 }, }, }, { { { 12015105,2801261,28198131,10151021,24818120,-4743133,-11194191,-5645734,5150968,7274186 }, { 2831366,-12492146,1478975,6122054,23825128,-12733586,31097299,6083058,31021603,-9793610 }, { -2529932,-2229646,445613,10720828,-13849527,-11505937,-23507731,16354465,15067285,-14147707 }, }, { { 7840942,14037873,-33364863,15934016,-728213,-3642706,21403988,1057586,-19379462,-12403220 }, { 915865,-16469274,15608285,-8789130,-24357026,6060030,-17371319,8410997,-7220461,16527025 }, { 32922597,-556987,20336074,-16184568,10903705,-5384487,16957574,52992,23834301,6588044 }, }, { { 32752030,11232950,3381995,-8714866,22652988,-10744103,17159699,16689107,-20314580,-1305992 }, { -4689649,9166776,-25710296,-10847306,11576752,12733943,7924251,-2752281,1976123,-7249027 }, { 21251222,16309901,-2983015,-6783122,30810597,12967303,156041,-3371252,12331345,-8237197 }, }, { { 8651614,-4477032,-16085636,-4996994,13002507,2950805,29054427,-5106970,10008136,-4667901 }, { 31486080,15114593,-14261250,12951354,14369431,-7387845,16347321,-13662089,8684155,-10532952 }, { 19443825,11385320,24468943,-9659068,-23919258,2187569,-26263207,-6086921,31316348,14219878 }, }, { { -28594490,1193785,32245219,11392485,31092169,15722801,27146014,6992409,29126555,9207390 }, { 32382935,1110093,18477781,11028262,-27411763,-7548111,-4980517,10843782,-7957600,-14435730 }, { 2814918,7836403,27519878,-7868156,-20894015,-11553689,-21494559,8550130,28346258,1994730 }, }, { { -19578299,8085545,-14000519,-3948622,2785838,-16231307,-19516951,7174894,22628102,8115180 }, { -30405132,955511,-11133838,-15078069,-32447087,-13278079,-25651578,3317160,-9943017,930272 }, { -15303681,-6833769,28856490,1357446,23421993,1057177,24091212,-1388970,-22765376,-10650715 }, }, { { -22751231,-5303997,-12907607,-12768866,-15811511,-7797053,-14839018,-16554220,-1867018,8398970 }, { -31969310,2106403,-4736360,1362501,12813763,16200670,22981545,-6291273,18009408,-15772772 }, { -17220923,-9545221,-27784654,14166835,29815394,7444469,29551787,-3727419,19288549,1325865 }, }, { { 15100157,-15835752,-23923978,-1005098,-26450192,15509408,12376730,-3479146,33166107,-8042750 }, { 20909231,13023121,-9209752,16251778,-5778415,-8094914,12412151,10018715,2213263,-13878373 }, { 32529814,-11074689,30361439,-16689753,-9135940,1513226,22922121,6382134,-5766928,8371348 }, }, }, { { { 9923462,11271500,12616794,3544722,-29998368,-1721626,12891687,-8193132,-26442943,10486144 }, { -22597207,-7012665,8587003,-8257861,4084309,-12970062,361726,2610596,-23921530,-11455195 }, { 5408411,-1136691,-4969122,10561668,24145918,14240566,31319731,-4235541,19985175,-3436086 }, }, { { -13994457,16616821,14549246,3341099,32155958,13648976,-17577068,8849297,65030,8370684 }, { -8320926,-12049626,31204563,5839400,-20627288,-1057277,-19442942,6922164,12743482,-9800518 }, { -2361371,12678785,28815050,4759974,-23893047,4884717,23783145,11038569,18800704,255233 }, }, { { -5269658,-1773886,13957886,7990715,23132995,728773,13393847,9066957,19258688,-14753793 }, { -2936654,-10827535,-10432089,14516793,-3640786,4372541,-31934921,2209390,-1524053,2055794 }, { 580882,16705327,5468415,-2683018,-30926419,-14696000,-7203346,-8994389,-30021019,7394435 }, }, { { 23838809,1822728,-15738443,15242727,8318092,-3733104,-21672180,-3492205,-4821741,14799921 }, { 13345610,9759151,3371034,-16137791,16353039,8577942,31129804,13496856,-9056018,7402518 }, { 2286874,-4435931,-20042458,-2008336,-13696227,5038122,11006906,-15760352,8205061,1607563 }, }, { { 14414086,-8002132,3331830,-3208217,22249151,-5594188,18364661,-2906958,30019587,-9029278 }, { -27688051,1585953,-10775053,931069,-29120221,-11002319,-14410829,12029093,9944378,8024 }, { 4368715,-3709630,29874200,-15022983,-20230386,-11410704,-16114594,-999085,-8142388,5640030 }, }, { { 10299610,13746483,11661824,16234854,7630238,5998374,9809887,-16694564,15219798,-14327783 }, { 27425505,-5719081,3055006,10660664,23458024,595578,-15398605,-1173195,-18342183,9742717 }, { 6744077,2427284,26042789,2720740,-847906,1118974,32324614,7406442,12420155,1994844 }, }, { { 14012521,-5024720,-18384453,-9578469,-26485342,-3936439,-13033478,-10909803,24319929,-6446333 }, { 16412690,-4507367,10772641,15929391,-17068788,-4658621,10555945,-10484049,-30102368,-4739048 }, { 22397382,-7767684,-9293161,-12792868,17166287,-9755136,-27333065,6199366,21880021,-12250760 }, }, { { -4283307,5368523,-31117018,8163389,-30323063,3209128,16557151,8890729,8840445,4957760 }, { -15447727,709327,-6919446,-10870178,-29777922,6522332,-21720181,12130072,-14796503,5005757 }, { -2114751,-14308128,23019042,15765735,-25269683,6002752,10183197,-13239326,-16395286,-2176112 }, }, }, { { { -19025756,1632005,13466291,-7995100,-23640451,16573537,-32013908,-3057104,22208662,2000468 }, { 3065073,-1412761,-25598674,-361432,-17683065,-5703415,-8164212,11248527,-3691214,-7414184 }, { 10379208,-6045554,8877319,1473647,-29291284,-12507580,16690915,2553332,-3132688,16400289 }, }, { { 15716668,1254266,-18472690,7446274,-8448918,6344164,-22097271,-7285580,26894937,9132066 }, { 24158887,12938817,11085297,-8177598,-28063478,-4457083,-30576463,64452,-6817084,-2692882 }, { 13488534,7794716,22236231,5989356,25426474,-12578208,2350710,-3418511,-4688006,2364226 }, }, { { 16335052,9132434,25640582,6678888,1725628,8517937,-11807024,-11697457,15445875,-7798101 }, { 29004207,-7867081,28661402,-640412,-12794003,-7943086,31863255,-4135540,-278050,-15759279 }, { -6122061,-14866665,-28614905,14569919,-10857999,-3591829,10343412,-6976290,-29828287,-10815811 }, }, { { 27081650,3463984,14099042,-4517604,1616303,-6205604,29542636,15372179,17293797,960709 }, { 20263915,11434237,-5765435,11236810,13505955,-10857102,-16111345,6493122,-19384511,7639714 }, { -2830798,-14839232,25403038,-8215196,-8317012,-16173699,18006287,-16043750,29994677,-15808121 }, }, { { 9769828,5202651,-24157398,-13631392,-28051003,-11561624,-24613141,-13860782,-31184575,709464 }, { 12286395,13076066,-21775189,-1176622,-25003198,4057652,-32018128,-8890874,16102007,13205847 }, { 13733362,5599946,10557076,3195751,-5557991,8536970,-25540170,8525972,10151379,10394400 }, }, { { 4024660,-16137551,22436262,12276534,-9099015,-2686099,19698229,11743039,-33302334,8934414 }, { -15879800,-4525240,-8580747,-2934061,14634845,-698278,-9449077,3137094,-11536886,11721158 }, { 17555939,-5013938,8268606,2331751,-22738815,9761013,9319229,8835153,-9205489,-1280045 }, }, { { -461409,-7830014,20614118,16688288,-7514766,-4807119,22300304,505429,6108462,-6183415 }, { -5070281,12367917,-30663534,3234473,32617080,-8422642,29880583,-13483331,-26898490,-7867459 }, { -31975283,5726539,26934134,10237677,-3173717,-605053,24199304,3795095,7592688,-14992079 }, }, { { 21594432,-14964228,17466408,-4077222,32537084,2739898,6407723,12018833,-28256052,4298412 }, { -20650503,-11961496,-27236275,570498,3767144,-1717540,13891942,-1569194,13717174,10805743 }, { -14676630,-15644296,15287174,11927123,24177847,-8175568,-796431,14860609,-26938930,-5863836 }, }, }, { { { 12962541,5311799,-10060768,11658280,18855286,-7954201,13286263,-12808704,-4381056,9882022 }, { 18512079,11319350,-20123124,15090309,18818594,5271736,-22727904,3666879,-23967430,-3299429 }, { -6789020,-3146043,16192429,13241070,15898607,-14206114,-10084880,-6661110,-2403099,5276065 }, }, { { 30169808,-5317648,26306206,-11750859,27814964,7069267,7152851,3684982,1449224,13082861 }, { 10342826,3098505,2119311,193222,25702612,12233820,23697382,15056736,-21016438,-8202000 }, { -33150110,3261608,22745853,7948688,19370557,-15177665,-26171976,6482814,-10300080,-11060101 }, }, { { 32869458,-5408545,25609743,15678670,-10687769,-15471071,26112421,2521008,-22664288,6904815 }, { 29506923,4457497,3377935,-9796444,-30510046,12935080,1561737,3841096,-29003639,-6657642 }, { 10340844,-6630377,-18656632,-2278430,12621151,-13339055,30878497,-11824370,-25584551,5181966 }, }, { { 25940115,-12658025,17324188,-10307374,-8671468,15029094,24396252,-16450922,-2322852,-12388574 }, { -21765684,9916823,-1300409,4079498,-1028346,11909559,1782390,12641087,20603771,-6561742 }, { -18882287,-11673380,24849422,11501709,13161720,-4768874,1925523,11914390,4662781,7820689 }, }, { { 12241050,-425982,8132691,9393934,32846760,-1599620,29749456,12172924,16136752,15264020 }, { -10349955,-14680563,-8211979,2330220,-17662549,-14545780,10658213,6671822,19012087,3772772 }, { 3753511,-3421066,10617074,2028709,14841030,-6721664,28718732,-15762884,20527771,12988982 }, }, { { -14822485,-5797269,-3707987,12689773,-898983,-10914866,-24183046,-10564943,3299665,-12424953 }, { -16777703,-15253301,-9642417,4978983,3308785,8755439,6943197,6461331,-25583147,8991218 }, { -17226263,1816362,-1673288,-6086439,31783888,-8175991,-32948145,7417950,-30242287,1507265 }, }, { { 29692663,6829891,-10498800,4334896,20945975,-11906496,-28887608,8209391,14606362,-10647073 }, { -3481570,8707081,32188102,5672294,22096700,1711240,-33020695,9761487,4170404,-2085325 }, { -11587470,14855945,-4127778,-1531857,-26649089,15084046,22186522,16002000,-14276837,-8400798 }, }, { { -4811456,13761029,-31703877,-2483919,-3312471,7869047,-7113572,-9620092,13240845,10965870 }, { -7742563,-8256762,-14768334,-13656260,-23232383,12387166,4498947,14147411,29514390,4302863 }, { -13413405,-12407859,20757302,-13801832,14785143,8976368,-5061276,-2144373,17846988,-13971927 }, }, }, { { { -2244452,-754728,-4597030,-1066309,-6247172,1455299,-21647728,-9214789,-5222701,12650267 }, { -9906797,-16070310,21134160,12198166,-27064575,708126,387813,13770293,-19134326,10958663 }, { 22470984,12369526,23446014,-5441109,-21520802,-9698723,-11772496,-11574455,-25083830,4271862 }, }, { { -25169565,-10053642,-19909332,15361595,-5984358,2159192,75375,-4278529,-32526221,8469673 }, { 15854970,4148314,-8893890,7259002,11666551,13824734,-30531198,2697372,24154791,-9460943 }, { 15446137,-15806644,29759747,14019369,30811221,-9610191,-31582008,12840104,24913809,9815020 }, }, { { -4709286,-5614269,-31841498,-12288893,-14443537,10799414,-9103676,13438769,18735128,9466238 }, { 11933045,9281483,5081055,-5183824,-2628162,-4905629,-7727821,-10896103,-22728655,16199064 }, { 14576810,379472,-26786533,-8317236,-29426508,-10812974,-102766,1876699,30801119,2164795 }, }, { { 15995086,3199873,13672555,13712240,-19378835,-4647646,-13081610,-15496269,-13492807,1268052 }, { -10290614,-3659039,-3286592,10948818,23037027,3794475,-3470338,-12600221,-17055369,3565904 }, { 29210088,-9419337,-5919792,-4952785,10834811,-13327726,-16512102,-10820713,-27162222,-14030531 }, }, { { -13161890,15508588,16663704,-8156150,-28349942,9019123,-29183421,-3769423,2244111,-14001979 }, { -5152875,-3800936,-9306475,-6071583,16243069,14684434,-25673088,-16180800,13491506,4641841 }, { 10813417,643330,-19188515,-728916,30292062,-16600078,27548447,-7721242,14476989,-12767431 }, }, { { 10292079,9984945,6481436,8279905,-7251514,7032743,27282937,-1644259,-27912810,12651324 }, { -31185513,-813383,22271204,11835308,10201545,15351028,17099662,3988035,21721536,-3148940 }, { 10202177,-6545839,-31373232,-9574638,-32150642,-8119683,-12906320,3852694,13216206,14842320 }, }, { { -15815640,-10601066,-6538952,-7258995,-6984659,-6581778,-31500847,13765824,-27434397,9900184 }, { 14465505,-13833331,-32133984,-14738873,-27443187,12990492,33046193,15796406,-7051866,-8040114 }, { 30924417,-8279620,6359016,-12816335,16508377,9071735,-25488601,15413635,9524356,-7018878 }, }, { { 12274201,-13175547,32627641,-1785326,6736625,13267305,5237659,-5109483,15663516,4035784 }, { -2951309,8903985,17349946,601635,-16432815,-4612556,-13732739,-15889334,-22258478,4659091 }, { -16916263,-4952973,-30393711,-15158821,20774812,15897498,5736189,15026997,-2178256,-13455585 }, }, }, { { { -8858980,-2219056,28571666,-10155518,-474467,-10105698,-3801496,278095,23440562,-290208 }, { 10226241,-5928702,15139956,120818,-14867693,5218603,32937275,11551483,-16571960,-7442864 }, { 17932739,-12437276,-24039557,10749060,11316803,7535897,22503767,5561594,-3646624,3898661 }, }, { { 7749907,-969567,-16339731,-16464,-25018111,15122143,-1573531,7152530,21831162,1245233 }, { 26958459,-14658026,4314586,8346991,-5677764,11960072,-32589295,-620035,-30402091,-16716212 }, { -12165896,9166947,33491384,13673479,29787085,13096535,6280834,14587357,-22338025,13987525 }, }, { { -24349909,7778775,21116000,15572597,-4833266,-5357778,-4300898,-5124639,-7469781,-2858068 }, { 9681908,-6737123,-31951644,13591838,-6883821,386950,31622781,6439245,-14581012,4091397 }, { -8426427,1470727,-28109679,-1596990,3978627,-5123623,-19622683,12092163,29077877,-14741988 }, }, { { 5269168,-6859726,-13230211,-8020715,25932563,1763552,-5606110,-5505881,-20017847,2357889 }, { 32264008,-15407652,-5387735,-1160093,-2091322,-3946900,23104804,-12869908,5727338,189038 }, { 14609123,-8954470,-6000566,-16622781,-14577387,-7743898,-26745169,10942115,-25888931,-14884697 }, }, { { 20513500,5557931,-15604613,7829531,26413943,-2019404,-21378968,7471781,13913677,-5137875 }, { -25574376,11967826,29233242,12948236,-6754465,4713227,-8940970,14059180,12878652,8511905 }, { -25656801,3393631,-2955415,-7075526,-2250709,9366908,-30223418,6812974,5568676,-3127656 }, }, { { 11630004,12144454,2116339,13606037,27378885,15676917,-17408753,-13504373,-14395196,8070818 }, { 27117696,-10007378,-31282771,-5570088,1127282,12772488,-29845906,10483306,-11552749,-1028714 }, { 10637467,-5688064,5674781,1072708,-26343588,-6982302,-1683975,9177853,-27493162,15431203 }, }, { { 20525145,10892566,-12742472,12779443,-29493034,16150075,-28240519,14943142,-15056790,-7935931 }, { -30024462,5626926,-551567,-9981087,753598,11981191,25244767,-3239766,-3356550,9594024 }, { -23752644,2636870,-5163910,-10103818,585134,7877383,11345683,-6492290,13352335,-10977084 }, }, { { -1931799,-5407458,3304649,-12884869,17015806,-4877091,-29783850,-7752482,-13215537,-319204 }, { 20239939,6607058,6203985,3483793,-18386976,-779229,-20723742,15077870,-22750759,14523817 }, { 27406042,-6041657,27423596,-4497394,4996214,10002360,-28842031,-4545494,-30172742,-4805667 }, }, }, { { { 11374242,12660715,17861383,-12540833,10935568,1099227,-13886076,-9091740,-27727044,11358504 }, { -12730809,10311867,1510375,10778093,-2119455,-9145702,32676003,11149336,-26123651,4985768 }, { -19096303,341147,-6197485,-239033,15756973,-8796662,-983043,13794114,-19414307,-15621255 }, }, { { 6490081,11940286,25495923,-7726360,8668373,-8751316,3367603,6970005,-1691065,-9004790 }, { 1656497,13457317,15370807,6364910,13605745,8362338,-19174622,-5475723,-16796596,-5031438 }, { -22273315,-13524424,-64685,-4334223,-18605636,-10921968,-20571065,-7007978,-99853,-10237333 }, }, { { 17747465,10039260,19368299,-4050591,-20630635,-16041286,31992683,-15857976,-29260363,-5511971 }, { 31932027,-4986141,-19612382,16366580,22023614,88450,11371999,-3744247,4882242,-10626905 }, { 29796507,37186,19818052,10115756,-11829032,3352736,18551198,3272828,-5190932,-4162409 }, }, { { 12501286,4044383,-8612957,-13392385,-32430052,5136599,-19230378,-3529697,330070,-3659409 }, { 6384877,2899513,17807477,7663917,-2358888,12363165,25366522,-8573892,-271295,12071499 }, { -8365515,-4042521,25133448,-4517355,-6211027,2265927,-32769618,1936675,-5159697,3829363 }, }, { { 28425966,-5835433,-577090,-4697198,-14217555,6870930,7921550,-6567787,26333140,14267664 }, { -11067219,11871231,27385719,-10559544,-4585914,-11189312,10004786,-8709488,-21761224,8930324 }, { -21197785,-16396035,25654216,-1725397,12282012,11008919,1541940,4757911,-26491501,-16408940 }, }, { { 13537262,-7759490,-20604840,10961927,-5922820,-13218065,-13156584,6217254,-15943699,13814990 }, { -17422573,15157790,18705543,29619,24409717,-260476,27361681,9257833,-1956526,-1776914 }, { -25045300,-10191966,15366585,15166509,-13105086,8423556,-29171540,12361135,-18685978,4578290 }, }, { { 24579768,3711570,1342322,-11180126,-27005135,14124956,-22544529,14074919,21964432,8235257 }, { -6528613,-2411497,9442966,-5925588,12025640,-1487420,-2981514,-1669206,13006806,2355433 }, { -16304899,-13605259,-6632427,-5142349,16974359,-10911083,27202044,1719366,1141648,-12796236 }, }, { { -12863944,-13219986,-8318266,-11018091,-6810145,-4843894,13475066,-3133972,32674895,13715045 }, { 11423335,-5468059,32344216,8962751,24989809,9241752,-13265253,16086212,-28740881,-15642093 }, { -1409668,12530728,-6368726,10847387,19531186,-14132160,-11709148,7791794,-27245943,4383347 }, }, }, { { { -28970898,5271447,-1266009,-9736989,-12455236,16732599,-4862407,-4906449,27193557,6245191 }, { -15193956,5362278,-1783893,2695834,4960227,12840725,23061898,3260492,22510453,8577507 }, { -12632451,11257346,-32692994,13548177,-721004,10879011,31168030,13952092,-29571492,-3635906 }, }, { { 3877321,-9572739,32416692,5405324,-11004407,-13656635,3759769,11935320,5611860,8164018 }, { -16275802,14667797,15906460,12155291,-22111149,-9039718,32003002,-8832289,5773085,-8422109 }, { -23788118,-8254300,1950875,8937633,18686727,16459170,-905725,12376320,31632953,190926 }, }, { { -24593607,-16138885,-8423991,13378746,14162407,6901328,-8288749,4508564,-25341555,-3627528 }, { 8884438,-5884009,6023974,10104341,-6881569,-4941533,18722941,-14786005,-1672488,827625 }, { -32720583,-16289296,-32503547,7101210,13354605,2659080,-1800575,-14108036,-24878478,1541286 }, }, { { 2901347,-1117687,3880376,-10059388,-17620940,-3612781,-21802117,-3567481,20456845,-1885033 }, { 27019610,12299467,-13658288,-1603234,-12861660,-4861471,-19540150,-5016058,29439641,15138866 }, { 21536104,-6626420,-32447818,-10690208,-22408077,5175814,-5420040,-16361163,7779328,109896 }, }, { { 30279744,14648750,-8044871,6425558,13639621,-743509,28698390,12180118,23177719,-554075 }, { 26572847,3405927,-31701700,12890905,-19265668,5335866,-6493768,2378492,4439158,-13279347 }, { -22716706,3489070,-9225266,-332753,18875722,-1140095,14819434,-12731527,-17717757,-5461437 }, }, { { -5056483,16566551,15953661,3767752,-10436499,15627060,-820954,2177225,8550082,-15114165 }, { -18473302,16596775,-381660,15663611,22860960,15585581,-27844109,-3582739,-23260460,-8428588 }, { -32480551,15707275,-8205912,-5652081,29464558,2713815,-22725137,15860482,-21902570,1494193 }, }, { { -19562091,-14087393,-25583872,-9299552,13127842,759709,21923482,16529112,8742704,12967017 }, { -28464899,1553205,32536856,-10473729,-24691605,-406174,-8914625,-2933896,-29903758,15553883 }, { 21877909,3230008,9881174,10539357,-4797115,2841332,11543572,14513274,19375923,-12647961 }, }, { { 8832269,-14495485,13253511,5137575,5037871,4078777,24880818,-6222716,2862653,9455043 }, { 29306751,5123106,20245049,-14149889,9592566,8447059,-2077124,-2990080,15511449,4789663 }, { -20679756,7004547,8824831,-9434977,-4045704,-3750736,-5754762,108893,23513200,16652362 }, }, }, { { { -33256173,4144782,-4476029,-6579123,10770039,-7155542,-6650416,-12936300,-18319198,10212860 }, { 2756081,8598110,7383731,-6859892,22312759,-1105012,21179801,2600940,-9988298,-12506466 }, { -24645692,13317462,-30449259,-15653928,21365574,-10869657,11344424,864440,-2499677,-16710063 }, }, { { -26432803,6148329,-17184412,-14474154,18782929,-275997,-22561534,211300,2719757,4940997 }, { -1323882,3911313,-6948744,14759765,-30027150,7851207,21690126,8518463,26699843,5276295 }, { -13149873,-6429067,9396249,365013,24703301,-10488939,1321586,149635,-15452774,7159369 }, }, { { 9987780,-3404759,17507962,9505530,9731535,-2165514,22356009,8312176,22477218,-8403385 }, { 18155857,-16504990,19744716,9006923,15154154,-10538976,24256460,-4864995,-22548173,9334109 }, { 2986088,-4911893,10776628,-3473844,10620590,-7083203,-21413845,14253545,-22587149,536906 }, }, { { 4377756,8115836,24567078,15495314,11625074,13064599,7390551,10589625,10838060,-15420424 }, { -19342404,867880,9277171,-3218459,-14431572,-1986443,19295826,-15796950,6378260,699185 }, { 7895026,4057113,-7081772,-13077756,-17886831,-323126,-716039,15693155,-5045064,-13373962 }, }, { { -7737563,-5869402,-14566319,-7406919,11385654,13201616,31730678,-10962840,-3918636,-9669325 }, { 10188286,-15770834,-7336361,13427543,22223443,14896287,30743455,7116568,-21786507,5427593 }, { 696102,13206899,27047647,-10632082,15285305,-9853179,10798490,-4578720,19236243,12477404 }, }, { { -11229439,11243796,-17054270,-8040865,-788228,-8167967,-3897669,11180504,-23169516,7733644 }, { 17800790,-14036179,-27000429,-11766671,23887827,3149671,23466177,-10538171,10322027,15313801 }, { 26246234,11968874,32263343,-5468728,6830755,-13323031,-15794704,-101982,-24449242,10890804 }, }, { { -31365647,10271363,-12660625,-6267268,16690207,-13062544,-14982212,16484931,25180797,-5334884 }, { -586574,10376444,-32586414,-11286356,19801893,10997610,2276632,9482883,316878,13820577 }, { -9882808,-4510367,-2115506,16457136,-11100081,11674996,30756178,-7515054,30696930,-3712849 }, }, { { 32988917,-9603412,12499366,7910787,-10617257,-11931514,-7342816,-9985397,-32349517,7392473 }, { -8855661,15927861,9866406,-3649411,-2396914,-16655781,-30409476,-9134995,25112947,-2926644 }, { -2504044,-436966,25621774,-5678772,15085042,-5479877,-24884878,-13526194,5537438,-13914319 }, }, }, { { { -11225584,2320285,-9584280,10149187,-33444663,5808648,-14876251,-1729667,31234590,6090599 }, { -9633316,116426,26083934,2897444,-6364437,-2688086,609721,15878753,-6970405,-9034768 }, { -27757857,247744,-15194774,-9002551,23288161,-10011936,-23869595,6503646,20650474,1804084 }, }, { { -27589786,15456424,8972517,8469608,15640622,4439847,3121995,-10329713,27842616,-202328 }, { -15306973,2839644,22530074,10026331,4602058,5048462,28248656,5031932,-11375082,12714369 }, { 20807691,-7270825,29286141,11421711,-27876523,-13868230,-21227475,1035546,-19733229,12796920 }, }, { { 12076899,-14301286,-8785001,-11848922,-25012791,16400684,-17591495,-12899438,3480665,-15182815 }, { -32361549,5457597,28548107,7833186,7303070,-11953545,-24363064,-15921875,-33374054,2771025 }, { -21389266,421932,26597266,6860826,22486084,-6737172,-17137485,-4210226,-24552282,15673397 }, }, { { -20184622,2338216,19788685,-9620956,-4001265,-8740893,-20271184,4733254,3727144,-12934448 }, { 6120119,814863,-11794402,-622716,6812205,-15747771,2019594,7975683,31123697,-10958981 }, { 30069250,-11435332,30434654,2958439,18399564,-976289,12296869,9204260,-16432438,9648165 }, }, { { 32705432,-1550977,30705658,7451065,-11805606,9631813,3305266,5248604,-26008332,-11377501 }, { 17219865,2375039,-31570947,-5575615,-19459679,9219903,294711,15298639,2662509,-16297073 }, { -1172927,-7558695,-4366770,-4287744,-21346413,-8434326,32087529,-1222777,32247248,-14389861 }, }, { { 14312628,1221556,17395390,-8700143,-4945741,-8684635,-28197744,-9637817,-16027623,-13378845 }, { -1428825,-9678990,-9235681,6549687,-7383069,-468664,23046502,9803137,17597934,2346211 }, { 18510800,15337574,26171504,981392,-22241552,7827556,-23491134,-11323352,3059833,-11782870 }, }, { { 10141598,6082907,17829293,-1947643,9830092,13613136,-25556636,-5544586,-33502212,3592096 }, { 33114168,-15889352,-26525686,-13343397,33076705,8716171,1151462,1521897,-982665,-6837803 }, { -32939165,-4255815,23947181,-324178,-33072974,-12305637,-16637686,3891704,26353178,693168 }, }, { { 30374239,1595580,-16884039,13186931,4600344,406904,9585294,-400668,31375464,14369965 }, { -14370654,-7772529,1510301,6434173,-18784789,-6262728,32732230,-13108839,17901441,16011505 }, { 18171223,-11934626,-12500402,15197122,-11038147,-15230035,-19172240,-16046376,8764035,12309598 }, }, }, { { { 5975908,-5243188,-19459362,-9681747,-11541277,14015782,-23665757,1228319,17544096,-10593782 }, { 5811932,-1715293,3442887,-2269310,-18367348,-8359541,-18044043,-15410127,-5565381,12348900 }, { -31399660,11407555,25755363,6891399,-3256938,14872274,-24849353,8141295,-10632534,-585479 }, }, { { -12675304,694026,-5076145,13300344,14015258,-14451394,-9698672,-11329050,30944593,1130208 }, { 8247766,-6710942,-26562381,-7709309,-14401939,-14648910,4652152,2488540,23550156,-271232 }, { 17294316,-3788438,7026748,15626851,22990044,113481,2267737,-5908146,-408818,-137719 }, }, { { 16091085,-16253926,18599252,7340678,2137637,-1221657,-3364161,14550936,3260525,-7166271 }, { -4910104,-13332887,18550887,10864893,-16459325,-7291596,-23028869,-13204905,-12748722,2701326 }, { -8574695,16099415,4629974,-16340524,-20786213,-6005432,-10018363,9276971,11329923,1862132 }, }, { { 14763076,-15903608,-30918270,3689867,3511892,10313526,-21951088,12219231,-9037963,-940300 }, { 8894987,-3446094,6150753,3013931,301220,15693451,-31981216,-2909717,-15438168,11595570 }, { 15214962,3537601,-26238722,-14058872,4418657,-15230761,13947276,10730794,-13489462,-4363670 }, }, { { -2538306,7682793,32759013,263109,-29984731,-7955452,-22332124,-10188635,977108,699994 }, { -12466472,4195084,-9211532,550904,-15565337,12917920,19118110,-439841,-30534533,-14337913 }, { 31788461,-14507657,4799989,7372237,8808585,-14747943,9408237,-10051775,12493932,-5409317 }, }, { { -25680606,5260744,-19235809,-6284470,-3695942,16566087,27218280,2607121,29375955,6024730 }, { 842132,-2794693,-4763381,-8722815,26332018,-12405641,11831880,6985184,-9940361,2854096 }, { -4847262,-7969331,2516242,-5847713,9695691,-7221186,16512645,960770,12121869,16648078 }, }, { { -15218652,14667096,-13336229,2013717,30598287,-464137,-31504922,-7882064,20237806,2838411 }, { -19288047,4453152,15298546,-16178388,22115043,-15972604,12544294,-13470457,1068881,-12499905 }, { -9558883,-16518835,33238498,13506958,30505848,-1114596,-8486907,-2630053,12521378,4845654 }, }, { { -28198521,10744108,-2958380,10199664,7759311,-13088600,3409348,-873400,-6482306,-12885870 }, { -23561822,6230156,-20382013,10655314,-24040585,-11621172,10477734,-1240216,-3113227,13974498 }, { 12966261,15550616,-32038948,-1615346,21025980,-629444,5642325,7188737,18895762,12629579 }, }, }, { { { 14741879,-14946887,22177208,-11721237,1279741,8058600,11758140,789443,32195181,3895677 }, { 10758205,15755439,-4509950,9243698,-4879422,6879879,-2204575,-3566119,-8982069,4429647 }, { -2453894,15725973,-20436342,-10410672,-5803908,-11040220,-7135870,-11642895,18047436,-15281743 }, }, { { -25173001,-11307165,29759956,11776784,-22262383,-15820455,10993114,-12850837,-17620701,-9408468 }, { 21987233,700364,-24505048,14972008,-7774265,-5718395,32155026,2581431,-29958985,8773375 }, { -25568350,454463,-13211935,16126715,25240068,8594567,20656846,12017935,-7874389,-13920155 }, }, { { 6028182,6263078,-31011806,-11301710,-818919,2461772,-31841174,-5468042,-1721788,-2776725 }, { -12278994,16624277,987579,-5922598,32908203,1248608,7719845,-4166698,28408820,6816612 }, { -10358094,-8237829,19549651,-12169222,22082623,16147817,20613181,13982702,-10339570,5067943 }, }, { { -30505967,-3821767,12074681,13582412,-19877972,2443951,-19719286,12746132,5331210,-10105944 }, { 30528811,3601899,-1957090,4619785,-27361822,-15436388,24180793,-12570394,27679908,-1648928 }, { 9402404,-13957065,32834043,10838634,-26580150,-13237195,26653274,-8685565,22611444,-12715406 }, }, { { 22190590,1118029,22736441,15130463,-30460692,-5991321,19189625,-4648942,4854859,6622139 }, { -8310738,-2953450,-8262579,-3388049,-10401731,-271929,13424426,-3567227,26404409,13001963 }, { -31241838,-15415700,-2994250,8939346,11562230,-12840670,-26064365,-11621720,-15405155,11020693 }, }, { { 1866042,-7949489,-7898649,-10301010,12483315,13477547,3175636,-12424163,28761762,1406734 }, { -448555,-1777666,13018551,3194501,-9580420,-11161737,24760585,-4347088,25577411,-13378680 }, { -24290378,4759345,-690653,-1852816,2066747,10693769,-29595790,9884936,-9368926,4745410 }, }, { { -9141284,6049714,-19531061,-4341411,-31260798,9944276,-15462008,-11311852,10931924,-11931931 }, { -16561513,14112680,-8012645,4817318,-8040464,-11414606,-22853429,10856641,-20470770,13434654 }, { 22759489,-10073434,-16766264,-1871422,13637442,-10168091,1765144,-12654326,28445307,-5364710 }, }, { { 29875063,12493613,2795536,-3786330,1710620,15181182,-10195717,-8788675,9074234,1167180 }, { -26205683,11014233,-9842651,-2635485,-26908120,7532294,-18716888,-9535498,3843903,9367684 }, { -10969595,-6403711,9591134,9582310,11349256,108879,16235123,8601684,-139197,4242895 }, }, }, { { { 22092954,-13191123,-2042793,-11968512,32186753,-11517388,-6574341,2470660,-27417366,16625501 }, { -11057722,3042016,13770083,-9257922,584236,-544855,-7770857,2602725,-27351616,14247413 }, { 6314175,-10264892,-32772502,15957557,-10157730,168750,-8618807,14290061,27108877,-1180880 }, }, { { -8586597,-7170966,13241782,10960156,-32991015,-13794596,33547976,-11058889,-27148451,981874 }, { 22833440,9293594,-32649448,-13618667,-9136966,14756819,-22928859,-13970780,-10479804,-16197962 }, { -7768587,3326786,-28111797,10783824,19178761,14905060,22680049,13906969,-15933690,3797899 }, }, { { 21721356,-4212746,-12206123,9310182,-3882239,-13653110,23740224,-2709232,20491983,-8042152 }, { 9209270,-15135055,-13256557,-6167798,-731016,15289673,25947805,15286587,30997318,-6703063 }, { 7392032,16618386,23946583,-8039892,-13265164,-1533858,-14197445,-2321576,17649998,-250080 }, }, { { -9301088,-14193827,30609526,-3049543,-25175069,-1283752,-15241566,-9525724,-2233253,7662146 }, { -17558673,1763594,-33114336,15908610,-30040870,-12174295,7335080,-8472199,-3174674,3440183 }, { -19889700,-5977008,-24111293,-9688870,10799743,-16571957,40450,-4431835,4862400,1133 }, }, { { -32856209,-7873957,-5422389,14860950,-16319031,7956142,7258061,311861,-30594991,-7379421 }, { -3773428,-1565936,28985340,7499440,24445838,9325937,29727763,16527196,18278453,15405622 }, { -4381906,8508652,-19898366,-3674424,-5984453,15149970,-13313598,843523,-21875062,13626197 }, }, { { 2281448,-13487055,-10915418,-2609910,1879358,16164207,-10783882,3953792,13340839,15928663 }, { 31727126,-7179855,-18437503,-8283652,2875793,-16390330,-25269894,-7014826,-23452306,5964753 }, { 4100420,-5959452,-17179337,6017714,-18705837,12227141,-26684835,11344144,2538215,-7570755 }, }, { { -9433605,6123113,11159803,-2156608,30016280,14966241,-20474983,1485421,-629256,-15958862 }, { -26804558,4260919,11851389,9658551,-32017107,16367492,-20205425,-13191288,11659922,-11115118 }, { 26180396,10015009,-30844224,-8581293,5418197,9480663,2231568,-10170080,33100372,-1306171 }, }, { { 15121113,-5201871,-10389905,15427821,-27509937,-15992507,21670947,4486675,-5931810,-14466380 }, { 16166486,-9483733,-11104130,6023908,-31926798,-1364923,2340060,-16254968,-10735770,-10039824 }, { 28042865,-3557089,-12126526,12259706,-3717498,-6945899,6766453,-8689599,18036436,5803270 }, }, }, { { { -817581,6763912,11803561,1585585,10958447,-2671165,23855391,4598332,-6159431,-14117438 }, { -31031306,-14256194,17332029,-2383520,31312682,-5967183,696309,50292,-20095739,11763584 }, { -594563,-2514283,-32234153,12643980,12650761,14811489,665117,-12613632,-19773211,-10713562 }, }, { { 30464590,-11262872,-4127476,-12734478,19835327,-7105613,-24396175,2075773,-17020157,992471 }, { 18357185,-6994433,7766382,16342475,-29324918,411174,14578841,8080033,-11574335,-10601610 }, { 19598397,10334610,12555054,2555664,18821899,-10339780,21873263,16014234,26224780,16452269 }, }, { { -30223925,5145196,5944548,16385966,3976735,2009897,-11377804,-7618186,-20533829,3698650 }, { 14187449,3448569,-10636236,-10810935,-22663880,-3433596,7268410,-10890444,27394301,12015369 }, { 19695761,16087646,28032085,12999827,6817792,11427614,20244189,-1312777,-13259127,-3402461 }, }, { { 30860103,12735208,-1888245,-4699734,-16974906,2256940,-8166013,12298312,-8550524,-10393462 }, { -5719826,-11245325,-1910649,15569035,26642876,-7587760,-5789354,-15118654,-4976164,12651793 }, { -2848395,9953421,11531313,-5282879,26895123,-12697089,-13118820,-16517902,9768698,-2533218 }, }, { { -24719459,1894651,-287698,-4704085,15348719,-8156530,32767513,12765450,4940095,10678226 }, { 18860224,15980149,-18987240,-1562570,-26233012,-11071856,-7843882,13944024,-24372348,16582019 }, { -15504260,4970268,-29893044,4175593,-20993212,-2199756,-11704054,15444560,-11003761,7989037 }, }, { { 31490452,5568061,-2412803,2182383,-32336847,4531686,-32078269,6200206,-19686113,-14800171 }, { -17308668,-15879940,-31522777,-2831,-32887382,16375549,8680158,-16371713,28550068,-6857132 }, { -28126887,-5688091,16837845,-1820458,-6850681,12700016,-30039981,4364038,1155602,5988841 }, }, { { 21890435,-13272907,-12624011,12154349,-7831873,15300496,23148983,-4470481,24618407,8283181 }, { -33136107,-10512751,9975416,6841041,-31559793,16356536,3070187,-7025928,1466169,10740210 }, { -1509399,-15488185,-13503385,-10655916,32799044,909394,-13938903,-5779719,-32164649,-15327040 }, }, { { 3960823,-14267803,-28026090,-15918051,-19404858,13146868,15567327,951507,-3260321,-573935 }, { 24740841,5052253,-30094131,8961361,25877428,6165135,-24368180,14397372,-7380369,-6144105 }, { -28888365,3510803,-28103278,-1158478,-11238128,-10631454,-15441463,-14453128,-1625486,-6494814 }, }, }, { { { 793299,-9230478,8836302,-6235707,-27360908,-2369593,33152843,-4885251,-9906200,-621852 }, { 5666233,525582,20782575,-8038419,-24538499,14657740,16099374,1468826,-6171428,-15186581 }, { -4859255,-3779343,-2917758,-6748019,7778750,11688288,-30404353,-9871238,-1558923,-9863646 }, }, { { 10896332,-7719704,824275,472601,-19460308,3009587,25248958,14783338,-30581476,-15757844 }, { 10566929,12612572,-31944212,11118703,-12633376,12362879,21752402,8822496,24003793,14264025 }, { 27713862,-7355973,-11008240,9227530,27050101,2504721,23886875,-13117525,13958495,-5732453 }, }, { { -23481610,4867226,-27247128,3900521,29838369,-8212291,-31889399,-10041781,7340521,-15410068 }, { 4646514,-8011124,-22766023,-11532654,23184553,8566613,31366726,-1381061,-15066784,-10375192 }, { -17270517,12723032,-16993061,14878794,21619651,-6197576,27584817,3093888,-8843694,3849921 }, }, { { -9064912,2103172,25561640,-15125738,-5239824,9582958,32477045,-9017955,5002294,-15550259 }, { -12057553,-11177906,21115585,-13365155,8808712,-12030708,16489530,13378448,-25845716,12741426 }, { -5946367,10645103,-30911586,15390284,-3286982,-7118677,24306472,15852464,28834118,-7646072 }, }, { { -17335748,-9107057,-24531279,9434953,-8472084,-583362,-13090771,455841,20461858,5491305 }, { 13669248,-16095482,-12481974,-10203039,-14569770,-11893198,-24995986,11293807,-28588204,-9421832 }, { 28497928,6272777,-33022994,14470570,8906179,-1225630,18504674,-14165166,29867745,-8795943 }, }, { { -16207023,13517196,-27799630,-13697798,24009064,-6373891,-6367600,-13175392,22853429,-4012011 }, { 24191378,16712145,-13931797,15217831,14542237,1646131,18603514,-11037887,12876623,-2112447 }, { 17902668,4518229,-411702,-2829247,26878217,5258055,-12860753,608397,16031844,3723494 }, }, { { -28632773,12763728,-20446446,7577504,33001348,-13017745,17558842,-7872890,23896954,-4314245 }, { -20005381,-12011952,31520464,605201,2543521,5991821,-2945064,7229064,-9919646,-8826859 }, { 28816045,298879,-28165016,-15920938,19000928,-1665890,-12680833,-2949325,-18051778,-2082915 }, }, { { 16000882,-344896,3493092,-11447198,-29504595,-13159789,12577740,16041268,-19715240,7847707 }, { 10151868,10572098,27312476,7922682,14825339,4723128,-32855931,-6519018,-10020567,3852848 }, { -11430470,15697596,-21121557,-4420647,5386314,15063598,16514493,-15932110,29330899,-15076224 }, }, }, { { { -25499735,-4378794,-15222908,-6901211,16615731,2051784,3303702,15490,-27548796,12314391 }, { 15683520,-6003043,18109120,-9980648,15337968,-5997823,-16717435,15921866,16103996,-3731215 }, { -23169824,-10781249,13588192,-1628807,-3798557,-1074929,-19273607,5402699,-29815713,-9841101 }, }, { { 23190676,2384583,-32714340,3462154,-29903655,-1529132,-11266856,8911517,-25205859,2739713 }, { 21374101,-3554250,-33524649,9874411,15377179,11831242,-33529904,6134907,4931255,11987849 }, { -7732,-2978858,-16223486,7277597,105524,-322051,-31480539,13861388,-30076310,10117930 }, }, { { -29501170,-10744872,-26163768,13051539,-25625564,5089643,-6325503,6704079,12890019,15728940 }, { -21972360,-11771379,-951059,-4418840,14704840,2695116,903376,-10428139,12885167,8311031 }, { -17516482,5352194,10384213,-13811658,7506451,13453191,26423267,4384730,1888765,-5435404 }, }, { { -25817338,-3107312,-13494599,-3182506,30896459,-13921729,-32251644,-12707869,-19464434,-3340243 }, { -23607977,-2665774,-526091,4651136,5765089,4618330,6092245,14845197,17151279,-9854116 }, { -24830458,-12733720,-15165978,10367250,-29530908,-265356,22825805,-7087279,-16866484,16176525 }, }, { { -23583256,6564961,20063689,3798228,-4740178,7359225,2006182,-10363426,-28746253,-10197509 }, { -10626600,-4486402,-13320562,-5125317,3432136,-6393229,23632037,-1940610,32808310,1099883 }, { 15030977,5768825,-27451236,-2887299,-6427378,-15361371,-15277896,-6809350,2051441,-15225865 }, }, { { -3362323,-7239372,7517890,9824992,23555850,295369,5148398,-14154188,-22686354,16633660 }, { 4577086,-16752288,13249841,-15304328,19958763,-14537274,18559670,-10759549,8402478,-9864273 }, { -28406330,-1051581,-26790155,-907698,-17212414,-11030789,9453451,-14980072,17983010,9967138 }, }, { { -25762494,6524722,26585488,9969270,24709298,1220360,-1677990,7806337,17507396,3651560 }, { -10420457,-4118111,14584639,15971087,-15768321,8861010,26556809,-5574557,-18553322,-11357135 }, { 2839101,14284142,4029895,3472686,14402957,12689363,-26642121,8459447,-5605463,-7621941 }, }, { { -4839289,-3535444,9744961,2871048,25113978,3187018,-25110813,-849066,17258084,-7977739 }, { 18164541,-10595176,-17154882,-1542417,19237078,-9745295,23357533,-15217008,26908270,12150756 }, { -30264870,-7647865,5112249,-7036672,-1499807,-6974257,43168,-5537701,-32302074,16215819 }, }, }, { { { -6898905,9824394,-12304779,-4401089,-31397141,-6276835,32574489,12532905,-7503072,-8675347 }, { -27343522,-16515468,-27151524,-10722951,946346,16291093,254968,7168080,21676107,-1943028 }, { 21260961,-8424752,-16831886,-11920822,-23677961,3968121,-3651949,-6215466,-3556191,-7913075 }, }, { { 16544754,13250366,-16804428,15546242,-4583003,12757258,-2462308,-8680336,-18907032,-9662799 }, { -2415239,-15577728,18312303,4964443,-15272530,-12653564,26820651,16690659,25459437,-4564609 }, { -25144690,11425020,28423002,-11020557,-6144921,-15826224,9142795,-2391602,-6432418,-1644817 }, }, { { -23104652,6253476,16964147,-3768872,-25113972,-12296437,-27457225,-16344658,6335692,7249989 }, { -30333227,13979675,7503222,-12368314,-11956721,-4621693,-30272269,2682242,25993170,-12478523 }, { 4364628,5930691,32304656,-10044554,-8054781,15091131,22857016,-10598955,31820368,15075278 }, }, { { 31879134,-8918693,17258761,90626,-8041836,-4917709,24162788,-9650886,-17970238,12833045 }, { 19073683,14851414,-24403169,-11860168,7625278,11091125,-19619190,2074449,-9413939,14905377 }, { 24483667,-11935567,-2518866,-11547418,-1553130,15355506,-25282080,9253129,27628530,-7555480 }, }, { { 17597607,8340603,19355617,552187,26198470,-3176583,4593324,-9157582,-14110875,15297016 }, { 510886,14337390,-31785257,16638632,6328095,2713355,-20217417,-11864220,8683221,2921426 }, { 18606791,11874196,27155355,-5281482,-24031742,6265446,-25178240,-1278924,4674690,13890525 }, }, { { 13609624,13069022,-27372361,-13055908,24360586,9592974,14977157,9835105,4389687,288396 }, { 9922506,-519394,13613107,5883594,-18758345,-434263,-12304062,8317628,23388070,16052080 }, { 12720016,11937594,-31970060,-5028689,26900120,8561328,-20155687,-11632979,-14754271,-10812892 }, }, { { 15961858,14150409,26716931,-665832,-22794328,13603569,11829573,7467844,-28822128,929275 }, { 11038231,-11582396,-27310482,-7316562,-10498527,-16307831,-23479533,-9371869,-21393143,2465074 }, { 20017163,-4323226,27915242,1529148,12396362,15675764,13817261,-9658066,2463391,-4622140 }, }, { { -16358878,-12663911,-12065183,4996454,-1256422,1073572,9583558,12851107,4003896,12673717 }, { -1731589,-15155870,-3262930,16143082,19294135,13385325,14741514,-9103726,7903886,2348101 }, { 24536016,-16515207,12715592,-3862155,1511293,10047386,-3842346,-7129159,-28377538,10048127 }, }, }, { { { -12622226,-6204820,30718825,2591312,-10617028,12192840,18873298,-7297090,-32297756,15221632 }, { -26478122,-11103864,11546244,-1852483,9180880,7656409,-21343950,2095755,29769758,6593415 }, { -31994208,-2907461,4176912,3264766,12538965,-868111,26312345,-6118678,30958054,8292160 }, }, { { 31429822,-13959116,29173532,15632448,12174511,-2760094,32808831,3977186,26143136,-3148876 }, { 22648901,1402143,-22799984,13746059,7936347,365344,-8668633,-1674433,-3758243,-2304625 }, { -15491917,8012313,-2514730,-12702462,-23965846,-10254029,-1612713,-1535569,-16664475,8194478 }, }, { { 27338066,-7507420,-7414224,10140405,-19026427,-6589889,27277191,8855376,28572286,3005164 }, { 26287124,4821776,25476601,-4145903,-3764513,-15788984,-18008582,1182479,-26094821,-13079595 }, { -7171154,3178080,23970071,6201893,-17195577,-4489192,-21876275,-13982627,32208683,-1198248 }, }, { { -16657702,2817643,-10286362,14811298,6024667,13349505,-27315504,-10497842,-27672585,-11539858 }, { 15941029,-9405932,-21367050,8062055,31876073,-238629,-15278393,-1444429,15397331,-4130193 }, { 8934485,-13485467,-23286397,-13423241,-32446090,14047986,31170398,-1441021,-27505566,15087184 }, }, { { -18357243,-2156491,24524913,-16677868,15520427,-6360776,-15502406,11461896,16788528,-5868942 }, { -1947386,16013773,21750665,3714552,-17401782,-16055433,-3770287,-10323320,31322514,-11615635 }, { 21426655,-5650218,-13648287,-5347537,-28812189,-4920970,-18275391,-14621414,13040862,-12112948 }, }, { { 11293895,12478086,-27136401,15083750,-29307421,14748872,14555558,-13417103,1613711,4896935 }, { -25894883,15323294,-8489791,-8057900,25967126,-13425460,2825960,-4897045,-23971776,-11267415 }, { -15924766,-5229880,-17443532,6410664,3622847,10243618,20615400,12405433,-23753030,-8436416 }, }, { { -7091295,12556208,-20191352,9025187,-17072479,4333801,4378436,2432030,23097949,-566018 }, { 4565804,-16025654,20084412,-7842817,1724999,189254,24767264,10103221,-18512313,2424778 }, { 366633,-11976806,8173090,-6890119,30788634,5745705,-7168678,1344109,-3642553,12412659 }, }, { { -24001791,7690286,14929416,-168257,-32210835,-13412986,24162697,-15326504,-3141501,11179385 }, { 18289522,-14724954,8056945,16430056,-21729724,7842514,-6001441,-1486897,-18684645,-11443503 }, { 476239,6601091,-6152790,-9723375,17503545,-4863900,27672959,13403813,11052904,5219329 }, }, }, { { { 20678546,-8375738,-32671898,8849123,-5009758,14574752,31186971,-3973730,9014762,-8579056 }, { -13644050,-10350239,-15962508,5075808,-1514661,-11534600,-33102500,9160280,8473550,-3256838 }, { 24900749,14435722,17209120,-15292541,-22592275,9878983,-7689309,-16335821,-24568481,11788948 }, }, { { -3118155,-11395194,-13802089,14797441,9652448,-6845904,-20037437,10410733,-24568470,-1458691 }, { -15659161,16736706,-22467150,10215878,-9097177,7563911,11871841,-12505194,-18513325,8464118 }, { -23400612,8348507,-14585951,-861714,-3950205,-6373419,14325289,8628612,33313881,-8370517 }, }, { { -20186973,-4967935,22367356,5271547,-1097117,-4788838,-24805667,-10236854,-8940735,-5818269 }, { -6948785,-1795212,-32625683,-16021179,32635414,-7374245,15989197,-12838188,28358192,-4253904 }, { -23561781,-2799059,-32351682,-1661963,-9147719,10429267,-16637684,4072016,-5351664,5596589 }, }, { { -28236598,-3390048,12312896,6213178,3117142,16078565,29266239,2557221,1768301,15373193 }, { -7243358,-3246960,-4593467,-7553353,-127927,-912245,-1090902,-4504991,-24660491,3442910 }, { -30210571,5124043,14181784,8197961,18964734,-11939093,22597931,7176455,-18585478,13365930 }, }, { { -7877390,-1499958,8324673,4690079,6261860,890446,24538107,-8570186,-9689599,-3031667 }, { 25008904,-10771599,-4305031,-9638010,16265036,15721635,683793,-11823784,15723479,-15163481 }, { -9660625,12374379,-27006999,-7026148,-7724114,-12314514,11879682,5400171,519526,-1235876 }, }, { { 22258397,-16332233,-7869817,14613016,-22520255,-2950923,-20353881,7315967,16648397,7605640 }, { -8081308,-8464597,-8223311,9719710,19259459,-15348212,23994942,-5281555,-9468848,4763278 }, { -21699244,9220969,-15730624,1084137,-25476107,-2852390,31088447,-7764523,-11356529,728112 }, }, { { 26047220,-11751471,-6900323,-16521798,24092068,9158119,-4273545,-12555558,-29365436,-5498272 }, { 17510331,-322857,5854289,8403524,17133918,-3112612,-28111007,12327945,10750447,10014012 }, { -10312768,3936952,9156313,-8897683,16498692,-994647,-27481051,-666732,3424691,7540221 }, }, { { 30322361,-6964110,11361005,-4143317,7433304,4989748,-7071422,-16317219,-9244265,15258046 }, { 13054562,-2779497,19155474,469045,-12482797,4566042,5631406,2711395,1062915,-5136345 }, { -19240248,-11254599,-29509029,-7499965,-5835763,13005411,-6066489,12194497,32960380,1459310 }, }, }, { { { 19852034,7027924,23669353,10020366,8586503,-6657907,394197,-6101885,18638003,-11174937 }, { 31395534,15098109,26581030,8030562,-16527914,-5007134,9012486,-7584354,-6643087,-5442636 }, { -9192165,-2347377,-1997099,4529534,25766844,607986,-13222,9677543,-32294889,-6456008 }, }, { { -2444496,-149937,29348902,8186665,1873760,12489863,-30934579,-7839692,-7852844,-8138429 }, { -15236356,-15433509,7766470,746860,26346930,-10221762,-27333451,10754588,-9431476,5203576 }, { 31834314,14135496,-770007,5159118,20917671,-16768096,-7467973,-7337524,31809243,7347066 }, }, { { -9606723,-11874240,20414459,13033986,13716524,-11691881,19797970,-12211255,15192876,-2087490 }, { -12663563,-2181719,1168162,-3804809,26747877,-14138091,10609330,12694420,33473243,-13382104 }, { 33184999,11180355,15832085,-11385430,-1633671,225884,15089336,-11023903,-6135662,14480053 }, }, { { 31308717,-5619998,31030840,-1897099,15674547,-6582883,5496208,13685227,27595050,8737275 }, { -20318852,-15150239,10933843,-16178022,8335352,-7546022,-31008351,-12610604,26498114,66511 }, { 22644454,-8761729,-16671776,4884562,-3105614,-13559366,30540766,-4286747,-13327787,-7515095 }, }, { { -28017847,9834845,18617207,-2681312,-3401956,-13307506,8205540,13585437,-17127465,15115439 }, { 23711543,-672915,31206561,-8362711,6164647,-9709987,-33535882,-1426096,8236921,16492939 }, { -23910559,-13515526,-26299483,-4503841,25005590,-7687270,19574902,10071562,6708380,-6222424 }, }, { { 2101391,-4930054,19702731,2367575,-15427167,1047675,5301017,9328700,29955601,-11678310 }, { 3096359,9271816,-21620864,-15521844,-14847996,-7592937,-25892142,-12635595,-9917575,6216608 }, { -32615849,338663,-25195611,2510422,-29213566,-13820213,24822830,-6146567,-26767480,7525079 }, }, { { -23066649,-13985623,16133487,-7896178,-3389565,778788,-910336,-2782495,-19386633,11994101 }, { 21691500,-13624626,-641331,-14367021,3285881,-3483596,-25064666,9718258,-7477437,13381418 }, { 18445390,-4202236,14979846,11622458,-1727110,-3582980,23111648,-6375247,28535282,15779576 }, }, { { 30098053,3089662,-9234387,16662135,-21306940,11308411,-14068454,12021730,9955285,-16303356 }, { 9734894,-14576830,-7473633,-9138735,2060392,11313496,-18426029,9924399,20194861,13380996 }, { -26378102,-7965207,-22167821,15789297,-18055342,-6168792,-1984914,15707771,26342023,10146099 }, }, }, { { { -26016874,-219943,21339191,-41388,19745256,-2878700,-29637280,2227040,21612326,-545728 }, { -13077387,1184228,23562814,-5970442,-20351244,-6348714,25764461,12243797,-20856566,11649658 }, { -10031494,11262626,27384172,2271902,26947504,-15997771,39944,6114064,33514190,2333242 }, }, { { -21433588,-12421821,8119782,7219913,-21830522,-9016134,-6679750,-12670638,24350578,-13450001 }, { -4116307,-11271533,-23886186,4843615,-30088339,690623,-31536088,-10406836,8317860,12352766 }, { 18200138,-14475911,-33087759,-2696619,-23702521,-9102511,-23552096,-2287550,20712163,6719373 }, }, { { 26656208,6075253,-7858556,1886072,-28344043,4262326,11117530,-3763210,26224235,-3297458 }, { -17168938,-14854097,-3395676,-16369877,-19954045,14050420,21728352,9493610,18620611,-16428628 }, { -13323321,13325349,11432106,5964811,18609221,6062965,-5269471,-9725556,-30701573,-16479657 }, }, { { -23860538,-11233159,26961357,1640861,-32413112,-16737940,12248509,-5240639,13735342,1934062 }, { 25089769,6742589,17081145,-13406266,21909293,-16067981,-15136294,-3765346,-21277997,5473616 }, { 31883677,-7961101,1083432,-11572403,22828471,13290673,-7125085,12469656,29111212,-5451014 }, }, { { 24244947,-15050407,-26262976,2791540,-14997599,16666678,24367466,6388839,-10295587,452383 }, { -25640782,-3417841,5217916,16224624,19987036,-4082269,-24236251,-5915248,15766062,8407814 }, { -20406999,13990231,15495425,16395525,5377168,15166495,-8917023,-4388953,-8067909,2276718 }, }, { { 30157918,12924066,-17712050,9245753,19895028,3368142,-23827587,5096219,22740376,-7303417 }, { 2041139,-14256350,7783687,13876377,-25946985,-13352459,24051124,13742383,-15637599,13295222 }, { 33338237,-8505733,12532113,7977527,9106186,-1715251,-17720195,-4612972,-4451357,-14669444 }, }, { { -20045281,5454097,-14346548,6447146,28862071,1883651,-2469266,-4141880,7770569,9620597 }, { 23208068,7979712,33071466,8149229,1758231,-10834995,30945528,-1694323,-33502340,-14767970 }, { 1439958,-16270480,-1079989,-793782,4625402,10647766,-5043801,1220118,30494170,-11440799 }, }, { { -5037580,-13028295,-2970559,-3061767,15640974,-6701666,-26739026,926050,-1684339,-13333647 }, { 13908495,-3549272,30919928,-6273825,-21521863,7989039,9021034,9078865,3353509,4033511 }, { -29663431,-15113610,32259991,-344482,24295849,-12912123,23161163,8839127,27485041,7356032 }, }, }, { { { 9661027,705443,11980065,-5370154,-1628543,14661173,-6346142,2625015,28431036,-16771834 }, { -23839233,-8311415,-25945511,7480958,-17681669,-8354183,-22545972,14150565,15970762,4099461 }, { 29262576,16756590,26350592,-8793563,8529671,-11208050,13617293,-9937143,11465739,8317062 }, }, { { -25493081,-6962928,32500200,-9419051,-23038724,-2302222,14898637,3848455,20969334,-5157516 }, { -20384450,-14347713,-18336405,13884722,-33039454,2842114,-21610826,-3649888,11177095,14989547 }, { -24496721,-11716016,16959896,2278463,12066309,10137771,13515641,2581286,-28487508,9930240 }, }, { { -17751622,-2097826,16544300,-13009300,-15914807,-14949081,18345767,-13403753,16291481,-5314038 }, { -33229194,2553288,32678213,9875984,8534129,6889387,-9676774,6957617,4368891,9788741 }, { 16660756,7281060,-10830758,12911820,20108584,-8101676,-21722536,-8613148,16250552,-11111103 }, }, { { -19765507,2390526,-16551031,14161980,1905286,6414907,4689584,10604807,-30190403,4782747 }, { -1354539,14736941,-7367442,-13292886,7710542,-14155590,-9981571,4383045,22546403,437323 }, { 31665577,-12180464,-16186830,1491339,-18368625,3294682,27343084,2786261,-30633590,-14097016 }, }, { { -14467279,-683715,-33374107,7448552,19294360,14334329,-19690631,2355319,-19284671,-6114373 }, { 15121312,-15796162,6377020,-6031361,-10798111,-12957845,18952177,15496498,-29380133,11754228 }, { -2637277,-13483075,8488727,-14303896,12728761,-1622493,7141596,11724556,22761615,-10134141 }, }, { { 16918416,11729663,-18083579,3022987,-31015732,-13339659,-28741185,-12227393,32851222,11717399 }, { 11166634,7338049,-6722523,4531520,-29468672,-7302055,31474879,3483633,-1193175,-4030831 }, { -185635,9921305,31456609,-13536438,-12013818,13348923,33142652,6546660,-19985279,-3948376 }, }, { { -32460596,11266712,-11197107,-7899103,31703694,3855903,-8537131,-12833048,-30772034,-15486313 }, { -18006477,12709068,3991746,-6479188,-21491523,-10550425,-31135347,-16049879,10928917,3011958 }, { -6957757,-15594337,31696059,334240,29576716,14796075,-30831056,-12805180,18008031,10258577 }, }, { { -22448644,15655569,7018479,-4410003,-30314266,-1201591,-1853465,1367120,25127874,6671743 }, { 29701166,-14373934,-10878120,9279288,-17568,13127210,21382910,11042292,25838796,4642684 }, { -20430234,14955537,-24126347,8124619,-5369288,-5990470,30468147,-13900640,18423289,4177476 }, }, }, libsignal-protocol-c-2.3.3/src/curve25519/ed25519/base2.h000066400000000000000000000045241363751346500222500ustar00rootroot00000000000000 { { 25967493,-14356035,29566456,3660896,-12694345,4014787,27544626,-11754271,-6079156,2047605 }, { -12545711,934262,-2722910,3049990,-727428,9406986,12720692,5043384,19500929,-15469378 }, { -8738181,4489570,9688441,-14785194,10184609,-12363380,29287919,11864899,-24514362,-4438546 }, }, { { 15636291,-9688557,24204773,-7912398,616977,-16685262,27787600,-14772189,28944400,-1550024 }, { 16568933,4717097,-11556148,-1102322,15682896,-11807043,16354577,-11775962,7689662,11199574 }, { 30464156,-5976125,-11779434,-15670865,23220365,15915852,7512774,10017326,-17749093,-9920357 }, }, { { 10861363,11473154,27284546,1981175,-30064349,12577861,32867885,14515107,-15438304,10819380 }, { 4708026,6336745,20377586,9066809,-11272109,6594696,-25653668,12483688,-12668491,5581306 }, { 19563160,16186464,-29386857,4097519,10237984,-4348115,28542350,13850243,-23678021,-15815942 }, }, { { 5153746,9909285,1723747,-2777874,30523605,5516873,19480852,5230134,-23952439,-15175766 }, { -30269007,-3463509,7665486,10083793,28475525,1649722,20654025,16520125,30598449,7715701 }, { 28881845,14381568,9657904,3680757,-20181635,7843316,-31400660,1370708,29794553,-1409300 }, }, { { -22518993,-6692182,14201702,-8745502,-23510406,8844726,18474211,-1361450,-13062696,13821877 }, { -6455177,-7839871,3374702,-4740862,-27098617,-10571707,31655028,-7212327,18853322,-14220951 }, { 4566830,-12963868,-28974889,-12240689,-7602672,-2830569,-8514358,-10431137,2207753,-3209784 }, }, { { -25154831,-4185821,29681144,7868801,-6854661,-9423865,-12437364,-663000,-31111463,-16132436 }, { 25576264,-2703214,7349804,-11814844,16472782,9300885,3844789,15725684,171356,6466918 }, { 23103977,13316479,9739013,-16149481,817875,-15038942,8965339,-14088058,-30714912,16193877 }, }, { { -33521811,3180713,-2394130,14003687,-16903474,-16270840,17238398,4729455,-18074513,9256800 }, { -25182317,-4174131,32336398,5036987,-21236817,11360617,22616405,9761698,-19827198,630305 }, { -13720693,2639453,-24237460,-7406481,9494427,-5774029,-6554551,-15960994,-2449256,-14291300 }, }, { { -3151181,-5046075,9282714,6866145,-31907062,-863023,-18940575,15033784,25105118,-7894876 }, { -24326370,15950226,-31801215,-14592823,-11662737,-5090925,1573892,-2625887,2198790,-15804619 }, { -3099351,10324967,-2241613,7453183,-5446979,-2735503,-13812022,-16236442,-32461234,-12290683 }, }, libsignal-protocol-c-2.3.3/src/curve25519/ed25519/d.h000066400000000000000000000001331363751346500214670ustar00rootroot00000000000000-10913610,13857413,-15372611,6949391,114729,-8787816,-6275908,-3247719,-18696448,-12055116 libsignal-protocol-c-2.3.3/src/curve25519/ed25519/d2.h000066400000000000000000000001321363751346500215500ustar00rootroot00000000000000-21827239,-5839606,-30745221,13898782,229458,15978800,-12551817,-6495438,29715968,9444199 libsignal-protocol-c-2.3.3/src/curve25519/ed25519/fe.h000066400000000000000000000036231363751346500216450ustar00rootroot00000000000000#ifndef FE_H #define FE_H #include "crypto_int32.h" typedef crypto_int32 fe[10]; /* fe means field element. Here the field is \Z/(2^255-19). An element t, entries t[0]...t[9], represents the integer t[0]+2^26 t[1]+2^51 t[2]+2^77 t[3]+2^102 t[4]+...+2^230 t[9]. Bounds on each t[i] vary depending on context. */ #define fe_frombytes crypto_sign_ed25519_ref10_fe_frombytes #define fe_tobytes crypto_sign_ed25519_ref10_fe_tobytes #define fe_copy crypto_sign_ed25519_ref10_fe_copy #define fe_isnonzero crypto_sign_ed25519_ref10_fe_isnonzero #define fe_isnegative crypto_sign_ed25519_ref10_fe_isnegative #define fe_0 crypto_sign_ed25519_ref10_fe_0 #define fe_1 crypto_sign_ed25519_ref10_fe_1 #define fe_cswap crypto_sign_ed25519_ref10_fe_cswap #define fe_cmov crypto_sign_ed25519_ref10_fe_cmov #define fe_add crypto_sign_ed25519_ref10_fe_add #define fe_sub crypto_sign_ed25519_ref10_fe_sub #define fe_neg crypto_sign_ed25519_ref10_fe_neg #define fe_mul crypto_sign_ed25519_ref10_fe_mul #define fe_sq crypto_sign_ed25519_ref10_fe_sq #define fe_sq2 crypto_sign_ed25519_ref10_fe_sq2 #define fe_mul121666 crypto_sign_ed25519_ref10_fe_mul121666 #define fe_invert crypto_sign_ed25519_ref10_fe_invert #define fe_pow22523 crypto_sign_ed25519_ref10_fe_pow22523 extern void fe_frombytes(fe,const unsigned char *); extern void fe_tobytes(unsigned char *,const fe); extern void fe_copy(fe,const fe); extern int fe_isnonzero(const fe); extern int fe_isnegative(const fe); extern void fe_0(fe); extern void fe_1(fe); extern void fe_cswap(fe,fe,unsigned int); extern void fe_cmov(fe,const fe,unsigned int); extern void fe_add(fe,const fe,const fe); extern void fe_sub(fe,const fe,const fe); extern void fe_neg(fe,const fe); extern void fe_mul(fe,const fe,const fe); extern void fe_sq(fe,const fe); extern void fe_sq2(fe,const fe); extern void fe_mul121666(fe,const fe); extern void fe_invert(fe,const fe); extern void fe_pow22523(fe,const fe); #endif libsignal-protocol-c-2.3.3/src/curve25519/ed25519/fe_0.c000066400000000000000000000002521363751346500220520ustar00rootroot00000000000000#include "fe.h" /* h = 0 */ void fe_0(fe h) { h[0] = 0; h[1] = 0; h[2] = 0; h[3] = 0; h[4] = 0; h[5] = 0; h[6] = 0; h[7] = 0; h[8] = 0; h[9] = 0; } libsignal-protocol-c-2.3.3/src/curve25519/ed25519/fe_1.c000066400000000000000000000002521363751346500220530ustar00rootroot00000000000000#include "fe.h" /* h = 1 */ void fe_1(fe h) { h[0] = 1; h[1] = 0; h[2] = 0; h[3] = 0; h[4] = 0; h[5] = 0; h[6] = 0; h[7] = 0; h[8] = 0; h[9] = 0; } libsignal-protocol-c-2.3.3/src/curve25519/ed25519/fe_add.c000066400000000000000000000023471363751346500224520ustar00rootroot00000000000000#include "fe.h" /* h = f + g Can overlap h with f or g. Preconditions: |f| bounded by 1.1*2^25,1.1*2^24,1.1*2^25,1.1*2^24,etc. |g| bounded by 1.1*2^25,1.1*2^24,1.1*2^25,1.1*2^24,etc. Postconditions: |h| bounded by 1.1*2^26,1.1*2^25,1.1*2^26,1.1*2^25,etc. */ void fe_add(fe h,const fe f,const fe g) { crypto_int32 f0 = f[0]; crypto_int32 f1 = f[1]; crypto_int32 f2 = f[2]; crypto_int32 f3 = f[3]; crypto_int32 f4 = f[4]; crypto_int32 f5 = f[5]; crypto_int32 f6 = f[6]; crypto_int32 f7 = f[7]; crypto_int32 f8 = f[8]; crypto_int32 f9 = f[9]; crypto_int32 g0 = g[0]; crypto_int32 g1 = g[1]; crypto_int32 g2 = g[2]; crypto_int32 g3 = g[3]; crypto_int32 g4 = g[4]; crypto_int32 g5 = g[5]; crypto_int32 g6 = g[6]; crypto_int32 g7 = g[7]; crypto_int32 g8 = g[8]; crypto_int32 g9 = g[9]; crypto_int32 h0 = f0 + g0; crypto_int32 h1 = f1 + g1; crypto_int32 h2 = f2 + g2; crypto_int32 h3 = f3 + g3; crypto_int32 h4 = f4 + g4; crypto_int32 h5 = f5 + g5; crypto_int32 h6 = f6 + g6; crypto_int32 h7 = f7 + g7; crypto_int32 h8 = f8 + g8; crypto_int32 h9 = f9 + g9; h[0] = h0; h[1] = h1; h[2] = h2; h[3] = h3; h[4] = h4; h[5] = h5; h[6] = h6; h[7] = h7; h[8] = h8; h[9] = h9; } libsignal-protocol-c-2.3.3/src/curve25519/ed25519/fe_cmov.c000066400000000000000000000024031363751346500226570ustar00rootroot00000000000000#include "fe.h" /* Replace (f,g) with (g,g) if b == 1; replace (f,g) with (f,g) if b == 0. Preconditions: b in {0,1}. */ void fe_cmov(fe f,const fe g,unsigned int b) { crypto_int32 f0 = f[0]; crypto_int32 f1 = f[1]; crypto_int32 f2 = f[2]; crypto_int32 f3 = f[3]; crypto_int32 f4 = f[4]; crypto_int32 f5 = f[5]; crypto_int32 f6 = f[6]; crypto_int32 f7 = f[7]; crypto_int32 f8 = f[8]; crypto_int32 f9 = f[9]; crypto_int32 g0 = g[0]; crypto_int32 g1 = g[1]; crypto_int32 g2 = g[2]; crypto_int32 g3 = g[3]; crypto_int32 g4 = g[4]; crypto_int32 g5 = g[5]; crypto_int32 g6 = g[6]; crypto_int32 g7 = g[7]; crypto_int32 g8 = g[8]; crypto_int32 g9 = g[9]; crypto_int32 x0 = f0 ^ g0; crypto_int32 x1 = f1 ^ g1; crypto_int32 x2 = f2 ^ g2; crypto_int32 x3 = f3 ^ g3; crypto_int32 x4 = f4 ^ g4; crypto_int32 x5 = f5 ^ g5; crypto_int32 x6 = f6 ^ g6; crypto_int32 x7 = f7 ^ g7; crypto_int32 x8 = f8 ^ g8; crypto_int32 x9 = f9 ^ g9; b = -b; x0 &= b; x1 &= b; x2 &= b; x3 &= b; x4 &= b; x5 &= b; x6 &= b; x7 &= b; x8 &= b; x9 &= b; f[0] = f0 ^ x0; f[1] = f1 ^ x1; f[2] = f2 ^ x2; f[3] = f3 ^ x3; f[4] = f4 ^ x4; f[5] = f5 ^ x5; f[6] = f6 ^ x6; f[7] = f7 ^ x7; f[8] = f8 ^ x8; f[9] = f9 ^ x9; } libsignal-protocol-c-2.3.3/src/curve25519/ed25519/fe_copy.c000066400000000000000000000007061363751346500226710ustar00rootroot00000000000000#include "fe.h" /* h = f */ void fe_copy(fe h,const fe f) { crypto_int32 f0 = f[0]; crypto_int32 f1 = f[1]; crypto_int32 f2 = f[2]; crypto_int32 f3 = f[3]; crypto_int32 f4 = f[4]; crypto_int32 f5 = f[5]; crypto_int32 f6 = f[6]; crypto_int32 f7 = f[7]; crypto_int32 f8 = f[8]; crypto_int32 f9 = f[9]; h[0] = f0; h[1] = f1; h[2] = f2; h[3] = f3; h[4] = f4; h[5] = f5; h[6] = f6; h[7] = f7; h[8] = f8; h[9] = f9; } libsignal-protocol-c-2.3.3/src/curve25519/ed25519/fe_frombytes.c000066400000000000000000000042561363751346500237350ustar00rootroot00000000000000#include "fe.h" #include "crypto_int64.h" #include "crypto_uint64.h" static crypto_uint64 load_3(const unsigned char *in) { crypto_uint64 result; result = (crypto_uint64) in[0]; result |= ((crypto_uint64) in[1]) << 8; result |= ((crypto_uint64) in[2]) << 16; return result; } static crypto_uint64 load_4(const unsigned char *in) { crypto_uint64 result; result = (crypto_uint64) in[0]; result |= ((crypto_uint64) in[1]) << 8; result |= ((crypto_uint64) in[2]) << 16; result |= ((crypto_uint64) in[3]) << 24; return result; } /* Ignores top bit of h. */ void fe_frombytes(fe h,const unsigned char *s) { crypto_int64 h0 = load_4(s); crypto_int64 h1 = load_3(s + 4) << 6; crypto_int64 h2 = load_3(s + 7) << 5; crypto_int64 h3 = load_3(s + 10) << 3; crypto_int64 h4 = load_3(s + 13) << 2; crypto_int64 h5 = load_4(s + 16); crypto_int64 h6 = load_3(s + 20) << 7; crypto_int64 h7 = load_3(s + 23) << 5; crypto_int64 h8 = load_3(s + 26) << 4; crypto_int64 h9 = (load_3(s + 29) & 8388607) << 2; crypto_int64 carry0; crypto_int64 carry1; crypto_int64 carry2; crypto_int64 carry3; crypto_int64 carry4; crypto_int64 carry5; crypto_int64 carry6; crypto_int64 carry7; crypto_int64 carry8; crypto_int64 carry9; carry9 = (h9 + (crypto_int64) (1<<24)) >> 25; h0 += carry9 * 19; h9 -= carry9 << 25; carry1 = (h1 + (crypto_int64) (1<<24)) >> 25; h2 += carry1; h1 -= carry1 << 25; carry3 = (h3 + (crypto_int64) (1<<24)) >> 25; h4 += carry3; h3 -= carry3 << 25; carry5 = (h5 + (crypto_int64) (1<<24)) >> 25; h6 += carry5; h5 -= carry5 << 25; carry7 = (h7 + (crypto_int64) (1<<24)) >> 25; h8 += carry7; h7 -= carry7 << 25; carry0 = (h0 + (crypto_int64) (1<<25)) >> 26; h1 += carry0; h0 -= carry0 << 26; carry2 = (h2 + (crypto_int64) (1<<25)) >> 26; h3 += carry2; h2 -= carry2 << 26; carry4 = (h4 + (crypto_int64) (1<<25)) >> 26; h5 += carry4; h4 -= carry4 << 26; carry6 = (h6 + (crypto_int64) (1<<25)) >> 26; h7 += carry6; h6 -= carry6 << 26; carry8 = (h8 + (crypto_int64) (1<<25)) >> 26; h9 += carry8; h8 -= carry8 << 26; h[0] = h0; h[1] = h1; h[2] = h2; h[3] = h3; h[4] = h4; h[5] = h5; h[6] = h6; h[7] = h7; h[8] = h8; h[9] = h9; } libsignal-protocol-c-2.3.3/src/curve25519/ed25519/fe_invert.c000066400000000000000000000002071363751346500232220ustar00rootroot00000000000000#include "fe.h" void fe_invert(fe out,const fe z) { fe t0; fe t1; fe t2; fe t3; int i; #include "pow225521.h" return; } libsignal-protocol-c-2.3.3/src/curve25519/ed25519/fe_isnegative.c000066400000000000000000000004121363751346500240470ustar00rootroot00000000000000#include "fe.h" /* return 1 if f is in {1,3,5,...,q-2} return 0 if f is in {0,2,4,...,q-1} Preconditions: |f| bounded by 1.1*2^26,1.1*2^25,1.1*2^26,1.1*2^25,etc. */ int fe_isnegative(const fe f) { unsigned char s[32]; fe_tobytes(s,f); return s[0] & 1; } libsignal-protocol-c-2.3.3/src/curve25519/ed25519/fe_isnonzero.c000066400000000000000000000007051363751346500237440ustar00rootroot00000000000000#include "fe.h" #include "crypto_verify_32.h" /* return nonzero if f == 0 return 0 if f != 0 Preconditions: |f| bounded by 1.1*2^26,1.1*2^25,1.1*2^26,1.1*2^25,etc. */ /* TREVOR'S COMMENT * * I think the above comment is wrong. Instead: * * return 0 if f == 0 * return -1 if f != 0 * * */ static const unsigned char zero[32]; int fe_isnonzero(const fe f) { unsigned char s[32]; fe_tobytes(s,f); return crypto_verify_32(s,zero); } libsignal-protocol-c-2.3.3/src/curve25519/ed25519/fe_mul.c000066400000000000000000000247701363751346500225230ustar00rootroot00000000000000#include "fe.h" #include "crypto_int64.h" /* h = f * g Can overlap h with f or g. Preconditions: |f| bounded by 1.65*2^26,1.65*2^25,1.65*2^26,1.65*2^25,etc. |g| bounded by 1.65*2^26,1.65*2^25,1.65*2^26,1.65*2^25,etc. Postconditions: |h| bounded by 1.01*2^25,1.01*2^24,1.01*2^25,1.01*2^24,etc. */ /* Notes on implementation strategy: Using schoolbook multiplication. Karatsuba would save a little in some cost models. Most multiplications by 2 and 19 are 32-bit precomputations; cheaper than 64-bit postcomputations. There is one remaining multiplication by 19 in the carry chain; one *19 precomputation can be merged into this, but the resulting data flow is considerably less clean. There are 12 carries below. 10 of them are 2-way parallelizable and vectorizable. Can get away with 11 carries, but then data flow is much deeper. With tighter constraints on inputs can squeeze carries into int32. */ void fe_mul(fe h,const fe f,const fe g) { crypto_int32 f0 = f[0]; crypto_int32 f1 = f[1]; crypto_int32 f2 = f[2]; crypto_int32 f3 = f[3]; crypto_int32 f4 = f[4]; crypto_int32 f5 = f[5]; crypto_int32 f6 = f[6]; crypto_int32 f7 = f[7]; crypto_int32 f8 = f[8]; crypto_int32 f9 = f[9]; crypto_int32 g0 = g[0]; crypto_int32 g1 = g[1]; crypto_int32 g2 = g[2]; crypto_int32 g3 = g[3]; crypto_int32 g4 = g[4]; crypto_int32 g5 = g[5]; crypto_int32 g6 = g[6]; crypto_int32 g7 = g[7]; crypto_int32 g8 = g[8]; crypto_int32 g9 = g[9]; crypto_int32 g1_19 = 19 * g1; /* 1.959375*2^29 */ crypto_int32 g2_19 = 19 * g2; /* 1.959375*2^30; still ok */ crypto_int32 g3_19 = 19 * g3; crypto_int32 g4_19 = 19 * g4; crypto_int32 g5_19 = 19 * g5; crypto_int32 g6_19 = 19 * g6; crypto_int32 g7_19 = 19 * g7; crypto_int32 g8_19 = 19 * g8; crypto_int32 g9_19 = 19 * g9; crypto_int32 f1_2 = 2 * f1; crypto_int32 f3_2 = 2 * f3; crypto_int32 f5_2 = 2 * f5; crypto_int32 f7_2 = 2 * f7; crypto_int32 f9_2 = 2 * f9; crypto_int64 f0g0 = f0 * (crypto_int64) g0; crypto_int64 f0g1 = f0 * (crypto_int64) g1; crypto_int64 f0g2 = f0 * (crypto_int64) g2; crypto_int64 f0g3 = f0 * (crypto_int64) g3; crypto_int64 f0g4 = f0 * (crypto_int64) g4; crypto_int64 f0g5 = f0 * (crypto_int64) g5; crypto_int64 f0g6 = f0 * (crypto_int64) g6; crypto_int64 f0g7 = f0 * (crypto_int64) g7; crypto_int64 f0g8 = f0 * (crypto_int64) g8; crypto_int64 f0g9 = f0 * (crypto_int64) g9; crypto_int64 f1g0 = f1 * (crypto_int64) g0; crypto_int64 f1g1_2 = f1_2 * (crypto_int64) g1; crypto_int64 f1g2 = f1 * (crypto_int64) g2; crypto_int64 f1g3_2 = f1_2 * (crypto_int64) g3; crypto_int64 f1g4 = f1 * (crypto_int64) g4; crypto_int64 f1g5_2 = f1_2 * (crypto_int64) g5; crypto_int64 f1g6 = f1 * (crypto_int64) g6; crypto_int64 f1g7_2 = f1_2 * (crypto_int64) g7; crypto_int64 f1g8 = f1 * (crypto_int64) g8; crypto_int64 f1g9_38 = f1_2 * (crypto_int64) g9_19; crypto_int64 f2g0 = f2 * (crypto_int64) g0; crypto_int64 f2g1 = f2 * (crypto_int64) g1; crypto_int64 f2g2 = f2 * (crypto_int64) g2; crypto_int64 f2g3 = f2 * (crypto_int64) g3; crypto_int64 f2g4 = f2 * (crypto_int64) g4; crypto_int64 f2g5 = f2 * (crypto_int64) g5; crypto_int64 f2g6 = f2 * (crypto_int64) g6; crypto_int64 f2g7 = f2 * (crypto_int64) g7; crypto_int64 f2g8_19 = f2 * (crypto_int64) g8_19; crypto_int64 f2g9_19 = f2 * (crypto_int64) g9_19; crypto_int64 f3g0 = f3 * (crypto_int64) g0; crypto_int64 f3g1_2 = f3_2 * (crypto_int64) g1; crypto_int64 f3g2 = f3 * (crypto_int64) g2; crypto_int64 f3g3_2 = f3_2 * (crypto_int64) g3; crypto_int64 f3g4 = f3 * (crypto_int64) g4; crypto_int64 f3g5_2 = f3_2 * (crypto_int64) g5; crypto_int64 f3g6 = f3 * (crypto_int64) g6; crypto_int64 f3g7_38 = f3_2 * (crypto_int64) g7_19; crypto_int64 f3g8_19 = f3 * (crypto_int64) g8_19; crypto_int64 f3g9_38 = f3_2 * (crypto_int64) g9_19; crypto_int64 f4g0 = f4 * (crypto_int64) g0; crypto_int64 f4g1 = f4 * (crypto_int64) g1; crypto_int64 f4g2 = f4 * (crypto_int64) g2; crypto_int64 f4g3 = f4 * (crypto_int64) g3; crypto_int64 f4g4 = f4 * (crypto_int64) g4; crypto_int64 f4g5 = f4 * (crypto_int64) g5; crypto_int64 f4g6_19 = f4 * (crypto_int64) g6_19; crypto_int64 f4g7_19 = f4 * (crypto_int64) g7_19; crypto_int64 f4g8_19 = f4 * (crypto_int64) g8_19; crypto_int64 f4g9_19 = f4 * (crypto_int64) g9_19; crypto_int64 f5g0 = f5 * (crypto_int64) g0; crypto_int64 f5g1_2 = f5_2 * (crypto_int64) g1; crypto_int64 f5g2 = f5 * (crypto_int64) g2; crypto_int64 f5g3_2 = f5_2 * (crypto_int64) g3; crypto_int64 f5g4 = f5 * (crypto_int64) g4; crypto_int64 f5g5_38 = f5_2 * (crypto_int64) g5_19; crypto_int64 f5g6_19 = f5 * (crypto_int64) g6_19; crypto_int64 f5g7_38 = f5_2 * (crypto_int64) g7_19; crypto_int64 f5g8_19 = f5 * (crypto_int64) g8_19; crypto_int64 f5g9_38 = f5_2 * (crypto_int64) g9_19; crypto_int64 f6g0 = f6 * (crypto_int64) g0; crypto_int64 f6g1 = f6 * (crypto_int64) g1; crypto_int64 f6g2 = f6 * (crypto_int64) g2; crypto_int64 f6g3 = f6 * (crypto_int64) g3; crypto_int64 f6g4_19 = f6 * (crypto_int64) g4_19; crypto_int64 f6g5_19 = f6 * (crypto_int64) g5_19; crypto_int64 f6g6_19 = f6 * (crypto_int64) g6_19; crypto_int64 f6g7_19 = f6 * (crypto_int64) g7_19; crypto_int64 f6g8_19 = f6 * (crypto_int64) g8_19; crypto_int64 f6g9_19 = f6 * (crypto_int64) g9_19; crypto_int64 f7g0 = f7 * (crypto_int64) g0; crypto_int64 f7g1_2 = f7_2 * (crypto_int64) g1; crypto_int64 f7g2 = f7 * (crypto_int64) g2; crypto_int64 f7g3_38 = f7_2 * (crypto_int64) g3_19; crypto_int64 f7g4_19 = f7 * (crypto_int64) g4_19; crypto_int64 f7g5_38 = f7_2 * (crypto_int64) g5_19; crypto_int64 f7g6_19 = f7 * (crypto_int64) g6_19; crypto_int64 f7g7_38 = f7_2 * (crypto_int64) g7_19; crypto_int64 f7g8_19 = f7 * (crypto_int64) g8_19; crypto_int64 f7g9_38 = f7_2 * (crypto_int64) g9_19; crypto_int64 f8g0 = f8 * (crypto_int64) g0; crypto_int64 f8g1 = f8 * (crypto_int64) g1; crypto_int64 f8g2_19 = f8 * (crypto_int64) g2_19; crypto_int64 f8g3_19 = f8 * (crypto_int64) g3_19; crypto_int64 f8g4_19 = f8 * (crypto_int64) g4_19; crypto_int64 f8g5_19 = f8 * (crypto_int64) g5_19; crypto_int64 f8g6_19 = f8 * (crypto_int64) g6_19; crypto_int64 f8g7_19 = f8 * (crypto_int64) g7_19; crypto_int64 f8g8_19 = f8 * (crypto_int64) g8_19; crypto_int64 f8g9_19 = f8 * (crypto_int64) g9_19; crypto_int64 f9g0 = f9 * (crypto_int64) g0; crypto_int64 f9g1_38 = f9_2 * (crypto_int64) g1_19; crypto_int64 f9g2_19 = f9 * (crypto_int64) g2_19; crypto_int64 f9g3_38 = f9_2 * (crypto_int64) g3_19; crypto_int64 f9g4_19 = f9 * (crypto_int64) g4_19; crypto_int64 f9g5_38 = f9_2 * (crypto_int64) g5_19; crypto_int64 f9g6_19 = f9 * (crypto_int64) g6_19; crypto_int64 f9g7_38 = f9_2 * (crypto_int64) g7_19; crypto_int64 f9g8_19 = f9 * (crypto_int64) g8_19; crypto_int64 f9g9_38 = f9_2 * (crypto_int64) g9_19; crypto_int64 h0 = f0g0+f1g9_38+f2g8_19+f3g7_38+f4g6_19+f5g5_38+f6g4_19+f7g3_38+f8g2_19+f9g1_38; crypto_int64 h1 = f0g1+f1g0 +f2g9_19+f3g8_19+f4g7_19+f5g6_19+f6g5_19+f7g4_19+f8g3_19+f9g2_19; crypto_int64 h2 = f0g2+f1g1_2 +f2g0 +f3g9_38+f4g8_19+f5g7_38+f6g6_19+f7g5_38+f8g4_19+f9g3_38; crypto_int64 h3 = f0g3+f1g2 +f2g1 +f3g0 +f4g9_19+f5g8_19+f6g7_19+f7g6_19+f8g5_19+f9g4_19; crypto_int64 h4 = f0g4+f1g3_2 +f2g2 +f3g1_2 +f4g0 +f5g9_38+f6g8_19+f7g7_38+f8g6_19+f9g5_38; crypto_int64 h5 = f0g5+f1g4 +f2g3 +f3g2 +f4g1 +f5g0 +f6g9_19+f7g8_19+f8g7_19+f9g6_19; crypto_int64 h6 = f0g6+f1g5_2 +f2g4 +f3g3_2 +f4g2 +f5g1_2 +f6g0 +f7g9_38+f8g8_19+f9g7_38; crypto_int64 h7 = f0g7+f1g6 +f2g5 +f3g4 +f4g3 +f5g2 +f6g1 +f7g0 +f8g9_19+f9g8_19; crypto_int64 h8 = f0g8+f1g7_2 +f2g6 +f3g5_2 +f4g4 +f5g3_2 +f6g2 +f7g1_2 +f8g0 +f9g9_38; crypto_int64 h9 = f0g9+f1g8 +f2g7 +f3g6 +f4g5 +f5g4 +f6g3 +f7g2 +f8g1 +f9g0 ; crypto_int64 carry0; crypto_int64 carry1; crypto_int64 carry2; crypto_int64 carry3; crypto_int64 carry4; crypto_int64 carry5; crypto_int64 carry6; crypto_int64 carry7; crypto_int64 carry8; crypto_int64 carry9; /* |h0| <= (1.65*1.65*2^52*(1+19+19+19+19)+1.65*1.65*2^50*(38+38+38+38+38)) i.e. |h0| <= 1.4*2^60; narrower ranges for h2, h4, h6, h8 |h1| <= (1.65*1.65*2^51*(1+1+19+19+19+19+19+19+19+19)) i.e. |h1| <= 1.7*2^59; narrower ranges for h3, h5, h7, h9 */ carry0 = (h0 + (crypto_int64) (1<<25)) >> 26; h1 += carry0; h0 -= carry0 << 26; carry4 = (h4 + (crypto_int64) (1<<25)) >> 26; h5 += carry4; h4 -= carry4 << 26; /* |h0| <= 2^25 */ /* |h4| <= 2^25 */ /* |h1| <= 1.71*2^59 */ /* |h5| <= 1.71*2^59 */ carry1 = (h1 + (crypto_int64) (1<<24)) >> 25; h2 += carry1; h1 -= carry1 << 25; carry5 = (h5 + (crypto_int64) (1<<24)) >> 25; h6 += carry5; h5 -= carry5 << 25; /* |h1| <= 2^24; from now on fits into int32 */ /* |h5| <= 2^24; from now on fits into int32 */ /* |h2| <= 1.41*2^60 */ /* |h6| <= 1.41*2^60 */ carry2 = (h2 + (crypto_int64) (1<<25)) >> 26; h3 += carry2; h2 -= carry2 << 26; carry6 = (h6 + (crypto_int64) (1<<25)) >> 26; h7 += carry6; h6 -= carry6 << 26; /* |h2| <= 2^25; from now on fits into int32 unchanged */ /* |h6| <= 2^25; from now on fits into int32 unchanged */ /* |h3| <= 1.71*2^59 */ /* |h7| <= 1.71*2^59 */ carry3 = (h3 + (crypto_int64) (1<<24)) >> 25; h4 += carry3; h3 -= carry3 << 25; carry7 = (h7 + (crypto_int64) (1<<24)) >> 25; h8 += carry7; h7 -= carry7 << 25; /* |h3| <= 2^24; from now on fits into int32 unchanged */ /* |h7| <= 2^24; from now on fits into int32 unchanged */ /* |h4| <= 1.72*2^34 */ /* |h8| <= 1.41*2^60 */ carry4 = (h4 + (crypto_int64) (1<<25)) >> 26; h5 += carry4; h4 -= carry4 << 26; carry8 = (h8 + (crypto_int64) (1<<25)) >> 26; h9 += carry8; h8 -= carry8 << 26; /* |h4| <= 2^25; from now on fits into int32 unchanged */ /* |h8| <= 2^25; from now on fits into int32 unchanged */ /* |h5| <= 1.01*2^24 */ /* |h9| <= 1.71*2^59 */ carry9 = (h9 + (crypto_int64) (1<<24)) >> 25; h0 += carry9 * 19; h9 -= carry9 << 25; /* |h9| <= 2^24; from now on fits into int32 unchanged */ /* |h0| <= 1.1*2^39 */ carry0 = (h0 + (crypto_int64) (1<<25)) >> 26; h1 += carry0; h0 -= carry0 << 26; /* |h0| <= 2^25; from now on fits into int32 unchanged */ /* |h1| <= 1.01*2^24 */ h[0] = h0; h[1] = h1; h[2] = h2; h[3] = h3; h[4] = h4; h[5] = h5; h[6] = h6; h[7] = h7; h[8] = h8; h[9] = h9; } libsignal-protocol-c-2.3.3/src/curve25519/ed25519/fe_neg.c000066400000000000000000000015271363751346500224720ustar00rootroot00000000000000#include "fe.h" /* h = -f Preconditions: |f| bounded by 1.1*2^25,1.1*2^24,1.1*2^25,1.1*2^24,etc. Postconditions: |h| bounded by 1.1*2^25,1.1*2^24,1.1*2^25,1.1*2^24,etc. */ void fe_neg(fe h,const fe f) { crypto_int32 f0 = f[0]; crypto_int32 f1 = f[1]; crypto_int32 f2 = f[2]; crypto_int32 f3 = f[3]; crypto_int32 f4 = f[4]; crypto_int32 f5 = f[5]; crypto_int32 f6 = f[6]; crypto_int32 f7 = f[7]; crypto_int32 f8 = f[8]; crypto_int32 f9 = f[9]; crypto_int32 h0 = -f0; crypto_int32 h1 = -f1; crypto_int32 h2 = -f2; crypto_int32 h3 = -f3; crypto_int32 h4 = -f4; crypto_int32 h5 = -f5; crypto_int32 h6 = -f6; crypto_int32 h7 = -f7; crypto_int32 h8 = -f8; crypto_int32 h9 = -f9; h[0] = h0; h[1] = h1; h[2] = h2; h[3] = h3; h[4] = h4; h[5] = h5; h[6] = h6; h[7] = h7; h[8] = h8; h[9] = h9; } libsignal-protocol-c-2.3.3/src/curve25519/ed25519/fe_pow22523.c000066400000000000000000000001771363751346500231240ustar00rootroot00000000000000#include "fe.h" void fe_pow22523(fe out,const fe z) { fe t0; fe t1; fe t2; int i; #include "pow22523.h" return; } libsignal-protocol-c-2.3.3/src/curve25519/ed25519/fe_sq.c000066400000000000000000000135341363751346500223450ustar00rootroot00000000000000#include "fe.h" #include "crypto_int64.h" /* h = f * f Can overlap h with f. Preconditions: |f| bounded by 1.65*2^26,1.65*2^25,1.65*2^26,1.65*2^25,etc. Postconditions: |h| bounded by 1.01*2^25,1.01*2^24,1.01*2^25,1.01*2^24,etc. */ /* See fe_mul.c for discussion of implementation strategy. */ void fe_sq(fe h,const fe f) { crypto_int32 f0 = f[0]; crypto_int32 f1 = f[1]; crypto_int32 f2 = f[2]; crypto_int32 f3 = f[3]; crypto_int32 f4 = f[4]; crypto_int32 f5 = f[5]; crypto_int32 f6 = f[6]; crypto_int32 f7 = f[7]; crypto_int32 f8 = f[8]; crypto_int32 f9 = f[9]; crypto_int32 f0_2 = 2 * f0; crypto_int32 f1_2 = 2 * f1; crypto_int32 f2_2 = 2 * f2; crypto_int32 f3_2 = 2 * f3; crypto_int32 f4_2 = 2 * f4; crypto_int32 f5_2 = 2 * f5; crypto_int32 f6_2 = 2 * f6; crypto_int32 f7_2 = 2 * f7; crypto_int32 f5_38 = 38 * f5; /* 1.959375*2^30 */ crypto_int32 f6_19 = 19 * f6; /* 1.959375*2^30 */ crypto_int32 f7_38 = 38 * f7; /* 1.959375*2^30 */ crypto_int32 f8_19 = 19 * f8; /* 1.959375*2^30 */ crypto_int32 f9_38 = 38 * f9; /* 1.959375*2^30 */ crypto_int64 f0f0 = f0 * (crypto_int64) f0; crypto_int64 f0f1_2 = f0_2 * (crypto_int64) f1; crypto_int64 f0f2_2 = f0_2 * (crypto_int64) f2; crypto_int64 f0f3_2 = f0_2 * (crypto_int64) f3; crypto_int64 f0f4_2 = f0_2 * (crypto_int64) f4; crypto_int64 f0f5_2 = f0_2 * (crypto_int64) f5; crypto_int64 f0f6_2 = f0_2 * (crypto_int64) f6; crypto_int64 f0f7_2 = f0_2 * (crypto_int64) f7; crypto_int64 f0f8_2 = f0_2 * (crypto_int64) f8; crypto_int64 f0f9_2 = f0_2 * (crypto_int64) f9; crypto_int64 f1f1_2 = f1_2 * (crypto_int64) f1; crypto_int64 f1f2_2 = f1_2 * (crypto_int64) f2; crypto_int64 f1f3_4 = f1_2 * (crypto_int64) f3_2; crypto_int64 f1f4_2 = f1_2 * (crypto_int64) f4; crypto_int64 f1f5_4 = f1_2 * (crypto_int64) f5_2; crypto_int64 f1f6_2 = f1_2 * (crypto_int64) f6; crypto_int64 f1f7_4 = f1_2 * (crypto_int64) f7_2; crypto_int64 f1f8_2 = f1_2 * (crypto_int64) f8; crypto_int64 f1f9_76 = f1_2 * (crypto_int64) f9_38; crypto_int64 f2f2 = f2 * (crypto_int64) f2; crypto_int64 f2f3_2 = f2_2 * (crypto_int64) f3; crypto_int64 f2f4_2 = f2_2 * (crypto_int64) f4; crypto_int64 f2f5_2 = f2_2 * (crypto_int64) f5; crypto_int64 f2f6_2 = f2_2 * (crypto_int64) f6; crypto_int64 f2f7_2 = f2_2 * (crypto_int64) f7; crypto_int64 f2f8_38 = f2_2 * (crypto_int64) f8_19; crypto_int64 f2f9_38 = f2 * (crypto_int64) f9_38; crypto_int64 f3f3_2 = f3_2 * (crypto_int64) f3; crypto_int64 f3f4_2 = f3_2 * (crypto_int64) f4; crypto_int64 f3f5_4 = f3_2 * (crypto_int64) f5_2; crypto_int64 f3f6_2 = f3_2 * (crypto_int64) f6; crypto_int64 f3f7_76 = f3_2 * (crypto_int64) f7_38; crypto_int64 f3f8_38 = f3_2 * (crypto_int64) f8_19; crypto_int64 f3f9_76 = f3_2 * (crypto_int64) f9_38; crypto_int64 f4f4 = f4 * (crypto_int64) f4; crypto_int64 f4f5_2 = f4_2 * (crypto_int64) f5; crypto_int64 f4f6_38 = f4_2 * (crypto_int64) f6_19; crypto_int64 f4f7_38 = f4 * (crypto_int64) f7_38; crypto_int64 f4f8_38 = f4_2 * (crypto_int64) f8_19; crypto_int64 f4f9_38 = f4 * (crypto_int64) f9_38; crypto_int64 f5f5_38 = f5 * (crypto_int64) f5_38; crypto_int64 f5f6_38 = f5_2 * (crypto_int64) f6_19; crypto_int64 f5f7_76 = f5_2 * (crypto_int64) f7_38; crypto_int64 f5f8_38 = f5_2 * (crypto_int64) f8_19; crypto_int64 f5f9_76 = f5_2 * (crypto_int64) f9_38; crypto_int64 f6f6_19 = f6 * (crypto_int64) f6_19; crypto_int64 f6f7_38 = f6 * (crypto_int64) f7_38; crypto_int64 f6f8_38 = f6_2 * (crypto_int64) f8_19; crypto_int64 f6f9_38 = f6 * (crypto_int64) f9_38; crypto_int64 f7f7_38 = f7 * (crypto_int64) f7_38; crypto_int64 f7f8_38 = f7_2 * (crypto_int64) f8_19; crypto_int64 f7f9_76 = f7_2 * (crypto_int64) f9_38; crypto_int64 f8f8_19 = f8 * (crypto_int64) f8_19; crypto_int64 f8f9_38 = f8 * (crypto_int64) f9_38; crypto_int64 f9f9_38 = f9 * (crypto_int64) f9_38; crypto_int64 h0 = f0f0 +f1f9_76+f2f8_38+f3f7_76+f4f6_38+f5f5_38; crypto_int64 h1 = f0f1_2+f2f9_38+f3f8_38+f4f7_38+f5f6_38; crypto_int64 h2 = f0f2_2+f1f1_2 +f3f9_76+f4f8_38+f5f7_76+f6f6_19; crypto_int64 h3 = f0f3_2+f1f2_2 +f4f9_38+f5f8_38+f6f7_38; crypto_int64 h4 = f0f4_2+f1f3_4 +f2f2 +f5f9_76+f6f8_38+f7f7_38; crypto_int64 h5 = f0f5_2+f1f4_2 +f2f3_2 +f6f9_38+f7f8_38; crypto_int64 h6 = f0f6_2+f1f5_4 +f2f4_2 +f3f3_2 +f7f9_76+f8f8_19; crypto_int64 h7 = f0f7_2+f1f6_2 +f2f5_2 +f3f4_2 +f8f9_38; crypto_int64 h8 = f0f8_2+f1f7_4 +f2f6_2 +f3f5_4 +f4f4 +f9f9_38; crypto_int64 h9 = f0f9_2+f1f8_2 +f2f7_2 +f3f6_2 +f4f5_2; crypto_int64 carry0; crypto_int64 carry1; crypto_int64 carry2; crypto_int64 carry3; crypto_int64 carry4; crypto_int64 carry5; crypto_int64 carry6; crypto_int64 carry7; crypto_int64 carry8; crypto_int64 carry9; carry0 = (h0 + (crypto_int64) (1<<25)) >> 26; h1 += carry0; h0 -= carry0 << 26; carry4 = (h4 + (crypto_int64) (1<<25)) >> 26; h5 += carry4; h4 -= carry4 << 26; carry1 = (h1 + (crypto_int64) (1<<24)) >> 25; h2 += carry1; h1 -= carry1 << 25; carry5 = (h5 + (crypto_int64) (1<<24)) >> 25; h6 += carry5; h5 -= carry5 << 25; carry2 = (h2 + (crypto_int64) (1<<25)) >> 26; h3 += carry2; h2 -= carry2 << 26; carry6 = (h6 + (crypto_int64) (1<<25)) >> 26; h7 += carry6; h6 -= carry6 << 26; carry3 = (h3 + (crypto_int64) (1<<24)) >> 25; h4 += carry3; h3 -= carry3 << 25; carry7 = (h7 + (crypto_int64) (1<<24)) >> 25; h8 += carry7; h7 -= carry7 << 25; carry4 = (h4 + (crypto_int64) (1<<25)) >> 26; h5 += carry4; h4 -= carry4 << 26; carry8 = (h8 + (crypto_int64) (1<<25)) >> 26; h9 += carry8; h8 -= carry8 << 26; carry9 = (h9 + (crypto_int64) (1<<24)) >> 25; h0 += carry9 * 19; h9 -= carry9 << 25; carry0 = (h0 + (crypto_int64) (1<<25)) >> 26; h1 += carry0; h0 -= carry0 << 26; h[0] = h0; h[1] = h1; h[2] = h2; h[3] = h3; h[4] = h4; h[5] = h5; h[6] = h6; h[7] = h7; h[8] = h8; h[9] = h9; } libsignal-protocol-c-2.3.3/src/curve25519/ed25519/fe_sq2.c000066400000000000000000000137321363751346500224270ustar00rootroot00000000000000#include "fe.h" #include "crypto_int64.h" /* h = 2 * f * f Can overlap h with f. Preconditions: |f| bounded by 1.65*2^26,1.65*2^25,1.65*2^26,1.65*2^25,etc. Postconditions: |h| bounded by 1.01*2^25,1.01*2^24,1.01*2^25,1.01*2^24,etc. */ /* See fe_mul.c for discussion of implementation strategy. */ void fe_sq2(fe h,const fe f) { crypto_int32 f0 = f[0]; crypto_int32 f1 = f[1]; crypto_int32 f2 = f[2]; crypto_int32 f3 = f[3]; crypto_int32 f4 = f[4]; crypto_int32 f5 = f[5]; crypto_int32 f6 = f[6]; crypto_int32 f7 = f[7]; crypto_int32 f8 = f[8]; crypto_int32 f9 = f[9]; crypto_int32 f0_2 = 2 * f0; crypto_int32 f1_2 = 2 * f1; crypto_int32 f2_2 = 2 * f2; crypto_int32 f3_2 = 2 * f3; crypto_int32 f4_2 = 2 * f4; crypto_int32 f5_2 = 2 * f5; crypto_int32 f6_2 = 2 * f6; crypto_int32 f7_2 = 2 * f7; crypto_int32 f5_38 = 38 * f5; /* 1.959375*2^30 */ crypto_int32 f6_19 = 19 * f6; /* 1.959375*2^30 */ crypto_int32 f7_38 = 38 * f7; /* 1.959375*2^30 */ crypto_int32 f8_19 = 19 * f8; /* 1.959375*2^30 */ crypto_int32 f9_38 = 38 * f9; /* 1.959375*2^30 */ crypto_int64 f0f0 = f0 * (crypto_int64) f0; crypto_int64 f0f1_2 = f0_2 * (crypto_int64) f1; crypto_int64 f0f2_2 = f0_2 * (crypto_int64) f2; crypto_int64 f0f3_2 = f0_2 * (crypto_int64) f3; crypto_int64 f0f4_2 = f0_2 * (crypto_int64) f4; crypto_int64 f0f5_2 = f0_2 * (crypto_int64) f5; crypto_int64 f0f6_2 = f0_2 * (crypto_int64) f6; crypto_int64 f0f7_2 = f0_2 * (crypto_int64) f7; crypto_int64 f0f8_2 = f0_2 * (crypto_int64) f8; crypto_int64 f0f9_2 = f0_2 * (crypto_int64) f9; crypto_int64 f1f1_2 = f1_2 * (crypto_int64) f1; crypto_int64 f1f2_2 = f1_2 * (crypto_int64) f2; crypto_int64 f1f3_4 = f1_2 * (crypto_int64) f3_2; crypto_int64 f1f4_2 = f1_2 * (crypto_int64) f4; crypto_int64 f1f5_4 = f1_2 * (crypto_int64) f5_2; crypto_int64 f1f6_2 = f1_2 * (crypto_int64) f6; crypto_int64 f1f7_4 = f1_2 * (crypto_int64) f7_2; crypto_int64 f1f8_2 = f1_2 * (crypto_int64) f8; crypto_int64 f1f9_76 = f1_2 * (crypto_int64) f9_38; crypto_int64 f2f2 = f2 * (crypto_int64) f2; crypto_int64 f2f3_2 = f2_2 * (crypto_int64) f3; crypto_int64 f2f4_2 = f2_2 * (crypto_int64) f4; crypto_int64 f2f5_2 = f2_2 * (crypto_int64) f5; crypto_int64 f2f6_2 = f2_2 * (crypto_int64) f6; crypto_int64 f2f7_2 = f2_2 * (crypto_int64) f7; crypto_int64 f2f8_38 = f2_2 * (crypto_int64) f8_19; crypto_int64 f2f9_38 = f2 * (crypto_int64) f9_38; crypto_int64 f3f3_2 = f3_2 * (crypto_int64) f3; crypto_int64 f3f4_2 = f3_2 * (crypto_int64) f4; crypto_int64 f3f5_4 = f3_2 * (crypto_int64) f5_2; crypto_int64 f3f6_2 = f3_2 * (crypto_int64) f6; crypto_int64 f3f7_76 = f3_2 * (crypto_int64) f7_38; crypto_int64 f3f8_38 = f3_2 * (crypto_int64) f8_19; crypto_int64 f3f9_76 = f3_2 * (crypto_int64) f9_38; crypto_int64 f4f4 = f4 * (crypto_int64) f4; crypto_int64 f4f5_2 = f4_2 * (crypto_int64) f5; crypto_int64 f4f6_38 = f4_2 * (crypto_int64) f6_19; crypto_int64 f4f7_38 = f4 * (crypto_int64) f7_38; crypto_int64 f4f8_38 = f4_2 * (crypto_int64) f8_19; crypto_int64 f4f9_38 = f4 * (crypto_int64) f9_38; crypto_int64 f5f5_38 = f5 * (crypto_int64) f5_38; crypto_int64 f5f6_38 = f5_2 * (crypto_int64) f6_19; crypto_int64 f5f7_76 = f5_2 * (crypto_int64) f7_38; crypto_int64 f5f8_38 = f5_2 * (crypto_int64) f8_19; crypto_int64 f5f9_76 = f5_2 * (crypto_int64) f9_38; crypto_int64 f6f6_19 = f6 * (crypto_int64) f6_19; crypto_int64 f6f7_38 = f6 * (crypto_int64) f7_38; crypto_int64 f6f8_38 = f6_2 * (crypto_int64) f8_19; crypto_int64 f6f9_38 = f6 * (crypto_int64) f9_38; crypto_int64 f7f7_38 = f7 * (crypto_int64) f7_38; crypto_int64 f7f8_38 = f7_2 * (crypto_int64) f8_19; crypto_int64 f7f9_76 = f7_2 * (crypto_int64) f9_38; crypto_int64 f8f8_19 = f8 * (crypto_int64) f8_19; crypto_int64 f8f9_38 = f8 * (crypto_int64) f9_38; crypto_int64 f9f9_38 = f9 * (crypto_int64) f9_38; crypto_int64 h0 = f0f0 +f1f9_76+f2f8_38+f3f7_76+f4f6_38+f5f5_38; crypto_int64 h1 = f0f1_2+f2f9_38+f3f8_38+f4f7_38+f5f6_38; crypto_int64 h2 = f0f2_2+f1f1_2 +f3f9_76+f4f8_38+f5f7_76+f6f6_19; crypto_int64 h3 = f0f3_2+f1f2_2 +f4f9_38+f5f8_38+f6f7_38; crypto_int64 h4 = f0f4_2+f1f3_4 +f2f2 +f5f9_76+f6f8_38+f7f7_38; crypto_int64 h5 = f0f5_2+f1f4_2 +f2f3_2 +f6f9_38+f7f8_38; crypto_int64 h6 = f0f6_2+f1f5_4 +f2f4_2 +f3f3_2 +f7f9_76+f8f8_19; crypto_int64 h7 = f0f7_2+f1f6_2 +f2f5_2 +f3f4_2 +f8f9_38; crypto_int64 h8 = f0f8_2+f1f7_4 +f2f6_2 +f3f5_4 +f4f4 +f9f9_38; crypto_int64 h9 = f0f9_2+f1f8_2 +f2f7_2 +f3f6_2 +f4f5_2; crypto_int64 carry0; crypto_int64 carry1; crypto_int64 carry2; crypto_int64 carry3; crypto_int64 carry4; crypto_int64 carry5; crypto_int64 carry6; crypto_int64 carry7; crypto_int64 carry8; crypto_int64 carry9; h0 += h0; h1 += h1; h2 += h2; h3 += h3; h4 += h4; h5 += h5; h6 += h6; h7 += h7; h8 += h8; h9 += h9; carry0 = (h0 + (crypto_int64) (1<<25)) >> 26; h1 += carry0; h0 -= carry0 << 26; carry4 = (h4 + (crypto_int64) (1<<25)) >> 26; h5 += carry4; h4 -= carry4 << 26; carry1 = (h1 + (crypto_int64) (1<<24)) >> 25; h2 += carry1; h1 -= carry1 << 25; carry5 = (h5 + (crypto_int64) (1<<24)) >> 25; h6 += carry5; h5 -= carry5 << 25; carry2 = (h2 + (crypto_int64) (1<<25)) >> 26; h3 += carry2; h2 -= carry2 << 26; carry6 = (h6 + (crypto_int64) (1<<25)) >> 26; h7 += carry6; h6 -= carry6 << 26; carry3 = (h3 + (crypto_int64) (1<<24)) >> 25; h4 += carry3; h3 -= carry3 << 25; carry7 = (h7 + (crypto_int64) (1<<24)) >> 25; h8 += carry7; h7 -= carry7 << 25; carry4 = (h4 + (crypto_int64) (1<<25)) >> 26; h5 += carry4; h4 -= carry4 << 26; carry8 = (h8 + (crypto_int64) (1<<25)) >> 26; h9 += carry8; h8 -= carry8 << 26; carry9 = (h9 + (crypto_int64) (1<<24)) >> 25; h0 += carry9 * 19; h9 -= carry9 << 25; carry0 = (h0 + (crypto_int64) (1<<25)) >> 26; h1 += carry0; h0 -= carry0 << 26; h[0] = h0; h[1] = h1; h[2] = h2; h[3] = h3; h[4] = h4; h[5] = h5; h[6] = h6; h[7] = h7; h[8] = h8; h[9] = h9; } libsignal-protocol-c-2.3.3/src/curve25519/ed25519/fe_sub.c000066400000000000000000000023471363751346500225130ustar00rootroot00000000000000#include "fe.h" /* h = f - g Can overlap h with f or g. Preconditions: |f| bounded by 1.1*2^25,1.1*2^24,1.1*2^25,1.1*2^24,etc. |g| bounded by 1.1*2^25,1.1*2^24,1.1*2^25,1.1*2^24,etc. Postconditions: |h| bounded by 1.1*2^26,1.1*2^25,1.1*2^26,1.1*2^25,etc. */ void fe_sub(fe h,const fe f,const fe g) { crypto_int32 f0 = f[0]; crypto_int32 f1 = f[1]; crypto_int32 f2 = f[2]; crypto_int32 f3 = f[3]; crypto_int32 f4 = f[4]; crypto_int32 f5 = f[5]; crypto_int32 f6 = f[6]; crypto_int32 f7 = f[7]; crypto_int32 f8 = f[8]; crypto_int32 f9 = f[9]; crypto_int32 g0 = g[0]; crypto_int32 g1 = g[1]; crypto_int32 g2 = g[2]; crypto_int32 g3 = g[3]; crypto_int32 g4 = g[4]; crypto_int32 g5 = g[5]; crypto_int32 g6 = g[6]; crypto_int32 g7 = g[7]; crypto_int32 g8 = g[8]; crypto_int32 g9 = g[9]; crypto_int32 h0 = f0 - g0; crypto_int32 h1 = f1 - g1; crypto_int32 h2 = f2 - g2; crypto_int32 h3 = f3 - g3; crypto_int32 h4 = f4 - g4; crypto_int32 h5 = f5 - g5; crypto_int32 h6 = f6 - g6; crypto_int32 h7 = f7 - g7; crypto_int32 h8 = f8 - g8; crypto_int32 h9 = f9 - g9; h[0] = h0; h[1] = h1; h[2] = h2; h[3] = h3; h[4] = h4; h[5] = h5; h[6] = h6; h[7] = h7; h[8] = h8; h[9] = h9; } libsignal-protocol-c-2.3.3/src/curve25519/ed25519/fe_tobytes.c000066400000000000000000000061651363751346500234150ustar00rootroot00000000000000#include "fe.h" /* Preconditions: |h| bounded by 1.1*2^26,1.1*2^25,1.1*2^26,1.1*2^25,etc. Write p=2^255-19; q=floor(h/p). Basic claim: q = floor(2^(-255)(h + 19 2^(-25)h9 + 2^(-1))). Proof: Have |h|<=p so |q|<=1 so |19^2 2^(-255) q|<1/4. Also have |h-2^230 h9|<2^231 so |19 2^(-255)(h-2^230 h9)|<1/4. Write y=2^(-1)-19^2 2^(-255)q-19 2^(-255)(h-2^230 h9). Then 0> 25; q = (h0 + q) >> 26; q = (h1 + q) >> 25; q = (h2 + q) >> 26; q = (h3 + q) >> 25; q = (h4 + q) >> 26; q = (h5 + q) >> 25; q = (h6 + q) >> 26; q = (h7 + q) >> 25; q = (h8 + q) >> 26; q = (h9 + q) >> 25; /* Goal: Output h-(2^255-19)q, which is between 0 and 2^255-20. */ h0 += 19 * q; /* Goal: Output h-2^255 q, which is between 0 and 2^255-20. */ carry0 = h0 >> 26; h1 += carry0; h0 -= carry0 << 26; carry1 = h1 >> 25; h2 += carry1; h1 -= carry1 << 25; carry2 = h2 >> 26; h3 += carry2; h2 -= carry2 << 26; carry3 = h3 >> 25; h4 += carry3; h3 -= carry3 << 25; carry4 = h4 >> 26; h5 += carry4; h4 -= carry4 << 26; carry5 = h5 >> 25; h6 += carry5; h5 -= carry5 << 25; carry6 = h6 >> 26; h7 += carry6; h6 -= carry6 << 26; carry7 = h7 >> 25; h8 += carry7; h7 -= carry7 << 25; carry8 = h8 >> 26; h9 += carry8; h8 -= carry8 << 26; carry9 = h9 >> 25; h9 -= carry9 << 25; /* h10 = carry9 */ /* Goal: Output h0+...+2^255 h10-2^255 q, which is between 0 and 2^255-20. Have h0+...+2^230 h9 between 0 and 2^255-1; evidently 2^255 h10-2^255 q = 0. Goal: Output h0+...+2^230 h9. */ s[0] = h0 >> 0; s[1] = h0 >> 8; s[2] = h0 >> 16; s[3] = (h0 >> 24) | (h1 << 2); s[4] = h1 >> 6; s[5] = h1 >> 14; s[6] = (h1 >> 22) | (h2 << 3); s[7] = h2 >> 5; s[8] = h2 >> 13; s[9] = (h2 >> 21) | (h3 << 5); s[10] = h3 >> 3; s[11] = h3 >> 11; s[12] = (h3 >> 19) | (h4 << 6); s[13] = h4 >> 2; s[14] = h4 >> 10; s[15] = h4 >> 18; s[16] = h5 >> 0; s[17] = h5 >> 8; s[18] = h5 >> 16; s[19] = (h5 >> 24) | (h6 << 1); s[20] = h6 >> 7; s[21] = h6 >> 15; s[22] = (h6 >> 23) | (h7 << 3); s[23] = h7 >> 5; s[24] = h7 >> 13; s[25] = (h7 >> 21) | (h8 << 4); s[26] = h8 >> 4; s[27] = h8 >> 12; s[28] = (h8 >> 20) | (h9 << 6); s[29] = h9 >> 2; s[30] = h9 >> 10; s[31] = h9 >> 18; } libsignal-protocol-c-2.3.3/src/curve25519/ed25519/ge.h000066400000000000000000000054651363751346500216540ustar00rootroot00000000000000#ifndef GE_H #define GE_H /* ge means group element. Here the group is the set of pairs (x,y) of field elements (see fe.h) satisfying -x^2 + y^2 = 1 + d x^2y^2 where d = -121665/121666. Representations: ge_p2 (projective): (X:Y:Z) satisfying x=X/Z, y=Y/Z ge_p3 (extended): (X:Y:Z:T) satisfying x=X/Z, y=Y/Z, XY=ZT ge_p1p1 (completed): ((X:Z),(Y:T)) satisfying x=X/Z, y=Y/T ge_precomp (Duif): (y+x,y-x,2dxy) */ #include "fe.h" typedef struct { fe X; fe Y; fe Z; } ge_p2; typedef struct { fe X; fe Y; fe Z; fe T; } ge_p3; typedef struct { fe X; fe Y; fe Z; fe T; } ge_p1p1; typedef struct { fe yplusx; fe yminusx; fe xy2d; } ge_precomp; typedef struct { fe YplusX; fe YminusX; fe Z; fe T2d; } ge_cached; #define ge_frombytes_negate_vartime crypto_sign_ed25519_ref10_ge_frombytes_negate_vartime #define ge_tobytes crypto_sign_ed25519_ref10_ge_tobytes #define ge_p3_tobytes crypto_sign_ed25519_ref10_ge_p3_tobytes #define ge_p2_0 crypto_sign_ed25519_ref10_ge_p2_0 #define ge_p3_0 crypto_sign_ed25519_ref10_ge_p3_0 #define ge_precomp_0 crypto_sign_ed25519_ref10_ge_precomp_0 #define ge_p3_to_p2 crypto_sign_ed25519_ref10_ge_p3_to_p2 #define ge_p3_to_cached crypto_sign_ed25519_ref10_ge_p3_to_cached #define ge_p1p1_to_p2 crypto_sign_ed25519_ref10_ge_p1p1_to_p2 #define ge_p1p1_to_p3 crypto_sign_ed25519_ref10_ge_p1p1_to_p3 #define ge_p2_dbl crypto_sign_ed25519_ref10_ge_p2_dbl #define ge_p3_dbl crypto_sign_ed25519_ref10_ge_p3_dbl #define ge_madd crypto_sign_ed25519_ref10_ge_madd #define ge_msub crypto_sign_ed25519_ref10_ge_msub #define ge_add crypto_sign_ed25519_ref10_ge_add #define ge_sub crypto_sign_ed25519_ref10_ge_sub #define ge_scalarmult_base crypto_sign_ed25519_ref10_ge_scalarmult_base #define ge_double_scalarmult_vartime crypto_sign_ed25519_ref10_ge_double_scalarmult_vartime extern void ge_tobytes(unsigned char *,const ge_p2 *); extern void ge_p3_tobytes(unsigned char *,const ge_p3 *); extern int ge_frombytes_negate_vartime(ge_p3 *,const unsigned char *); extern void ge_p2_0(ge_p2 *); extern void ge_p3_0(ge_p3 *); extern void ge_precomp_0(ge_precomp *); extern void ge_p3_to_p2(ge_p2 *,const ge_p3 *); extern void ge_p3_to_cached(ge_cached *,const ge_p3 *); extern void ge_p1p1_to_p2(ge_p2 *,const ge_p1p1 *); extern void ge_p1p1_to_p3(ge_p3 *,const ge_p1p1 *); extern void ge_p2_dbl(ge_p1p1 *,const ge_p2 *); extern void ge_p3_dbl(ge_p1p1 *,const ge_p3 *); extern void ge_madd(ge_p1p1 *,const ge_p3 *,const ge_precomp *); extern void ge_msub(ge_p1p1 *,const ge_p3 *,const ge_precomp *); extern void ge_add(ge_p1p1 *,const ge_p3 *,const ge_cached *); extern void ge_sub(ge_p1p1 *,const ge_p3 *,const ge_cached *); extern void ge_scalarmult_base(ge_p3 *,const unsigned char *); extern void ge_double_scalarmult_vartime(ge_p2 *,const unsigned char *,const ge_p3 *,const unsigned char *); #endif libsignal-protocol-c-2.3.3/src/curve25519/ed25519/ge_add.c000066400000000000000000000001751363751346500224500ustar00rootroot00000000000000#include "ge.h" /* r = p + q */ void ge_add(ge_p1p1 *r,const ge_p3 *p,const ge_cached *q) { fe t0; #include "ge_add.h" } libsignal-protocol-c-2.3.3/src/curve25519/ed25519/ge_add.h000066400000000000000000000040401363751346500224500ustar00rootroot00000000000000 /* qhasm: enter ge_add */ /* qhasm: fe X1 */ /* qhasm: fe Y1 */ /* qhasm: fe Z1 */ /* qhasm: fe Z2 */ /* qhasm: fe T1 */ /* qhasm: fe ZZ */ /* qhasm: fe YpX2 */ /* qhasm: fe YmX2 */ /* qhasm: fe T2d2 */ /* qhasm: fe X3 */ /* qhasm: fe Y3 */ /* qhasm: fe Z3 */ /* qhasm: fe T3 */ /* qhasm: fe YpX1 */ /* qhasm: fe YmX1 */ /* qhasm: fe A */ /* qhasm: fe B */ /* qhasm: fe C */ /* qhasm: fe D */ /* qhasm: YpX1 = Y1+X1 */ /* asm 1: fe_add(>YpX1=fe#1,YpX1=r->X,Y,X); */ fe_add(r->X,p->Y,p->X); /* qhasm: YmX1 = Y1-X1 */ /* asm 1: fe_sub(>YmX1=fe#2,YmX1=r->Y,Y,X); */ fe_sub(r->Y,p->Y,p->X); /* qhasm: A = YpX1*YpX2 */ /* asm 1: fe_mul(>A=fe#3,A=r->Z,X,YplusX); */ fe_mul(r->Z,r->X,q->YplusX); /* qhasm: B = YmX1*YmX2 */ /* asm 1: fe_mul(>B=fe#2,B=r->Y,Y,YminusX); */ fe_mul(r->Y,r->Y,q->YminusX); /* qhasm: C = T2d2*T1 */ /* asm 1: fe_mul(>C=fe#4,C=r->T,T2d,T); */ fe_mul(r->T,q->T2d,p->T); /* qhasm: ZZ = Z1*Z2 */ /* asm 1: fe_mul(>ZZ=fe#1,ZZ=r->X,Z,Z); */ fe_mul(r->X,p->Z,q->Z); /* qhasm: D = 2*ZZ */ /* asm 1: fe_add(>D=fe#5,D=t0,X,X); */ fe_add(t0,r->X,r->X); /* qhasm: X3 = A-B */ /* asm 1: fe_sub(>X3=fe#1,X3=r->X,Z,Y); */ fe_sub(r->X,r->Z,r->Y); /* qhasm: Y3 = A+B */ /* asm 1: fe_add(>Y3=fe#2,Y3=r->Y,Z,Y); */ fe_add(r->Y,r->Z,r->Y); /* qhasm: Z3 = D+C */ /* asm 1: fe_add(>Z3=fe#3,Z3=r->Z,T); */ fe_add(r->Z,t0,r->T); /* qhasm: T3 = D-C */ /* asm 1: fe_sub(>T3=fe#4,T3=r->T,T); */ fe_sub(r->T,t0,r->T); /* qhasm: return */ libsignal-protocol-c-2.3.3/src/curve25519/ed25519/ge_double_scalarmult.c000066400000000000000000000045031363751346500254200ustar00rootroot00000000000000#include "ge.h" static void slide(signed char *r,const unsigned char *a) { int i; int b; int k; for (i = 0;i < 256;++i) r[i] = 1 & (a[i >> 3] >> (i & 7)); for (i = 0;i < 256;++i) if (r[i]) { for (b = 1;b <= 6 && i + b < 256;++b) { if (r[i + b]) { if (r[i] + (r[i + b] << b) <= 15) { r[i] += r[i + b] << b; r[i + b] = 0; } else if (r[i] - (r[i + b] << b) >= -15) { r[i] -= r[i + b] << b; for (k = i + b;k < 256;++k) { if (!r[k]) { r[k] = 1; break; } r[k] = 0; } } else break; } } } } static ge_precomp Bi[8] = { #include "base2.h" } ; /* r = a * A + b * B where a = a[0]+256*a[1]+...+256^31 a[31]. and b = b[0]+256*b[1]+...+256^31 b[31]. B is the Ed25519 base point (x,4/5) with x positive. */ void ge_double_scalarmult_vartime(ge_p2 *r,const unsigned char *a,const ge_p3 *A,const unsigned char *b) { signed char aslide[256]; signed char bslide[256]; ge_cached Ai[8]; /* A,3A,5A,7A,9A,11A,13A,15A */ ge_p1p1 t; ge_p3 u; ge_p3 A2; int i; slide(aslide,a); slide(bslide,b); ge_p3_to_cached(&Ai[0],A); ge_p3_dbl(&t,A); ge_p1p1_to_p3(&A2,&t); ge_add(&t,&A2,&Ai[0]); ge_p1p1_to_p3(&u,&t); ge_p3_to_cached(&Ai[1],&u); ge_add(&t,&A2,&Ai[1]); ge_p1p1_to_p3(&u,&t); ge_p3_to_cached(&Ai[2],&u); ge_add(&t,&A2,&Ai[2]); ge_p1p1_to_p3(&u,&t); ge_p3_to_cached(&Ai[3],&u); ge_add(&t,&A2,&Ai[3]); ge_p1p1_to_p3(&u,&t); ge_p3_to_cached(&Ai[4],&u); ge_add(&t,&A2,&Ai[4]); ge_p1p1_to_p3(&u,&t); ge_p3_to_cached(&Ai[5],&u); ge_add(&t,&A2,&Ai[5]); ge_p1p1_to_p3(&u,&t); ge_p3_to_cached(&Ai[6],&u); ge_add(&t,&A2,&Ai[6]); ge_p1p1_to_p3(&u,&t); ge_p3_to_cached(&Ai[7],&u); ge_p2_0(r); for (i = 255;i >= 0;--i) { if (aslide[i] || bslide[i]) break; } for (;i >= 0;--i) { ge_p2_dbl(&t,r); if (aslide[i] > 0) { ge_p1p1_to_p3(&u,&t); ge_add(&t,&u,&Ai[aslide[i]/2]); } else if (aslide[i] < 0) { ge_p1p1_to_p3(&u,&t); ge_sub(&t,&u,&Ai[(-aslide[i])/2]); } if (bslide[i] > 0) { ge_p1p1_to_p3(&u,&t); ge_madd(&t,&u,&Bi[bslide[i]/2]); } else if (bslide[i] < 0) { ge_p1p1_to_p3(&u,&t); ge_msub(&t,&u,&Bi[(-bslide[i])/2]); } ge_p1p1_to_p2(r,&t); } } libsignal-protocol-c-2.3.3/src/curve25519/ed25519/ge_frombytes.c000066400000000000000000000017331363751346500237330ustar00rootroot00000000000000#include "ge.h" static const fe d = { #include "d.h" } ; static const fe sqrtm1 = { #include "sqrtm1.h" } ; int ge_frombytes_negate_vartime(ge_p3 *h,const unsigned char *s) { fe u; fe v; fe v3; fe vxx; fe check; fe_frombytes(h->Y,s); fe_1(h->Z); fe_sq(u,h->Y); fe_mul(v,u,d); fe_sub(u,u,h->Z); /* u = y^2-1 */ fe_add(v,v,h->Z); /* v = dy^2+1 */ fe_sq(v3,v); fe_mul(v3,v3,v); /* v3 = v^3 */ fe_sq(h->X,v3); fe_mul(h->X,h->X,v); fe_mul(h->X,h->X,u); /* x = uv^7 */ fe_pow22523(h->X,h->X); /* x = (uv^7)^((q-5)/8) */ fe_mul(h->X,h->X,v3); fe_mul(h->X,h->X,u); /* x = uv^3(uv^7)^((q-5)/8) */ fe_sq(vxx,h->X); fe_mul(vxx,vxx,v); fe_sub(check,vxx,u); /* vx^2-u */ if (fe_isnonzero(check)) { fe_add(check,vxx,u); /* vx^2+u */ if (fe_isnonzero(check)) return -1; fe_mul(h->X,h->X,sqrtm1); } if (fe_isnegative(h->X) == (s[31] >> 7)) fe_neg(h->X,h->X); fe_mul(h->T,h->X,h->Y); return 0; } libsignal-protocol-c-2.3.3/src/curve25519/ed25519/ge_madd.c000066400000000000000000000002001363751346500226120ustar00rootroot00000000000000#include "ge.h" /* r = p + q */ void ge_madd(ge_p1p1 *r,const ge_p3 *p,const ge_precomp *q) { fe t0; #include "ge_madd.h" } libsignal-protocol-c-2.3.3/src/curve25519/ed25519/ge_madd.h000066400000000000000000000035541363751346500226360ustar00rootroot00000000000000 /* qhasm: enter ge_madd */ /* qhasm: fe X1 */ /* qhasm: fe Y1 */ /* qhasm: fe Z1 */ /* qhasm: fe T1 */ /* qhasm: fe ypx2 */ /* qhasm: fe ymx2 */ /* qhasm: fe xy2d2 */ /* qhasm: fe X3 */ /* qhasm: fe Y3 */ /* qhasm: fe Z3 */ /* qhasm: fe T3 */ /* qhasm: fe YpX1 */ /* qhasm: fe YmX1 */ /* qhasm: fe A */ /* qhasm: fe B */ /* qhasm: fe C */ /* qhasm: fe D */ /* qhasm: YpX1 = Y1+X1 */ /* asm 1: fe_add(>YpX1=fe#1,YpX1=r->X,Y,X); */ fe_add(r->X,p->Y,p->X); /* qhasm: YmX1 = Y1-X1 */ /* asm 1: fe_sub(>YmX1=fe#2,YmX1=r->Y,Y,X); */ fe_sub(r->Y,p->Y,p->X); /* qhasm: A = YpX1*ypx2 */ /* asm 1: fe_mul(>A=fe#3,A=r->Z,X,yplusx); */ fe_mul(r->Z,r->X,q->yplusx); /* qhasm: B = YmX1*ymx2 */ /* asm 1: fe_mul(>B=fe#2,B=r->Y,Y,yminusx); */ fe_mul(r->Y,r->Y,q->yminusx); /* qhasm: C = xy2d2*T1 */ /* asm 1: fe_mul(>C=fe#4,C=r->T,xy2d,T); */ fe_mul(r->T,q->xy2d,p->T); /* qhasm: D = 2*Z1 */ /* asm 1: fe_add(>D=fe#5,D=t0,Z,Z); */ fe_add(t0,p->Z,p->Z); /* qhasm: X3 = A-B */ /* asm 1: fe_sub(>X3=fe#1,X3=r->X,Z,Y); */ fe_sub(r->X,r->Z,r->Y); /* qhasm: Y3 = A+B */ /* asm 1: fe_add(>Y3=fe#2,Y3=r->Y,Z,Y); */ fe_add(r->Y,r->Z,r->Y); /* qhasm: Z3 = D+C */ /* asm 1: fe_add(>Z3=fe#3,Z3=r->Z,T); */ fe_add(r->Z,t0,r->T); /* qhasm: T3 = D-C */ /* asm 1: fe_sub(>T3=fe#4,T3=r->T,T); */ fe_sub(r->T,t0,r->T); /* qhasm: return */ libsignal-protocol-c-2.3.3/src/curve25519/ed25519/ge_msub.c000066400000000000000000000002001363751346500226530ustar00rootroot00000000000000#include "ge.h" /* r = p - q */ void ge_msub(ge_p1p1 *r,const ge_p3 *p,const ge_precomp *q) { fe t0; #include "ge_msub.h" } libsignal-protocol-c-2.3.3/src/curve25519/ed25519/ge_msub.h000066400000000000000000000035541363751346500226770ustar00rootroot00000000000000 /* qhasm: enter ge_msub */ /* qhasm: fe X1 */ /* qhasm: fe Y1 */ /* qhasm: fe Z1 */ /* qhasm: fe T1 */ /* qhasm: fe ypx2 */ /* qhasm: fe ymx2 */ /* qhasm: fe xy2d2 */ /* qhasm: fe X3 */ /* qhasm: fe Y3 */ /* qhasm: fe Z3 */ /* qhasm: fe T3 */ /* qhasm: fe YpX1 */ /* qhasm: fe YmX1 */ /* qhasm: fe A */ /* qhasm: fe B */ /* qhasm: fe C */ /* qhasm: fe D */ /* qhasm: YpX1 = Y1+X1 */ /* asm 1: fe_add(>YpX1=fe#1,YpX1=r->X,Y,X); */ fe_add(r->X,p->Y,p->X); /* qhasm: YmX1 = Y1-X1 */ /* asm 1: fe_sub(>YmX1=fe#2,YmX1=r->Y,Y,X); */ fe_sub(r->Y,p->Y,p->X); /* qhasm: A = YpX1*ymx2 */ /* asm 1: fe_mul(>A=fe#3,A=r->Z,X,yminusx); */ fe_mul(r->Z,r->X,q->yminusx); /* qhasm: B = YmX1*ypx2 */ /* asm 1: fe_mul(>B=fe#2,B=r->Y,Y,yplusx); */ fe_mul(r->Y,r->Y,q->yplusx); /* qhasm: C = xy2d2*T1 */ /* asm 1: fe_mul(>C=fe#4,C=r->T,xy2d,T); */ fe_mul(r->T,q->xy2d,p->T); /* qhasm: D = 2*Z1 */ /* asm 1: fe_add(>D=fe#5,D=t0,Z,Z); */ fe_add(t0,p->Z,p->Z); /* qhasm: X3 = A-B */ /* asm 1: fe_sub(>X3=fe#1,X3=r->X,Z,Y); */ fe_sub(r->X,r->Z,r->Y); /* qhasm: Y3 = A+B */ /* asm 1: fe_add(>Y3=fe#2,Y3=r->Y,Z,Y); */ fe_add(r->Y,r->Z,r->Y); /* qhasm: Z3 = D-C */ /* asm 1: fe_sub(>Z3=fe#3,Z3=r->Z,T); */ fe_sub(r->Z,t0,r->T); /* qhasm: T3 = D+C */ /* asm 1: fe_add(>T3=fe#4,T3=r->T,T); */ fe_add(r->T,t0,r->T); /* qhasm: return */ libsignal-protocol-c-2.3.3/src/curve25519/ed25519/ge_p1p1_to_p2.c000066400000000000000000000002451363751346500236020ustar00rootroot00000000000000#include "ge.h" /* r = p */ extern void ge_p1p1_to_p2(ge_p2 *r,const ge_p1p1 *p) { fe_mul(r->X,p->X,p->T); fe_mul(r->Y,p->Y,p->Z); fe_mul(r->Z,p->Z,p->T); } libsignal-protocol-c-2.3.3/src/curve25519/ed25519/ge_p1p1_to_p3.c000066400000000000000000000002771363751346500236100ustar00rootroot00000000000000#include "ge.h" /* r = p */ extern void ge_p1p1_to_p3(ge_p3 *r,const ge_p1p1 *p) { fe_mul(r->X,p->X,p->T); fe_mul(r->Y,p->Y,p->Z); fe_mul(r->Z,p->Z,p->T); fe_mul(r->T,p->X,p->Y); } libsignal-protocol-c-2.3.3/src/curve25519/ed25519/ge_p2_0.c000066400000000000000000000001261363751346500224540ustar00rootroot00000000000000#include "ge.h" void ge_p2_0(ge_p2 *h) { fe_0(h->X); fe_1(h->Y); fe_1(h->Z); } libsignal-protocol-c-2.3.3/src/curve25519/ed25519/ge_p2_dbl.c000066400000000000000000000001601363751346500230540ustar00rootroot00000000000000#include "ge.h" /* r = 2 * p */ void ge_p2_dbl(ge_p1p1 *r,const ge_p2 *p) { fe t0; #include "ge_p2_dbl.h" } libsignal-protocol-c-2.3.3/src/curve25519/ed25519/ge_p2_dbl.h000066400000000000000000000027041363751346500230670ustar00rootroot00000000000000 /* qhasm: enter ge_p2_dbl */ /* qhasm: fe X1 */ /* qhasm: fe Y1 */ /* qhasm: fe Z1 */ /* qhasm: fe A */ /* qhasm: fe AA */ /* qhasm: fe XX */ /* qhasm: fe YY */ /* qhasm: fe B */ /* qhasm: fe X3 */ /* qhasm: fe Y3 */ /* qhasm: fe Z3 */ /* qhasm: fe T3 */ /* qhasm: XX=X1^2 */ /* asm 1: fe_sq(>XX=fe#1,XX=r->X,X); */ fe_sq(r->X,p->X); /* qhasm: YY=Y1^2 */ /* asm 1: fe_sq(>YY=fe#3,YY=r->Z,Y); */ fe_sq(r->Z,p->Y); /* qhasm: B=2*Z1^2 */ /* asm 1: fe_sq2(>B=fe#4,B=r->T,Z); */ fe_sq2(r->T,p->Z); /* qhasm: A=X1+Y1 */ /* asm 1: fe_add(>A=fe#2,A=r->Y,X,Y); */ fe_add(r->Y,p->X,p->Y); /* qhasm: AA=A^2 */ /* asm 1: fe_sq(>AA=fe#5,AA=t0,Y); */ fe_sq(t0,r->Y); /* qhasm: Y3=YY+XX */ /* asm 1: fe_add(>Y3=fe#2,Y3=r->Y,Z,X); */ fe_add(r->Y,r->Z,r->X); /* qhasm: Z3=YY-XX */ /* asm 1: fe_sub(>Z3=fe#3,Z3=r->Z,Z,X); */ fe_sub(r->Z,r->Z,r->X); /* qhasm: X3=AA-Y3 */ /* asm 1: fe_sub(>X3=fe#1,X3=r->X,Y); */ fe_sub(r->X,t0,r->Y); /* qhasm: T3=B-Z3 */ /* asm 1: fe_sub(>T3=fe#4,T3=r->T,T,Z); */ fe_sub(r->T,r->T,r->Z); /* qhasm: return */ libsignal-protocol-c-2.3.3/src/curve25519/ed25519/ge_p3_0.c000066400000000000000000000001441363751346500224550ustar00rootroot00000000000000#include "ge.h" void ge_p3_0(ge_p3 *h) { fe_0(h->X); fe_1(h->Y); fe_1(h->Z); fe_0(h->T); } libsignal-protocol-c-2.3.3/src/curve25519/ed25519/ge_p3_dbl.c000066400000000000000000000002031363751346500230530ustar00rootroot00000000000000#include "ge.h" /* r = 2 * p */ void ge_p3_dbl(ge_p1p1 *r,const ge_p3 *p) { ge_p2 q; ge_p3_to_p2(&q,p); ge_p2_dbl(r,&q); } libsignal-protocol-c-2.3.3/src/curve25519/ed25519/ge_p3_to_cached.c000066400000000000000000000003661363751346500242350ustar00rootroot00000000000000#include "ge.h" /* r = p */ static const fe d2 = { #include "d2.h" } ; extern void ge_p3_to_cached(ge_cached *r,const ge_p3 *p) { fe_add(r->YplusX,p->Y,p->X); fe_sub(r->YminusX,p->Y,p->X); fe_copy(r->Z,p->Z); fe_mul(r->T2d,p->T,d2); } libsignal-protocol-c-2.3.3/src/curve25519/ed25519/ge_p3_to_p2.c000066400000000000000000000002251363751346500233410ustar00rootroot00000000000000#include "ge.h" /* r = p */ extern void ge_p3_to_p2(ge_p2 *r,const ge_p3 *p) { fe_copy(r->X,p->X); fe_copy(r->Y,p->Y); fe_copy(r->Z,p->Z); } libsignal-protocol-c-2.3.3/src/curve25519/ed25519/ge_p3_tobytes.c000066400000000000000000000003441363751346500240110ustar00rootroot00000000000000#include "ge.h" void ge_p3_tobytes(unsigned char *s,const ge_p3 *h) { fe recip; fe x; fe y; fe_invert(recip,h->Z); fe_mul(x,h->X,recip); fe_mul(y,h->Y,recip); fe_tobytes(s,y); s[31] ^= fe_isnegative(x) << 7; } libsignal-protocol-c-2.3.3/src/curve25519/ed25519/ge_precomp_0.c000066400000000000000000000001561363751346500236030ustar00rootroot00000000000000#include "ge.h" void ge_precomp_0(ge_precomp *h) { fe_1(h->yplusx); fe_1(h->yminusx); fe_0(h->xy2d); } libsignal-protocol-c-2.3.3/src/curve25519/ed25519/ge_scalarmult_base.c000066400000000000000000000046551363751346500250700ustar00rootroot00000000000000#include "ge.h" #include "crypto_uint32.h" static unsigned char equal(signed char b,signed char c) { unsigned char ub = b; unsigned char uc = c; unsigned char x = ub ^ uc; /* 0: yes; 1..255: no */ crypto_uint32 y = x; /* 0: yes; 1..255: no */ y -= 1; /* 4294967295: yes; 0..254: no */ y >>= 31; /* 1: yes; 0: no */ return y; } static unsigned char negative(signed char b) { unsigned long long x = b; /* 18446744073709551361..18446744073709551615: yes; 0..255: no */ x >>= 63; /* 1: yes; 0: no */ return x; } static void cmov(ge_precomp *t,ge_precomp *u,unsigned char b) { fe_cmov(t->yplusx,u->yplusx,b); fe_cmov(t->yminusx,u->yminusx,b); fe_cmov(t->xy2d,u->xy2d,b); } /* base[i][j] = (j+1)*256^i*B */ static ge_precomp base[32][8] = { #include "base.h" } ; static void select(ge_precomp *t,int pos,signed char b) { ge_precomp minust; unsigned char bnegative = negative(b); unsigned char babs = b - (((-bnegative) & b) << 1); ge_precomp_0(t); cmov(t,&base[pos][0],equal(babs,1)); cmov(t,&base[pos][1],equal(babs,2)); cmov(t,&base[pos][2],equal(babs,3)); cmov(t,&base[pos][3],equal(babs,4)); cmov(t,&base[pos][4],equal(babs,5)); cmov(t,&base[pos][5],equal(babs,6)); cmov(t,&base[pos][6],equal(babs,7)); cmov(t,&base[pos][7],equal(babs,8)); fe_copy(minust.yplusx,t->yminusx); fe_copy(minust.yminusx,t->yplusx); fe_neg(minust.xy2d,t->xy2d); cmov(t,&minust,bnegative); } /* h = a * B where a = a[0]+256*a[1]+...+256^31 a[31] B is the Ed25519 base point (x,4/5) with x positive. Preconditions: a[31] <= 127 */ void ge_scalarmult_base(ge_p3 *h,const unsigned char *a) { signed char e[64]; signed char carry; ge_p1p1 r; ge_p2 s; ge_precomp t; int i; for (i = 0;i < 32;++i) { e[2 * i + 0] = (a[i] >> 0) & 15; e[2 * i + 1] = (a[i] >> 4) & 15; } /* each e[i] is between 0 and 15 */ /* e[63] is between 0 and 7 */ carry = 0; for (i = 0;i < 63;++i) { e[i] += carry; carry = e[i] + 8; carry >>= 4; e[i] -= carry << 4; } e[63] += carry; /* each e[i] is between -8 and 8 */ ge_p3_0(h); for (i = 1;i < 64;i += 2) { select(&t,i / 2,e[i]); ge_madd(&r,h,&t); ge_p1p1_to_p3(h,&r); } ge_p3_dbl(&r,h); ge_p1p1_to_p2(&s,&r); ge_p2_dbl(&r,&s); ge_p1p1_to_p2(&s,&r); ge_p2_dbl(&r,&s); ge_p1p1_to_p2(&s,&r); ge_p2_dbl(&r,&s); ge_p1p1_to_p3(h,&r); for (i = 0;i < 64;i += 2) { select(&t,i / 2,e[i]); ge_madd(&r,h,&t); ge_p1p1_to_p3(h,&r); } } libsignal-protocol-c-2.3.3/src/curve25519/ed25519/ge_sub.c000066400000000000000000000001751363751346500225110ustar00rootroot00000000000000#include "ge.h" /* r = p - q */ void ge_sub(ge_p1p1 *r,const ge_p3 *p,const ge_cached *q) { fe t0; #include "ge_sub.h" } libsignal-protocol-c-2.3.3/src/curve25519/ed25519/ge_sub.h000066400000000000000000000040401363751346500225110ustar00rootroot00000000000000 /* qhasm: enter ge_sub */ /* qhasm: fe X1 */ /* qhasm: fe Y1 */ /* qhasm: fe Z1 */ /* qhasm: fe Z2 */ /* qhasm: fe T1 */ /* qhasm: fe ZZ */ /* qhasm: fe YpX2 */ /* qhasm: fe YmX2 */ /* qhasm: fe T2d2 */ /* qhasm: fe X3 */ /* qhasm: fe Y3 */ /* qhasm: fe Z3 */ /* qhasm: fe T3 */ /* qhasm: fe YpX1 */ /* qhasm: fe YmX1 */ /* qhasm: fe A */ /* qhasm: fe B */ /* qhasm: fe C */ /* qhasm: fe D */ /* qhasm: YpX1 = Y1+X1 */ /* asm 1: fe_add(>YpX1=fe#1,YpX1=r->X,Y,X); */ fe_add(r->X,p->Y,p->X); /* qhasm: YmX1 = Y1-X1 */ /* asm 1: fe_sub(>YmX1=fe#2,YmX1=r->Y,Y,X); */ fe_sub(r->Y,p->Y,p->X); /* qhasm: A = YpX1*YmX2 */ /* asm 1: fe_mul(>A=fe#3,A=r->Z,X,YminusX); */ fe_mul(r->Z,r->X,q->YminusX); /* qhasm: B = YmX1*YpX2 */ /* asm 1: fe_mul(>B=fe#2,B=r->Y,Y,YplusX); */ fe_mul(r->Y,r->Y,q->YplusX); /* qhasm: C = T2d2*T1 */ /* asm 1: fe_mul(>C=fe#4,C=r->T,T2d,T); */ fe_mul(r->T,q->T2d,p->T); /* qhasm: ZZ = Z1*Z2 */ /* asm 1: fe_mul(>ZZ=fe#1,ZZ=r->X,Z,Z); */ fe_mul(r->X,p->Z,q->Z); /* qhasm: D = 2*ZZ */ /* asm 1: fe_add(>D=fe#5,D=t0,X,X); */ fe_add(t0,r->X,r->X); /* qhasm: X3 = A-B */ /* asm 1: fe_sub(>X3=fe#1,X3=r->X,Z,Y); */ fe_sub(r->X,r->Z,r->Y); /* qhasm: Y3 = A+B */ /* asm 1: fe_add(>Y3=fe#2,Y3=r->Y,Z,Y); */ fe_add(r->Y,r->Z,r->Y); /* qhasm: Z3 = D-C */ /* asm 1: fe_sub(>Z3=fe#3,Z3=r->Z,T); */ fe_sub(r->Z,t0,r->T); /* qhasm: T3 = D+C */ /* asm 1: fe_add(>T3=fe#4,T3=r->T,T); */ fe_add(r->T,t0,r->T); /* qhasm: return */ libsignal-protocol-c-2.3.3/src/curve25519/ed25519/ge_tobytes.c000066400000000000000000000003411363751346500234040ustar00rootroot00000000000000#include "ge.h" void ge_tobytes(unsigned char *s,const ge_p2 *h) { fe recip; fe x; fe y; fe_invert(recip,h->Z); fe_mul(x,h->X,recip); fe_mul(y,h->Y,recip); fe_tobytes(s,y); s[31] ^= fe_isnegative(x) << 7; } libsignal-protocol-c-2.3.3/src/curve25519/ed25519/nacl_includes/000077500000000000000000000000001363751346500237015ustar00rootroot00000000000000libsignal-protocol-c-2.3.3/src/curve25519/ed25519/nacl_includes/crypto_int32.h000066400000000000000000000001211363751346500264030ustar00rootroot00000000000000#ifndef crypto_int32_h #define crypto_int32_h typedef int crypto_int32; #endif libsignal-protocol-c-2.3.3/src/curve25519/ed25519/nacl_includes/crypto_int64.h000066400000000000000000000001271363751346500264160ustar00rootroot00000000000000#ifndef crypto_int64_h #define crypto_int64_h typedef long long crypto_int64; #endif libsignal-protocol-c-2.3.3/src/curve25519/ed25519/nacl_includes/crypto_sign.h000066400000000000000000000013571363751346500264200ustar00rootroot00000000000000#ifndef crypto_sign_H #define crypto_sign_H #include "crypto_sign_edwards25519sha512batch.h" #define crypto_sign crypto_sign_edwards25519sha512batch #define crypto_sign_open crypto_sign_edwards25519sha512batch_open #define crypto_sign_keypair crypto_sign_edwards25519sha512batch_keypair #define crypto_sign_BYTES crypto_sign_edwards25519sha512batch_BYTES #define crypto_sign_PUBLICKEYBYTES crypto_sign_edwards25519sha512batch_PUBLICKEYBYTES #define crypto_sign_SECRETKEYBYTES crypto_sign_edwards25519sha512batch_SECRETKEYBYTES #define crypto_sign_PRIMITIVE "edwards25519sha512batch" #define crypto_sign_IMPLEMENTATION crypto_sign_edwards25519sha512batch_IMPLEMENTATION #define crypto_sign_VERSION crypto_sign_edwards25519sha512batch_VERSION #endif crypto_sign_edwards25519sha512batch.h000066400000000000000000000037621363751346500324100ustar00rootroot00000000000000libsignal-protocol-c-2.3.3/src/curve25519/ed25519/nacl_includes#ifndef crypto_sign_edwards25519sha512batch_H #define crypto_sign_edwards25519sha512batch_H #define crypto_sign_edwards25519sha512batch_ref10_SECRETKEYBYTES 64 #define crypto_sign_edwards25519sha512batch_ref10_PUBLICKEYBYTES 32 #define crypto_sign_edwards25519sha512batch_ref10_BYTES 64 #ifdef __cplusplus #include extern std::string crypto_sign_edwards25519sha512batch_ref10(const std::string &,const std::string &); extern std::string crypto_sign_edwards25519sha512batch_ref10_open(const std::string &,const std::string &); extern std::string crypto_sign_edwards25519sha512batch_ref10_keypair(std::string *); extern "C" { #endif extern int crypto_sign_edwards25519sha512batch_ref10(unsigned char *,unsigned long long *,const unsigned char *,unsigned long long,const unsigned char *); extern int crypto_sign_edwards25519sha512batch_ref10_open(unsigned char *,unsigned long long *,const unsigned char *,unsigned long long,const unsigned char *); extern int crypto_sign_edwards25519sha512batch_ref10_keypair(unsigned char *,unsigned char *); #ifdef __cplusplus } #endif #define crypto_sign_edwards25519sha512batch crypto_sign_edwards25519sha512batch_ref10 #define crypto_sign_edwards25519sha512batch_open crypto_sign_edwards25519sha512batch_ref10_open #define crypto_sign_edwards25519sha512batch_keypair crypto_sign_edwards25519sha512batch_ref10_keypair #define crypto_sign_edwards25519sha512batch_BYTES crypto_sign_edwards25519sha512batch_ref10_BYTES #define crypto_sign_edwards25519sha512batch_PUBLICKEYBYTES crypto_sign_edwards25519sha512batch_ref10_PUBLICKEYBYTES #define crypto_sign_edwards25519sha512batch_SECRETKEYBYTES crypto_sign_edwards25519sha512batch_ref10_SECRETKEYBYTES #define crypto_sign_edwards25519sha512batch_IMPLEMENTATION "crypto_sign/edwards25519sha512batch/ref10" #ifndef crypto_sign_edwards25519sha512batch_ref10_VERSION #define crypto_sign_edwards25519sha512batch_ref10_VERSION "-" #endif #define crypto_sign_edwards25519sha512batch_VERSION crypto_sign_edwards25519sha512batch_ref10_VERSION #endif libsignal-protocol-c-2.3.3/src/curve25519/ed25519/nacl_includes/crypto_uint32.h000066400000000000000000000001351363751346500265750ustar00rootroot00000000000000#ifndef crypto_uint32_h #define crypto_uint32_h typedef unsigned int crypto_uint32; #endif libsignal-protocol-c-2.3.3/src/curve25519/ed25519/nacl_includes/crypto_uint64.h000066400000000000000000000001431363751346500266010ustar00rootroot00000000000000#ifndef crypto_uint64_h #define crypto_uint64_h typedef unsigned long long crypto_uint64; #endif libsignal-protocol-c-2.3.3/src/curve25519/ed25519/nacl_includes/crypto_verify_32.h000066400000000000000000000011031363751346500272550ustar00rootroot00000000000000#ifndef crypto_verify_32_H #define crypto_verify_32_H #define crypto_verify_32_ref_BYTES 32 #ifdef __cplusplus #include extern "C" { #endif extern int crypto_verify_32_ref(const unsigned char *,const unsigned char *); #ifdef __cplusplus } #endif #define crypto_verify_32 crypto_verify_32_ref #define crypto_verify_32_BYTES crypto_verify_32_ref_BYTES #define crypto_verify_32_IMPLEMENTATION "crypto_verify/32/ref" #ifndef crypto_verify_32_ref_VERSION #define crypto_verify_32_ref_VERSION "-" #endif #define crypto_verify_32_VERSION crypto_verify_32_ref_VERSION #endif libsignal-protocol-c-2.3.3/src/curve25519/ed25519/nacl_sha512/000077500000000000000000000000001363751346500230765ustar00rootroot00000000000000libsignal-protocol-c-2.3.3/src/curve25519/ed25519/nacl_sha512/blocks.c000066400000000000000000000144201363751346500245200ustar00rootroot00000000000000#include typedef uint64_t uint64; static uint64 load_bigendian(const unsigned char *x) { return (uint64) (x[7]) \ | (((uint64) (x[6])) << 8) \ | (((uint64) (x[5])) << 16) \ | (((uint64) (x[4])) << 24) \ | (((uint64) (x[3])) << 32) \ | (((uint64) (x[2])) << 40) \ | (((uint64) (x[1])) << 48) \ | (((uint64) (x[0])) << 56) ; } static void store_bigendian(unsigned char *x,uint64 u) { x[7] = u; u >>= 8; x[6] = u; u >>= 8; x[5] = u; u >>= 8; x[4] = u; u >>= 8; x[3] = u; u >>= 8; x[2] = u; u >>= 8; x[1] = u; u >>= 8; x[0] = u; } #define SHR(x,c) ((x) >> (c)) #define ROTR(x,c) (((x) >> (c)) | ((x) << (64 - (c)))) #define Ch(x,y,z) ((x & y) ^ (~x & z)) #define Maj(x,y,z) ((x & y) ^ (x & z) ^ (y & z)) #define Sigma0(x) (ROTR(x,28) ^ ROTR(x,34) ^ ROTR(x,39)) #define Sigma1(x) (ROTR(x,14) ^ ROTR(x,18) ^ ROTR(x,41)) #define sigma0(x) (ROTR(x, 1) ^ ROTR(x, 8) ^ SHR(x,7)) #define sigma1(x) (ROTR(x,19) ^ ROTR(x,61) ^ SHR(x,6)) #define M(w0,w14,w9,w1) w0 = sigma1(w14) + w9 + sigma0(w1) + w0; #define EXPAND \ M(w0 ,w14,w9 ,w1 ) \ M(w1 ,w15,w10,w2 ) \ M(w2 ,w0 ,w11,w3 ) \ M(w3 ,w1 ,w12,w4 ) \ M(w4 ,w2 ,w13,w5 ) \ M(w5 ,w3 ,w14,w6 ) \ M(w6 ,w4 ,w15,w7 ) \ M(w7 ,w5 ,w0 ,w8 ) \ M(w8 ,w6 ,w1 ,w9 ) \ M(w9 ,w7 ,w2 ,w10) \ M(w10,w8 ,w3 ,w11) \ M(w11,w9 ,w4 ,w12) \ M(w12,w10,w5 ,w13) \ M(w13,w11,w6 ,w14) \ M(w14,w12,w7 ,w15) \ M(w15,w13,w8 ,w0 ) #define F(w,k) \ T1 = h + Sigma1(e) + Ch(e,f,g) + k + w; \ T2 = Sigma0(a) + Maj(a,b,c); \ h = g; \ g = f; \ f = e; \ e = d + T1; \ d = c; \ c = b; \ b = a; \ a = T1 + T2; int crypto_hashblocks_sha512(unsigned char *statebytes,const unsigned char *in,unsigned long long inlen) { uint64 state[8]; uint64 a; uint64 b; uint64 c; uint64 d; uint64 e; uint64 f; uint64 g; uint64 h; uint64 T1; uint64 T2; a = load_bigendian(statebytes + 0); state[0] = a; b = load_bigendian(statebytes + 8); state[1] = b; c = load_bigendian(statebytes + 16); state[2] = c; d = load_bigendian(statebytes + 24); state[3] = d; e = load_bigendian(statebytes + 32); state[4] = e; f = load_bigendian(statebytes + 40); state[5] = f; g = load_bigendian(statebytes + 48); state[6] = g; h = load_bigendian(statebytes + 56); state[7] = h; while (inlen >= 128) { uint64 w0 = load_bigendian(in + 0); uint64 w1 = load_bigendian(in + 8); uint64 w2 = load_bigendian(in + 16); uint64 w3 = load_bigendian(in + 24); uint64 w4 = load_bigendian(in + 32); uint64 w5 = load_bigendian(in + 40); uint64 w6 = load_bigendian(in + 48); uint64 w7 = load_bigendian(in + 56); uint64 w8 = load_bigendian(in + 64); uint64 w9 = load_bigendian(in + 72); uint64 w10 = load_bigendian(in + 80); uint64 w11 = load_bigendian(in + 88); uint64 w12 = load_bigendian(in + 96); uint64 w13 = load_bigendian(in + 104); uint64 w14 = load_bigendian(in + 112); uint64 w15 = load_bigendian(in + 120); F(w0 ,0x428a2f98d728ae22ULL) F(w1 ,0x7137449123ef65cdULL) F(w2 ,0xb5c0fbcfec4d3b2fULL) F(w3 ,0xe9b5dba58189dbbcULL) F(w4 ,0x3956c25bf348b538ULL) F(w5 ,0x59f111f1b605d019ULL) F(w6 ,0x923f82a4af194f9bULL) F(w7 ,0xab1c5ed5da6d8118ULL) F(w8 ,0xd807aa98a3030242ULL) F(w9 ,0x12835b0145706fbeULL) F(w10,0x243185be4ee4b28cULL) F(w11,0x550c7dc3d5ffb4e2ULL) F(w12,0x72be5d74f27b896fULL) F(w13,0x80deb1fe3b1696b1ULL) F(w14,0x9bdc06a725c71235ULL) F(w15,0xc19bf174cf692694ULL) EXPAND F(w0 ,0xe49b69c19ef14ad2ULL) F(w1 ,0xefbe4786384f25e3ULL) F(w2 ,0x0fc19dc68b8cd5b5ULL) F(w3 ,0x240ca1cc77ac9c65ULL) F(w4 ,0x2de92c6f592b0275ULL) F(w5 ,0x4a7484aa6ea6e483ULL) F(w6 ,0x5cb0a9dcbd41fbd4ULL) F(w7 ,0x76f988da831153b5ULL) F(w8 ,0x983e5152ee66dfabULL) F(w9 ,0xa831c66d2db43210ULL) F(w10,0xb00327c898fb213fULL) F(w11,0xbf597fc7beef0ee4ULL) F(w12,0xc6e00bf33da88fc2ULL) F(w13,0xd5a79147930aa725ULL) F(w14,0x06ca6351e003826fULL) F(w15,0x142929670a0e6e70ULL) EXPAND F(w0 ,0x27b70a8546d22ffcULL) F(w1 ,0x2e1b21385c26c926ULL) F(w2 ,0x4d2c6dfc5ac42aedULL) F(w3 ,0x53380d139d95b3dfULL) F(w4 ,0x650a73548baf63deULL) F(w5 ,0x766a0abb3c77b2a8ULL) F(w6 ,0x81c2c92e47edaee6ULL) F(w7 ,0x92722c851482353bULL) F(w8 ,0xa2bfe8a14cf10364ULL) F(w9 ,0xa81a664bbc423001ULL) F(w10,0xc24b8b70d0f89791ULL) F(w11,0xc76c51a30654be30ULL) F(w12,0xd192e819d6ef5218ULL) F(w13,0xd69906245565a910ULL) F(w14,0xf40e35855771202aULL) F(w15,0x106aa07032bbd1b8ULL) EXPAND F(w0 ,0x19a4c116b8d2d0c8ULL) F(w1 ,0x1e376c085141ab53ULL) F(w2 ,0x2748774cdf8eeb99ULL) F(w3 ,0x34b0bcb5e19b48a8ULL) F(w4 ,0x391c0cb3c5c95a63ULL) F(w5 ,0x4ed8aa4ae3418acbULL) F(w6 ,0x5b9cca4f7763e373ULL) F(w7 ,0x682e6ff3d6b2b8a3ULL) F(w8 ,0x748f82ee5defb2fcULL) F(w9 ,0x78a5636f43172f60ULL) F(w10,0x84c87814a1f0ab72ULL) F(w11,0x8cc702081a6439ecULL) F(w12,0x90befffa23631e28ULL) F(w13,0xa4506cebde82bde9ULL) F(w14,0xbef9a3f7b2c67915ULL) F(w15,0xc67178f2e372532bULL) EXPAND F(w0 ,0xca273eceea26619cULL) F(w1 ,0xd186b8c721c0c207ULL) F(w2 ,0xeada7dd6cde0eb1eULL) F(w3 ,0xf57d4f7fee6ed178ULL) F(w4 ,0x06f067aa72176fbaULL) F(w5 ,0x0a637dc5a2c898a6ULL) F(w6 ,0x113f9804bef90daeULL) F(w7 ,0x1b710b35131c471bULL) F(w8 ,0x28db77f523047d84ULL) F(w9 ,0x32caab7b40c72493ULL) F(w10,0x3c9ebe0a15c9bebcULL) F(w11,0x431d67c49c100d4cULL) F(w12,0x4cc5d4becb3e42b6ULL) F(w13,0x597f299cfc657e2aULL) F(w14,0x5fcb6fab3ad6faecULL) F(w15,0x6c44198c4a475817ULL) a += state[0]; b += state[1]; c += state[2]; d += state[3]; e += state[4]; f += state[5]; g += state[6]; h += state[7]; state[0] = a; state[1] = b; state[2] = c; state[3] = d; state[4] = e; state[5] = f; state[6] = g; state[7] = h; in += 128; inlen -= 128; } store_bigendian(statebytes + 0,state[0]); store_bigendian(statebytes + 8,state[1]); store_bigendian(statebytes + 16,state[2]); store_bigendian(statebytes + 24,state[3]); store_bigendian(statebytes + 32,state[4]); store_bigendian(statebytes + 40,state[5]); store_bigendian(statebytes + 48,state[6]); store_bigendian(statebytes + 56,state[7]); return 0; } libsignal-protocol-c-2.3.3/src/curve25519/ed25519/nacl_sha512/hash.c000066400000000000000000000034171363751346500241720ustar00rootroot00000000000000/* 20080913 D. J. Bernstein Public domain. */ #include typedef uint64_t uint64; extern int crypto_hashblocks_sha512(unsigned char *statebytes,const unsigned char *in,unsigned long long inlen); #define blocks crypto_hashblocks_sha512 static const unsigned char iv[64] = { 0x6a,0x09,0xe6,0x67,0xf3,0xbc,0xc9,0x08, 0xbb,0x67,0xae,0x85,0x84,0xca,0xa7,0x3b, 0x3c,0x6e,0xf3,0x72,0xfe,0x94,0xf8,0x2b, 0xa5,0x4f,0xf5,0x3a,0x5f,0x1d,0x36,0xf1, 0x51,0x0e,0x52,0x7f,0xad,0xe6,0x82,0xd1, 0x9b,0x05,0x68,0x8c,0x2b,0x3e,0x6c,0x1f, 0x1f,0x83,0xd9,0xab,0xfb,0x41,0xbd,0x6b, 0x5b,0xe0,0xcd,0x19,0x13,0x7e,0x21,0x79 } ; int crypto_hash_sha512(unsigned char *out,const unsigned char *in,unsigned long long inlen) { unsigned char h[64]; unsigned char padded[256]; int i; unsigned long long bytes = inlen; for (i = 0;i < 64;++i) h[i] = iv[i]; blocks(h,in,inlen); in += inlen; inlen &= 127; in -= inlen; for (i = 0;i < inlen;++i) padded[i] = in[i]; padded[inlen] = 0x80; if (inlen < 112) { for (i = inlen + 1;i < 119;++i) padded[i] = 0; padded[119] = bytes >> 61; padded[120] = bytes >> 53; padded[121] = bytes >> 45; padded[122] = bytes >> 37; padded[123] = bytes >> 29; padded[124] = bytes >> 21; padded[125] = bytes >> 13; padded[126] = bytes >> 5; padded[127] = bytes << 3; blocks(h,padded,128); } else { for (i = inlen + 1;i < 247;++i) padded[i] = 0; padded[247] = bytes >> 61; padded[248] = bytes >> 53; padded[249] = bytes >> 45; padded[250] = bytes >> 37; padded[251] = bytes >> 29; padded[252] = bytes >> 21; padded[253] = bytes >> 13; padded[254] = bytes >> 5; padded[255] = bytes << 3; blocks(h,padded,256); } for (i = 0;i < 64;++i) out[i] = h[i]; return 0; } libsignal-protocol-c-2.3.3/src/curve25519/ed25519/open.c000066400000000000000000000020141363751346500222000ustar00rootroot00000000000000#include #include "crypto_sign.h" #include "crypto_hash_sha512.h" #include "crypto_verify_32.h" #include "ge.h" #include "sc.h" int crypto_sign_open( unsigned char *m,unsigned long long *mlen, const unsigned char *sm,unsigned long long smlen, const unsigned char *pk ) { unsigned char pkcopy[32]; unsigned char rcopy[32]; unsigned char scopy[32]; unsigned char h[64]; unsigned char rcheck[32]; ge_p3 A; ge_p2 R; if (smlen < 64) goto badsig; if (sm[63] & 224) goto badsig; if (ge_frombytes_negate_vartime(&A,pk) != 0) goto badsig; memmove(pkcopy,pk,32); memmove(rcopy,sm,32); memmove(scopy,sm + 32,32); memmove(m,sm,smlen); memmove(m + 32,pkcopy,32); crypto_hash_sha512(h,m,smlen); sc_reduce(h); ge_double_scalarmult_vartime(&R,h,&A,scopy); ge_tobytes(rcheck,&R); if (crypto_verify_32(rcheck,rcopy) == 0) { memmove(m,m + 64,smlen - 64); memset(m + smlen - 64,0,64); *mlen = smlen - 64; return 0; } badsig: *mlen = -1; memset(m,0,smlen); return -1; } libsignal-protocol-c-2.3.3/src/curve25519/ed25519/pow22523.h000066400000000000000000000126161363751346500224600ustar00rootroot00000000000000 /* qhasm: fe z1 */ /* qhasm: fe z2 */ /* qhasm: fe z8 */ /* qhasm: fe z9 */ /* qhasm: fe z11 */ /* qhasm: fe z22 */ /* qhasm: fe z_5_0 */ /* qhasm: fe z_10_5 */ /* qhasm: fe z_10_0 */ /* qhasm: fe z_20_10 */ /* qhasm: fe z_20_0 */ /* qhasm: fe z_40_20 */ /* qhasm: fe z_40_0 */ /* qhasm: fe z_50_10 */ /* qhasm: fe z_50_0 */ /* qhasm: fe z_100_50 */ /* qhasm: fe z_100_0 */ /* qhasm: fe z_200_100 */ /* qhasm: fe z_200_0 */ /* qhasm: fe z_250_50 */ /* qhasm: fe z_250_0 */ /* qhasm: fe z_252_2 */ /* qhasm: fe z_252_3 */ /* qhasm: enter pow22523 */ /* qhasm: z2 = z1^2^1 */ /* asm 1: fe_sq(>z2=fe#1,z2=fe#1,>z2=fe#1); */ /* asm 2: fe_sq(>z2=t0,z2=t0,>z2=t0); */ fe_sq(t0,z); for (i = 1;i < 1;++i) fe_sq(t0,t0); /* qhasm: z8 = z2^2^2 */ /* asm 1: fe_sq(>z8=fe#2,z8=fe#2,>z8=fe#2); */ /* asm 2: fe_sq(>z8=t1,z8=t1,>z8=t1); */ fe_sq(t1,t0); for (i = 1;i < 2;++i) fe_sq(t1,t1); /* qhasm: z9 = z1*z8 */ /* asm 1: fe_mul(>z9=fe#2,z9=t1,z11=fe#1,z11=t0,z22=fe#1,z22=fe#1,>z22=fe#1); */ /* asm 2: fe_sq(>z22=t0,z22=t0,>z22=t0); */ fe_sq(t0,t0); for (i = 1;i < 1;++i) fe_sq(t0,t0); /* qhasm: z_5_0 = z9*z22 */ /* asm 1: fe_mul(>z_5_0=fe#1,z_5_0=t0,z_10_5=fe#2,z_10_5=fe#2,>z_10_5=fe#2); */ /* asm 2: fe_sq(>z_10_5=t1,z_10_5=t1,>z_10_5=t1); */ fe_sq(t1,t0); for (i = 1;i < 5;++i) fe_sq(t1,t1); /* qhasm: z_10_0 = z_10_5*z_5_0 */ /* asm 1: fe_mul(>z_10_0=fe#1,z_10_0=t0,z_20_10=fe#2,z_20_10=fe#2,>z_20_10=fe#2); */ /* asm 2: fe_sq(>z_20_10=t1,z_20_10=t1,>z_20_10=t1); */ fe_sq(t1,t0); for (i = 1;i < 10;++i) fe_sq(t1,t1); /* qhasm: z_20_0 = z_20_10*z_10_0 */ /* asm 1: fe_mul(>z_20_0=fe#2,z_20_0=t1,z_40_20=fe#3,z_40_20=fe#3,>z_40_20=fe#3); */ /* asm 2: fe_sq(>z_40_20=t2,z_40_20=t2,>z_40_20=t2); */ fe_sq(t2,t1); for (i = 1;i < 20;++i) fe_sq(t2,t2); /* qhasm: z_40_0 = z_40_20*z_20_0 */ /* asm 1: fe_mul(>z_40_0=fe#2,z_40_0=t1,z_50_10=fe#2,z_50_10=fe#2,>z_50_10=fe#2); */ /* asm 2: fe_sq(>z_50_10=t1,z_50_10=t1,>z_50_10=t1); */ fe_sq(t1,t1); for (i = 1;i < 10;++i) fe_sq(t1,t1); /* qhasm: z_50_0 = z_50_10*z_10_0 */ /* asm 1: fe_mul(>z_50_0=fe#1,z_50_0=t0,z_100_50=fe#2,z_100_50=fe#2,>z_100_50=fe#2); */ /* asm 2: fe_sq(>z_100_50=t1,z_100_50=t1,>z_100_50=t1); */ fe_sq(t1,t0); for (i = 1;i < 50;++i) fe_sq(t1,t1); /* qhasm: z_100_0 = z_100_50*z_50_0 */ /* asm 1: fe_mul(>z_100_0=fe#2,z_100_0=t1,z_200_100=fe#3,z_200_100=fe#3,>z_200_100=fe#3); */ /* asm 2: fe_sq(>z_200_100=t2,z_200_100=t2,>z_200_100=t2); */ fe_sq(t2,t1); for (i = 1;i < 100;++i) fe_sq(t2,t2); /* qhasm: z_200_0 = z_200_100*z_100_0 */ /* asm 1: fe_mul(>z_200_0=fe#2,z_200_0=t1,z_250_50=fe#2,z_250_50=fe#2,>z_250_50=fe#2); */ /* asm 2: fe_sq(>z_250_50=t1,z_250_50=t1,>z_250_50=t1); */ fe_sq(t1,t1); for (i = 1;i < 50;++i) fe_sq(t1,t1); /* qhasm: z_250_0 = z_250_50*z_50_0 */ /* asm 1: fe_mul(>z_250_0=fe#1,z_250_0=t0,z_252_2=fe#1,z_252_2=fe#1,>z_252_2=fe#1); */ /* asm 2: fe_sq(>z_252_2=t0,z_252_2=t0,>z_252_2=t0); */ fe_sq(t0,t0); for (i = 1;i < 2;++i) fe_sq(t0,t0); /* qhasm: z_252_3 = z_252_2*z1 */ /* asm 1: fe_mul(>z_252_3=fe#12,z_252_3=out,z2=fe#1,z2=fe#1,>z2=fe#1); */ /* asm 2: fe_sq(>z2=t0,z2=t0,>z2=t0); */ fe_sq(t0,z); for (i = 1;i < 1;++i) fe_sq(t0,t0); /* qhasm: z8 = z2^2^2 */ /* asm 1: fe_sq(>z8=fe#2,z8=fe#2,>z8=fe#2); */ /* asm 2: fe_sq(>z8=t1,z8=t1,>z8=t1); */ fe_sq(t1,t0); for (i = 1;i < 2;++i) fe_sq(t1,t1); /* qhasm: z9 = z1*z8 */ /* asm 1: fe_mul(>z9=fe#2,z9=t1,z11=fe#1,z11=t0,z22=fe#3,z22=fe#3,>z22=fe#3); */ /* asm 2: fe_sq(>z22=t2,z22=t2,>z22=t2); */ fe_sq(t2,t0); for (i = 1;i < 1;++i) fe_sq(t2,t2); /* qhasm: z_5_0 = z9*z22 */ /* asm 1: fe_mul(>z_5_0=fe#2,z_5_0=t1,z_10_5=fe#3,z_10_5=fe#3,>z_10_5=fe#3); */ /* asm 2: fe_sq(>z_10_5=t2,z_10_5=t2,>z_10_5=t2); */ fe_sq(t2,t1); for (i = 1;i < 5;++i) fe_sq(t2,t2); /* qhasm: z_10_0 = z_10_5*z_5_0 */ /* asm 1: fe_mul(>z_10_0=fe#2,z_10_0=t1,z_20_10=fe#3,z_20_10=fe#3,>z_20_10=fe#3); */ /* asm 2: fe_sq(>z_20_10=t2,z_20_10=t2,>z_20_10=t2); */ fe_sq(t2,t1); for (i = 1;i < 10;++i) fe_sq(t2,t2); /* qhasm: z_20_0 = z_20_10*z_10_0 */ /* asm 1: fe_mul(>z_20_0=fe#3,z_20_0=t2,z_40_20=fe#4,z_40_20=fe#4,>z_40_20=fe#4); */ /* asm 2: fe_sq(>z_40_20=t3,z_40_20=t3,>z_40_20=t3); */ fe_sq(t3,t2); for (i = 1;i < 20;++i) fe_sq(t3,t3); /* qhasm: z_40_0 = z_40_20*z_20_0 */ /* asm 1: fe_mul(>z_40_0=fe#3,z_40_0=t2,z_50_10=fe#3,z_50_10=fe#3,>z_50_10=fe#3); */ /* asm 2: fe_sq(>z_50_10=t2,z_50_10=t2,>z_50_10=t2); */ fe_sq(t2,t2); for (i = 1;i < 10;++i) fe_sq(t2,t2); /* qhasm: z_50_0 = z_50_10*z_10_0 */ /* asm 1: fe_mul(>z_50_0=fe#2,z_50_0=t1,z_100_50=fe#3,z_100_50=fe#3,>z_100_50=fe#3); */ /* asm 2: fe_sq(>z_100_50=t2,z_100_50=t2,>z_100_50=t2); */ fe_sq(t2,t1); for (i = 1;i < 50;++i) fe_sq(t2,t2); /* qhasm: z_100_0 = z_100_50*z_50_0 */ /* asm 1: fe_mul(>z_100_0=fe#3,z_100_0=t2,z_200_100=fe#4,z_200_100=fe#4,>z_200_100=fe#4); */ /* asm 2: fe_sq(>z_200_100=t3,z_200_100=t3,>z_200_100=t3); */ fe_sq(t3,t2); for (i = 1;i < 100;++i) fe_sq(t3,t3); /* qhasm: z_200_0 = z_200_100*z_100_0 */ /* asm 1: fe_mul(>z_200_0=fe#3,z_200_0=t2,z_250_50=fe#3,z_250_50=fe#3,>z_250_50=fe#3); */ /* asm 2: fe_sq(>z_250_50=t2,z_250_50=t2,>z_250_50=t2); */ fe_sq(t2,t2); for (i = 1;i < 50;++i) fe_sq(t2,t2); /* qhasm: z_250_0 = z_250_50*z_50_0 */ /* asm 1: fe_mul(>z_250_0=fe#2,z_250_0=t1,z_255_5=fe#2,z_255_5=fe#2,>z_255_5=fe#2); */ /* asm 2: fe_sq(>z_255_5=t1,z_255_5=t1,>z_255_5=t1); */ fe_sq(t1,t1); for (i = 1;i < 5;++i) fe_sq(t1,t1); /* qhasm: z_255_21 = z_255_5*z11 */ /* asm 1: fe_mul(>z_255_21=fe#12,z_255_21=out,> 5); crypto_int64 a2 = 2097151 & (load_3(a + 5) >> 2); crypto_int64 a3 = 2097151 & (load_4(a + 7) >> 7); crypto_int64 a4 = 2097151 & (load_4(a + 10) >> 4); crypto_int64 a5 = 2097151 & (load_3(a + 13) >> 1); crypto_int64 a6 = 2097151 & (load_4(a + 15) >> 6); crypto_int64 a7 = 2097151 & (load_3(a + 18) >> 3); crypto_int64 a8 = 2097151 & load_3(a + 21); crypto_int64 a9 = 2097151 & (load_4(a + 23) >> 5); crypto_int64 a10 = 2097151 & (load_3(a + 26) >> 2); crypto_int64 a11 = (load_4(a + 28) >> 7); crypto_int64 b0 = 2097151 & load_3(b); crypto_int64 b1 = 2097151 & (load_4(b + 2) >> 5); crypto_int64 b2 = 2097151 & (load_3(b + 5) >> 2); crypto_int64 b3 = 2097151 & (load_4(b + 7) >> 7); crypto_int64 b4 = 2097151 & (load_4(b + 10) >> 4); crypto_int64 b5 = 2097151 & (load_3(b + 13) >> 1); crypto_int64 b6 = 2097151 & (load_4(b + 15) >> 6); crypto_int64 b7 = 2097151 & (load_3(b + 18) >> 3); crypto_int64 b8 = 2097151 & load_3(b + 21); crypto_int64 b9 = 2097151 & (load_4(b + 23) >> 5); crypto_int64 b10 = 2097151 & (load_3(b + 26) >> 2); crypto_int64 b11 = (load_4(b + 28) >> 7); crypto_int64 c0 = 2097151 & load_3(c); crypto_int64 c1 = 2097151 & (load_4(c + 2) >> 5); crypto_int64 c2 = 2097151 & (load_3(c + 5) >> 2); crypto_int64 c3 = 2097151 & (load_4(c + 7) >> 7); crypto_int64 c4 = 2097151 & (load_4(c + 10) >> 4); crypto_int64 c5 = 2097151 & (load_3(c + 13) >> 1); crypto_int64 c6 = 2097151 & (load_4(c + 15) >> 6); crypto_int64 c7 = 2097151 & (load_3(c + 18) >> 3); crypto_int64 c8 = 2097151 & load_3(c + 21); crypto_int64 c9 = 2097151 & (load_4(c + 23) >> 5); crypto_int64 c10 = 2097151 & (load_3(c + 26) >> 2); crypto_int64 c11 = (load_4(c + 28) >> 7); crypto_int64 s0; crypto_int64 s1; crypto_int64 s2; crypto_int64 s3; crypto_int64 s4; crypto_int64 s5; crypto_int64 s6; crypto_int64 s7; crypto_int64 s8; crypto_int64 s9; crypto_int64 s10; crypto_int64 s11; crypto_int64 s12; crypto_int64 s13; crypto_int64 s14; crypto_int64 s15; crypto_int64 s16; crypto_int64 s17; crypto_int64 s18; crypto_int64 s19; crypto_int64 s20; crypto_int64 s21; crypto_int64 s22; crypto_int64 s23; crypto_int64 carry0; crypto_int64 carry1; crypto_int64 carry2; crypto_int64 carry3; crypto_int64 carry4; crypto_int64 carry5; crypto_int64 carry6; crypto_int64 carry7; crypto_int64 carry8; crypto_int64 carry9; crypto_int64 carry10; crypto_int64 carry11; crypto_int64 carry12; crypto_int64 carry13; crypto_int64 carry14; crypto_int64 carry15; crypto_int64 carry16; crypto_int64 carry17; crypto_int64 carry18; crypto_int64 carry19; crypto_int64 carry20; crypto_int64 carry21; crypto_int64 carry22; s0 = c0 + a0*b0; s1 = c1 + a0*b1 + a1*b0; s2 = c2 + a0*b2 + a1*b1 + a2*b0; s3 = c3 + a0*b3 + a1*b2 + a2*b1 + a3*b0; s4 = c4 + a0*b4 + a1*b3 + a2*b2 + a3*b1 + a4*b0; s5 = c5 + a0*b5 + a1*b4 + a2*b3 + a3*b2 + a4*b1 + a5*b0; s6 = c6 + a0*b6 + a1*b5 + a2*b4 + a3*b3 + a4*b2 + a5*b1 + a6*b0; s7 = c7 + a0*b7 + a1*b6 + a2*b5 + a3*b4 + a4*b3 + a5*b2 + a6*b1 + a7*b0; s8 = c8 + a0*b8 + a1*b7 + a2*b6 + a3*b5 + a4*b4 + a5*b3 + a6*b2 + a7*b1 + a8*b0; s9 = c9 + a0*b9 + a1*b8 + a2*b7 + a3*b6 + a4*b5 + a5*b4 + a6*b3 + a7*b2 + a8*b1 + a9*b0; s10 = c10 + a0*b10 + a1*b9 + a2*b8 + a3*b7 + a4*b6 + a5*b5 + a6*b4 + a7*b3 + a8*b2 + a9*b1 + a10*b0; s11 = c11 + a0*b11 + a1*b10 + a2*b9 + a3*b8 + a4*b7 + a5*b6 + a6*b5 + a7*b4 + a8*b3 + a9*b2 + a10*b1 + a11*b0; s12 = a1*b11 + a2*b10 + a3*b9 + a4*b8 + a5*b7 + a6*b6 + a7*b5 + a8*b4 + a9*b3 + a10*b2 + a11*b1; s13 = a2*b11 + a3*b10 + a4*b9 + a5*b8 + a6*b7 + a7*b6 + a8*b5 + a9*b4 + a10*b3 + a11*b2; s14 = a3*b11 + a4*b10 + a5*b9 + a6*b8 + a7*b7 + a8*b6 + a9*b5 + a10*b4 + a11*b3; s15 = a4*b11 + a5*b10 + a6*b9 + a7*b8 + a8*b7 + a9*b6 + a10*b5 + a11*b4; s16 = a5*b11 + a6*b10 + a7*b9 + a8*b8 + a9*b7 + a10*b6 + a11*b5; s17 = a6*b11 + a7*b10 + a8*b9 + a9*b8 + a10*b7 + a11*b6; s18 = a7*b11 + a8*b10 + a9*b9 + a10*b8 + a11*b7; s19 = a8*b11 + a9*b10 + a10*b9 + a11*b8; s20 = a9*b11 + a10*b10 + a11*b9; s21 = a10*b11 + a11*b10; s22 = a11*b11; s23 = 0; carry0 = (s0 + (1<<20)) >> 21; s1 += carry0; s0 -= carry0 << 21; carry2 = (s2 + (1<<20)) >> 21; s3 += carry2; s2 -= carry2 << 21; carry4 = (s4 + (1<<20)) >> 21; s5 += carry4; s4 -= carry4 << 21; carry6 = (s6 + (1<<20)) >> 21; s7 += carry6; s6 -= carry6 << 21; carry8 = (s8 + (1<<20)) >> 21; s9 += carry8; s8 -= carry8 << 21; carry10 = (s10 + (1<<20)) >> 21; s11 += carry10; s10 -= carry10 << 21; carry12 = (s12 + (1<<20)) >> 21; s13 += carry12; s12 -= carry12 << 21; carry14 = (s14 + (1<<20)) >> 21; s15 += carry14; s14 -= carry14 << 21; carry16 = (s16 + (1<<20)) >> 21; s17 += carry16; s16 -= carry16 << 21; carry18 = (s18 + (1<<20)) >> 21; s19 += carry18; s18 -= carry18 << 21; carry20 = (s20 + (1<<20)) >> 21; s21 += carry20; s20 -= carry20 << 21; carry22 = (s22 + (1<<20)) >> 21; s23 += carry22; s22 -= carry22 << 21; carry1 = (s1 + (1<<20)) >> 21; s2 += carry1; s1 -= carry1 << 21; carry3 = (s3 + (1<<20)) >> 21; s4 += carry3; s3 -= carry3 << 21; carry5 = (s5 + (1<<20)) >> 21; s6 += carry5; s5 -= carry5 << 21; carry7 = (s7 + (1<<20)) >> 21; s8 += carry7; s7 -= carry7 << 21; carry9 = (s9 + (1<<20)) >> 21; s10 += carry9; s9 -= carry9 << 21; carry11 = (s11 + (1<<20)) >> 21; s12 += carry11; s11 -= carry11 << 21; carry13 = (s13 + (1<<20)) >> 21; s14 += carry13; s13 -= carry13 << 21; carry15 = (s15 + (1<<20)) >> 21; s16 += carry15; s15 -= carry15 << 21; carry17 = (s17 + (1<<20)) >> 21; s18 += carry17; s17 -= carry17 << 21; carry19 = (s19 + (1<<20)) >> 21; s20 += carry19; s19 -= carry19 << 21; carry21 = (s21 + (1<<20)) >> 21; s22 += carry21; s21 -= carry21 << 21; s11 += s23 * 666643; s12 += s23 * 470296; s13 += s23 * 654183; s14 -= s23 * 997805; s15 += s23 * 136657; s16 -= s23 * 683901; s23 = 0; s10 += s22 * 666643; s11 += s22 * 470296; s12 += s22 * 654183; s13 -= s22 * 997805; s14 += s22 * 136657; s15 -= s22 * 683901; s22 = 0; s9 += s21 * 666643; s10 += s21 * 470296; s11 += s21 * 654183; s12 -= s21 * 997805; s13 += s21 * 136657; s14 -= s21 * 683901; s21 = 0; s8 += s20 * 666643; s9 += s20 * 470296; s10 += s20 * 654183; s11 -= s20 * 997805; s12 += s20 * 136657; s13 -= s20 * 683901; s20 = 0; s7 += s19 * 666643; s8 += s19 * 470296; s9 += s19 * 654183; s10 -= s19 * 997805; s11 += s19 * 136657; s12 -= s19 * 683901; s19 = 0; s6 += s18 * 666643; s7 += s18 * 470296; s8 += s18 * 654183; s9 -= s18 * 997805; s10 += s18 * 136657; s11 -= s18 * 683901; s18 = 0; carry6 = (s6 + (1<<20)) >> 21; s7 += carry6; s6 -= carry6 << 21; carry8 = (s8 + (1<<20)) >> 21; s9 += carry8; s8 -= carry8 << 21; carry10 = (s10 + (1<<20)) >> 21; s11 += carry10; s10 -= carry10 << 21; carry12 = (s12 + (1<<20)) >> 21; s13 += carry12; s12 -= carry12 << 21; carry14 = (s14 + (1<<20)) >> 21; s15 += carry14; s14 -= carry14 << 21; carry16 = (s16 + (1<<20)) >> 21; s17 += carry16; s16 -= carry16 << 21; carry7 = (s7 + (1<<20)) >> 21; s8 += carry7; s7 -= carry7 << 21; carry9 = (s9 + (1<<20)) >> 21; s10 += carry9; s9 -= carry9 << 21; carry11 = (s11 + (1<<20)) >> 21; s12 += carry11; s11 -= carry11 << 21; carry13 = (s13 + (1<<20)) >> 21; s14 += carry13; s13 -= carry13 << 21; carry15 = (s15 + (1<<20)) >> 21; s16 += carry15; s15 -= carry15 << 21; s5 += s17 * 666643; s6 += s17 * 470296; s7 += s17 * 654183; s8 -= s17 * 997805; s9 += s17 * 136657; s10 -= s17 * 683901; s17 = 0; s4 += s16 * 666643; s5 += s16 * 470296; s6 += s16 * 654183; s7 -= s16 * 997805; s8 += s16 * 136657; s9 -= s16 * 683901; s16 = 0; s3 += s15 * 666643; s4 += s15 * 470296; s5 += s15 * 654183; s6 -= s15 * 997805; s7 += s15 * 136657; s8 -= s15 * 683901; s15 = 0; s2 += s14 * 666643; s3 += s14 * 470296; s4 += s14 * 654183; s5 -= s14 * 997805; s6 += s14 * 136657; s7 -= s14 * 683901; s14 = 0; s1 += s13 * 666643; s2 += s13 * 470296; s3 += s13 * 654183; s4 -= s13 * 997805; s5 += s13 * 136657; s6 -= s13 * 683901; s13 = 0; s0 += s12 * 666643; s1 += s12 * 470296; s2 += s12 * 654183; s3 -= s12 * 997805; s4 += s12 * 136657; s5 -= s12 * 683901; s12 = 0; carry0 = (s0 + (1<<20)) >> 21; s1 += carry0; s0 -= carry0 << 21; carry2 = (s2 + (1<<20)) >> 21; s3 += carry2; s2 -= carry2 << 21; carry4 = (s4 + (1<<20)) >> 21; s5 += carry4; s4 -= carry4 << 21; carry6 = (s6 + (1<<20)) >> 21; s7 += carry6; s6 -= carry6 << 21; carry8 = (s8 + (1<<20)) >> 21; s9 += carry8; s8 -= carry8 << 21; carry10 = (s10 + (1<<20)) >> 21; s11 += carry10; s10 -= carry10 << 21; carry1 = (s1 + (1<<20)) >> 21; s2 += carry1; s1 -= carry1 << 21; carry3 = (s3 + (1<<20)) >> 21; s4 += carry3; s3 -= carry3 << 21; carry5 = (s5 + (1<<20)) >> 21; s6 += carry5; s5 -= carry5 << 21; carry7 = (s7 + (1<<20)) >> 21; s8 += carry7; s7 -= carry7 << 21; carry9 = (s9 + (1<<20)) >> 21; s10 += carry9; s9 -= carry9 << 21; carry11 = (s11 + (1<<20)) >> 21; s12 += carry11; s11 -= carry11 << 21; s0 += s12 * 666643; s1 += s12 * 470296; s2 += s12 * 654183; s3 -= s12 * 997805; s4 += s12 * 136657; s5 -= s12 * 683901; s12 = 0; carry0 = s0 >> 21; s1 += carry0; s0 -= carry0 << 21; carry1 = s1 >> 21; s2 += carry1; s1 -= carry1 << 21; carry2 = s2 >> 21; s3 += carry2; s2 -= carry2 << 21; carry3 = s3 >> 21; s4 += carry3; s3 -= carry3 << 21; carry4 = s4 >> 21; s5 += carry4; s4 -= carry4 << 21; carry5 = s5 >> 21; s6 += carry5; s5 -= carry5 << 21; carry6 = s6 >> 21; s7 += carry6; s6 -= carry6 << 21; carry7 = s7 >> 21; s8 += carry7; s7 -= carry7 << 21; carry8 = s8 >> 21; s9 += carry8; s8 -= carry8 << 21; carry9 = s9 >> 21; s10 += carry9; s9 -= carry9 << 21; carry10 = s10 >> 21; s11 += carry10; s10 -= carry10 << 21; carry11 = s11 >> 21; s12 += carry11; s11 -= carry11 << 21; s0 += s12 * 666643; s1 += s12 * 470296; s2 += s12 * 654183; s3 -= s12 * 997805; s4 += s12 * 136657; s5 -= s12 * 683901; s12 = 0; carry0 = s0 >> 21; s1 += carry0; s0 -= carry0 << 21; carry1 = s1 >> 21; s2 += carry1; s1 -= carry1 << 21; carry2 = s2 >> 21; s3 += carry2; s2 -= carry2 << 21; carry3 = s3 >> 21; s4 += carry3; s3 -= carry3 << 21; carry4 = s4 >> 21; s5 += carry4; s4 -= carry4 << 21; carry5 = s5 >> 21; s6 += carry5; s5 -= carry5 << 21; carry6 = s6 >> 21; s7 += carry6; s6 -= carry6 << 21; carry7 = s7 >> 21; s8 += carry7; s7 -= carry7 << 21; carry8 = s8 >> 21; s9 += carry8; s8 -= carry8 << 21; carry9 = s9 >> 21; s10 += carry9; s9 -= carry9 << 21; carry10 = s10 >> 21; s11 += carry10; s10 -= carry10 << 21; s[0] = s0 >> 0; s[1] = s0 >> 8; s[2] = (s0 >> 16) | (s1 << 5); s[3] = s1 >> 3; s[4] = s1 >> 11; s[5] = (s1 >> 19) | (s2 << 2); s[6] = s2 >> 6; s[7] = (s2 >> 14) | (s3 << 7); s[8] = s3 >> 1; s[9] = s3 >> 9; s[10] = (s3 >> 17) | (s4 << 4); s[11] = s4 >> 4; s[12] = s4 >> 12; s[13] = (s4 >> 20) | (s5 << 1); s[14] = s5 >> 7; s[15] = (s5 >> 15) | (s6 << 6); s[16] = s6 >> 2; s[17] = s6 >> 10; s[18] = (s6 >> 18) | (s7 << 3); s[19] = s7 >> 5; s[20] = s7 >> 13; s[21] = s8 >> 0; s[22] = s8 >> 8; s[23] = (s8 >> 16) | (s9 << 5); s[24] = s9 >> 3; s[25] = s9 >> 11; s[26] = (s9 >> 19) | (s10 << 2); s[27] = s10 >> 6; s[28] = (s10 >> 14) | (s11 << 7); s[29] = s11 >> 1; s[30] = s11 >> 9; s[31] = s11 >> 17; } libsignal-protocol-c-2.3.3/src/curve25519/ed25519/sc_reduce.c000066400000000000000000000177131363751346500232070ustar00rootroot00000000000000#include "sc.h" #include "crypto_int64.h" #include "crypto_uint32.h" #include "crypto_uint64.h" static crypto_uint64 load_3(const unsigned char *in) { crypto_uint64 result; result = (crypto_uint64) in[0]; result |= ((crypto_uint64) in[1]) << 8; result |= ((crypto_uint64) in[2]) << 16; return result; } static crypto_uint64 load_4(const unsigned char *in) { crypto_uint64 result; result = (crypto_uint64) in[0]; result |= ((crypto_uint64) in[1]) << 8; result |= ((crypto_uint64) in[2]) << 16; result |= ((crypto_uint64) in[3]) << 24; return result; } /* Input: s[0]+256*s[1]+...+256^63*s[63] = s Output: s[0]+256*s[1]+...+256^31*s[31] = s mod l where l = 2^252 + 27742317777372353535851937790883648493. Overwrites s in place. */ void sc_reduce(unsigned char *s) { crypto_int64 s0 = 2097151 & load_3(s); crypto_int64 s1 = 2097151 & (load_4(s + 2) >> 5); crypto_int64 s2 = 2097151 & (load_3(s + 5) >> 2); crypto_int64 s3 = 2097151 & (load_4(s + 7) >> 7); crypto_int64 s4 = 2097151 & (load_4(s + 10) >> 4); crypto_int64 s5 = 2097151 & (load_3(s + 13) >> 1); crypto_int64 s6 = 2097151 & (load_4(s + 15) >> 6); crypto_int64 s7 = 2097151 & (load_3(s + 18) >> 3); crypto_int64 s8 = 2097151 & load_3(s + 21); crypto_int64 s9 = 2097151 & (load_4(s + 23) >> 5); crypto_int64 s10 = 2097151 & (load_3(s + 26) >> 2); crypto_int64 s11 = 2097151 & (load_4(s + 28) >> 7); crypto_int64 s12 = 2097151 & (load_4(s + 31) >> 4); crypto_int64 s13 = 2097151 & (load_3(s + 34) >> 1); crypto_int64 s14 = 2097151 & (load_4(s + 36) >> 6); crypto_int64 s15 = 2097151 & (load_3(s + 39) >> 3); crypto_int64 s16 = 2097151 & load_3(s + 42); crypto_int64 s17 = 2097151 & (load_4(s + 44) >> 5); crypto_int64 s18 = 2097151 & (load_3(s + 47) >> 2); crypto_int64 s19 = 2097151 & (load_4(s + 49) >> 7); crypto_int64 s20 = 2097151 & (load_4(s + 52) >> 4); crypto_int64 s21 = 2097151 & (load_3(s + 55) >> 1); crypto_int64 s22 = 2097151 & (load_4(s + 57) >> 6); crypto_int64 s23 = (load_4(s + 60) >> 3); crypto_int64 carry0; crypto_int64 carry1; crypto_int64 carry2; crypto_int64 carry3; crypto_int64 carry4; crypto_int64 carry5; crypto_int64 carry6; crypto_int64 carry7; crypto_int64 carry8; crypto_int64 carry9; crypto_int64 carry10; crypto_int64 carry11; crypto_int64 carry12; crypto_int64 carry13; crypto_int64 carry14; crypto_int64 carry15; crypto_int64 carry16; s11 += s23 * 666643; s12 += s23 * 470296; s13 += s23 * 654183; s14 -= s23 * 997805; s15 += s23 * 136657; s16 -= s23 * 683901; s23 = 0; s10 += s22 * 666643; s11 += s22 * 470296; s12 += s22 * 654183; s13 -= s22 * 997805; s14 += s22 * 136657; s15 -= s22 * 683901; s22 = 0; s9 += s21 * 666643; s10 += s21 * 470296; s11 += s21 * 654183; s12 -= s21 * 997805; s13 += s21 * 136657; s14 -= s21 * 683901; s21 = 0; s8 += s20 * 666643; s9 += s20 * 470296; s10 += s20 * 654183; s11 -= s20 * 997805; s12 += s20 * 136657; s13 -= s20 * 683901; s20 = 0; s7 += s19 * 666643; s8 += s19 * 470296; s9 += s19 * 654183; s10 -= s19 * 997805; s11 += s19 * 136657; s12 -= s19 * 683901; s19 = 0; s6 += s18 * 666643; s7 += s18 * 470296; s8 += s18 * 654183; s9 -= s18 * 997805; s10 += s18 * 136657; s11 -= s18 * 683901; s18 = 0; carry6 = (s6 + (1<<20)) >> 21; s7 += carry6; s6 -= carry6 << 21; carry8 = (s8 + (1<<20)) >> 21; s9 += carry8; s8 -= carry8 << 21; carry10 = (s10 + (1<<20)) >> 21; s11 += carry10; s10 -= carry10 << 21; carry12 = (s12 + (1<<20)) >> 21; s13 += carry12; s12 -= carry12 << 21; carry14 = (s14 + (1<<20)) >> 21; s15 += carry14; s14 -= carry14 << 21; carry16 = (s16 + (1<<20)) >> 21; s17 += carry16; s16 -= carry16 << 21; carry7 = (s7 + (1<<20)) >> 21; s8 += carry7; s7 -= carry7 << 21; carry9 = (s9 + (1<<20)) >> 21; s10 += carry9; s9 -= carry9 << 21; carry11 = (s11 + (1<<20)) >> 21; s12 += carry11; s11 -= carry11 << 21; carry13 = (s13 + (1<<20)) >> 21; s14 += carry13; s13 -= carry13 << 21; carry15 = (s15 + (1<<20)) >> 21; s16 += carry15; s15 -= carry15 << 21; s5 += s17 * 666643; s6 += s17 * 470296; s7 += s17 * 654183; s8 -= s17 * 997805; s9 += s17 * 136657; s10 -= s17 * 683901; s17 = 0; s4 += s16 * 666643; s5 += s16 * 470296; s6 += s16 * 654183; s7 -= s16 * 997805; s8 += s16 * 136657; s9 -= s16 * 683901; s16 = 0; s3 += s15 * 666643; s4 += s15 * 470296; s5 += s15 * 654183; s6 -= s15 * 997805; s7 += s15 * 136657; s8 -= s15 * 683901; s15 = 0; s2 += s14 * 666643; s3 += s14 * 470296; s4 += s14 * 654183; s5 -= s14 * 997805; s6 += s14 * 136657; s7 -= s14 * 683901; s14 = 0; s1 += s13 * 666643; s2 += s13 * 470296; s3 += s13 * 654183; s4 -= s13 * 997805; s5 += s13 * 136657; s6 -= s13 * 683901; s13 = 0; s0 += s12 * 666643; s1 += s12 * 470296; s2 += s12 * 654183; s3 -= s12 * 997805; s4 += s12 * 136657; s5 -= s12 * 683901; s12 = 0; carry0 = (s0 + (1<<20)) >> 21; s1 += carry0; s0 -= carry0 << 21; carry2 = (s2 + (1<<20)) >> 21; s3 += carry2; s2 -= carry2 << 21; carry4 = (s4 + (1<<20)) >> 21; s5 += carry4; s4 -= carry4 << 21; carry6 = (s6 + (1<<20)) >> 21; s7 += carry6; s6 -= carry6 << 21; carry8 = (s8 + (1<<20)) >> 21; s9 += carry8; s8 -= carry8 << 21; carry10 = (s10 + (1<<20)) >> 21; s11 += carry10; s10 -= carry10 << 21; carry1 = (s1 + (1<<20)) >> 21; s2 += carry1; s1 -= carry1 << 21; carry3 = (s3 + (1<<20)) >> 21; s4 += carry3; s3 -= carry3 << 21; carry5 = (s5 + (1<<20)) >> 21; s6 += carry5; s5 -= carry5 << 21; carry7 = (s7 + (1<<20)) >> 21; s8 += carry7; s7 -= carry7 << 21; carry9 = (s9 + (1<<20)) >> 21; s10 += carry9; s9 -= carry9 << 21; carry11 = (s11 + (1<<20)) >> 21; s12 += carry11; s11 -= carry11 << 21; s0 += s12 * 666643; s1 += s12 * 470296; s2 += s12 * 654183; s3 -= s12 * 997805; s4 += s12 * 136657; s5 -= s12 * 683901; s12 = 0; carry0 = s0 >> 21; s1 += carry0; s0 -= carry0 << 21; carry1 = s1 >> 21; s2 += carry1; s1 -= carry1 << 21; carry2 = s2 >> 21; s3 += carry2; s2 -= carry2 << 21; carry3 = s3 >> 21; s4 += carry3; s3 -= carry3 << 21; carry4 = s4 >> 21; s5 += carry4; s4 -= carry4 << 21; carry5 = s5 >> 21; s6 += carry5; s5 -= carry5 << 21; carry6 = s6 >> 21; s7 += carry6; s6 -= carry6 << 21; carry7 = s7 >> 21; s8 += carry7; s7 -= carry7 << 21; carry8 = s8 >> 21; s9 += carry8; s8 -= carry8 << 21; carry9 = s9 >> 21; s10 += carry9; s9 -= carry9 << 21; carry10 = s10 >> 21; s11 += carry10; s10 -= carry10 << 21; carry11 = s11 >> 21; s12 += carry11; s11 -= carry11 << 21; s0 += s12 * 666643; s1 += s12 * 470296; s2 += s12 * 654183; s3 -= s12 * 997805; s4 += s12 * 136657; s5 -= s12 * 683901; s12 = 0; carry0 = s0 >> 21; s1 += carry0; s0 -= carry0 << 21; carry1 = s1 >> 21; s2 += carry1; s1 -= carry1 << 21; carry2 = s2 >> 21; s3 += carry2; s2 -= carry2 << 21; carry3 = s3 >> 21; s4 += carry3; s3 -= carry3 << 21; carry4 = s4 >> 21; s5 += carry4; s4 -= carry4 << 21; carry5 = s5 >> 21; s6 += carry5; s5 -= carry5 << 21; carry6 = s6 >> 21; s7 += carry6; s6 -= carry6 << 21; carry7 = s7 >> 21; s8 += carry7; s7 -= carry7 << 21; carry8 = s8 >> 21; s9 += carry8; s8 -= carry8 << 21; carry9 = s9 >> 21; s10 += carry9; s9 -= carry9 << 21; carry10 = s10 >> 21; s11 += carry10; s10 -= carry10 << 21; s[0] = s0 >> 0; s[1] = s0 >> 8; s[2] = (s0 >> 16) | (s1 << 5); s[3] = s1 >> 3; s[4] = s1 >> 11; s[5] = (s1 >> 19) | (s2 << 2); s[6] = s2 >> 6; s[7] = (s2 >> 14) | (s3 << 7); s[8] = s3 >> 1; s[9] = s3 >> 9; s[10] = (s3 >> 17) | (s4 << 4); s[11] = s4 >> 4; s[12] = s4 >> 12; s[13] = (s4 >> 20) | (s5 << 1); s[14] = s5 >> 7; s[15] = (s5 >> 15) | (s6 << 6); s[16] = s6 >> 2; s[17] = s6 >> 10; s[18] = (s6 >> 18) | (s7 << 3); s[19] = s7 >> 5; s[20] = s7 >> 13; s[21] = s8 >> 0; s[22] = s8 >> 8; s[23] = (s8 >> 16) | (s9 << 5); s[24] = s9 >> 3; s[25] = s9 >> 11; s[26] = (s9 >> 19) | (s10 << 2); s[27] = s10 >> 6; s[28] = (s10 >> 14) | (s11 << 7); s[29] = s11 >> 1; s[30] = s11 >> 9; s[31] = s11 >> 17; } libsignal-protocol-c-2.3.3/src/curve25519/ed25519/sign.c000066400000000000000000000014611363751346500222040ustar00rootroot00000000000000#include #include "crypto_sign.h" #include "crypto_hash_sha512.h" #include "ge.h" #include "sc.h" int crypto_sign( unsigned char *sm,unsigned long long *smlen, const unsigned char *m,unsigned long long mlen, const unsigned char *sk ) { unsigned char pk[32]; unsigned char az[64]; unsigned char nonce[64]; unsigned char hram[64]; ge_p3 R; memmove(pk,sk + 32,32); crypto_hash_sha512(az,sk,32); az[0] &= 248; az[31] &= 63; az[31] |= 64; *smlen = mlen + 64; memmove(sm + 64,m,mlen); memmove(sm + 32,az + 32,32); crypto_hash_sha512(nonce,sm + 32,mlen + 32); memmove(sm + 32,pk,32); sc_reduce(nonce); ge_scalarmult_base(&R,nonce); ge_p3_tobytes(sm,&R); crypto_hash_sha512(hram,sm,mlen + 64); sc_reduce(hram); sc_muladd(sm + 32,hram,az,nonce); return 0; } libsignal-protocol-c-2.3.3/src/curve25519/ed25519/sqrtm1.h000066400000000000000000000001271363751346500224760ustar00rootroot00000000000000-32595792,-7943725,9377950,3500415,12389472,-272473,-25146209,-2005654,326686,11406482 libsignal-protocol-c-2.3.3/src/curve25519/ed25519/tests/000077500000000000000000000000001363751346500222405ustar00rootroot00000000000000libsignal-protocol-c-2.3.3/src/curve25519/ed25519/tests/internal_fast_tests.c000066400000000000000000000367351363751346500264750ustar00rootroot00000000000000#include #include #include #include "crypto_hash_sha512.h" #include "keygen.h" #include "curve_sigs.h" #include "xeddsa.h" #include "crypto_additions.h" #include "ge.h" #include "utility.h" #include "gen_crypto_additions.h" #include "gen_x.h" #include "internal_fast_tests.h" #include #define ERROR(...) do {if (!silent) { printf(__VA_ARGS__); abort(); } else return -1; } while (0) #define INFO(...) do {if (!silent) printf(__VA_ARGS__);} while (0) #define TEST(msg, cond) \ do { \ if ((cond)) { \ INFO("%s good\n", msg); \ } \ else { \ ERROR("%s BAD!!!\n", msg); \ } \ } while (0) int sha512_fast_test(int silent) { unsigned char sha512_input[112] = "abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmnhijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu"; unsigned char sha512_correct_output[64] = { 0x8E, 0x95, 0x9B, 0x75, 0xDA, 0xE3, 0x13, 0xDA, 0x8C, 0xF4, 0xF7, 0x28, 0x14, 0xFC, 0x14, 0x3F, 0x8F, 0x77, 0x79, 0xC6, 0xEB, 0x9F, 0x7F, 0xA1, 0x72, 0x99, 0xAE, 0xAD, 0xB6, 0x88, 0x90, 0x18, 0x50, 0x1D, 0x28, 0x9E, 0x49, 0x00, 0xF7, 0xE4, 0x33, 0x1B, 0x99, 0xDE, 0xC4, 0xB5, 0x43, 0x3A, 0xC7, 0xD3, 0x29, 0xEE, 0xB6, 0xDD, 0x26, 0x54, 0x5E, 0x96, 0xE5, 0x5B, 0x87, 0x4B, 0xE9, 0x09 }; unsigned char sha512_actual_output[64]; crypto_hash_sha512(sha512_actual_output, sha512_input, sizeof(sha512_input)); TEST("SHA512 #1", memcmp(sha512_actual_output, sha512_correct_output, 64) == 0); sha512_input[111] ^= 1; crypto_hash_sha512(sha512_actual_output, sha512_input, sizeof(sha512_input)); TEST("SHA512 #2", memcmp(sha512_actual_output, sha512_correct_output, 64) != 0); return 0; } int strict_fast_test(int silent) { unsigned char unreduced1[32] = { 0xFE, 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, }; unsigned char unreduced2[32] = { 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, }; unsigned char unreduced3[32] = { 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, }; unsigned char q[32] = { 0xed, 0xd3, 0xf5, 0x5c, 0x1a, 0x63, 0x12, 0x58, 0xd6, 0x9c, 0xf7, 0xa2, 0xde, 0xf9, 0xde, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, }; unsigned char qminus1[32] = { 0xec, 0xd3, 0xf5, 0x5c, 0x1a, 0x63, 0x12, 0x58, 0xd6, 0x9c, 0xf7, 0xa2, 0xde, 0xf9, 0xde, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, }; unsigned char qplus1[32] = { 0xee, 0xd3, 0xf5, 0x5c, 0x1a, 0x63, 0x12, 0x58, 0xd6, 0x9c, 0xf7, 0xa2, 0xde, 0xf9, 0xde, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, }; TEST("fe_isreduced", (fe_isreduced(unreduced1) == 0) && (fe_isreduced(unreduced2) == 0) && (fe_isreduced(unreduced3) == 1) ); TEST("sc_isreduced", (sc_isreduced(q) == 0) && (sc_isreduced(qminus1) == 1) && (sc_isreduced(qplus1) == 0) ); return 0; } int ge_fast_test(int silent) { const unsigned char B_bytes[] = { 0x58, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, }; const unsigned char misc_bytes[] = { 0x57, 0x17, 0xfa, 0xce, 0xca, 0xb9, 0xdf, 0x0e, 0x90, 0x67, 0xaa, 0x46, 0xba, 0x83, 0x2f, 0xeb, 0x1c, 0x49, 0xd0, 0x21, 0xb1, 0x33, 0xff, 0x11, 0xc9, 0x7a, 0xb8, 0xcf, 0xe3, 0x29, 0x46, 0x17, }; unsigned char q_scalar[32] = { 0xed, 0xd3, 0xf5, 0x5c, 0x1a, 0x63, 0x12, 0x58, 0xd6, 0x9c, 0xf7, 0xa2, 0xde, 0xf9, 0xde, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, }; unsigned char c_scalar[32] = { 0x08, 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 }; unsigned char neutral_bytes[] = { 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 }; /* unsigned char one_scalar[32] = { 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, }; const unsigned char B_bytes[] = { 0x58, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, }; */ ge_p3 point1, point2, B_point, misc_point, miscneg_point; unsigned char output1[32], output2[32]; if (ge_frombytes_negate_vartime(&B_point, B_bytes) != 0) TEST("Failure to parse point #1", 0); if (ge_frombytes_negate_vartime(&miscneg_point, misc_bytes) != 0) TEST("Failure to parse point #2", 0); ge_neg(&B_point, &B_point); ge_neg(&misc_point, &miscneg_point); /* q*B == neutral */ ge_scalarmult_base(&point1, q_scalar); ge_scalarmult(&point2, q_scalar, &B_point); ge_p3_tobytes(output1, &point1); ge_p3_tobytes(output2, &point2); TEST("qB == qB", memcmp(output1, output2, 32) == 0 && memcmp(output1, neutral_bytes, 32) == 0); TEST("qB isneutral", ge_isneutral(&point1 ) && ge_isneutral(&point2) && !ge_isneutral(&B_point)); /* cB == cB, cX == cX */ ge_scalarmult_cofactor(&point1, &B_point); ge_scalarmult_base(&point2, c_scalar); ge_p3_tobytes(output1, &point1); ge_p3_tobytes(output2, &point2); TEST("cB == cB", memcmp(output1, output2, 32) == 0); ge_scalarmult_cofactor(&point1, &misc_point); ge_scalarmult(&point2, c_scalar, &misc_point); ge_p3_tobytes(output1, &point1); ge_p3_tobytes(output2, &point2); TEST("cX == cX", memcmp(output1, output2, 32) == 0); /* */ ge_p3_add(&point1, &misc_point, &miscneg_point); TEST("X + -X isneutral", ge_isneutral(&point1)); return 0; } int elligator_fast_test(int silent) { unsigned char elligator_correct_output[32] = { 0x5f, 0x35, 0x20, 0x00, 0x1c, 0x6c, 0x99, 0x36, 0xa3, 0x12, 0x06, 0xaf, 0xe7, 0xc7, 0xac, 0x22, 0x4e, 0x88, 0x61, 0x61, 0x9b, 0xf9, 0x88, 0x72, 0x44, 0x49, 0x15, 0x89, 0x9d, 0x95, 0xf4, 0x6e }; unsigned char hashtopoint_correct_output1[32] = { 0xce, 0x89, 0x9f, 0xb2, 0x8f, 0xf7, 0x20, 0x91, 0x5e, 0x14, 0xf5, 0xb7, 0x99, 0x08, 0xab, 0x17, 0xaa, 0x2e, 0xe2, 0x45, 0xb4, 0xfc, 0x2b, 0xf6, 0x06, 0x36, 0x29, 0x40, 0xed, 0x7d, 0xe7, 0xed }; unsigned char hashtopoint_correct_output2[32] = { 0xa0, 0x35, 0xbb, 0xa9, 0x4d, 0x30, 0x55, 0x33, 0x0d, 0xce, 0xc2, 0x7f, 0x83, 0xde, 0x79, 0xd0, 0x89, 0x67, 0x72, 0x4c, 0x07, 0x8d, 0x68, 0x9d, 0x61, 0x52, 0x1d, 0xf9, 0x2c, 0x5c, 0xba, 0x77 }; int count; fe in, out; unsigned char bytes[32]; fe_0(in); fe_0(out); for (count = 0; count < 32; count++) { bytes[count] = count; } fe_frombytes(in, bytes); elligator(out, in); fe_tobytes(bytes, out); TEST("Elligator vector", memcmp(bytes, elligator_correct_output, 32) == 0); /* Elligator(0) == 0 test */ fe_0(in); elligator(out, in); TEST("Elligator(0) == 0", memcmp(in, out, 32) == 0); /* ge_montx_to_p3(0) -> order2 point test */ fe one, negone, zero; fe_1(one); fe_0(zero); fe_sub(negone, zero, one); ge_p3 p3; ge_montx_to_p3(&p3, zero, 0); TEST("ge_montx_to_p3(0) == order 2 point", fe_isequal(p3.X, zero) && fe_isequal(p3.Y, negone) && fe_isequal(p3.Z, one) && fe_isequal(p3.T, zero)); /* Hash to point vector test */ unsigned char htp[32]; for (count=0; count < 32; count++) { htp[count] = count; } hash_to_point(&p3, htp, 32); ge_p3_tobytes(htp, &p3); TEST("hash_to_point #1", memcmp(htp, hashtopoint_correct_output1, 32) == 0); for (count=0; count < 32; count++) { htp[count] = count+1; } hash_to_point(&p3, htp, 32); ge_p3_tobytes(htp, &p3); TEST("hash_to_point #2", memcmp(htp, hashtopoint_correct_output2, 32) == 0); return 0; } int curvesigs_fast_test(int silent) { unsigned char signature_correct[64] = { 0xcf, 0x87, 0x3d, 0x03, 0x79, 0xac, 0x20, 0xe8, 0x89, 0x3e, 0x55, 0x67, 0xee, 0x0f, 0x89, 0x51, 0xf8, 0xdb, 0x84, 0x0d, 0x26, 0xb2, 0x43, 0xb4, 0x63, 0x52, 0x66, 0x89, 0xd0, 0x1c, 0xa7, 0x18, 0xac, 0x18, 0x9f, 0xb1, 0x67, 0x85, 0x74, 0xeb, 0xdd, 0xe5, 0x69, 0x33, 0x06, 0x59, 0x44, 0x8b, 0x0b, 0xd6, 0xc1, 0x97, 0x3f, 0x7d, 0x78, 0x0a, 0xb3, 0x95, 0x18, 0x62, 0x68, 0x03, 0xd7, 0x82, }; const int MSG_LEN = 200; unsigned char privkey[32]; unsigned char pubkey[32]; unsigned char signature[64]; unsigned char msg[MSG_LEN]; unsigned char random[64]; memset(privkey, 0, 32); memset(pubkey, 0, 32); memset(signature, 0, 64); memset(msg, 0, MSG_LEN); memset(random, 0, 64); privkey[8] = 189; /* just so there's some bits set */ sc_clamp(privkey); /* Signature vector test */ curve25519_keygen(pubkey, privkey); curve25519_sign(signature, privkey, msg, MSG_LEN, random); TEST("Curvesig sign", memcmp(signature, signature_correct, 64) == 0); TEST("Curvesig verify #1", curve25519_verify(signature, pubkey, msg, MSG_LEN) == 0); signature[0] ^= 1; TEST("Curvesig verify #2", curve25519_verify(signature, pubkey, msg, MSG_LEN) != 0); return 0; } int xeddsa_fast_test(int silent) { unsigned char signature_correct[64] = { 0x11, 0xc7, 0xf3, 0xe6, 0xc4, 0xdf, 0x9e, 0x8a, 0x51, 0x50, 0xe1, 0xdb, 0x3b, 0x30, 0xf9, 0x2d, 0xe3, 0xa3, 0xb3, 0xaa, 0x43, 0x86, 0x56, 0x54, 0x5f, 0xa7, 0x39, 0x0f, 0x4b, 0xcc, 0x7b, 0xb2, 0x6c, 0x43, 0x1d, 0x9e, 0x90, 0x64, 0x3e, 0x4f, 0x0e, 0xaa, 0x0e, 0x9c, 0x55, 0x77, 0x66, 0xfa, 0x69, 0xad, 0xa5, 0x76, 0xd6, 0x3d, 0xca, 0xf2, 0xac, 0x32, 0x6c, 0x11, 0xd0, 0xb9, 0x77, 0x02, }; const int MSG_LEN = 200; unsigned char privkey[32]; unsigned char pubkey[32]; unsigned char signature[64]; unsigned char msg[MSG_LEN]; unsigned char random[64]; memset(privkey, 0, 32); memset(pubkey, 0, 32); memset(signature, 0, 64); memset(msg, 0, MSG_LEN); memset(random, 0, 64); privkey[8] = 189; /* just so there's some bits set */ sc_clamp(privkey); /* Signature vector test */ curve25519_keygen(pubkey, privkey); xed25519_sign(signature, privkey, msg, MSG_LEN, random); TEST("XEdDSA sign", memcmp(signature, signature_correct, 64) == 0); TEST("XEdDSA verify #1", xed25519_verify(signature, pubkey, msg, MSG_LEN) == 0); signature[0] ^= 1; TEST("XEdDSA verify #2", xed25519_verify(signature, pubkey, msg, MSG_LEN) != 0); memset(pubkey, 0xFF, 32); TEST("XEdDSA verify #3", xed25519_verify(signature, pubkey, msg, MSG_LEN) != 0); return 0; } int generalized_xeddsa_fast_test(int silent) { unsigned char signature1[64]; unsigned char signature2[64]; unsigned char privkey[32]; unsigned char pubkey[32]; unsigned char msg1[1000]; unsigned char msg2[1000]; unsigned char random[64]; memset(signature1, 0, 64); memset(signature2, 0, 64); memset(privkey, 0xF0, 32); memset(pubkey, 2, 32); memset(msg1, 0x10, 1000); memset(msg2, 0x20, 1000); memset(random, 0xBC, 64); sc_clamp(privkey); curve25519_keygen(pubkey, privkey); msg2[0] = 1; TEST("generalized xeddsa sign #1", generalized_xeddsa_25519_sign(signature1, privkey, msg1, 100, random, NULL, 0) == 0); TEST("generalized xeddsa sign #2", generalized_xeddsa_25519_sign(signature2, privkey, msg2, 100, random, NULL, 0) == 0); TEST("generalized (old) xeddsa verify #1", xed25519_verify(signature1, pubkey, msg1, 100) == 0); TEST("generalized (old) xeddsa verify #2", xed25519_verify(signature2, pubkey, msg2, 100) == 0); TEST("generalized (old) xeddsa verify #3", xed25519_verify(signature1, pubkey, msg2, 100) != 0); TEST("generalized (old) xeddsa verify #4", xed25519_verify(signature2, pubkey, msg1, 100) != 0); TEST("generalized xeddsa verify #1", generalized_xeddsa_25519_verify(signature1, pubkey, msg1, 100, NULL, 0) == 0); TEST("generalized xeddsa verify #2", generalized_xeddsa_25519_verify(signature2, pubkey, msg2, 100, NULL, 0) == 0); TEST("generalized xeddsa verify #3", generalized_xeddsa_25519_verify(signature1, pubkey, msg2, 100, NULL, 0) != 0); TEST("generalized xeddsa verify #4", generalized_xeddsa_25519_verify(signature2, pubkey, msg1, 100, NULL, 0) != 0); return 0; } int generalized_xveddsa_fast_test(int silent) { unsigned char signature1[96]; unsigned char signature2[96]; unsigned char privkey[32]; unsigned char pubkey[32]; unsigned char msg1[1000]; unsigned char msg2[1000]; unsigned char random[64]; unsigned char vrf[32]; memset(signature1, 0, 64); memset(signature2, 0, 64); memset(privkey, 1, 32); memset(pubkey, 2, 32); memset(msg1, 0x11, 1000); memset(msg2, 0x22, 1000); memset(random, 0xAB, 64); sc_clamp(privkey); curve25519_keygen(pubkey, privkey); msg2[0] ^= 1; TEST("generalized xveddsa sign #1", generalized_xveddsa_25519_sign(signature1, privkey, msg1, 100, random, NULL, 0) == 0); TEST("generalized xveddsa sign #2", generalized_xveddsa_25519_sign(signature2, privkey, msg2, 100, random, (unsigned char*)"abc", 3) == 0); TEST("generalized xveddsa verify #1", generalized_xveddsa_25519_verify(vrf, signature1, pubkey, msg1, 100, NULL, 0) == 0); TEST("generalized xveddsa verify #2", generalized_xveddsa_25519_verify(vrf, signature2, pubkey, msg2, 100, (unsigned char*)"abc", 3) == 0); TEST("generalized xveddsa verify #3", generalized_xveddsa_25519_verify(vrf, signature1, pubkey, msg2, 100, NULL, 0) != 0); TEST("generalized xveddsa verify #4", generalized_xveddsa_25519_verify(vrf, signature2, pubkey, msg1, 100, (unsigned char*)"abc", 3) != 0); unsigned char signature3[96]; unsigned char vrf3[96]; random[0] ^= 1; TEST("generalized xveddsa sign #3", generalized_xveddsa_25519_sign(signature3, privkey, msg1, 100, random, NULL, 0) == 0); TEST("generalized xveddsa verify #5", generalized_xveddsa_25519_verify(vrf, signature1, pubkey, msg1, 100, NULL, 0) == 0); TEST("generalized xveddsa verify #6", generalized_xveddsa_25519_verify(vrf3, signature3, pubkey, msg1, 100, NULL, 0) == 0); TEST("generalized xveddsa VRFs equal", memcmp(vrf, vrf3, 32) == 0); TEST("generalized xveddsa Kv equal", memcmp(signature1+0, signature3+0, 32) == 0); TEST("generalized xveddsa h not equal", memcmp(signature1+32, signature3+32, 32) != 0); TEST("generalized xveddsa s not equal", memcmp(signature1+64, signature3+64, 32) != 0); return 0; } int all_fast_tests(int silent) { int result; if ((result = sha512_fast_test(silent)) != 0) return -1; if ((result = strict_fast_test(silent)) != 0) return -2; if ((result = ge_fast_test(silent)) != 0) return -3; if ((result = elligator_fast_test(silent)) != 0) return -3; if ((result = curvesigs_fast_test(silent)) != 0) return -4; if ((result = xeddsa_fast_test(silent)) != 0) return -5; if ((result = generalized_xeddsa_fast_test(silent)) != 0) return -6; if ((result = generalized_xveddsa_fast_test(silent)) != 0) return -7; return 0; } libsignal-protocol-c-2.3.3/src/curve25519/ed25519/tests/internal_fast_tests.h000066400000000000000000000010631363751346500264640ustar00rootroot00000000000000#ifndef __INTERNAL_FAST_TESTS_H__ #define __INTERNAL_FAST_TESTS_H__ /* silent = 0 : prints info+error messages to stdout, abort() on test failure * silent = 1 : returns 0 for success, anything else for failure */ int sha512_fast_test(int silent); int strict_fast_test(int silent); int elligator_fast_test(int silent); int curvesigs_fast_test(int silent); int xeddsa_fast_test(int silent); int vxeddsa_fast_test(int silent); int generalized_xeddsa_fast_test(int silent); int generalized_xveddsa_fast_test(int silent); int all_fast_tests(int silent); #endif libsignal-protocol-c-2.3.3/src/curve25519/ed25519/tests/internal_slow_tests.c000066400000000000000000000270301363751346500265100ustar00rootroot00000000000000#include #include #include #include "crypto_hash_sha512.h" #include "keygen.h" #include "curve_sigs.h" #include "xeddsa.h" #include "crypto_additions.h" #include "ge.h" #include "utility.h" #include "gen_x.h" #include "internal_slow_tests.h" #include #define ERROR(...) do {if (!silent) { printf(__VA_ARGS__); abort(); } else return -1; } while (0) #define INFO(...) do {if (!silent) printf(__VA_ARGS__);} while (0) #define TEST(msg, cond) \ do { \ if ((cond)) { \ INFO("%s good\n", msg); \ } \ else { \ ERROR("%s BAD!!!\n", msg); \ } \ } while (0) int curvesigs_slow_test(int silent, int iterations) { unsigned char signature_10k_correct[64] = { 0xfc, 0xba, 0x55, 0xc4, 0x85, 0x4a, 0x42, 0x25, 0x19, 0xab, 0x08, 0x8d, 0xfe, 0xb5, 0x13, 0xb6, 0x0d, 0x24, 0xbb, 0x16, 0x27, 0x55, 0x71, 0x48, 0xdd, 0x20, 0xb1, 0xcd, 0x2a, 0xd6, 0x7e, 0x35, 0xef, 0x33, 0x4c, 0x7b, 0x6d, 0x94, 0x6f, 0x52, 0xec, 0x43, 0xd7, 0xe6, 0x35, 0x24, 0xcd, 0x5b, 0x5d, 0xdc, 0xb2, 0x32, 0xc6, 0x22, 0x53, 0xf3, 0x38, 0x02, 0xf8, 0x28, 0x28, 0xc5, 0x65, 0x05, }; int count; const int MSG_LEN = 200; unsigned char privkey[32]; unsigned char pubkey[32]; unsigned char signature[64]; unsigned char msg[MSG_LEN]; unsigned char random[64]; memset(privkey, 0, 32); memset(pubkey, 0, 32); memset(signature, 0, 64); memset(msg, 0, MSG_LEN); memset(random, 0, 64); /* Signature random test */ INFO("Pseudorandom curvesigs...\n"); for (count = 1; count <= iterations; count++) { unsigned char b[64]; crypto_hash_sha512(b, signature, 64); memmove(privkey, b, 32); crypto_hash_sha512(b, privkey, 32); memmove(random, b, 64); sc_clamp(privkey); curve25519_keygen(pubkey, privkey); curve25519_sign(signature, privkey, msg, MSG_LEN, random); if (curve25519_verify(signature, pubkey, msg, MSG_LEN) != 0) ERROR("Curvesig verify failure #1 %d\n", count); if (b[63] & 1) signature[count % 64] ^= 1; else msg[count % MSG_LEN] ^= 1; if (curve25519_verify(signature, pubkey, msg, MSG_LEN) == 0) ERROR("Curvesig verify failure #2 %d\n", count); if (count == 10000) { if (memcmp(signature, signature_10k_correct, 64) != 0) ERROR("Curvesig signature 10K doesn't match %d\n", count); } if (count == 100000) print_bytes("100K curvesigs", signature, 64); if (count == 1000000) print_bytes("1M curvesigs", signature, 64); if (count == 10000000) print_bytes("10M curvesigs", signature, 64); } INFO("good\n"); return 0; } int xeddsa_slow_test(int silent, int iterations) { unsigned char signature_10k_correct[64] = { 0x15, 0x29, 0x03, 0x38, 0x66, 0x16, 0xcd, 0x26, 0xbb, 0x3e, 0xec, 0xe2, 0x9f, 0x72, 0xa2, 0x5c, 0x7d, 0x05, 0xc9, 0xcb, 0x84, 0x3f, 0x92, 0x96, 0xb3, 0xfb, 0xb9, 0xdd, 0xd6, 0xed, 0x99, 0x04, 0xc1, 0xa8, 0x02, 0x16, 0xcf, 0x49, 0x3f, 0xf1, 0xbe, 0x69, 0xf9, 0xf1, 0xcc, 0x16, 0xd7, 0xdc, 0x6e, 0xd3, 0x78, 0xaa, 0x04, 0xeb, 0x71, 0x51, 0x9d, 0xe8, 0x7a, 0x5b, 0xd8, 0x49, 0x7b, 0x05, }; int count; const int MSG_LEN = 200; unsigned char privkey[32]; unsigned char pubkey[32]; unsigned char signature[96]; unsigned char msg[MSG_LEN]; unsigned char random[64]; memset(privkey, 0, 32); memset(pubkey, 0, 32); memset(signature, 1, 64); memset(msg, 0, MSG_LEN); memset(random, 0, 64); /* Signature random test */ INFO("Pseudorandom XEdDSA...\n"); for (count = 1; count <= iterations; count++) { unsigned char b[64]; crypto_hash_sha512(b, signature, 64); memmove(privkey, b, 32); crypto_hash_sha512(b, privkey, 32); memmove(random, b, 64); sc_clamp(privkey); curve25519_keygen(pubkey, privkey); xed25519_sign(signature, privkey, msg, MSG_LEN, random); if (xed25519_verify(signature, pubkey, msg, MSG_LEN) != 0) ERROR("XEdDSA verify failure #1 %d\n", count); if (b[63] & 1) signature[count % 64] ^= 1; else msg[count % MSG_LEN] ^= 1; if (xed25519_verify(signature, pubkey, msg, MSG_LEN) == 0) ERROR("XEdDSA verify failure #2 %d\n", count); if (count == 10000) { if (memcmp(signature, signature_10k_correct, 64) != 0) ERROR("XEDSA signature 10K doesn't match %d\n", count); } if (count == 100000) print_bytes("100K XEdDSA", signature, 64); if (count == 1000000) print_bytes("1M XEdDSA", signature, 64); if (count == 10000000) print_bytes("10M XEdDSA", signature, 64); } INFO("good\n"); return 0; } int xeddsa_to_curvesigs_slow_test(int silent, int iterations) { unsigned char signature_10k_correct[64] = { 0x33, 0x50, 0xa8, 0x68, 0xcd, 0x9e, 0x74, 0x99, 0xa3, 0x5c, 0x33, 0x75, 0x2b, 0x22, 0x03, 0xf8, 0xb5, 0x0f, 0xea, 0x8c, 0x33, 0x1c, 0x68, 0x8b, 0xbb, 0xf3, 0x31, 0xcf, 0x7c, 0x42, 0x37, 0x35, 0xa0, 0x0e, 0x15, 0xb8, 0x5d, 0x2b, 0xe1, 0xa2, 0x03, 0x77, 0x94, 0x3d, 0x13, 0x5c, 0xd4, 0x9b, 0x6a, 0x31, 0xf4, 0xdc, 0xfe, 0x24, 0xad, 0x54, 0xeb, 0xd2, 0x98, 0x47, 0xf1, 0xcc, 0xbf, 0x0d }; int count; const int MSG_LEN = 200; unsigned char privkey[32]; unsigned char pubkey[32]; unsigned char signature[96]; unsigned char msg[MSG_LEN]; unsigned char random[64]; memset(privkey, 0, 32); memset(pubkey, 0, 32); memset(signature, 2, 64); memset(msg, 0, MSG_LEN); memset(random, 0, 64); /* Signature random test */ INFO("Pseudorandom XEdDSA/Curvesigs...\n"); for (count = 1; count <= iterations; count++) { unsigned char b[64]; crypto_hash_sha512(b, signature, 64); memmove(privkey, b, 32); crypto_hash_sha512(b, privkey, 32); memmove(random, b, 64); sc_clamp(privkey); curve25519_keygen(pubkey, privkey); xed25519_sign(signature, privkey, msg, MSG_LEN, random); if (curve25519_verify(signature, pubkey, msg, MSG_LEN) != 0) ERROR("XEdDSA/Curvesigs verify failure #1 %d\n", count); if (b[63] & 1) signature[count % 64] ^= 1; else msg[count % MSG_LEN] ^= 1; if (curve25519_verify(signature, pubkey, msg, MSG_LEN) == 0) ERROR("XEdDSA/Curvesigs verify failure #2 %d\n", count); if (count == 10000) { if (memcmp(signature, signature_10k_correct, 64) != 0) ERROR("XEdDSA/Curvesigs signature 10K doesn't match %d\n", count); } if (count == 100000) print_bytes("100K XEdDSA/C", signature, 64); if (count == 1000000) print_bytes("1M XEdDSA/C", signature, 64); if (count == 10000000) print_bytes("10M XEdDSA/C", signature, 64); } INFO("good\n"); return 0; } int generalized_xveddsa_slow_test(int silent, int iterations) { unsigned char signature_10k_correct[96] = { 0x89, 0x21, 0xf5, 0x2f, 0x37, 0x72, 0x08, 0x55, 0x18, 0x9d, 0x24, 0xed, 0x86, 0xb1, 0x7a, 0x02, 0xbf, 0x29, 0x5e, 0xa7, 0x45, 0xdc, 0x80, 0x03, 0x7f, 0x4f, 0xca, 0x79, 0xe0, 0x95, 0xd0, 0xa1, 0xb5, 0x99, 0xbe, 0xbd, 0xef, 0xbe, 0xa4, 0xdc, 0x0c, 0x07, 0x6a, 0xf7, 0x7f, 0xe1, 0x1c, 0xb8, 0x18, 0x84, 0xb8, 0xb4, 0xcf, 0x38, 0x7d, 0x98, 0x37, 0xd8, 0x40, 0x23, 0x42, 0x12, 0x70, 0x06, 0xb0, 0xd1, 0x0c, 0xc0, 0x1c, 0xa6, 0x9a, 0x2f, 0xb4, 0x02, 0xd6, 0x37, 0x22, 0xe9, 0xfb, 0x00, 0x22, 0x02, 0x5a, 0xf4, 0x40, 0x43, 0xb8, 0xe9, 0xf4, 0x13, 0x44, 0x16, 0x19, 0x8d, 0x7e, 0x02, }; unsigned char signature_100k_correct[96] = { 0xc4, 0x99, 0x64, 0x1f, 0x94, 0x95, 0xf4, 0x57, 0xa0, 0xb9, 0x3d, 0xc3, 0xb5, 0x2e, 0x1e, 0xdd, 0x92, 0xf2, 0x4c, 0xb2, 0x01, 0x36, 0x3d, 0xf2, 0xea, 0x2c, 0xdc, 0x32, 0x21, 0x5f, 0xc5, 0xd2, 0xff, 0x16, 0x41, 0x71, 0x3a, 0x77, 0x79, 0xeb, 0x67, 0x20, 0xc4, 0xec, 0x39, 0xe1, 0x54, 0x2d, 0x40, 0x10, 0xf9, 0xca, 0xc5, 0x21, 0x0a, 0x47, 0x63, 0x99, 0x23, 0x04, 0x9d, 0x03, 0x1a, 0x06, 0x00, 0xb9, 0x56, 0x7e, 0xef, 0xee, 0x0b, 0x40, 0x59, 0xc1, 0x86, 0xd9, 0xa7, 0x87, 0x70, 0xec, 0x05, 0x89, 0xbe, 0x71, 0x43, 0xd1, 0xf5, 0x61, 0x5e, 0x00, 0x41, 0xde, 0x1f, 0x41, 0x2d, 0x0e, }; /* unsigned char signature_1m_correct[96] = { 0xf8, 0xb1, 0x20, 0xf2, 0x1e, 0x5c, 0xbf, 0x5f, 0xea, 0x07, 0xcb, 0xb5, 0x77, 0xb8, 0x03, 0xbc, 0xcb, 0x6d, 0xf1, 0xc1, 0xa5, 0x03, 0x05, 0x7b, 0x01, 0x63, 0x9b, 0xf9, 0xed, 0x3e, 0x57, 0x47, 0xd2, 0x5b, 0xf4, 0x7e, 0x7c, 0x45, 0xce, 0xfc, 0x06, 0xb3, 0xf4, 0x05, 0x81, 0x9f, 0x53, 0xb0, 0x18, 0xe3, 0xfa, 0xcb, 0xb2, 0x52, 0x3e, 0x57, 0xcb, 0x34, 0xcc, 0x81, 0x60, 0xb9, 0x0b, 0x04, 0x07, 0x79, 0xc0, 0x53, 0xad, 0xc4, 0x4b, 0xd0, 0xb5, 0x7d, 0x95, 0x4e, 0xbe, 0xa5, 0x75, 0x0c, 0xd4, 0xbf, 0xa7, 0xc0, 0xcf, 0xba, 0xe7, 0x7c, 0xe2, 0x90, 0xef, 0x61, 0xa9, 0x29, 0x66, 0x0d, }; unsigned char signature_10m_correct[96] = { 0xf5, 0xa4, 0xbc, 0xec, 0xc3, 0x3d, 0xd0, 0x43, 0xd2, 0x81, 0x27, 0x9e, 0xf0, 0x4c, 0xbe, 0xf3, 0x77, 0x01, 0x56, 0x41, 0x0e, 0xff, 0x0c, 0xb9, 0x66, 0xec, 0x4d, 0xe0, 0xb7, 0x25, 0x63, 0x6b, 0x5c, 0x08, 0x39, 0x80, 0x4e, 0x37, 0x1b, 0x2c, 0x46, 0x6f, 0x86, 0x99, 0x1c, 0x4e, 0x31, 0x60, 0xdb, 0x4c, 0xfe, 0xc5, 0xa2, 0x4d, 0x71, 0x2b, 0xd6, 0xd0, 0xc3, 0x98, 0x88, 0xdb, 0x0e, 0x0c, 0x68, 0x4a, 0xd3, 0xc7, 0x56, 0xac, 0x8d, 0x95, 0x7b, 0xbd, 0x99, 0x50, 0xe8, 0xd3, 0xea, 0xf3, 0x7b, 0x26, 0xf2, 0xa2, 0x2b, 0x02, 0x58, 0xca, 0xbd, 0x2c, 0x2b, 0xf7, 0x77, 0x58, 0xfe, 0x09, }; */ int count; const int MSG_LEN = 200; unsigned char privkey[32]; unsigned char pubkey[32]; unsigned char signature[96]; unsigned char msg[MSG_LEN]; unsigned char random[64]; unsigned char vrf_out[32]; memset(privkey, 0, 32); memset(pubkey, 0, 32); memset(signature, 3, 96); memset(msg, 0, MSG_LEN); memset(random, 0, 64); INFO("Pseudorandom XVEdDSA...\n"); for (count = 1; count <= iterations; count++) { unsigned char b[64]; crypto_hash_sha512(b, signature, 96); memmove(privkey, b, 32); crypto_hash_sha512(b, privkey, 32); memmove(random, b, 64); sc_clamp(privkey); curve25519_keygen(pubkey, privkey); generalized_xveddsa_25519_sign(signature, privkey, msg, MSG_LEN, random, NULL, 0); if (generalized_xveddsa_25519_verify(vrf_out, signature, pubkey, msg, MSG_LEN, NULL, 0) != 0) ERROR("XVEdDSA verify failure #1 %d\n", count); if (b[63] & 1) signature[count % 96] ^= 1; else msg[count % MSG_LEN] ^= 1; if (generalized_xveddsa_25519_verify(vrf_out, signature, pubkey, msg, MSG_LEN, NULL, 0) == 0) ERROR("XVEdDSA verify failure #2 %d\n", count); if (count == 10000) print_bytes("10K XVEdDSA", signature, 96); if (count == 100000) print_bytes("100K XVEdDSA", signature, 96); if (count == 1000000) print_bytes("1M XVEdDSA", signature, 96); if (count == 10000000) print_bytes("10M XVEdDSA", signature, 96); if (count == 100000000) print_bytes("100M XVEdDSA", signature, 96); if (count == 10000) { if (memcmp(signature, signature_10k_correct, 96) != 0) ERROR("XVEDDSA 10K doesn't match %d\n", count); } if (count == 100000) { if (memcmp(signature, signature_100k_correct, 96) != 0) ERROR("XVEDDSA 100K doesn't match %d\n", count); } /* if (count == 1000000) { if (memcmp(signature, signature_1m_correct, 96) != 0) ERROR("XVEDDSA 1m doesn't match %d\n", count); } if (count == 10000000) { if (memcmp(signature, signature_10m_correct, 96) != 0) ERROR("XVEDDSA 10m doesn't match %d\n", count); } if (count == 100000000) { if (memcmp(signature, signature_100m_correct, 96) != 0) ERROR("XVEDDSA 100m doesn't match %d\n", count); } */ } INFO("good\n"); return 0; } libsignal-protocol-c-2.3.3/src/curve25519/ed25519/tests/internal_slow_tests.h000066400000000000000000000010341363751346500265110ustar00rootroot00000000000000#ifndef __INTERNAL_SLOW_TESTS_H__ #define __INTERNAL_SLOW_TESTS_H__ /* silent = 0 : prints info+error messages to stdout, abort() on test failure * silent = 1 : returns 0 for success, anything else for failure * iterations : hardcoded known-good values are at 10000, so run at least this many */ int curvesigs_slow_test(int silent, int iterations); int xeddsa_slow_test(int silent, int iterations); int xeddsa_to_curvesigs_slow_test(int silent, int iterations); int generalized_xveddsa_slow_test(int silent, int iterations); #endif libsignal-protocol-c-2.3.3/src/device_consistency.c000066400000000000000000000503451363751346500224010ustar00rootroot00000000000000#include "device_consistency.h" #include #include #include "signal_protocol_internal.h" #include "curve.h" #include "WhisperTextProtocol.pb-c.h" #include "signal_utarray.h" #define CODE_VERSION 0 struct device_consistency_signature { signal_type_base base; signal_buffer *signature; signal_buffer *vrf_output; }; struct device_consistency_commitment { signal_type_base base; uint32_t generation; signal_buffer *serialized; }; struct device_consistency_message { signal_type_base base; device_consistency_signature *signature; uint32_t generation; signal_buffer *serialized; }; struct device_consistency_signature_list { UT_array *values; }; static int device_consistency_message_create(device_consistency_message **message); static void device_consistency_signature_list_sort(device_consistency_signature_list *list); /*------------------------------------------------------------------------*/ int device_consistency_signature_create(device_consistency_signature **signature, const uint8_t *signature_data, size_t signature_len, const uint8_t *vrf_output_data, size_t vrf_output_len) { int result = 0; device_consistency_signature *result_signature = 0; result_signature = malloc(sizeof(device_consistency_signature)); if(!result_signature) { result = SG_ERR_NOMEM; goto complete; } memset(result_signature, 0, sizeof(device_consistency_signature)); SIGNAL_INIT(result_signature, device_consistency_signature_destroy); result_signature->signature = signal_buffer_create(signature_data, signature_len); if(!result_signature->signature) { result = SG_ERR_NOMEM; goto complete; } result_signature->vrf_output = signal_buffer_create(vrf_output_data, vrf_output_len); if(!result_signature->vrf_output) { result = SG_ERR_NOMEM; goto complete; } complete: if(result >= 0) { *signature = result_signature; } else { SIGNAL_UNREF(result_signature); } return result; } signal_buffer *device_consistency_signature_get_signature(const device_consistency_signature *signature) { assert(signature); return signature->signature; } signal_buffer *device_consistency_signature_get_vrf_output(const device_consistency_signature *signature) { assert(signature); return signature->vrf_output; } void device_consistency_signature_destroy(signal_type_base *type) { device_consistency_signature *signature = (device_consistency_signature *)type; signal_buffer_free(signature->signature); signal_buffer_free(signature->vrf_output); free(signature); } /*------------------------------------------------------------------------*/ int device_consistency_commitment_create(device_consistency_commitment **commitment, uint32_t generation, ec_public_key_list *identity_key_list, signal_context *global_context) { static const char version[] = "DeviceConsistencyCommitment_V0"; int result = 0; void *digest_context = 0; device_consistency_commitment *result_commitment = 0; ec_public_key_list *sorted_list = 0; uint8_t gen_data[4]; unsigned int list_size; unsigned int i; result_commitment = malloc(sizeof(device_consistency_commitment)); if(!result_commitment) { result = SG_ERR_NOMEM; goto complete; } memset(result_commitment, 0, sizeof(device_consistency_commitment)); SIGNAL_INIT(result_commitment, device_consistency_commitment_destroy); sorted_list = ec_public_key_list_copy(identity_key_list); if(!sorted_list) { result = SG_ERR_NOMEM; goto complete; } ec_public_key_list_sort(sorted_list); result = signal_sha512_digest_init(global_context, &digest_context); if(result < 0) { goto complete; } result = signal_sha512_digest_update(global_context, digest_context, (uint8_t *)version, sizeof(version) - 1); if(result < 0) { goto complete; } gen_data[3] = (uint8_t)(generation); gen_data[2] = (uint8_t)(generation >> 8); gen_data[1] = (uint8_t)(generation >> 16); gen_data[0] = (uint8_t)(generation >> 24); result = signal_sha512_digest_update(global_context, digest_context, gen_data, sizeof(gen_data)); if(result < 0) { goto complete; } list_size = ec_public_key_list_size(sorted_list); for(i = 0; i < list_size; i++) { signal_buffer *key_buffer = 0; ec_public_key *key = ec_public_key_list_at(sorted_list, i); result = ec_public_key_serialize(&key_buffer, key); if(result < 0) { goto complete; } result = signal_sha512_digest_update(global_context, digest_context, signal_buffer_data(key_buffer), signal_buffer_len(key_buffer)); signal_buffer_free(key_buffer); if(result < 0) { goto complete; } } result_commitment->generation = generation; result = signal_sha512_digest_final(global_context, digest_context, &result_commitment->serialized); complete: if(sorted_list) { ec_public_key_list_free(sorted_list); } if(digest_context) { signal_sha512_digest_cleanup(global_context, digest_context); } if(result >= 0) { *commitment = result_commitment; } else { SIGNAL_UNREF(result_commitment); } return result; } uint32_t device_consistency_commitment_get_generation(const device_consistency_commitment *commitment) { assert(commitment); return commitment->generation; } signal_buffer *device_consistency_commitment_get_serialized(const device_consistency_commitment *commitment) { assert(commitment); return commitment->serialized; } void device_consistency_commitment_destroy(signal_type_base *type) { device_consistency_commitment *commitment = (device_consistency_commitment *)type; signal_buffer_free(commitment->serialized); free(commitment); } /*------------------------------------------------------------------------*/ int device_consistency_message_create(device_consistency_message **message) { int result = 0; device_consistency_message *result_message = 0; result_message = malloc(sizeof(device_consistency_message)); if(!result_message) { result = SG_ERR_NOMEM; goto complete; } memset(result_message, 0, sizeof(device_consistency_message)); SIGNAL_INIT(result_message, device_consistency_message_destroy); complete: if(result >= 0) { *message = result_message; } return result; } int device_consistency_message_create_from_pair(device_consistency_message **message, device_consistency_commitment *commitment, ec_key_pair *identity_key_pair, signal_context *global_context) { int result = 0; device_consistency_message *result_message = 0; signal_buffer *commitment_buffer = 0; signal_buffer *signature_buffer = 0; signal_buffer *vrf_output_buffer = 0; signal_buffer *serialized_signature_buffer = 0; Textsecure__DeviceConsistencyCodeMessage message_structure = TEXTSECURE__DEVICE_CONSISTENCY_CODE_MESSAGE__INIT; size_t len = 0; uint8_t *data = 0; size_t result_size = 0; /* Create message instance */ result = device_consistency_message_create(&result_message); if(result < 0) { goto complete; } /* Calculate VRF signature */ commitment_buffer = device_consistency_commitment_get_serialized(commitment); result = curve_calculate_vrf_signature(global_context, &signature_buffer, ec_key_pair_get_private(identity_key_pair), signal_buffer_data(commitment_buffer), signal_buffer_len(commitment_buffer)); if(result < 0) { goto complete; } /* Verify VRF signature */ result = curve_verify_vrf_signature(global_context, &vrf_output_buffer, ec_key_pair_get_public(identity_key_pair), signal_buffer_data(commitment_buffer), signal_buffer_len(commitment_buffer), signal_buffer_data(signature_buffer), signal_buffer_len(signature_buffer)); if(result < 0) { goto complete; } result_message->generation = device_consistency_commitment_get_generation(commitment); /* Create and assign the signature */ result = device_consistency_signature_create(&result_message->signature, signal_buffer_data(signature_buffer), signal_buffer_len(signature_buffer), signal_buffer_data(vrf_output_buffer), signal_buffer_len(vrf_output_buffer)); if(result < 0) { goto complete; } serialized_signature_buffer = device_consistency_signature_get_signature(result_message->signature); /* Serialize the message */ message_structure.generation = device_consistency_commitment_get_generation(commitment); message_structure.has_generation = 1; message_structure.signature.data = signal_buffer_data(serialized_signature_buffer); message_structure.signature.len = signal_buffer_len(serialized_signature_buffer); message_structure.has_signature = 1; len = textsecure__device_consistency_code_message__get_packed_size(&message_structure); result_message->serialized = signal_buffer_alloc(len); if(!result_message->serialized) { result = SG_ERR_NOMEM; goto complete; } data = signal_buffer_data(result_message->serialized); result_size = textsecure__device_consistency_code_message__pack(&message_structure, data); if(result_size != len) { result = SG_ERR_INVALID_PROTO_BUF; goto complete; } complete: signal_buffer_free(signature_buffer); signal_buffer_free(vrf_output_buffer); if(result >= 0) { *message = result_message; } else { SIGNAL_UNREF(result_message); } if(result == SG_ERR_INVALID_KEY || result == SG_ERR_VRF_SIG_VERIF_FAILED) { result = SG_ERR_UNKNOWN; } return result; } int device_consistency_message_create_from_serialized(device_consistency_message **message, device_consistency_commitment *commitment, const uint8_t *serialized_data, size_t serialized_len, ec_public_key *identity_key, signal_context *global_context) { int result = 0; device_consistency_message *result_message = 0; Textsecure__DeviceConsistencyCodeMessage *message_structure = 0; signal_buffer *commitment_buffer = 0; signal_buffer *vrf_output_buffer = 0; /* Create message instance */ result = device_consistency_message_create(&result_message); if(result < 0) { goto complete; } /* Deserialize the message */ message_structure = textsecure__device_consistency_code_message__unpack(0, serialized_len, serialized_data); if(!message_structure) { result = SG_ERR_INVALID_PROTO_BUF; goto complete; } if(!message_structure->has_generation || !message_structure->has_signature) { result = SG_ERR_INVALID_PROTO_BUF; goto complete; } /* Verify VRF signature */ commitment_buffer = device_consistency_commitment_get_serialized(commitment); result = curve_verify_vrf_signature(global_context, &vrf_output_buffer, identity_key, signal_buffer_data(commitment_buffer), signal_buffer_len(commitment_buffer), message_structure->signature.data, message_structure->signature.len); if(result < 0) { goto complete; } /* Assign the message fields */ result_message->generation = message_structure->generation; result = device_consistency_signature_create(&result_message->signature, message_structure->signature.data, message_structure->signature.len, signal_buffer_data(vrf_output_buffer), signal_buffer_len(vrf_output_buffer)); if(result < 0) { goto complete; } result_message->serialized = signal_buffer_create(serialized_data, serialized_len); if(!result_message->serialized) { result = SG_ERR_NOMEM; } complete: if(message_structure) { textsecure__device_consistency_code_message__free_unpacked(message_structure, 0); } signal_buffer_free(vrf_output_buffer); if(result >= 0) { *message = result_message; } else { SIGNAL_UNREF(result_message); } if(result == SG_ERR_INVALID_PROTO_BUF || result == SG_ERR_INVALID_KEY || result == SG_ERR_VRF_SIG_VERIF_FAILED) { result = SG_ERR_INVALID_MESSAGE; } return result; } signal_buffer *device_consistency_message_get_serialized(const device_consistency_message *message) { assert(message); return message->serialized; } device_consistency_signature *device_consistency_message_get_signature(const device_consistency_message *message) { assert(message); return message->signature; } uint32_t device_consistency_signature_get_generation(const device_consistency_message *message) { assert(message); return message->generation; } void device_consistency_message_destroy(signal_type_base *type) { device_consistency_message *message = (device_consistency_message *)type; SIGNAL_UNREF(message->signature); signal_buffer_free(message->serialized); free(message); } /*------------------------------------------------------------------------*/ int device_consistency_code_generate_for(device_consistency_commitment *commitment, device_consistency_signature_list *signatures, char **code_string, signal_context *global_context) { int result = 0; char *result_string = 0; void *digest_context = 0; device_consistency_signature_list *sorted_list = 0; uint8_t version_data[2]; signal_buffer *commitment_buffer; unsigned int list_size; unsigned int i; signal_buffer *hash_buffer = 0; uint8_t *data = 0; size_t len = 0; char *encoded_string = 0; sorted_list = device_consistency_signature_list_copy(signatures); if(!sorted_list) { result = SG_ERR_NOMEM; goto complete; } device_consistency_signature_list_sort(sorted_list); result = signal_sha512_digest_init(global_context, &digest_context); if(result < 0) { goto complete; } version_data[1] = (uint8_t)(CODE_VERSION); version_data[0] = (uint8_t)(CODE_VERSION >> 8); result = signal_sha512_digest_update(global_context, digest_context, version_data, sizeof(version_data)); if(result < 0) { goto complete; } commitment_buffer = device_consistency_commitment_get_serialized(commitment); result = signal_sha512_digest_update(global_context, digest_context, signal_buffer_data(commitment_buffer), signal_buffer_len(commitment_buffer)); if(result < 0) { goto complete; } list_size = device_consistency_signature_list_size(sorted_list); for(i = 0; i < list_size; i++) { device_consistency_signature *signature = device_consistency_signature_list_at(sorted_list, i); signal_buffer *vrf_output = device_consistency_signature_get_vrf_output(signature); result = signal_sha512_digest_update(global_context, digest_context, signal_buffer_data(vrf_output), signal_buffer_len(vrf_output)); if(result < 0) { goto complete; } } result = signal_sha512_digest_final(global_context, digest_context, &hash_buffer); if(result < 0) { goto complete; } data = signal_buffer_data(hash_buffer); len = signal_buffer_len(hash_buffer); if(len < 10) { result = SG_ERR_UNKNOWN; goto complete; } encoded_string = malloc(11); if(!encoded_string) { result = SG_ERR_NOMEM; goto complete; } for(i = 0; i < 10; i += 5) { uint64_t chunk = ((uint64_t)data[i] & 0xFFL) << 32 | ((uint64_t)data[i + 1] & 0xFFL) << 24 | ((uint64_t)data[i + 2] & 0xFFL) << 16 | ((uint64_t)data[i + 3] & 0xFFL) << 8 | ((uint64_t)data[i + 4] & 0xFFL); #if _WINDOWS sprintf_s(encoded_string + i, 6, "%05d", (int)(chunk % 100000)); #else snprintf(encoded_string + i, 6, "%05d", (int)(chunk % 100000)); #endif } result_string = malloc(7); if(!result_string) { result = SG_ERR_NOMEM; goto complete; } memcpy(result_string, encoded_string, 6); result_string[6] = '\0'; complete: if(sorted_list) { device_consistency_signature_list_free(sorted_list); } if(digest_context) { signal_sha512_digest_cleanup(global_context, digest_context); } signal_buffer_free(hash_buffer); free(encoded_string); if(result >= 0) { *code_string = result_string; } return result; } /*------------------------------------------------------------------------*/ device_consistency_signature_list *device_consistency_signature_list_alloc() { int result = 0; device_consistency_signature_list *list = malloc(sizeof(device_consistency_signature_list)); if(!list) { result = SG_ERR_NOMEM; goto complete; } memset(list, 0, sizeof(device_consistency_signature_list)); utarray_new(list->values, &ut_ptr_icd); complete: if(result < 0) { if(list) { free(list); } return 0; } else { return list; } } device_consistency_signature_list *device_consistency_signature_list_copy(const device_consistency_signature_list *list) { int result = 0; device_consistency_signature_list *result_list = 0; unsigned int size; unsigned int i; device_consistency_signature **p; result_list = device_consistency_signature_list_alloc(); if(!result_list) { result = SG_ERR_NOMEM; goto complete; } size = utarray_len(list->values); utarray_reserve(result_list->values, size); for (i = 0; i < size; i++) { p = (device_consistency_signature **)utarray_eltptr(list->values, i); result = device_consistency_signature_list_push_back(result_list, *p); if(result < 0) { goto complete; } } complete: if(result < 0) { if(result_list) { device_consistency_signature_list_free(result_list); } return 0; } else { return result_list; } } int device_consistency_signature_list_push_back(device_consistency_signature_list *list, device_consistency_signature *value) { int result = 0; assert(list); assert(value); utarray_push_back(list->values, &value); SIGNAL_REF(value); complete: return result; } unsigned int device_consistency_signature_list_size(const device_consistency_signature_list *list) { assert(list); return utarray_len(list->values); } device_consistency_signature *device_consistency_signature_list_at(const device_consistency_signature_list *list, unsigned int index) { device_consistency_signature **value = 0; assert(list); assert(index < utarray_len(list->values)); value = (device_consistency_signature **)utarray_eltptr(list->values, index); assert(*value); return *value; } int device_consistency_signature_list_sort_comparator(const void *a, const void *b) { int result; const device_consistency_signature *sig1 = *((const device_consistency_signature **)a); const device_consistency_signature *sig2 = *((const device_consistency_signature **)b); signal_buffer *buf1 = device_consistency_signature_get_vrf_output(sig1); signal_buffer *buf2 = device_consistency_signature_get_vrf_output(sig2); size_t len1 = signal_buffer_len(buf1); size_t len2 = signal_buffer_len(buf2); if(len1 == len2) { result = memcmp(signal_buffer_data(buf1), signal_buffer_data(buf2), len1); } else if (len1 < len2) { result = -1; } else { result = 1; } return result; } void device_consistency_signature_list_sort(device_consistency_signature_list *list) { assert(list); utarray_sort(list->values, device_consistency_signature_list_sort_comparator); } void device_consistency_signature_list_free(device_consistency_signature_list *list) { unsigned int size; unsigned int i; device_consistency_signature **p; if(list) { size = utarray_len(list->values); for (i = 0; i < size; i++) { p = (device_consistency_signature **)utarray_eltptr(list->values, i); SIGNAL_UNREF(*p); } utarray_free(list->values); free(list); } } libsignal-protocol-c-2.3.3/src/device_consistency.h000066400000000000000000000055401363751346500224030ustar00rootroot00000000000000#ifndef DEVICE_CONSISTENCY_H #define DEVICE_CONSISTENCY_H #include "signal_protocol_types.h" #ifdef __cplusplus extern "C" { #endif int device_consistency_signature_create(device_consistency_signature **signature, const uint8_t *signature_data, size_t signature_len, const uint8_t *vrf_output_data, size_t vrf_output_len); signal_buffer *device_consistency_signature_get_signature(const device_consistency_signature *signature); signal_buffer *device_consistency_signature_get_vrf_output(const device_consistency_signature *signature); void device_consistency_signature_destroy(signal_type_base *type); int device_consistency_commitment_create(device_consistency_commitment **commitment, uint32_t generation, ec_public_key_list *identity_key_list, signal_context *global_context); uint32_t device_consistency_commitment_get_generation(const device_consistency_commitment *commitment); signal_buffer *device_consistency_commitment_get_serialized(const device_consistency_commitment *commitment); void device_consistency_commitment_destroy(signal_type_base *type); int device_consistency_message_create_from_pair(device_consistency_message **message, device_consistency_commitment *commitment, ec_key_pair *identity_key_pair, signal_context *global_context); int device_consistency_message_create_from_serialized(device_consistency_message **message, device_consistency_commitment *commitment, const uint8_t *serialized_data, size_t serialized_len, ec_public_key *identity_key, signal_context *global_context); signal_buffer *device_consistency_message_get_serialized(const device_consistency_message *message); device_consistency_signature *device_consistency_message_get_signature(const device_consistency_message *message); uint32_t device_consistency_signature_get_generation(const device_consistency_message *message); void device_consistency_message_destroy(signal_type_base *type); int device_consistency_code_generate_for(device_consistency_commitment *commitment, device_consistency_signature_list *signatures, char **code_string, signal_context *global_context); device_consistency_signature_list *device_consistency_signature_list_alloc(void); device_consistency_signature_list *device_consistency_signature_list_copy(const device_consistency_signature_list *list); int device_consistency_signature_list_push_back(device_consistency_signature_list *list, device_consistency_signature *value); unsigned int device_consistency_signature_list_size(const device_consistency_signature_list *list); device_consistency_signature *device_consistency_signature_list_at(const device_consistency_signature_list *list, unsigned int index); void device_consistency_signature_list_free(device_consistency_signature_list *list); #ifdef __cplusplus } #endif #endif /* DEVICE_CONSISTENCY_H */ libsignal-protocol-c-2.3.3/src/fingerprint.c000066400000000000000000000625321363751346500210510ustar00rootroot00000000000000#include "fingerprint.h" #include #include #include "FingerprintProtocol.pb-c.h" #include "signal_protocol_internal.h" #include "vpool.h" #define FINGERPRINT_VERSION 0 #define FINGERPRINT_LENGTH 30 #define MAX(a,b) (((a)>(b))?(a):(b)) struct fingerprint { signal_type_base base; displayable_fingerprint *displayable; scannable_fingerprint *scannable; }; struct displayable_fingerprint { signal_type_base base; char *local_fingerprint; char *remote_fingerprint; char *display_text; }; struct scannable_fingerprint { signal_type_base base; uint32_t version; char *local_stable_identifier; signal_buffer *local_fingerprint; char *remote_stable_identifier; signal_buffer *remote_fingerprint; }; struct fingerprint_generator { int iterations; int scannable_version; signal_context *global_context; }; static int fingerprint_generator_get_logical_key_bytes(signal_buffer **key_bytes, const ec_public_key_list *unsorted_key_list); static int fingerprint_generator_create_for_impl(fingerprint_generator *generator, const char *local_stable_identifier, const signal_buffer *local_identity_buffer, const char *remote_stable_identifier, const signal_buffer *remote_identity_buffer, fingerprint **fingerprint_val); static int fingerprint_generator_get_fingerprint(fingerprint_generator *generator, signal_buffer **fingerprint_buffer, const char *stable_identifier, const signal_buffer *identity_buffer); static int fingerprint_generator_create_display_string(fingerprint_generator *generator, char **display_string, signal_buffer *fingerprint_buffer); int fingerprint_generator_create(fingerprint_generator **generator, int iterations, int scannable_version, signal_context *global_context) { fingerprint_generator *result_generator; assert(global_context); if(scannable_version < 0 || scannable_version > 1) { return SG_ERR_INVAL; } result_generator = malloc(sizeof(fingerprint_generator)); if(!result_generator) { return SG_ERR_NOMEM; } memset(result_generator, 0, sizeof(fingerprint_generator)); result_generator->iterations = iterations; result_generator->scannable_version = scannable_version; result_generator->global_context = global_context; *generator = result_generator; return 0; } int fingerprint_generator_create_for(fingerprint_generator *generator, const char *local_stable_identifier, const ec_public_key *local_identity_key, const char *remote_stable_identifier, const ec_public_key *remote_identity_key, fingerprint **fingerprint_val) { int result = 0; signal_buffer *local_key_buffer = 0; signal_buffer *remote_key_buffer = 0; result = ec_public_key_serialize(&local_key_buffer, local_identity_key); if(result < 0) { goto complete; } result = ec_public_key_serialize(&remote_key_buffer, remote_identity_key); if(result < 0) { goto complete; } result = fingerprint_generator_create_for_impl(generator, local_stable_identifier, local_key_buffer, remote_stable_identifier, remote_key_buffer, fingerprint_val); complete: signal_buffer_free(local_key_buffer); signal_buffer_free(remote_key_buffer); return result; } int fingerprint_generator_create_for_list(fingerprint_generator *generator, const char *local_stable_identifier, const ec_public_key_list *local_identity_key_list, const char *remote_stable_identifier, const ec_public_key_list *remote_identity_key_list, fingerprint **fingerprint_val) { int result = 0; signal_buffer *local_key_buffer = 0; signal_buffer *remote_key_buffer = 0; result = fingerprint_generator_get_logical_key_bytes(&local_key_buffer, local_identity_key_list); if(result < 0) { goto complete; } result = fingerprint_generator_get_logical_key_bytes(&remote_key_buffer, remote_identity_key_list); if(result < 0) { goto complete; } result = fingerprint_generator_create_for_impl(generator, local_stable_identifier, local_key_buffer, remote_stable_identifier, remote_key_buffer, fingerprint_val); complete: signal_buffer_free(local_key_buffer); signal_buffer_free(remote_key_buffer); return result; } int fingerprint_generator_create_for_impl(fingerprint_generator *generator, const char *local_stable_identifier, const signal_buffer *local_identity_buffer, const char *remote_stable_identifier, const signal_buffer *remote_identity_buffer, fingerprint **fingerprint_val) { int result = 0; fingerprint *result_fingerprint = 0; signal_buffer *local_fingerprint_buffer = 0; signal_buffer *remote_fingerprint_buffer = 0; displayable_fingerprint *displayable = 0; char *displayable_local = 0; char *displayable_remote = 0; scannable_fingerprint *scannable = 0; result = fingerprint_generator_get_fingerprint(generator, &local_fingerprint_buffer, local_stable_identifier, local_identity_buffer); if(result < 0) { goto complete; } result = fingerprint_generator_get_fingerprint(generator, &remote_fingerprint_buffer, remote_stable_identifier, remote_identity_buffer); if(result < 0) { goto complete; } result = fingerprint_generator_create_display_string(generator, &displayable_local, local_fingerprint_buffer); if(result < 0) { goto complete; } result = fingerprint_generator_create_display_string(generator, &displayable_remote, remote_fingerprint_buffer); if(result < 0) { goto complete; } result = displayable_fingerprint_create(&displayable, displayable_local, displayable_remote); if(result < 0) { goto complete; } if(generator->scannable_version == 0) { result = scannable_fingerprint_create(&scannable, 0, local_stable_identifier, local_identity_buffer, remote_stable_identifier, remote_identity_buffer); } else if(generator->scannable_version == 1) { result = scannable_fingerprint_create(&scannable, 1, 0, local_fingerprint_buffer, 0, remote_fingerprint_buffer); } else { result = SG_ERR_INVAL; } if(result < 0) { goto complete; } result = fingerprint_create(&result_fingerprint, displayable, scannable); complete: signal_buffer_free(local_fingerprint_buffer); signal_buffer_free(remote_fingerprint_buffer); if(displayable_local) { free(displayable_local); } if(displayable_remote) { free(displayable_remote); } SIGNAL_UNREF(displayable); SIGNAL_UNREF(scannable); if(result >= 0) { *fingerprint_val = result_fingerprint; } return result; } int fingerprint_generator_get_logical_key_bytes(signal_buffer **key_bytes, const ec_public_key_list *unsorted_key_list) { int result = 0; ec_public_key_list *sorted_key_list = 0; ec_public_key *key_element = 0; unsigned int list_size = 0; unsigned int i = 0; struct vpool vp; signal_buffer *buffer = 0; vpool_init(&vp, 1024, 0); sorted_key_list = ec_public_key_list_copy(unsorted_key_list); if(!sorted_key_list) { result = SG_ERR_NOMEM; goto complete; } ec_public_key_list_sort(sorted_key_list); list_size = ec_public_key_list_size(sorted_key_list); for(i = 0; i < list_size; i++) { key_element = ec_public_key_list_at(sorted_key_list, i); result = ec_public_key_serialize(&buffer, key_element); if (result < 0) { goto complete; } if(!vpool_insert(&vp, vpool_get_length(&vp), signal_buffer_data(buffer), signal_buffer_len(buffer))) { result = SG_ERR_NOMEM; goto complete; } signal_buffer_free(buffer); buffer = 0; } buffer = signal_buffer_create(vpool_get_buf(&vp), vpool_get_length(&vp)); if(!buffer) { result = SG_ERR_NOMEM; goto complete; } complete: ec_public_key_list_free(sorted_key_list); vpool_final(&vp); if(result >= 0) { *key_bytes = buffer; } else { signal_buffer_free(buffer); } return result; } int fingerprint_generator_get_fingerprint(fingerprint_generator *generator, signal_buffer **fingerprint_buffer, const char *stable_identifier, const signal_buffer *identity_buffer) { int result = 0; void *digest_context = 0; signal_buffer *hash_buffer = 0; signal_buffer *hash_out_buffer = 0; uint8_t *data = 0; size_t len = 0; int i = 0; assert(generator); assert(stable_identifier); assert(identity_buffer); result = signal_sha512_digest_init(generator->global_context, &digest_context); if(result < 0) { goto complete; } len = 2 + signal_buffer_len(identity_buffer) + strlen(stable_identifier); hash_buffer = signal_buffer_alloc(len); if(!hash_buffer) { result = SG_ERR_NOMEM; goto complete; } data = signal_buffer_data(hash_buffer); memset(data, 0, len); data[0] = 0; data[1] = (uint8_t)FINGERPRINT_VERSION; memcpy(data + 2, signal_buffer_const_data(identity_buffer), signal_buffer_len(identity_buffer)); memcpy(data + 2 + signal_buffer_len(identity_buffer), stable_identifier, strlen(stable_identifier)); for(i = 0; i < generator->iterations; i++) { data = signal_buffer_data(hash_buffer); len = signal_buffer_len(hash_buffer); result = signal_sha512_digest_update(generator->global_context, digest_context, data, len); if(result < 0) { goto complete; } result = signal_sha512_digest_update(generator->global_context, digest_context, signal_buffer_const_data(identity_buffer), signal_buffer_len(identity_buffer)); if(result < 0) { goto complete; } result = signal_sha512_digest_final(generator->global_context, digest_context, &hash_out_buffer); if(result < 0) { goto complete; } signal_buffer_free(hash_buffer); hash_buffer = hash_out_buffer; hash_out_buffer = 0; } len = signal_buffer_len(hash_buffer); if(len < FINGERPRINT_LENGTH) { result = SG_ERR_UNKNOWN; goto complete; } complete: if(digest_context) { signal_sha512_digest_cleanup(generator->global_context, digest_context); } if(result >= 0) { *fingerprint_buffer = hash_buffer; } else { signal_buffer_free(hash_buffer); } return result; } int fingerprint_generator_create_display_string(fingerprint_generator *generator, char **display_string, signal_buffer *fingerprint_buffer) { int result = 0; char *result_string = 0; uint8_t *data = 0; size_t len = 0; int i = 0; assert(generator); assert(fingerprint_buffer); data = signal_buffer_data(fingerprint_buffer); len = signal_buffer_len(fingerprint_buffer); if(len < FINGERPRINT_LENGTH) { result = SG_ERR_UNKNOWN; goto complete; } result_string = malloc(FINGERPRINT_LENGTH+1); if(!result_string) { result = SG_ERR_NOMEM; goto complete; } for(i = 0; i < FINGERPRINT_LENGTH; i += 5) { uint64_t chunk = ((uint64_t)data[i] & 0xFFL) << 32 | ((uint64_t)data[i + 1] & 0xFFL) << 24 | ((uint64_t)data[i + 2] & 0xFFL) << 16 | ((uint64_t)data[i + 3] & 0xFFL) << 8 | ((uint64_t)data[i + 4] & 0xFFL); #if _WINDOWS sprintf_s(result_string + i, 6, "%05d", (int)(chunk % 100000)); #else snprintf(result_string + i, 6, "%05d", (int)(chunk % 100000)); #endif } complete: if(result >= 0) { *display_string = result_string; } return result; } void fingerprint_generator_free(fingerprint_generator *generator) { if(generator) { free(generator); } } int fingerprint_create(fingerprint **fingerprint_val, displayable_fingerprint *displayable, scannable_fingerprint *scannable) { fingerprint *result = malloc(sizeof(fingerprint)); if(!result) { return SG_ERR_NOMEM; } memset(result, 0, sizeof(fingerprint)); SIGNAL_INIT(result, fingerprint_destroy); if(displayable) { result->displayable = displayable; SIGNAL_REF(displayable); } if(scannable) { result->scannable = scannable; SIGNAL_REF(scannable); } *fingerprint_val = result; return 0; } displayable_fingerprint *fingerprint_get_displayable(const fingerprint *fingerprint_val) { assert(fingerprint_val); return fingerprint_val->displayable; } scannable_fingerprint *fingerprint_get_scannable(const fingerprint *fingerprint_val) { assert(fingerprint_val); return fingerprint_val->scannable; } void fingerprint_destroy(signal_type_base *type) { fingerprint *fingerprint_val = (fingerprint *)type; SIGNAL_UNREF(fingerprint_val->displayable); SIGNAL_UNREF(fingerprint_val->scannable); free(fingerprint_val); } int displayable_fingerprint_create(displayable_fingerprint **displayable, const char *local_fingerprint, const char *remote_fingerprint) { int result = 0; size_t local_len = 0; size_t remote_len = 0; displayable_fingerprint *result_displayable = 0; char *display_text = 0; if(!local_fingerprint || !remote_fingerprint) { return SG_ERR_INVAL; } result_displayable = malloc(sizeof(displayable_fingerprint)); if(!result_displayable) { return SG_ERR_NOMEM; } memset(result_displayable, 0, sizeof(displayable_fingerprint)); SIGNAL_INIT(result_displayable, displayable_fingerprint_destroy); result_displayable->local_fingerprint = strdup(local_fingerprint); if(!result_displayable->local_fingerprint) { result = SG_ERR_NOMEM; goto complete; } result_displayable->remote_fingerprint = strdup(remote_fingerprint); if(!result_displayable->remote_fingerprint) { result = SG_ERR_NOMEM; goto complete; } local_len = strlen(local_fingerprint); remote_len = strlen(remote_fingerprint); display_text = malloc(local_len + remote_len + 1); if(!display_text) { result = SG_ERR_NOMEM; goto complete; } if(strcmp(local_fingerprint, remote_fingerprint) <= 0) { memcpy(display_text, local_fingerprint, local_len); memcpy(display_text + local_len, remote_fingerprint, remote_len + 1); } else { memcpy(display_text, remote_fingerprint, remote_len); memcpy(display_text + remote_len, local_fingerprint, local_len + 1); } result_displayable->display_text = display_text; complete: if(result < 0) { SIGNAL_UNREF(result_displayable); } else { *displayable = result_displayable; } return result; } const char *displayable_fingerprint_local(const displayable_fingerprint *displayable) { assert(displayable); return displayable->local_fingerprint; } const char *displayable_fingerprint_remote(const displayable_fingerprint *displayable) { assert(displayable); return displayable->remote_fingerprint; } const char *displayable_fingerprint_text(const displayable_fingerprint *displayable) { assert(displayable); return displayable->display_text; } void displayable_fingerprint_destroy(signal_type_base *type) { displayable_fingerprint *displayable = (displayable_fingerprint *)type; if(displayable->local_fingerprint) { free(displayable->local_fingerprint); } if(displayable->remote_fingerprint) { free(displayable->remote_fingerprint); } if(displayable->display_text) { free(displayable->display_text); } free(displayable); } int scannable_fingerprint_create(scannable_fingerprint **scannable, uint32_t version, const char *local_stable_identifier, const signal_buffer *local_fingerprint, const char *remote_stable_identifier, const signal_buffer *remote_fingerprint) { int result = 0; scannable_fingerprint *result_scannable = 0; if(version == 0 && (!local_stable_identifier || !remote_stable_identifier)) { return SG_ERR_INVAL; } if(!local_fingerprint || !remote_fingerprint) { return SG_ERR_INVAL; } result_scannable = malloc(sizeof(scannable_fingerprint)); if(!result_scannable) { return SG_ERR_NOMEM; } memset(result_scannable, 0, sizeof(scannable_fingerprint)); SIGNAL_INIT(result_scannable, scannable_fingerprint_destroy); result_scannable->version = version; if(version == 0 && local_stable_identifier) { result_scannable->local_stable_identifier = strdup(local_stable_identifier); if(!result_scannable->local_stable_identifier) { result = SG_ERR_NOMEM; goto complete; } } if(version == 0) { result_scannable->local_fingerprint = signal_buffer_copy(local_fingerprint); } else { result_scannable->local_fingerprint = signal_buffer_n_copy(local_fingerprint, 32); } if(!result_scannable->local_fingerprint) { result = SG_ERR_NOMEM; goto complete; } if(version == 0 && remote_stable_identifier) { result_scannable->remote_stable_identifier = strdup(remote_stable_identifier); if(!result_scannable->remote_stable_identifier) { result = SG_ERR_NOMEM; goto complete; } } if(version == 0) { result_scannable->remote_fingerprint = signal_buffer_copy(remote_fingerprint); } else { result_scannable->remote_fingerprint = signal_buffer_n_copy(remote_fingerprint, 32); } if(!result_scannable->remote_fingerprint) { result = SG_ERR_NOMEM; goto complete; } complete: if(result < 0) { SIGNAL_UNREF(result_scannable); } else { *scannable = result_scannable; } return result; } int scannable_fingerprint_serialize(signal_buffer **buffer, const scannable_fingerprint *scannable) { int result = 0; size_t result_size = 0; signal_buffer *result_buf = 0; Textsecure__CombinedFingerprints combined_fingerprint = TEXTSECURE__COMBINED_FINGERPRINTS__INIT; Textsecure__LogicalFingerprint local_fingerprint = TEXTSECURE__LOGICAL_FINGERPRINT__INIT; Textsecure__LogicalFingerprint remote_fingerprint = TEXTSECURE__LOGICAL_FINGERPRINT__INIT; size_t len = 0; uint8_t *data = 0; combined_fingerprint.version = scannable->version; combined_fingerprint.has_version = 1; if(scannable->local_fingerprint) { if(scannable->version == 0 && scannable->local_stable_identifier) { signal_protocol_str_serialize_protobuf(&local_fingerprint.identifier, scannable->local_stable_identifier); local_fingerprint.has_identifier = 1; } local_fingerprint.content.data = signal_buffer_data(scannable->local_fingerprint); local_fingerprint.content.len = signal_buffer_len(scannable->local_fingerprint); local_fingerprint.has_content = 1; combined_fingerprint.localfingerprint = &local_fingerprint; } if(scannable->remote_fingerprint) { if(scannable->version == 0 && scannable->remote_stable_identifier) { signal_protocol_str_serialize_protobuf(&remote_fingerprint.identifier, scannable->remote_stable_identifier); remote_fingerprint.has_identifier = 1; } remote_fingerprint.content.data = signal_buffer_data(scannable->remote_fingerprint); remote_fingerprint.content.len = signal_buffer_len(scannable->remote_fingerprint); remote_fingerprint.has_content = 1; combined_fingerprint.remotefingerprint = &remote_fingerprint; } len = textsecure__combined_fingerprints__get_packed_size(&combined_fingerprint); result_buf = signal_buffer_alloc(len); if(!result_buf) { result = SG_ERR_NOMEM; goto complete; } data = signal_buffer_data(result_buf); result_size = textsecure__combined_fingerprints__pack(&combined_fingerprint, data); if(result_size != len) { signal_buffer_free(result_buf); result = SG_ERR_INVALID_PROTO_BUF; result_buf = 0; goto complete; } complete: if(result >= 0) { *buffer = result_buf; } return result; } int scannable_fingerprint_deserialize(scannable_fingerprint **scannable, const uint8_t *data, size_t len, signal_context *global_context) { int result = 0; Textsecure__CombinedFingerprints *combined_fingerprint = 0; uint32_t version = 0; char *local_stable_identifier = 0; signal_buffer *local_fingerprint = 0; char *remote_stable_identifier = 0; signal_buffer *remote_fingerprint = 0; combined_fingerprint = textsecure__combined_fingerprints__unpack(0, len, data); if(!combined_fingerprint) { result = SG_ERR_INVALID_PROTO_BUF; goto complete; } if(combined_fingerprint->has_version) { version = combined_fingerprint->version; } if(combined_fingerprint->localfingerprint) { if(combined_fingerprint->localfingerprint->has_identifier) { local_stable_identifier = signal_protocol_str_deserialize_protobuf(&combined_fingerprint->localfingerprint->identifier); if(!local_stable_identifier) { result = SG_ERR_NOMEM; goto complete; } } if(combined_fingerprint->localfingerprint->has_content) { local_fingerprint = signal_buffer_create( combined_fingerprint->localfingerprint->content.data, combined_fingerprint->localfingerprint->content.len); if(!local_fingerprint) { result = SG_ERR_NOMEM; goto complete; } } } if(combined_fingerprint->remotefingerprint) { if(combined_fingerprint->remotefingerprint->has_identifier) { remote_stable_identifier = signal_protocol_str_deserialize_protobuf(&combined_fingerprint->remotefingerprint->identifier); if(!remote_stable_identifier) { result = SG_ERR_NOMEM; goto complete; } } if(combined_fingerprint->remotefingerprint->has_content) { remote_fingerprint = signal_buffer_create( combined_fingerprint->remotefingerprint->content.data, combined_fingerprint->remotefingerprint->content.len); if(!remote_fingerprint) { result = SG_ERR_NOMEM; goto complete; } } } result = scannable_fingerprint_create(scannable, version, local_stable_identifier, local_fingerprint, remote_stable_identifier, remote_fingerprint); complete: if(combined_fingerprint) { textsecure__combined_fingerprints__free_unpacked(combined_fingerprint, 0); } if(local_stable_identifier) { free(local_stable_identifier); } if(remote_stable_identifier) { free(remote_stable_identifier); } signal_buffer_free(local_fingerprint); signal_buffer_free(remote_fingerprint); return result; } uint32_t scannable_fingerprint_get_version(const scannable_fingerprint *scannable) { assert(scannable); return scannable->version; } const char *scannable_fingerprint_get_local_stable_identifier(const scannable_fingerprint *scannable) { assert(scannable); return scannable->local_stable_identifier; } signal_buffer *scannable_fingerprint_get_local_fingerprint(const scannable_fingerprint *scannable) { assert(scannable); return scannable->local_fingerprint; } const char *scannable_fingerprint_get_remote_stable_identifier(const scannable_fingerprint *scannable) { assert(scannable); return scannable->remote_stable_identifier; } signal_buffer *scannable_fingerprint_get_remote_fingerprint(const scannable_fingerprint *scannable) { assert(scannable); return scannable->remote_fingerprint; } int scannable_fingerprint_compare(const scannable_fingerprint *scannable, const scannable_fingerprint *other_scannable) { if(!other_scannable->remote_fingerprint || !other_scannable->local_fingerprint || other_scannable->version != scannable->version) { return SG_ERR_FP_VERSION_MISMATCH; } if(scannable->version == 0) { if(strcmp(scannable->local_stable_identifier, other_scannable->remote_stable_identifier) != 0) { return SG_ERR_FP_IDENT_MISMATCH; } if(strcmp(scannable->remote_stable_identifier, other_scannable->local_stable_identifier) != 0) { return SG_ERR_FP_IDENT_MISMATCH; } } if(signal_buffer_compare(scannable->local_fingerprint, other_scannable->remote_fingerprint) != 0) { return 0; } if(signal_buffer_compare(scannable->remote_fingerprint, other_scannable->local_fingerprint) != 0) { return 0; } return 1; } void scannable_fingerprint_destroy(signal_type_base *type) { scannable_fingerprint *scannable = (scannable_fingerprint *)type; if(scannable->local_stable_identifier) { free(scannable->local_stable_identifier); } if(scannable->remote_stable_identifier) { free(scannable->remote_stable_identifier); } signal_buffer_free(scannable->local_fingerprint); signal_buffer_free(scannable->remote_fingerprint); free(scannable); } libsignal-protocol-c-2.3.3/src/fingerprint.h000066400000000000000000000120371363751346500210510ustar00rootroot00000000000000#ifndef FINGERPRINT_H #define FINGERPRINT_H #include "signal_protocol_types.h" #ifdef __cplusplus extern "C" { #endif /** * Construct a fingerprint generator for 60 digit numerics. * * @param generator set to a freshly allocated generator instance * @param iterations The number of internal iterations to perform in the process of * generating a fingerprint. This needs to be constant, and synchronized * across all clients. * * The higher the iteration count, the higher the security level: * - 1024 ~ 109.7 bits * - 1400 > 110 bits * - 5200 > 112 bits * @param scannable_version The format version for the scannable fingerprint (0 or 1) * @param global_context the global library context * @return 0 on success, or negative on failure */ int fingerprint_generator_create(fingerprint_generator **generator, int iterations, int scannable_version, signal_context *global_context); /** * Generate a scannable and displayble fingerprint. * * @param local_stable_identifier The client's "stable" identifier. * @param local_identity_key The client's identity key. * @param remote_stable_identifier The remote party's "stable" identifier. * @param remote_identity_key The remote party's identity key. * @param fingerprint_val Set to a freshly allocated unique fingerprint for this conversation * @return 0 on success, or negative on failure */ int fingerprint_generator_create_for(fingerprint_generator *generator, const char *local_stable_identifier, const ec_public_key *local_identity_key, const char *remote_stable_identifier, const ec_public_key *remote_identity_key, fingerprint **fingerprint_val); /** * Generate a scannable and displayble fingerprint for a list of keys * * @param local_stable_identifier The client's "stable" identifier. * @param local_identity_key_list The client's identity key list. * @param remote_stable_identifier The remote party's "stable" identifier. * @param remote_identity_key_list The remote party's identity key list. * @param fingerprint_val Set to a freshly allocated unique fingerprint for this conversation * @return 0 on success, or negative on failure */ int fingerprint_generator_create_for_list(fingerprint_generator *generator, const char *local_stable_identifier, const ec_public_key_list *local_identity_key_list, const char *remote_stable_identifier, const ec_public_key_list *remote_identity_key_list, fingerprint **fingerprint_val); void fingerprint_generator_free(fingerprint_generator *generator); int fingerprint_create(fingerprint **fingerprint_val, displayable_fingerprint *displayable, scannable_fingerprint *scannable); displayable_fingerprint *fingerprint_get_displayable(const fingerprint *fingerprint_val); scannable_fingerprint *fingerprint_get_scannable(const fingerprint *fingerprint_val); void fingerprint_destroy(signal_type_base *type); int displayable_fingerprint_create(displayable_fingerprint **displayable, const char *local_fingerprint, const char *remote_fingerprint); const char *displayable_fingerprint_local(const displayable_fingerprint *displayable); const char *displayable_fingerprint_remote(const displayable_fingerprint *displayable); const char *displayable_fingerprint_text(const displayable_fingerprint *displayable); void displayable_fingerprint_destroy(signal_type_base *type); int scannable_fingerprint_create(scannable_fingerprint **scannable, uint32_t version, const char *local_stable_identifier, const signal_buffer *local_fingerprint, const char *remote_stable_identifier, const signal_buffer *remote_fingerprint); int scannable_fingerprint_serialize(signal_buffer **buffer, const scannable_fingerprint *scannable); int scannable_fingerprint_deserialize(scannable_fingerprint **scannable, const uint8_t *data, size_t len, signal_context *global_context); uint32_t scannable_fingerprint_get_version(const scannable_fingerprint *scannable); const char *scannable_fingerprint_get_local_stable_identifier(const scannable_fingerprint *scannable); signal_buffer *scannable_fingerprint_get_local_fingerprint(const scannable_fingerprint *scannable); const char *scannable_fingerprint_get_remote_stable_identifier(const scannable_fingerprint *scannable); signal_buffer *scannable_fingerprint_get_remote_fingerprint(const scannable_fingerprint *scannable); /** * Compare a scanned QR code with what we expect. * @param scannable The local scannable data * @param other_scannable The data from the scanned code * @retval 1 if the scannable codes match * @retval 0 if the scannable codes do not match * @retval SG_ERR_FP_VERSION_MISMATCH if the scanned fingerprint is the wrong version * @retval SG_ERR_FP_IDENT_MISMATCH if the scanned fingerprint is for the wrong stable identifier */ int scannable_fingerprint_compare(const scannable_fingerprint *scannable, const scannable_fingerprint *other_scannable); void scannable_fingerprint_destroy(signal_type_base *type); #ifdef __cplusplus } #endif #endif /* FINGERPRINT_H */ libsignal-protocol-c-2.3.3/src/group_cipher.c000066400000000000000000000242461363751346500212100ustar00rootroot00000000000000#include "group_cipher.h" #include #include #include "protocol.h" #include "sender_key.h" #include "sender_key_record.h" #include "sender_key_state.h" #include "signal_protocol_internal.h" struct group_cipher { signal_protocol_store_context *store; const signal_protocol_sender_key_name *sender_key_id; signal_context *global_context; int (*decrypt_callback)(group_cipher *cipher, signal_buffer *plaintext, void *decrypt_context); int inside_callback; void *user_data; }; static int group_cipher_get_sender_key(group_cipher *cipher, sender_message_key **sender_key, sender_key_state *state, uint32_t iteration); static int group_cipher_decrypt_callback(group_cipher *cipher, signal_buffer *plaintext, void *decrypt_context); int group_cipher_create(group_cipher **cipher, signal_protocol_store_context *store, const signal_protocol_sender_key_name *sender_key_id, signal_context *global_context) { group_cipher *result_cipher; assert(store); assert(global_context); result_cipher = malloc(sizeof(group_cipher)); if(!result_cipher) { return SG_ERR_NOMEM; } memset(result_cipher, 0, sizeof(group_cipher)); result_cipher->store = store; result_cipher->sender_key_id = sender_key_id; result_cipher->global_context = global_context; *cipher = result_cipher; return 0; } void group_cipher_set_user_data(group_cipher *cipher, void *user_data) { assert(cipher); cipher->user_data = user_data; } void *group_cipher_get_user_data(group_cipher *cipher) { assert(cipher); return cipher->user_data; } void group_cipher_set_decryption_callback(group_cipher *cipher, int (*callback)(group_cipher *cipher, signal_buffer *plaintext, void *decrypt_context)) { assert(cipher); cipher->decrypt_callback = callback; } int group_cipher_encrypt(group_cipher *cipher, const uint8_t *padded_plaintext, size_t padded_plaintext_len, ciphertext_message **encrypted_message) { int result = 0; sender_key_message *result_message = 0; sender_key_record *record = 0; sender_key_state *state = 0; ec_private_key *signing_key_private = 0; sender_message_key *sender_key = 0; sender_chain_key *next_chain_key = 0; signal_buffer *sender_cipher_key = 0; signal_buffer *sender_cipher_iv = 0; signal_buffer *ciphertext = 0; assert(cipher); signal_lock(cipher->global_context); if(cipher->inside_callback == 1) { result = SG_ERR_INVAL; goto complete; } result = signal_protocol_sender_key_load_key(cipher->store, &record, cipher->sender_key_id); if(result < 0) { goto complete; } result = sender_key_record_get_sender_key_state(record, &state); if(result < 0) { goto complete; } signing_key_private = sender_key_state_get_signing_key_private(state); if(!signing_key_private) { result = SG_ERR_INVALID_KEY; goto complete; } result = sender_chain_key_create_message_key(sender_key_state_get_chain_key(state), &sender_key); if(result < 0) { goto complete; } sender_cipher_key = sender_message_key_get_cipher_key(sender_key); sender_cipher_iv = sender_message_key_get_iv(sender_key); result = signal_encrypt(cipher->global_context, &ciphertext, SG_CIPHER_AES_CBC_PKCS5, signal_buffer_data(sender_cipher_key), signal_buffer_len(sender_cipher_key), signal_buffer_data(sender_cipher_iv), signal_buffer_len(sender_cipher_iv), padded_plaintext, padded_plaintext_len); if(result < 0) { goto complete; } result = sender_key_message_create(&result_message, sender_key_state_get_key_id(state), sender_message_key_get_iteration(sender_key), signal_buffer_data(ciphertext), signal_buffer_len(ciphertext), signing_key_private, cipher->global_context); if(result < 0) { goto complete; } result = sender_chain_key_create_next(sender_key_state_get_chain_key(state), &next_chain_key); if(result < 0) { goto complete; } sender_key_state_set_chain_key(state, next_chain_key); result = signal_protocol_sender_key_store_key(cipher->store, cipher->sender_key_id, record); complete: if(result >= 0) { *encrypted_message = (ciphertext_message *)result_message; } else { if(result == SG_ERR_INVALID_KEY_ID) { result = SG_ERR_NO_SESSION; } SIGNAL_UNREF(result_message); } signal_buffer_free(ciphertext); SIGNAL_UNREF(next_chain_key); SIGNAL_UNREF(sender_key); SIGNAL_UNREF(record); signal_unlock(cipher->global_context); return result; } int group_cipher_decrypt(group_cipher *cipher, sender_key_message *ciphertext, void *decrypt_context, signal_buffer **plaintext) { int result = 0; signal_buffer *result_buf = 0; sender_key_record *record = 0; sender_key_state *state = 0; sender_message_key *sender_key = 0; signal_buffer *sender_cipher_key = 0; signal_buffer *sender_cipher_iv = 0; signal_buffer *ciphertext_body = 0; assert(cipher); signal_lock(cipher->global_context); if(cipher->inside_callback == 1) { result = SG_ERR_INVAL; goto complete; } result = signal_protocol_sender_key_load_key(cipher->store, &record, cipher->sender_key_id); if(result < 0) { goto complete; } if(sender_key_record_is_empty(record)) { result = SG_ERR_NO_SESSION; signal_log(cipher->global_context, SG_LOG_WARNING, "No sender key for: %s::%s::%d", cipher->sender_key_id->group_id, cipher->sender_key_id->sender.name, cipher->sender_key_id->sender.device_id); goto complete; } result = sender_key_record_get_sender_key_state_by_id(record, &state, sender_key_message_get_key_id(ciphertext)); if(result < 0) { goto complete; } result = sender_key_message_verify_signature(ciphertext, sender_key_state_get_signing_key_public(state)); if(result < 0) { goto complete; } result = group_cipher_get_sender_key(cipher, &sender_key, state, sender_key_message_get_iteration(ciphertext)); if(result < 0) { goto complete; } sender_cipher_key = sender_message_key_get_cipher_key(sender_key); sender_cipher_iv = sender_message_key_get_iv(sender_key); ciphertext_body = sender_key_message_get_ciphertext(ciphertext); result = signal_decrypt(cipher->global_context, &result_buf, SG_CIPHER_AES_CBC_PKCS5, signal_buffer_data(sender_cipher_key), signal_buffer_len(sender_cipher_key), signal_buffer_data(sender_cipher_iv), signal_buffer_len(sender_cipher_iv), signal_buffer_data(ciphertext_body), signal_buffer_len(ciphertext_body)); if(result < 0) { goto complete; } result = group_cipher_decrypt_callback(cipher, result_buf, decrypt_context); if(result < 0) { goto complete; } result = signal_protocol_sender_key_store_key(cipher->store, cipher->sender_key_id, record); complete: SIGNAL_UNREF(sender_key); SIGNAL_UNREF(record); if(result >= 0) { *plaintext = result_buf; } else { if(result == SG_ERR_INVALID_KEY || result == SG_ERR_INVALID_KEY_ID) { result = SG_ERR_INVALID_MESSAGE; } signal_buffer_free(result_buf); } signal_unlock(cipher->global_context); return result; } int group_cipher_get_sender_key(group_cipher *cipher, sender_message_key **sender_key, sender_key_state *state, uint32_t iteration) { int result = 0; sender_message_key *result_key = 0; sender_chain_key *chain_key = 0; sender_chain_key *next_chain_key = 0; sender_message_key *message_key = 0; chain_key = sender_key_state_get_chain_key(state); SIGNAL_REF(chain_key); if(sender_chain_key_get_iteration(chain_key) > iteration) { if(sender_key_state_has_sender_message_key(state, iteration)) { result_key = sender_key_state_remove_sender_message_key(state, iteration); if(!result_key) { result = SG_ERR_UNKNOWN; } goto complete; } else { result = SG_ERR_DUPLICATE_MESSAGE; signal_log(cipher->global_context, SG_LOG_WARNING, "Received message with old counter: %d, %d", sender_chain_key_get_iteration(chain_key), iteration); goto complete; } } if(iteration - sender_chain_key_get_iteration(chain_key) > 2000) { result = SG_ERR_INVALID_MESSAGE; signal_log(cipher->global_context, SG_LOG_WARNING, "Over 2000 messages into the future!"); goto complete; } while(sender_chain_key_get_iteration(chain_key) < iteration) { result = sender_chain_key_create_message_key(chain_key, &message_key); if(result < 0) { goto complete; } result = sender_key_state_add_sender_message_key(state, message_key); if(result < 0) { goto complete; } SIGNAL_UNREF(message_key); result = sender_chain_key_create_next(chain_key, &next_chain_key); if(result < 0) { goto complete; } SIGNAL_UNREF(chain_key); chain_key = next_chain_key; next_chain_key = 0; } result = sender_chain_key_create_next(chain_key, &next_chain_key); if(result < 0) { goto complete; } sender_key_state_set_chain_key(state, next_chain_key); result = sender_chain_key_create_message_key(chain_key, &result_key); complete: SIGNAL_UNREF(message_key); SIGNAL_UNREF(chain_key); SIGNAL_UNREF(next_chain_key); if(result >= 0) { *sender_key = result_key; } return result; } static int group_cipher_decrypt_callback(group_cipher *cipher, signal_buffer *plaintext, void *decrypt_context) { int result = 0; if(cipher->decrypt_callback) { cipher->inside_callback = 1; result = cipher->decrypt_callback(cipher, plaintext, decrypt_context); cipher->inside_callback = 0; } return result; } void group_cipher_free(group_cipher *cipher) { if(cipher) { free(cipher); } } libsignal-protocol-c-2.3.3/src/group_cipher.h000066400000000000000000000104401363751346500212040ustar00rootroot00000000000000#ifndef GROUP_CIPHER_H #define GROUP_CIPHER_H #include #include #include "signal_protocol_types.h" #ifdef __cplusplus extern "C" { #endif /* * The main entry point for Signal Protocol group encrypt/decrypt operations. * * Once a session has been established with group_session_builder and a * sender_key_distribution_message has been distributed to each member of * the group, this class can be used for all subsequent encrypt/decrypt * operations within that session (i.e. until group membership changes). */ /** * Construct a group cipher for encrypt/decrypt operations. * * The store and global contexts must remain valid for the lifetime of the * group cipher. * * When finished, free the returned instance by calling group_cipher_free(). * * @param cipher set to a freshly allocated group cipher instance * @param store the signal_protocol_store_context to store all state information in * @param sender_key_id the sender that messages will be encrypted to or decrypted from * @param global_context the global library context * @return 0 on success, or negative on failure */ int group_cipher_create(group_cipher **cipher, signal_protocol_store_context *store, const signal_protocol_sender_key_name *sender_key_id, signal_context *global_context); /** * Set the optional user data pointer for the group cipher. * * This is to give callback functions a way of accessing app specific * context information for this cipher. */ void group_cipher_set_user_data(group_cipher *cipher, void *user_data); /** * Get the optional user data pointer for the group cipher. * * This is to give callback functions a way of accessing app specific * context information for this cipher. */ void *group_cipher_get_user_data(group_cipher *cipher); /** * Set the callback function that is called during the decrypt process. * * The callback function is called from within group_cipher_decrypt() after * decryption is complete but before the updated session state has been * committed to the session store. If the callback function returns a * negative value, then the decrypt function will immediately fail with * an error. * * This a callback allows some implementations to store the committed plaintext * to their local message store first, in case they are concerned with a crash * or write error happening between the time the session state is updated but * before they're able to successfully store the plaintext to disk. * * @param callback the callback function to set */ void group_cipher_set_decryption_callback(group_cipher *cipher, int (*callback)(group_cipher *cipher, signal_buffer *plaintext, void *decrypt_context)); /** * Encrypt a message. * * @param padded_plaintext The plaintext message bytes, optionally padded to a constant multiple. * @param padded_plaintext_len The length of the data pointed to by padded_message * @param encrypted_message Set to a ciphertext message encrypted to the group+sender+device tuple. * * @retval SG_SUCCESS Success * @retval SG_ERR_NO_SESSION if there is no established session for this contact. * @retval SG_ERR_INVALID_KEY if there is no valid private key for this session. */ int group_cipher_encrypt(group_cipher *cipher, const uint8_t *padded_plaintext, size_t padded_plaintext_len, ciphertext_message **encrypted_message); /** * Decrypt a message. * * @param ciphertext The sender_key_message to decrypt. * @param decrypt_context Optional context pointer associated with the * ciphertext, which is passed to the decryption callback function * @param plaintext Set to a newly allocated buffer containing the plaintext. * * @retval SG_SUCCESS Success * @retval SG_ERR_INVALID_MESSAGE if the input is not valid ciphertext. * @retval SG_ERR_DUPLICATE_MESSAGE if the input is a message that has already been received. * @retval SG_ERR_LEGACY_MESSAGE if the input is a message formatted by a protocol version that * is no longer supported. * @retval SG_ERR_NO_SESSION if there is no established session for this contact. */ int group_cipher_decrypt(group_cipher *cipher, sender_key_message *ciphertext, void *decrypt_context, signal_buffer **plaintext); void group_cipher_free(group_cipher *cipher); #ifdef __cplusplus } #endif #endif /* GROUP_CIPHER_H */ libsignal-protocol-c-2.3.3/src/group_session_builder.c000066400000000000000000000105441363751346500231230ustar00rootroot00000000000000#include "group_session_builder.h" #include #include #include "sender_key_record.h" #include "sender_key_state.h" #include "sender_key.h" #include "protocol.h" #include "key_helper.h" #include "signal_protocol_internal.h" struct group_session_builder { signal_protocol_store_context *store; signal_context *global_context; }; int group_session_builder_create(group_session_builder **builder, signal_protocol_store_context *store, signal_context *global_context) { group_session_builder *result = 0; assert(store); assert(global_context); result = malloc(sizeof(group_session_builder)); if(!result) { return SG_ERR_NOMEM; } memset(result, 0, sizeof(group_session_builder)); result->store = store; result->global_context = global_context; *builder = result; return 0; } int group_session_builder_process_session(group_session_builder *builder, const signal_protocol_sender_key_name *sender_key_name, sender_key_distribution_message *distribution_message) { int result = 0; sender_key_record *record = 0; assert(builder); assert(builder->store); signal_lock(builder->global_context); result = signal_protocol_sender_key_load_key(builder->store, &record, sender_key_name); if(result < 0) { goto complete; } result = sender_key_record_add_sender_key_state(record, sender_key_distribution_message_get_id(distribution_message), sender_key_distribution_message_get_iteration(distribution_message), sender_key_distribution_message_get_chain_key(distribution_message), sender_key_distribution_message_get_signature_key(distribution_message)); if(result < 0) { goto complete; } result = signal_protocol_sender_key_store_key(builder->store, sender_key_name, record); complete: SIGNAL_UNREF(record); signal_unlock(builder->global_context); return result; } int group_session_builder_create_session(group_session_builder *builder, sender_key_distribution_message **distribution_message, const signal_protocol_sender_key_name *sender_key_name) { int result = 0; sender_key_record *record = 0; sender_key_state *state = 0; uint32_t sender_key_id = 0; signal_buffer *sender_key = 0; ec_key_pair *sender_signing_key = 0; sender_chain_key *chain_key = 0; signal_buffer *seed = 0; assert(builder); assert(builder->store); signal_lock(builder->global_context); result = signal_protocol_sender_key_load_key(builder->store, &record, sender_key_name); if(result < 0) { goto complete; } if(sender_key_record_is_empty(record)) { result = signal_protocol_key_helper_generate_sender_key_id(&sender_key_id, builder->global_context); if(result < 0) { goto complete; } result = signal_protocol_key_helper_generate_sender_key(&sender_key, builder->global_context); if(result < 0) { goto complete; } result = signal_protocol_key_helper_generate_sender_signing_key(&sender_signing_key, builder->global_context); if(result < 0) { goto complete; } result = sender_key_record_set_sender_key_state(record, sender_key_id, 0, sender_key, sender_signing_key); if(result < 0) { goto complete; } result = signal_protocol_sender_key_store_key(builder->store, sender_key_name, record); if(result < 0) { goto complete; } } result = sender_key_record_get_sender_key_state(record, &state); if(result < 0) { goto complete; } chain_key = sender_key_state_get_chain_key(state); seed = sender_chain_key_get_seed(chain_key); result = sender_key_distribution_message_create(distribution_message, sender_key_state_get_key_id(state), sender_chain_key_get_iteration(chain_key), signal_buffer_data(seed), signal_buffer_len(seed), sender_key_state_get_signing_key_public(state), builder->global_context); complete: signal_buffer_free(sender_key); SIGNAL_UNREF(sender_signing_key); SIGNAL_UNREF(record); signal_unlock(builder->global_context); return result; } void group_session_builder_free(group_session_builder *builder) { if(builder) { free(builder); } } libsignal-protocol-c-2.3.3/src/group_session_builder.h000066400000000000000000000047071363751346500231340ustar00rootroot00000000000000#ifndef GROUP_SESSION_BUILDER_H #define GROUP_SESSION_BUILDER_H #include "signal_protocol_types.h" #ifdef __cplusplus extern "C" { #endif /* * Group session builder is responsible for setting up group sender key encrypted sessions. * * Once a session has been established, group_cipher can be used to * encrypt/decrypt messages in that session. *

* The built sessions are unidirectional: they can be used either for sending * or for receiving, but not both. * * Sessions are constructed per (groupId + senderId + deviceId) tuple. Remote logical users * are identified by their senderId, and each logical recipientId can have multiple physical * devices. */ /** * Constructs a group session builder. * * The store and global contexts must remain valid for the lifetime of the * session builder. * * When finished, free the returned instance by calling group_session_builder_free(). * * @param builder set to a freshly allocated group session builder instance * @param store the signal_protocol_store_context to store all state information in * @param global_context the global library context * @return 0 on success, or negative on failure */ int group_session_builder_create(group_session_builder **builder, signal_protocol_store_context *store, signal_context *global_context); /** * Construct a group session for receiving messages from senderKeyName. * * @param sender_key_name the (groupId, senderId, deviceId) tuple associated * with the sender_key_distribution_message * @param distribution_message a received sender_key_distribution_message * @return 0 on success, or negative on failure */ int group_session_builder_process_session(group_session_builder *builder, const signal_protocol_sender_key_name *sender_key_name, sender_key_distribution_message *distribution_message); /** * Construct a group session for sending messages. * * @param distribution_message a distribution message to be allocated and populated * @param sender_key_name the (groupId, senderId, deviceId) tuple. In this * case, the sender should be the caller * @return 0 on success, or negative on failure */ int group_session_builder_create_session(group_session_builder *builder, sender_key_distribution_message **distribution_message, const signal_protocol_sender_key_name *sender_key_name); void group_session_builder_free(group_session_builder *builder); #ifdef __cplusplus } #endif #endif /* GROUP_SESSION_BUILDER_H */ libsignal-protocol-c-2.3.3/src/hkdf.c000066400000000000000000000150731363751346500174340ustar00rootroot00000000000000#include "hkdf.h" #include #include #include #include #include #include "signal_protocol_internal.h" #define HASH_OUTPUT_SIZE 32 #define MIN(a,b) (((a)<(b))?(a):(b)) #define MAX(a,b) (((a)>(b))?(a):(b)) struct hkdf_context { signal_type_base base; signal_context *global_context; int iteration_start_offset; }; int hkdf_create(hkdf_context **context, int message_version, signal_context *global_context) { assert(global_context); *context = malloc(sizeof(hkdf_context)); if(!(*context)) { return SG_ERR_NOMEM; } memset(*context, 0, sizeof(hkdf_context)); SIGNAL_INIT(*context, hkdf_destroy); (*context)->global_context = global_context; if(message_version == 2) { (*context)->iteration_start_offset = 0; } else if(message_version == 3) { (*context)->iteration_start_offset = 1; } else { free(*context); return SG_ERR_INVAL; } return 0; } ssize_t hkdf_extract(hkdf_context *context, uint8_t **output, const uint8_t *salt, size_t salt_len, const uint8_t *input_key_material, size_t input_key_material_len) { int result = 0; signal_buffer *mac_buffer = 0; uint8_t *mac = 0; size_t mac_len = 0; void *hmac_context; assert(context); result = signal_hmac_sha256_init(context->global_context, &hmac_context, salt, salt_len); if(result < 0) { goto complete; } result = signal_hmac_sha256_update(context->global_context, hmac_context, input_key_material, input_key_material_len); if(result < 0) { goto complete; } result = signal_hmac_sha256_final(context->global_context, hmac_context, &mac_buffer); if(result < 0) { goto complete; } mac_len = signal_buffer_len(mac_buffer); mac = malloc(mac_len); if(!mac) { result = SG_ERR_NOMEM; goto complete; } memcpy(mac, signal_buffer_data(mac_buffer), mac_len); complete: signal_hmac_sha256_cleanup(context->global_context, hmac_context); signal_buffer_free(mac_buffer); if(result >= 0) { *output = mac; return (ssize_t)mac_len; } else { return result; } } ssize_t hkdf_expand(hkdf_context *context, uint8_t **output, const uint8_t *prk, size_t prk_len, const uint8_t *info, size_t info_len, size_t output_len) { int iterations = (int)ceil((double)output_len / (double)HASH_OUTPUT_SIZE); size_t remaining_len = output_len; signal_buffer *step_buffer = 0; size_t step_size = 0; uint8_t *result_buf = 0; size_t result_buf_len = 0; void *hmac_context = 0; int result = 0; uint8_t i; assert(context); for(i = context->iteration_start_offset; i < iterations + context->iteration_start_offset; i++) { result = signal_hmac_sha256_init(context->global_context, &hmac_context, prk, prk_len); if(result < 0) { goto complete; } if(step_buffer) { result = signal_hmac_sha256_update(context->global_context, hmac_context, signal_buffer_data(step_buffer), signal_buffer_len(step_buffer)); if(result < 0) { goto complete; } signal_buffer_free(step_buffer); step_buffer = 0; } if(info) { result = signal_hmac_sha256_update(context->global_context, hmac_context, info, info_len); if(result < 0) { goto complete; } } result = signal_hmac_sha256_update(context->global_context, hmac_context, &i, sizeof(uint8_t)); if(result < 0) { goto complete; } result = signal_hmac_sha256_final(context->global_context, hmac_context, &step_buffer); if(result < 0) { goto complete; } signal_hmac_sha256_cleanup(context->global_context, hmac_context); hmac_context = 0; step_size = MIN(remaining_len, signal_buffer_len(step_buffer)); if(!result_buf) { result_buf = malloc(step_size); if(!result_buf) { result = SG_ERR_NOMEM; goto complete; } memcpy(result_buf, signal_buffer_data(step_buffer), step_size); result_buf_len = step_size; } else { uint8_t *tmp_buf = realloc(result_buf, result_buf_len + step_size); if(!tmp_buf) { result = SG_ERR_NOMEM; goto complete; } result_buf = tmp_buf; memcpy(result_buf + result_buf_len, signal_buffer_data(step_buffer), step_size); result_buf_len += step_size; } remaining_len -= step_size; } complete: if(hmac_context) { signal_hmac_sha256_cleanup(context->global_context, hmac_context); } signal_buffer_free(step_buffer); if(result < 0) { free(result_buf); return result; } else { *output = result_buf; return (ssize_t)result_buf_len; } } ssize_t hkdf_derive_secrets(hkdf_context *context, uint8_t **output, const uint8_t *input_key_material, size_t input_key_material_len, const uint8_t *salt, size_t salt_len, const uint8_t *info, size_t info_len, size_t output_len) { ssize_t result = 0; uint8_t *prk = 0; ssize_t prk_len = 0; assert(context); prk_len = hkdf_extract(context, &prk, salt, salt_len, input_key_material, input_key_material_len); if(prk_len < 0) { signal_log(context->global_context, SG_LOG_ERROR, "hkdf_extract error: %d", prk_len); return prk_len; } result = hkdf_expand(context, output, prk, (size_t)prk_len, info, info_len, output_len); if(prk) { free(prk); } return result; } int hkdf_compare(const hkdf_context *context1, const hkdf_context *context2) { if(context1 == context2) { return 0; } else if(context1 == 0 && context2 != 0) { return -1; } else if(context1 != 0 && context2 == 0) { return 1; } else if(context1->iteration_start_offset < context2->iteration_start_offset) { return -1; } else if(context1->iteration_start_offset > context2->iteration_start_offset) { return 1; } else { return 0; } } void hkdf_destroy(signal_type_base *type) { hkdf_context *context = (hkdf_context *)type; free(context); } libsignal-protocol-c-2.3.3/src/hkdf.h000066400000000000000000000012561363751346500174370ustar00rootroot00000000000000#ifndef HKDF_H #define HKDF_H #include #include #include "signal_protocol_types.h" #ifdef __cplusplus extern "C" { #endif int hkdf_create(hkdf_context **context, int message_version, signal_context *global_context); ssize_t hkdf_derive_secrets(hkdf_context *context, uint8_t **output, const uint8_t *input_key_material, size_t input_key_material_len, const uint8_t *salt, size_t salt_len, const uint8_t *info, size_t info_len, size_t output_len); int hkdf_compare(const hkdf_context *context1, const hkdf_context *context2); void hkdf_destroy(signal_type_base *type); #ifdef __cplusplus } #endif #endif /* HKDF_H */ libsignal-protocol-c-2.3.3/src/key_helper.c000066400000000000000000000176021363751346500206470ustar00rootroot00000000000000#include "key_helper.h" #include #include "session_pre_key.h" #include "ratchet.h" #include "curve.h" #include "signal_protocol_internal.h" #include "utlist.h" struct signal_protocol_key_helper_pre_key_list_node { session_pre_key *element; struct signal_protocol_key_helper_pre_key_list_node *next; }; int signal_protocol_key_helper_generate_identity_key_pair(ratchet_identity_key_pair **key_pair, signal_context *global_context) { int result = 0; ratchet_identity_key_pair *result_pair = 0; ec_key_pair *ec_pair = 0; ec_public_key *public_key = 0; ec_private_key *private_key = 0; assert(global_context); result = curve_generate_key_pair(global_context, &ec_pair); if(result < 0) { goto complete; } public_key = ec_key_pair_get_public(ec_pair); private_key = ec_key_pair_get_private(ec_pair); result = ratchet_identity_key_pair_create( &result_pair, public_key, private_key); complete: if(result >= 0) { *key_pair = result_pair; } SIGNAL_UNREF(ec_pair); return result; } int signal_protocol_key_helper_generate_registration_id(uint32_t *registration_id, int extended_range, signal_context *global_context) { uint32_t range; uint32_t id_value; int result = 0; assert(global_context); assert(global_context->crypto_provider.random_func); if(extended_range == 0) { range = 16380; } else if(extended_range == 1) { range = INT32_MAX - 1; } else { return SG_ERR_INVAL; } result = global_context->crypto_provider.random_func( (uint8_t *)(&id_value), sizeof(id_value), global_context->crypto_provider.user_data); if(result < 0) { return result; } id_value = (id_value % range) + 1; *registration_id = id_value; return 0; } int signal_protocol_key_helper_get_random_sequence(int *value, int max, signal_context *global_context) { int result = 0; int32_t result_value; assert(global_context); assert(global_context->crypto_provider.random_func); result = global_context->crypto_provider.random_func( (uint8_t *)(&result_value), sizeof(result_value), global_context->crypto_provider.user_data); if(result < 0) { return result; } result_value = ((result_value & 0x7FFFFFFF) % max); *value = result_value; return 0; } int signal_protocol_key_helper_generate_pre_keys(signal_protocol_key_helper_pre_key_list_node **head, unsigned int start, unsigned int count, signal_context *global_context) { int result = 0; ec_key_pair *ec_pair = 0; session_pre_key *pre_key = 0; signal_protocol_key_helper_pre_key_list_node *result_head = 0; signal_protocol_key_helper_pre_key_list_node *cur_node = 0; signal_protocol_key_helper_pre_key_list_node *node = 0; unsigned int start_index = start - 1; unsigned int i; assert(global_context); for(i = 0; i < count; i++) { uint32_t id = 0; result = curve_generate_key_pair(global_context, &ec_pair); if(result < 0) { goto complete; } id = ((start_index + i) % (PRE_KEY_MEDIUM_MAX_VALUE - 1)) + 1; result = session_pre_key_create(&pre_key, id, ec_pair); if(result < 0) { goto complete; } SIGNAL_UNREF(ec_pair); ec_pair = 0; node = malloc(sizeof(signal_protocol_key_helper_pre_key_list_node)); if(!node) { result = SG_ERR_NOMEM; goto complete; } node->element = pre_key; node->next = 0; if(!result_head) { result_head = node; cur_node = node; } else { cur_node->next = node; cur_node = node; } pre_key = 0; node = 0; } complete: if(ec_pair) { SIGNAL_UNREF(ec_pair); } if(pre_key) { SIGNAL_UNREF(pre_key); } if(node) { free(node); } if(result < 0) { if(result_head) { signal_protocol_key_helper_pre_key_list_node *tmp_node; LL_FOREACH_SAFE(result_head, cur_node, tmp_node) { LL_DELETE(result_head, cur_node); SIGNAL_UNREF(cur_node->element); free(cur_node); } } } else { *head = result_head; } return result; } session_pre_key *signal_protocol_key_helper_key_list_element(const signal_protocol_key_helper_pre_key_list_node *node) { assert(node); assert(node->element); return node->element; } signal_protocol_key_helper_pre_key_list_node *signal_protocol_key_helper_key_list_next(const signal_protocol_key_helper_pre_key_list_node *node) { assert(node); return node->next; } void signal_protocol_key_helper_key_list_free(signal_protocol_key_helper_pre_key_list_node *head) { if(head) { signal_protocol_key_helper_pre_key_list_node *cur_node; signal_protocol_key_helper_pre_key_list_node *tmp_node; LL_FOREACH_SAFE(head, cur_node, tmp_node) { LL_DELETE(head, cur_node); SIGNAL_UNREF(cur_node->element); free(cur_node); } } } int signal_protocol_key_helper_generate_signed_pre_key(session_signed_pre_key **signed_pre_key, const ratchet_identity_key_pair *identity_key_pair, uint32_t signed_pre_key_id, uint64_t timestamp, signal_context *global_context) { int result = 0; session_signed_pre_key *result_signed_pre_key = 0; ec_key_pair *ec_pair = 0; signal_buffer *public_buf = 0; signal_buffer *signature_buf = 0; ec_public_key *public_key = 0; ec_private_key *private_key = 0; assert(global_context); result = curve_generate_key_pair(global_context, &ec_pair); if(result < 0) { goto complete; } public_key = ec_key_pair_get_public(ec_pair); result = ec_public_key_serialize(&public_buf, public_key); if(result < 0) { goto complete; } private_key = ratchet_identity_key_pair_get_private(identity_key_pair); result = curve_calculate_signature(global_context, &signature_buf, private_key, signal_buffer_data(public_buf), signal_buffer_len(public_buf)); if(result < 0) { goto complete; } result = session_signed_pre_key_create(&result_signed_pre_key, signed_pre_key_id, timestamp, ec_pair, signal_buffer_data(signature_buf), signal_buffer_len(signature_buf)); complete: SIGNAL_UNREF(ec_pair); signal_buffer_free(public_buf); signal_buffer_free(signature_buf); if(result >= 0) { *signed_pre_key = result_signed_pre_key; } return result; } int signal_protocol_key_helper_generate_sender_signing_key(ec_key_pair **key_pair, signal_context *global_context) { int result; assert(global_context); result = curve_generate_key_pair(global_context, key_pair); return result; } int signal_protocol_key_helper_generate_sender_key(signal_buffer **key_buffer, signal_context *global_context) { int result = 0; signal_buffer *result_buffer = 0; assert(global_context); result_buffer = signal_buffer_alloc(32); if(!result_buffer) { result = SG_ERR_NOMEM; goto complete; } result = signal_crypto_random(global_context, signal_buffer_data(result_buffer), signal_buffer_len(result_buffer)); complete: if(result < 0) { signal_buffer_free(result_buffer); } else { *key_buffer = result_buffer; result = 0; } return result; } int signal_protocol_key_helper_generate_sender_key_id(uint32_t *key_id, signal_context *global_context) { int result; int value; result = signal_protocol_key_helper_get_random_sequence(&value, INT32_MAX, global_context); if(result >= 0) { *key_id = (uint32_t)value; } return result; } libsignal-protocol-c-2.3.3/src/key_helper.h000066400000000000000000000107201363751346500206460ustar00rootroot00000000000000#ifndef KEY_HELPER_H #define KEY_HELPER_H #include #include "signal_protocol_types.h" #ifdef __cplusplus extern "C" { #endif /** * Generate an identity key pair. Clients should only do this once, * at install time. * * @param key_pair the generated identity key pair * @return 0 on success, or negative on failure */ int signal_protocol_key_helper_generate_identity_key_pair(ratchet_identity_key_pair **key_pair, signal_context *global_context); /** * Generate a registration ID. Clients should only do this once, * at install time. * * @param registration_id set to the generated registration ID * @param extended_range By default (0), the generated registration * ID is sized to require the minimal possible protobuf * encoding overhead. Specify true (1) if the caller needs * the full range of MAX_INT at the cost of slightly * higher encoding overhead. * @return 0 on success, or negative on failure */ int signal_protocol_key_helper_generate_registration_id(uint32_t *registration_id, int extended_range, signal_context *global_context); /** * Generate a random number between 0 (inclusive) and the provided maximum (exclusive). * * @param value set to the next random number * @param max the maximum bound on the value of the random number * @return 0 on success, or negative on failure */ int signal_protocol_key_helper_get_random_sequence(int *value, int max, signal_context *global_context); /** * Generate a list of PreKeys. Clients should do this at install time, and * subsequently any time the list of PreKeys stored on the server runs low. * * Pre key IDs are shorts, so they will eventually be repeated. Clients should * store pre keys in a circular buffer, so that they are repeated as infrequently * as possible. * * When finished with this list, the caller should free it by calling * signal_protocol_key_helper_key_list_free(). * * @param head pointer to the head of the key list * @param start the starting pre key ID, inclusive. * @param count the number of pre keys to generate. * @return 0 on success, or negative on failure */ int signal_protocol_key_helper_generate_pre_keys(signal_protocol_key_helper_pre_key_list_node **head, unsigned int start, unsigned int count, signal_context *global_context); /** * Get the pre key element for the current node in the key list. * * @param node current list node * @return pre key element */ session_pre_key *signal_protocol_key_helper_key_list_element(const signal_protocol_key_helper_pre_key_list_node *node); /** * Get the next element in the key list. * * @param node current list node * @return next list node, or 0 if at the end of the list */ signal_protocol_key_helper_pre_key_list_node *signal_protocol_key_helper_key_list_next(const signal_protocol_key_helper_pre_key_list_node *node); /** * Free the key list. * * @param head pointer to the head of the list to free */ void signal_protocol_key_helper_key_list_free(signal_protocol_key_helper_pre_key_list_node *head); /** * Generate a signed pre key * * @param signed_pre_key set to the generated pre key * @param identity_key_pair the local client's identity key pair. * @param signed_pre_key_id the pre key ID to assign the generated signed pre key * @param timestamp the current time in milliseconds since the UNIX epoch * * @return 0 on success, or negative on failure */ int signal_protocol_key_helper_generate_signed_pre_key(session_signed_pre_key **signed_pre_key, const ratchet_identity_key_pair *identity_key_pair, uint32_t signed_pre_key_id, uint64_t timestamp, signal_context *global_context); /* * Generate a sender signing key pair * * @param key_pair the generated key pair * @return 0 on success, or negative on failure */ int signal_protocol_key_helper_generate_sender_signing_key(ec_key_pair **key_pair, signal_context *global_context); /* * Generate a sender key * * @param key_buffer buffer to be allocated and populated with the result * @return 0 on success, or negative on failure */ int signal_protocol_key_helper_generate_sender_key(signal_buffer **key_buffer, signal_context *global_context); /* * Generate a sender key ID * * @param key_id assigned to the generated ID * @return 0 on success, or negative on failure */ int signal_protocol_key_helper_generate_sender_key_id(uint32_t *key_id, signal_context *global_context); #ifdef __cplusplus } #endif #endif /* KEY_HELPER_H */ libsignal-protocol-c-2.3.3/src/libsignal-protocol-c.pc.in000066400000000000000000000005321363751346500233220ustar00rootroot00000000000000prefix=@CMAKE_INSTALL_PREFIX@ exec_prefix=@CMAKE_INSTALL_PREFIX@ libdir=@LIB_INSTALL_DIR@ sharedlibdir=@LIB_INSTALL_DIR@ includedir=@INCLUDE_INSTALL_DIR@ Name: @PROJECT_NAME@ Description: Signal Protocol C Library Version: @SIGNAL_PROTOCOL_C_VERSION@ Requires: Libs: -L${libdir} -L${sharedlibdir} -l@PROJECT_NAME@ Cflags: -I${includedir}/signallibsignal-protocol-c-2.3.3/src/protobuf-c/000077500000000000000000000000001363751346500204265ustar00rootroot00000000000000libsignal-protocol-c-2.3.3/src/protobuf-c/CMakeLists.txt000066400000000000000000000014131363751346500231650ustar00rootroot00000000000000IF(CMAKE_COMPILER_IS_GNUCC OR CMAKE_C_COMPILER_ID MATCHES "Clang") SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wno-shadow") ENDIF(CMAKE_COMPILER_IS_GNUCC OR CMAKE_C_COMPILER_ID MATCHES "Clang") IF(CMAKE_COMPILER_IS_GNUCC) SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wno-sign-compare") IF(GCC_WARN_SIGN_CONVERSION) SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wno-sign-conversion") ENDIF(GCC_WARN_SIGN_CONVERSION) ENDIF(CMAKE_COMPILER_IS_GNUCC) IF(CMAKE_C_COMPILER_ID MATCHES "Clang") SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wno-shorten-64-to-32") ENDIF(CMAKE_C_COMPILER_ID MATCHES "Clang") set(protobuf_SRCS protobuf-c.c ) add_library(protobuf-c OBJECT ${protobuf_SRCS}) # Add -fPIC flag if(BUILD_SHARED_LIBS) set_property(TARGET protobuf-c PROPERTY POSITION_INDEPENDENT_CODE ON) endif() libsignal-protocol-c-2.3.3/src/protobuf-c/protobuf-c.c000066400000000000000000002634601363751346500226650ustar00rootroot00000000000000/* * Copyright (c) 2008-2015, Dave Benson and the protobuf-c authors. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are * met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * * Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the following disclaimer * in the documentation and/or other materials provided with the * distribution. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /*! \file * Support library for `protoc-c` generated code. * * This file implements the public API used by the code generated * by `protoc-c`. * * \authors Dave Benson and the protobuf-c authors * * \copyright 2008-2014. Licensed under the terms of the [BSD-2-Clause] license. */ /** * \todo 64-BIT OPTIMIZATION: certain implementations use 32-bit math * even on 64-bit platforms (uint64_size, uint64_pack, parse_uint64). * * \todo Use size_t consistently. */ #include /* for malloc, free */ #include /* for strcmp, strlen, memcpy, memmove, memset */ #include "protobuf-c.h" #define TRUE 1 #define FALSE 0 #define PROTOBUF_C__ASSERT_NOT_REACHED() assert(0) /* Workaround for Microsoft compilers. */ #ifdef _MSC_VER # define inline __inline #endif /** * \defgroup internal Internal functions and macros * * These are not exported by the library but are useful to developers working * on `libprotobuf-c` itself. */ /** * \defgroup macros Utility macros for manipulating structures * * Macros and constants used to manipulate the base "classes" generated by * `protobuf-c`. They also define limits and check correctness. * * \ingroup internal * @{ */ /** The maximum length of a 64-bit integer in varint encoding. */ #define MAX_UINT64_ENCODED_SIZE 10 #ifndef PROTOBUF_C_UNPACK_ERROR # define PROTOBUF_C_UNPACK_ERROR(...) #endif /** * Internal `ProtobufCMessage` manipulation macro. * * Base macro for manipulating a `ProtobufCMessage`. Used by STRUCT_MEMBER() and * STRUCT_MEMBER_PTR(). */ #define STRUCT_MEMBER_P(struct_p, struct_offset) \ ((void *) ((uint8_t *) (struct_p) + (struct_offset))) /** * Return field in a `ProtobufCMessage` based on offset. * * Take a pointer to a `ProtobufCMessage` and find the field at the offset. * Cast it to the passed type. */ #define STRUCT_MEMBER(member_type, struct_p, struct_offset) \ (*(member_type *) STRUCT_MEMBER_P((struct_p), (struct_offset))) /** * Return field in a `ProtobufCMessage` based on offset. * * Take a pointer to a `ProtobufCMessage` and find the field at the offset. Cast * it to a pointer to the passed type. */ #define STRUCT_MEMBER_PTR(member_type, struct_p, struct_offset) \ ((member_type *) STRUCT_MEMBER_P((struct_p), (struct_offset))) /* Assertions for magic numbers. */ #define ASSERT_IS_ENUM_DESCRIPTOR(desc) \ assert((desc)->magic == PROTOBUF_C__ENUM_DESCRIPTOR_MAGIC) #define ASSERT_IS_MESSAGE_DESCRIPTOR(desc) \ assert((desc)->magic == PROTOBUF_C__MESSAGE_DESCRIPTOR_MAGIC) #define ASSERT_IS_MESSAGE(message) \ ASSERT_IS_MESSAGE_DESCRIPTOR((message)->descriptor) #define ASSERT_IS_SERVICE_DESCRIPTOR(desc) \ assert((desc)->magic == PROTOBUF_C__SERVICE_DESCRIPTOR_MAGIC) /**@}*/ /* --- version --- */ const char * protobuf_c_version(void) { return PROTOBUF_C_VERSION; } uint32_t protobuf_c_version_number(void) { return PROTOBUF_C_VERSION_NUMBER; } /* --- allocator --- */ static void * system_alloc(void *allocator_data, size_t size) { return malloc(size); } static void system_free(void *allocator_data, void *data) { free(data); } static inline void * do_alloc(ProtobufCAllocator *allocator, size_t size) { return allocator->alloc(allocator->allocator_data, size); } static inline void do_free(ProtobufCAllocator *allocator, void *data) { if (data != NULL) allocator->free(allocator->allocator_data, data); } /* * This allocator uses the system's malloc() and free(). It is the default * allocator used if NULL is passed as the ProtobufCAllocator to an exported * function. */ static ProtobufCAllocator protobuf_c__allocator = { &system_alloc, &system_free, NULL }; /* === buffer-simple === */ void protobuf_c_buffer_simple_append(ProtobufCBuffer *buffer, size_t len, const uint8_t *data) { ProtobufCBufferSimple *simp = (ProtobufCBufferSimple *) buffer; size_t new_len = simp->len + len; if (new_len > simp->alloced) { ProtobufCAllocator *allocator = simp->allocator; size_t new_alloced = simp->alloced * 2; uint8_t *new_data; if (allocator == NULL) allocator = &protobuf_c__allocator; while (new_alloced < new_len) new_alloced += new_alloced; new_data = do_alloc(allocator, new_alloced); if (!new_data) return; memcpy(new_data, simp->data, simp->len); if (simp->must_free_data) do_free(allocator, simp->data); else simp->must_free_data = TRUE; simp->data = new_data; simp->alloced = new_alloced; } memcpy(simp->data + simp->len, data, len); simp->len = new_len; } /** * \defgroup packedsz protobuf_c_message_get_packed_size() implementation * * Routines mainly used by protobuf_c_message_get_packed_size(). * * \ingroup internal * @{ */ /** * Return the number of bytes required to store the tag for the field. Includes * 3 bits for the wire-type, and a single bit that denotes the end-of-tag. * * \param number * Field tag to encode. * \return * Number of bytes required. */ static inline size_t get_tag_size(unsigned number) { if (number < (1 << 4)) { return 1; } else if (number < (1 << 11)) { return 2; } else if (number < (1 << 18)) { return 3; } else if (number < (1 << 25)) { return 4; } else { return 5; } } /** * Return the number of bytes required to store a variable-length unsigned * 32-bit integer in base-128 varint encoding. * * \param v * Value to encode. * \return * Number of bytes required. */ static inline size_t uint32_size(uint32_t v) { if (v < (1 << 7)) { return 1; } else if (v < (1 << 14)) { return 2; } else if (v < (1 << 21)) { return 3; } else if (v < (1 << 28)) { return 4; } else { return 5; } } /** * Return the number of bytes required to store a variable-length signed 32-bit * integer in base-128 varint encoding. * * \param v * Value to encode. * \return * Number of bytes required. */ static inline size_t int32_size(int32_t v) { if (v < 0) { return 10; } else if (v < (1 << 7)) { return 1; } else if (v < (1 << 14)) { return 2; } else if (v < (1 << 21)) { return 3; } else if (v < (1 << 28)) { return 4; } else { return 5; } } /** * Return the ZigZag-encoded 32-bit unsigned integer form of a 32-bit signed * integer. * * \param v * Value to encode. * \return * ZigZag encoded integer. */ static inline uint32_t zigzag32(int32_t v) { if (v < 0) return ((uint32_t) (-v)) * 2 - 1; else return v * 2; } /** * Return the number of bytes required to store a signed 32-bit integer, * converted to an unsigned 32-bit integer with ZigZag encoding, using base-128 * varint encoding. * * \param v * Value to encode. * \return * Number of bytes required. */ static inline size_t sint32_size(int32_t v) { return uint32_size(zigzag32(v)); } /** * Return the number of bytes required to store a 64-bit unsigned integer in * base-128 varint encoding. * * \param v * Value to encode. * \return * Number of bytes required. */ static inline size_t uint64_size(uint64_t v) { uint32_t upper_v = (uint32_t) (v >> 32); if (upper_v == 0) { return uint32_size((uint32_t) v); } else if (upper_v < (1 << 3)) { return 5; } else if (upper_v < (1 << 10)) { return 6; } else if (upper_v < (1 << 17)) { return 7; } else if (upper_v < (1 << 24)) { return 8; } else if (upper_v < (1U << 31)) { return 9; } else { return 10; } } /** * Return the ZigZag-encoded 64-bit unsigned integer form of a 64-bit signed * integer. * * \param v * Value to encode. * \return * ZigZag encoded integer. */ static inline uint64_t zigzag64(int64_t v) { if (v < 0) return ((uint64_t) (-v)) * 2 - 1; else return v * 2; } /** * Return the number of bytes required to store a signed 64-bit integer, * converted to an unsigned 64-bit integer with ZigZag encoding, using base-128 * varint encoding. * * \param v * Value to encode. * \return * Number of bytes required. */ static inline size_t sint64_size(int64_t v) { return uint64_size(zigzag64(v)); } /** * Calculate the serialized size of a single required message field, including * the space needed by the preceding tag. * * \param field * Field descriptor for member. * \param member * Field to encode. * \return * Number of bytes required. */ static size_t required_field_get_packed_size(const ProtobufCFieldDescriptor *field, const void *member) { size_t rv = get_tag_size(field->id); switch (field->type) { case PROTOBUF_C_TYPE_SINT32: return rv + sint32_size(*(const int32_t *) member); case PROTOBUF_C_TYPE_INT32: return rv + int32_size(*(const uint32_t *) member); case PROTOBUF_C_TYPE_UINT32: return rv + uint32_size(*(const uint32_t *) member); case PROTOBUF_C_TYPE_SINT64: return rv + sint64_size(*(const int64_t *) member); case PROTOBUF_C_TYPE_INT64: case PROTOBUF_C_TYPE_UINT64: return rv + uint64_size(*(const uint64_t *) member); case PROTOBUF_C_TYPE_SFIXED32: case PROTOBUF_C_TYPE_FIXED32: return rv + 4; case PROTOBUF_C_TYPE_SFIXED64: case PROTOBUF_C_TYPE_FIXED64: return rv + 8; case PROTOBUF_C_TYPE_BOOL: return rv + 1; case PROTOBUF_C_TYPE_FLOAT: return rv + 4; case PROTOBUF_C_TYPE_DOUBLE: return rv + 8; case PROTOBUF_C_TYPE_ENUM: /* \todo Is this correct for negative-valued enums? */ return rv + uint32_size(*(const uint32_t *) member); case PROTOBUF_C_TYPE_STRING: { const char *str = *(char * const *) member; size_t len = str ? strlen(str) : 0; return rv + uint32_size(len) + len; } case PROTOBUF_C_TYPE_BYTES: { size_t len = ((const ProtobufCBinaryData *) member)->len; return rv + uint32_size(len) + len; } case PROTOBUF_C_TYPE_MESSAGE: { const ProtobufCMessage *msg = *(ProtobufCMessage * const *) member; size_t subrv = msg ? protobuf_c_message_get_packed_size(msg) : 0; return rv + uint32_size(subrv) + subrv; } } PROTOBUF_C__ASSERT_NOT_REACHED(); return 0; } /** * Calculate the serialized size of a single oneof message field, including * the space needed by the preceding tag. Returns 0 if the oneof field isn't * selected or is not set. * * \param field * Field descriptor for member. * \param oneof_case * A pointer to the case enum that selects the field in the oneof. * \param member * Field to encode. * \return * Number of bytes required. */ static size_t oneof_field_get_packed_size(const ProtobufCFieldDescriptor *field, const uint32_t *oneof_case, const void *member) { if (*oneof_case == field->id) { if (field->type == PROTOBUF_C_TYPE_MESSAGE || field->type == PROTOBUF_C_TYPE_STRING) { const void *ptr = *(const void * const *) member; if (ptr == NULL || ptr == field->default_value) return 0; } } else { return 0; } return required_field_get_packed_size(field, member); } /** * Calculate the serialized size of a single optional message field, including * the space needed by the preceding tag. Returns 0 if the optional field isn't * set. * * \param field * Field descriptor for member. * \param has * True if the field exists, false if not. * \param member * Field to encode. * \return * Number of bytes required. */ static size_t optional_field_get_packed_size(const ProtobufCFieldDescriptor *field, const protobuf_c_boolean *has, const void *member) { if (field->type == PROTOBUF_C_TYPE_MESSAGE || field->type == PROTOBUF_C_TYPE_STRING) { const void *ptr = *(const void * const *) member; if (ptr == NULL || ptr == field->default_value) return 0; } else { if (!*has) return 0; } return required_field_get_packed_size(field, member); } /** * Calculate the serialized size of repeated message fields, which may consist * of any number of values (including 0). Includes the space needed by the * preceding tags (as needed). * * \param field * Field descriptor for member. * \param count * Number of repeated field members. * \param member * Field to encode. * \return * Number of bytes required. */ static size_t repeated_field_get_packed_size(const ProtobufCFieldDescriptor *field, size_t count, const void *member) { size_t header_size; size_t rv = 0; unsigned i; void *array = *(void * const *) member; if (count == 0) return 0; header_size = get_tag_size(field->id); if (0 == (field->flags & PROTOBUF_C_FIELD_FLAG_PACKED)) header_size *= count; switch (field->type) { case PROTOBUF_C_TYPE_SINT32: for (i = 0; i < count; i++) rv += sint32_size(((int32_t *) array)[i]); break; case PROTOBUF_C_TYPE_INT32: for (i = 0; i < count; i++) rv += int32_size(((uint32_t *) array)[i]); break; case PROTOBUF_C_TYPE_UINT32: case PROTOBUF_C_TYPE_ENUM: for (i = 0; i < count; i++) rv += uint32_size(((uint32_t *) array)[i]); break; case PROTOBUF_C_TYPE_SINT64: for (i = 0; i < count; i++) rv += sint64_size(((int64_t *) array)[i]); break; case PROTOBUF_C_TYPE_INT64: case PROTOBUF_C_TYPE_UINT64: for (i = 0; i < count; i++) rv += uint64_size(((uint64_t *) array)[i]); break; case PROTOBUF_C_TYPE_SFIXED32: case PROTOBUF_C_TYPE_FIXED32: case PROTOBUF_C_TYPE_FLOAT: rv += 4 * count; break; case PROTOBUF_C_TYPE_SFIXED64: case PROTOBUF_C_TYPE_FIXED64: case PROTOBUF_C_TYPE_DOUBLE: rv += 8 * count; break; case PROTOBUF_C_TYPE_BOOL: rv += count; break; case PROTOBUF_C_TYPE_STRING: for (i = 0; i < count; i++) { size_t len = strlen(((char **) array)[i]); rv += uint32_size(len) + len; } break; case PROTOBUF_C_TYPE_BYTES: for (i = 0; i < count; i++) { size_t len = ((ProtobufCBinaryData *) array)[i].len; rv += uint32_size(len) + len; } break; case PROTOBUF_C_TYPE_MESSAGE: for (i = 0; i < count; i++) { size_t len = protobuf_c_message_get_packed_size( ((ProtobufCMessage **) array)[i]); rv += uint32_size(len) + len; } break; } if (0 != (field->flags & PROTOBUF_C_FIELD_FLAG_PACKED)) header_size += uint32_size(rv); return header_size + rv; } /** * Calculate the serialized size of an unknown field, i.e. one that is passed * through mostly uninterpreted. This is required for forward compatibility if * new fields are added to the message descriptor. * * \param field * Unknown field type. * \return * Number of bytes required. */ static inline size_t unknown_field_get_packed_size(const ProtobufCMessageUnknownField *field) { return get_tag_size(field->tag) + field->len; } /**@}*/ /* * Calculate the serialized size of the message. */ size_t protobuf_c_message_get_packed_size(const ProtobufCMessage *message) { unsigned i; size_t rv = 0; ASSERT_IS_MESSAGE(message); for (i = 0; i < message->descriptor->n_fields; i++) { const ProtobufCFieldDescriptor *field = message->descriptor->fields + i; const void *member = ((const char *) message) + field->offset; const void *qmember = ((const char *) message) + field->quantifier_offset; if (field->label == PROTOBUF_C_LABEL_REQUIRED) { rv += required_field_get_packed_size(field, member); } else if (field->label == PROTOBUF_C_LABEL_OPTIONAL) { if (0 != (field->flags & PROTOBUF_C_FIELD_FLAG_ONEOF)) rv += oneof_field_get_packed_size(field, qmember, member); else rv += optional_field_get_packed_size(field, qmember, member); } else { rv += repeated_field_get_packed_size( field, *(const size_t *) qmember, member ); } } for (i = 0; i < message->n_unknown_fields; i++) rv += unknown_field_get_packed_size(&message->unknown_fields[i]); return rv; } /** * \defgroup pack protobuf_c_message_pack() implementation * * Routines mainly used by protobuf_c_message_pack(). * * \ingroup internal * @{ */ /** * Pack an unsigned 32-bit integer in base-128 varint encoding and return the * number of bytes written, which must be 5 or less. * * \param value * Value to encode. * \param[out] out * Packed value. * \return * Number of bytes written to `out`. */ static inline size_t uint32_pack(uint32_t value, uint8_t *out) { unsigned rv = 0; if (value >= 0x80) { out[rv++] = value | 0x80; value >>= 7; if (value >= 0x80) { out[rv++] = value | 0x80; value >>= 7; if (value >= 0x80) { out[rv++] = value | 0x80; value >>= 7; if (value >= 0x80) { out[rv++] = value | 0x80; value >>= 7; } } } } /* assert: value<128 */ out[rv++] = value; return rv; } /** * Pack a signed 32-bit integer and return the number of bytes written. * Negative numbers are encoded as two's complement 64-bit integers. * * \param value * Value to encode. * \param[out] out * Packed value. * \return * Number of bytes written to `out`. */ static inline size_t int32_pack(int32_t value, uint8_t *out) { if (value < 0) { out[0] = value | 0x80; out[1] = (value >> 7) | 0x80; out[2] = (value >> 14) | 0x80; out[3] = (value >> 21) | 0x80; out[4] = (value >> 28) | 0x80; out[5] = out[6] = out[7] = out[8] = 0xff; out[9] = 0x01; return 10; } else { return uint32_pack(value, out); } } /** * Pack a signed 32-bit integer using ZigZag encoding and return the number of * bytes written. * * \param value * Value to encode. * \param[out] out * Packed value. * \return * Number of bytes written to `out`. */ static inline size_t sint32_pack(int32_t value, uint8_t *out) { return uint32_pack(zigzag32(value), out); } /** * Pack a 64-bit unsigned integer using base-128 varint encoding and return the * number of bytes written. * * \param value * Value to encode. * \param[out] out * Packed value. * \return * Number of bytes written to `out`. */ static size_t uint64_pack(uint64_t value, uint8_t *out) { uint32_t hi = (uint32_t) (value >> 32); uint32_t lo = (uint32_t) value; unsigned rv; if (hi == 0) return uint32_pack((uint32_t) lo, out); out[0] = (lo) | 0x80; out[1] = (lo >> 7) | 0x80; out[2] = (lo >> 14) | 0x80; out[3] = (lo >> 21) | 0x80; if (hi < 8) { out[4] = (hi << 4) | (lo >> 28); return 5; } else { out[4] = ((hi & 7) << 4) | (lo >> 28) | 0x80; hi >>= 3; } rv = 5; while (hi >= 128) { out[rv++] = hi | 0x80; hi >>= 7; } out[rv++] = hi; return rv; } /** * Pack a 64-bit signed integer in ZigZag encoding and return the number of * bytes written. * * \param value * Value to encode. * \param[out] out * Packed value. * \return * Number of bytes written to `out`. */ static inline size_t sint64_pack(int64_t value, uint8_t *out) { return uint64_pack(zigzag64(value), out); } /** * Pack a 32-bit quantity in little-endian byte order. Used for protobuf wire * types fixed32, sfixed32, float. Similar to "htole32". * * \param value * Value to encode. * \param[out] out * Packed value. * \return * Number of bytes written to `out`. */ static inline size_t fixed32_pack(uint32_t value, void *out) { #if !defined(WORDS_BIGENDIAN) memcpy(out, &value, 4); #else uint8_t *buf = out; buf[0] = value; buf[1] = value >> 8; buf[2] = value >> 16; buf[3] = value >> 24; #endif return 4; } /** * Pack a 64-bit quantity in little-endian byte order. Used for protobuf wire * types fixed64, sfixed64, double. Similar to "htole64". * * \todo The big-endian impl is really only good for 32-bit machines, a 64-bit * version would be appreciated, plus a way to decide to use 64-bit math where * convenient. * * \param value * Value to encode. * \param[out] out * Packed value. * \return * Number of bytes written to `out`. */ static inline size_t fixed64_pack(uint64_t value, void *out) { #if !defined(WORDS_BIGENDIAN) memcpy(out, &value, 8); #else fixed32_pack(value, out); fixed32_pack(value >> 32, ((char *) out) + 4); #endif return 8; } /** * Pack a boolean value as an integer and return the number of bytes written. * * \todo Perhaps on some platforms *out = !!value would be a better impl, b/c * that is idiomatic C++ in some STL implementations. * * \param value * Value to encode. * \param[out] out * Packed value. * \return * Number of bytes written to `out`. */ static inline size_t boolean_pack(protobuf_c_boolean value, uint8_t *out) { *out = value ? TRUE : FALSE; return 1; } /** * Pack a NUL-terminated C string and return the number of bytes written. The * output includes a length delimiter. * * The NULL pointer is treated as an empty string. This isn't really necessary, * but it allows people to leave required strings blank. (See Issue #13 in the * bug tracker for a little more explanation). * * \param str * String to encode. * \param[out] out * Packed value. * \return * Number of bytes written to `out`. */ static inline size_t string_pack(const char *str, uint8_t *out) { if (str == NULL) { out[0] = 0; return 1; } else { size_t len = strlen(str); size_t rv = uint32_pack(len, out); memcpy(out + rv, str, len); return rv + len; } } /** * Pack a ProtobufCBinaryData and return the number of bytes written. The output * includes a length delimiter. * * \param bd * ProtobufCBinaryData to encode. * \param[out] out * Packed value. * \return * Number of bytes written to `out`. */ static inline size_t binary_data_pack(const ProtobufCBinaryData *bd, uint8_t *out) { size_t len = bd->len; size_t rv = uint32_pack(len, out); memcpy(out + rv, bd->data, len); return rv + len; } /** * Pack a ProtobufCMessage and return the number of bytes written. The output * includes a length delimiter. * * \param message * ProtobufCMessage object to pack. * \param[out] out * Packed message. * \return * Number of bytes written to `out`. */ static inline size_t prefixed_message_pack(const ProtobufCMessage *message, uint8_t *out) { if (message == NULL) { out[0] = 0; return 1; } else { size_t rv = protobuf_c_message_pack(message, out + 1); uint32_t rv_packed_size = uint32_size(rv); if (rv_packed_size != 1) memmove(out + rv_packed_size, out + 1, rv); return uint32_pack(rv, out) + rv; } } /** * Pack a field tag. * * Wire-type will be added in required_field_pack(). * * \todo Just call uint64_pack on 64-bit platforms. * * \param id * Tag value to encode. * \param[out] out * Packed value. * \return * Number of bytes written to `out`. */ static size_t tag_pack(uint32_t id, uint8_t *out) { if (id < (1 << (32 - 3))) return uint32_pack(id << 3, out); else return uint64_pack(((uint64_t) id) << 3, out); } /** * Pack a required field and return the number of bytes written. * * \param field * Field descriptor. * \param member * The field member. * \param[out] out * Packed value. * \return * Number of bytes written to `out`. */ static size_t required_field_pack(const ProtobufCFieldDescriptor *field, const void *member, uint8_t *out) { size_t rv = tag_pack(field->id, out); switch (field->type) { case PROTOBUF_C_TYPE_SINT32: out[0] |= PROTOBUF_C_WIRE_TYPE_VARINT; return rv + sint32_pack(*(const int32_t *) member, out + rv); case PROTOBUF_C_TYPE_INT32: out[0] |= PROTOBUF_C_WIRE_TYPE_VARINT; return rv + int32_pack(*(const uint32_t *) member, out + rv); case PROTOBUF_C_TYPE_UINT32: case PROTOBUF_C_TYPE_ENUM: out[0] |= PROTOBUF_C_WIRE_TYPE_VARINT; return rv + uint32_pack(*(const uint32_t *) member, out + rv); case PROTOBUF_C_TYPE_SINT64: out[0] |= PROTOBUF_C_WIRE_TYPE_VARINT; return rv + sint64_pack(*(const int64_t *) member, out + rv); case PROTOBUF_C_TYPE_INT64: case PROTOBUF_C_TYPE_UINT64: out[0] |= PROTOBUF_C_WIRE_TYPE_VARINT; return rv + uint64_pack(*(const uint64_t *) member, out + rv); case PROTOBUF_C_TYPE_SFIXED32: case PROTOBUF_C_TYPE_FIXED32: case PROTOBUF_C_TYPE_FLOAT: out[0] |= PROTOBUF_C_WIRE_TYPE_32BIT; return rv + fixed32_pack(*(const uint32_t *) member, out + rv); case PROTOBUF_C_TYPE_SFIXED64: case PROTOBUF_C_TYPE_FIXED64: case PROTOBUF_C_TYPE_DOUBLE: out[0] |= PROTOBUF_C_WIRE_TYPE_64BIT; return rv + fixed64_pack(*(const uint64_t *) member, out + rv); case PROTOBUF_C_TYPE_BOOL: out[0] |= PROTOBUF_C_WIRE_TYPE_VARINT; return rv + boolean_pack(*(const protobuf_c_boolean *) member, out + rv); case PROTOBUF_C_TYPE_STRING: out[0] |= PROTOBUF_C_WIRE_TYPE_LENGTH_PREFIXED; return rv + string_pack(*(char *const *) member, out + rv); case PROTOBUF_C_TYPE_BYTES: out[0] |= PROTOBUF_C_WIRE_TYPE_LENGTH_PREFIXED; return rv + binary_data_pack((const ProtobufCBinaryData *) member, out + rv); case PROTOBUF_C_TYPE_MESSAGE: out[0] |= PROTOBUF_C_WIRE_TYPE_LENGTH_PREFIXED; return rv + prefixed_message_pack(*(ProtobufCMessage * const *) member, out + rv); } PROTOBUF_C__ASSERT_NOT_REACHED(); return 0; } /** * Pack a oneof field and return the number of bytes written. Only packs the * field that is selected by the case enum. * * \param field * Field descriptor. * \param oneof_case * A pointer to the case enum that selects the field in the oneof. * \param member * The field member. * \param[out] out * Packed value. * \return * Number of bytes written to `out`. */ static size_t oneof_field_pack(const ProtobufCFieldDescriptor *field, const uint32_t *oneof_case, const void *member, uint8_t *out) { if (*oneof_case == field->id) { if (field->type == PROTOBUF_C_TYPE_MESSAGE || field->type == PROTOBUF_C_TYPE_STRING) { const void *ptr = *(const void * const *) member; if (ptr == NULL || ptr == field->default_value) return 0; } } else { return 0; } return required_field_pack(field, member, out); } /** * Pack an optional field and return the number of bytes written. * * \param field * Field descriptor. * \param has * Whether the field is set. * \param member * The field member. * \param[out] out * Packed value. * \return * Number of bytes written to `out`. */ static size_t optional_field_pack(const ProtobufCFieldDescriptor *field, const protobuf_c_boolean *has, const void *member, uint8_t *out) { if (field->type == PROTOBUF_C_TYPE_MESSAGE || field->type == PROTOBUF_C_TYPE_STRING) { const void *ptr = *(const void * const *) member; if (ptr == NULL || ptr == field->default_value) return 0; } else { if (!*has) return 0; } return required_field_pack(field, member, out); } /** * Given a field type, return the in-memory size. * * \todo Implement as a table lookup. * * \param type * Field type. * \return * Size of the field. */ static inline size_t sizeof_elt_in_repeated_array(ProtobufCType type) { switch (type) { case PROTOBUF_C_TYPE_SINT32: case PROTOBUF_C_TYPE_INT32: case PROTOBUF_C_TYPE_UINT32: case PROTOBUF_C_TYPE_SFIXED32: case PROTOBUF_C_TYPE_FIXED32: case PROTOBUF_C_TYPE_FLOAT: case PROTOBUF_C_TYPE_ENUM: return 4; case PROTOBUF_C_TYPE_SINT64: case PROTOBUF_C_TYPE_INT64: case PROTOBUF_C_TYPE_UINT64: case PROTOBUF_C_TYPE_SFIXED64: case PROTOBUF_C_TYPE_FIXED64: case PROTOBUF_C_TYPE_DOUBLE: return 8; case PROTOBUF_C_TYPE_BOOL: return sizeof(protobuf_c_boolean); case PROTOBUF_C_TYPE_STRING: case PROTOBUF_C_TYPE_MESSAGE: return sizeof(void *); case PROTOBUF_C_TYPE_BYTES: return sizeof(ProtobufCBinaryData); } PROTOBUF_C__ASSERT_NOT_REACHED(); return 0; } /** * Pack an array of 32-bit quantities. * * \param[out] out * Destination. * \param[in] in * Source. * \param[in] n * Number of elements in the source array. */ static void copy_to_little_endian_32(void *out, const void *in, const unsigned n) { #if !defined(WORDS_BIGENDIAN) memcpy(out, in, n * 4); #else unsigned i; const uint32_t *ini = in; for (i = 0; i < n; i++) fixed32_pack(ini[i], (uint32_t *) out + i); #endif } /** * Pack an array of 64-bit quantities. * * \param[out] out * Destination. * \param[in] in * Source. * \param[in] n * Number of elements in the source array. */ static void copy_to_little_endian_64(void *out, const void *in, const unsigned n) { #if !defined(WORDS_BIGENDIAN) memcpy(out, in, n * 8); #else unsigned i; const uint64_t *ini = in; for (i = 0; i < n; i++) fixed64_pack(ini[i], (uint64_t *) out + i); #endif } /** * Get the minimum number of bytes required to pack a field value of a * particular type. * * \param type * Field type. * \return * Number of bytes. */ static unsigned get_type_min_size(ProtobufCType type) { if (type == PROTOBUF_C_TYPE_SFIXED32 || type == PROTOBUF_C_TYPE_FIXED32 || type == PROTOBUF_C_TYPE_FLOAT) { return 4; } if (type == PROTOBUF_C_TYPE_SFIXED64 || type == PROTOBUF_C_TYPE_FIXED64 || type == PROTOBUF_C_TYPE_DOUBLE) { return 8; } return 1; } /** * Packs the elements of a repeated field and returns the serialised field and * its length. * * \param field * Field descriptor. * \param count * Number of elements in the repeated field array. * \param member * Pointer to the elements for this repeated field. * \param[out] out * Serialised representation of the repeated field. * \return * Number of bytes serialised to `out`. */ static size_t repeated_field_pack(const ProtobufCFieldDescriptor *field, size_t count, const void *member, uint8_t *out) { void *array = *(void * const *) member; unsigned i; if (0 != (field->flags & PROTOBUF_C_FIELD_FLAG_PACKED)) { unsigned header_len; unsigned len_start; unsigned min_length; unsigned payload_len; unsigned length_size_min; unsigned actual_length_size; uint8_t *payload_at; if (count == 0) return 0; header_len = tag_pack(field->id, out); out[0] |= PROTOBUF_C_WIRE_TYPE_LENGTH_PREFIXED; len_start = header_len; min_length = get_type_min_size(field->type) * count; length_size_min = uint32_size(min_length); header_len += length_size_min; payload_at = out + header_len; switch (field->type) { case PROTOBUF_C_TYPE_SFIXED32: case PROTOBUF_C_TYPE_FIXED32: case PROTOBUF_C_TYPE_FLOAT: copy_to_little_endian_32(payload_at, array, count); payload_at += count * 4; break; case PROTOBUF_C_TYPE_SFIXED64: case PROTOBUF_C_TYPE_FIXED64: case PROTOBUF_C_TYPE_DOUBLE: copy_to_little_endian_64(payload_at, array, count); payload_at += count * 8; break; case PROTOBUF_C_TYPE_INT32: { const int32_t *arr = (const int32_t *) array; for (i = 0; i < count; i++) payload_at += int32_pack(arr[i], payload_at); break; } case PROTOBUF_C_TYPE_SINT32: { const int32_t *arr = (const int32_t *) array; for (i = 0; i < count; i++) payload_at += sint32_pack(arr[i], payload_at); break; } case PROTOBUF_C_TYPE_SINT64: { const int64_t *arr = (const int64_t *) array; for (i = 0; i < count; i++) payload_at += sint64_pack(arr[i], payload_at); break; } case PROTOBUF_C_TYPE_ENUM: case PROTOBUF_C_TYPE_UINT32: { const uint32_t *arr = (const uint32_t *) array; for (i = 0; i < count; i++) payload_at += uint32_pack(arr[i], payload_at); break; } case PROTOBUF_C_TYPE_INT64: case PROTOBUF_C_TYPE_UINT64: { const uint64_t *arr = (const uint64_t *) array; for (i = 0; i < count; i++) payload_at += uint64_pack(arr[i], payload_at); break; } case PROTOBUF_C_TYPE_BOOL: { const protobuf_c_boolean *arr = (const protobuf_c_boolean *) array; for (i = 0; i < count; i++) payload_at += boolean_pack(arr[i], payload_at); break; } default: PROTOBUF_C__ASSERT_NOT_REACHED(); } payload_len = payload_at - (out + header_len); actual_length_size = uint32_size(payload_len); if (length_size_min != actual_length_size) { assert(actual_length_size == length_size_min + 1); memmove(out + header_len + 1, out + header_len, payload_len); header_len++; } uint32_pack(payload_len, out + len_start); return header_len + payload_len; } else { /* not "packed" cased */ /* CONSIDER: optimize this case a bit (by putting the loop inside the switch) */ size_t rv = 0; unsigned siz = sizeof_elt_in_repeated_array(field->type); for (i = 0; i < count; i++) { rv += required_field_pack(field, array, out + rv); array = (char *)array + siz; } return rv; } } static size_t unknown_field_pack(const ProtobufCMessageUnknownField *field, uint8_t *out) { size_t rv = tag_pack(field->tag, out); out[0] |= field->wire_type; memcpy(out + rv, field->data, field->len); return rv + field->len; } /**@}*/ size_t protobuf_c_message_pack(const ProtobufCMessage *message, uint8_t *out) { unsigned i; size_t rv = 0; ASSERT_IS_MESSAGE(message); for (i = 0; i < message->descriptor->n_fields; i++) { const ProtobufCFieldDescriptor *field = message->descriptor->fields + i; const void *member = ((const char *) message) + field->offset; /* * It doesn't hurt to compute qmember (a pointer to the * quantifier field of the structure), but the pointer is only * valid if the field is: * - a repeated field, or * - a field that is part of a oneof * - an optional field that isn't a pointer type * (Meaning: not a message or a string). */ const void *qmember = ((const char *) message) + field->quantifier_offset; if (field->label == PROTOBUF_C_LABEL_REQUIRED) { rv += required_field_pack(field, member, out + rv); } else if (field->label == PROTOBUF_C_LABEL_OPTIONAL) { if (0 != (field->flags & PROTOBUF_C_FIELD_FLAG_ONEOF)) rv += oneof_field_pack (field, qmember, member, out + rv); else rv += optional_field_pack(field, qmember, member, out + rv); } else { rv += repeated_field_pack(field, *(const size_t *) qmember, member, out + rv); } } for (i = 0; i < message->n_unknown_fields; i++) rv += unknown_field_pack(&message->unknown_fields[i], out + rv); return rv; } /** * \defgroup packbuf protobuf_c_message_pack_to_buffer() implementation * * Routines mainly used by protobuf_c_message_pack_to_buffer(). * * \ingroup internal * @{ */ /** * Pack a required field to a virtual buffer. * * \param field * Field descriptor. * \param member * The element to be packed. * \param[out] buffer * Virtual buffer to append data to. * \return * Number of bytes packed. */ static size_t required_field_pack_to_buffer(const ProtobufCFieldDescriptor *field, const void *member, ProtobufCBuffer *buffer) { size_t rv; uint8_t scratch[MAX_UINT64_ENCODED_SIZE * 2]; rv = tag_pack(field->id, scratch); switch (field->type) { case PROTOBUF_C_TYPE_SINT32: scratch[0] |= PROTOBUF_C_WIRE_TYPE_VARINT; rv += sint32_pack(*(const int32_t *) member, scratch + rv); buffer->append(buffer, rv, scratch); break; case PROTOBUF_C_TYPE_INT32: scratch[0] |= PROTOBUF_C_WIRE_TYPE_VARINT; rv += int32_pack(*(const uint32_t *) member, scratch + rv); buffer->append(buffer, rv, scratch); break; case PROTOBUF_C_TYPE_UINT32: case PROTOBUF_C_TYPE_ENUM: scratch[0] |= PROTOBUF_C_WIRE_TYPE_VARINT; rv += uint32_pack(*(const uint32_t *) member, scratch + rv); buffer->append(buffer, rv, scratch); break; case PROTOBUF_C_TYPE_SINT64: scratch[0] |= PROTOBUF_C_WIRE_TYPE_VARINT; rv += sint64_pack(*(const int64_t *) member, scratch + rv); buffer->append(buffer, rv, scratch); break; case PROTOBUF_C_TYPE_INT64: case PROTOBUF_C_TYPE_UINT64: scratch[0] |= PROTOBUF_C_WIRE_TYPE_VARINT; rv += uint64_pack(*(const uint64_t *) member, scratch + rv); buffer->append(buffer, rv, scratch); break; case PROTOBUF_C_TYPE_SFIXED32: case PROTOBUF_C_TYPE_FIXED32: case PROTOBUF_C_TYPE_FLOAT: scratch[0] |= PROTOBUF_C_WIRE_TYPE_32BIT; rv += fixed32_pack(*(const uint32_t *) member, scratch + rv); buffer->append(buffer, rv, scratch); break; case PROTOBUF_C_TYPE_SFIXED64: case PROTOBUF_C_TYPE_FIXED64: case PROTOBUF_C_TYPE_DOUBLE: scratch[0] |= PROTOBUF_C_WIRE_TYPE_64BIT; rv += fixed64_pack(*(const uint64_t *) member, scratch + rv); buffer->append(buffer, rv, scratch); break; case PROTOBUF_C_TYPE_BOOL: scratch[0] |= PROTOBUF_C_WIRE_TYPE_VARINT; rv += boolean_pack(*(const protobuf_c_boolean *) member, scratch + rv); buffer->append(buffer, rv, scratch); break; case PROTOBUF_C_TYPE_STRING: { const char *str = *(char *const *) member; size_t sublen = str ? strlen(str) : 0; scratch[0] |= PROTOBUF_C_WIRE_TYPE_LENGTH_PREFIXED; rv += uint32_pack(sublen, scratch + rv); buffer->append(buffer, rv, scratch); buffer->append(buffer, sublen, (const uint8_t *) str); rv += sublen; break; } case PROTOBUF_C_TYPE_BYTES: { const ProtobufCBinaryData *bd = ((const ProtobufCBinaryData *) member); size_t sublen = bd->len; scratch[0] |= PROTOBUF_C_WIRE_TYPE_LENGTH_PREFIXED; rv += uint32_pack(sublen, scratch + rv); buffer->append(buffer, rv, scratch); buffer->append(buffer, sublen, bd->data); rv += sublen; break; } case PROTOBUF_C_TYPE_MESSAGE: { uint8_t simple_buffer_scratch[256]; size_t sublen; const ProtobufCMessage *msg = *(ProtobufCMessage * const *) member; ProtobufCBufferSimple simple_buffer = PROTOBUF_C_BUFFER_SIMPLE_INIT(simple_buffer_scratch); scratch[0] |= PROTOBUF_C_WIRE_TYPE_LENGTH_PREFIXED; if (msg == NULL) sublen = 0; else sublen = protobuf_c_message_pack_to_buffer(msg, &simple_buffer.base); rv += uint32_pack(sublen, scratch + rv); buffer->append(buffer, rv, scratch); buffer->append(buffer, sublen, simple_buffer.data); rv += sublen; PROTOBUF_C_BUFFER_SIMPLE_CLEAR(&simple_buffer); break; } default: PROTOBUF_C__ASSERT_NOT_REACHED(); } return rv; } /** * Pack a oneof field to a buffer. Only packs the field that is selected by the case enum. * * \param field * Field descriptor. * \param oneof_case * A pointer to the case enum that selects the field in the oneof. * \param member * The element to be packed. * \param[out] buffer * Virtual buffer to append data to. * \return * Number of bytes serialised to `buffer`. */ static size_t oneof_field_pack_to_buffer(const ProtobufCFieldDescriptor *field, const uint32_t *oneof_case, const void *member, ProtobufCBuffer *buffer) { if (*oneof_case == field->id) { if (field->type == PROTOBUF_C_TYPE_MESSAGE || field->type == PROTOBUF_C_TYPE_STRING) { const void *ptr = *(const void *const *) member; if (ptr == NULL || ptr == field->default_value) return 0; } } else { return 0; } return required_field_pack_to_buffer(field, member, buffer); } /** * Pack an optional field to a buffer. * * \param field * Field descriptor. * \param has * Whether the field is set. * \param member * The element to be packed. * \param[out] buffer * Virtual buffer to append data to. * \return * Number of bytes serialised to `buffer`. */ static size_t optional_field_pack_to_buffer(const ProtobufCFieldDescriptor *field, const protobuf_c_boolean *has, const void *member, ProtobufCBuffer *buffer) { if (field->type == PROTOBUF_C_TYPE_MESSAGE || field->type == PROTOBUF_C_TYPE_STRING) { const void *ptr = *(const void *const *) member; if (ptr == NULL || ptr == field->default_value) return 0; } else { if (!*has) return 0; } return required_field_pack_to_buffer(field, member, buffer); } /** * Get the packed size of an array of same field type. * * \param field * Field descriptor. * \param count * Number of elements of this type. * \param array * The elements to get the size of. * \return * Number of bytes required. */ static size_t get_packed_payload_length(const ProtobufCFieldDescriptor *field, unsigned count, const void *array) { unsigned rv = 0; unsigned i; switch (field->type) { case PROTOBUF_C_TYPE_SFIXED32: case PROTOBUF_C_TYPE_FIXED32: case PROTOBUF_C_TYPE_FLOAT: return count * 4; case PROTOBUF_C_TYPE_SFIXED64: case PROTOBUF_C_TYPE_FIXED64: case PROTOBUF_C_TYPE_DOUBLE: return count * 8; case PROTOBUF_C_TYPE_INT32: { const int32_t *arr = (const int32_t *) array; for (i = 0; i < count; i++) rv += int32_size(arr[i]); break; } case PROTOBUF_C_TYPE_SINT32: { const int32_t *arr = (const int32_t *) array; for (i = 0; i < count; i++) rv += sint32_size(arr[i]); break; } case PROTOBUF_C_TYPE_ENUM: case PROTOBUF_C_TYPE_UINT32: { const uint32_t *arr = (const uint32_t *) array; for (i = 0; i < count; i++) rv += uint32_size(arr[i]); break; } case PROTOBUF_C_TYPE_SINT64: { const int64_t *arr = (const int64_t *) array; for (i = 0; i < count; i++) rv += sint64_size(arr[i]); break; } case PROTOBUF_C_TYPE_INT64: case PROTOBUF_C_TYPE_UINT64: { const uint64_t *arr = (const uint64_t *) array; for (i = 0; i < count; i++) rv += uint64_size(arr[i]); break; } case PROTOBUF_C_TYPE_BOOL: return count; default: PROTOBUF_C__ASSERT_NOT_REACHED(); } return rv; } /** * Pack an array of same field type to a virtual buffer. * * \param field * Field descriptor. * \param count * Number of elements of this type. * \param array * The elements to get the size of. * \param[out] buffer * Virtual buffer to append data to. * \return * Number of bytes packed. */ static size_t pack_buffer_packed_payload(const ProtobufCFieldDescriptor *field, unsigned count, const void *array, ProtobufCBuffer *buffer) { uint8_t scratch[16]; size_t rv = 0; unsigned i; switch (field->type) { case PROTOBUF_C_TYPE_SFIXED32: case PROTOBUF_C_TYPE_FIXED32: case PROTOBUF_C_TYPE_FLOAT: #if !defined(WORDS_BIGENDIAN) rv = count * 4; goto no_packing_needed; #else for (i = 0; i < count; i++) { unsigned len = fixed32_pack(((uint32_t *) array)[i], scratch); buffer->append(buffer, len, scratch); rv += len; } break; #endif case PROTOBUF_C_TYPE_SFIXED64: case PROTOBUF_C_TYPE_FIXED64: case PROTOBUF_C_TYPE_DOUBLE: #if !defined(WORDS_BIGENDIAN) rv = count * 8; goto no_packing_needed; #else for (i = 0; i < count; i++) { unsigned len = fixed64_pack(((uint64_t *) array)[i], scratch); buffer->append(buffer, len, scratch); rv += len; } break; #endif case PROTOBUF_C_TYPE_INT32: for (i = 0; i < count; i++) { unsigned len = int32_pack(((int32_t *) array)[i], scratch); buffer->append(buffer, len, scratch); rv += len; } break; case PROTOBUF_C_TYPE_SINT32: for (i = 0; i < count; i++) { unsigned len = sint32_pack(((int32_t *) array)[i], scratch); buffer->append(buffer, len, scratch); rv += len; } break; case PROTOBUF_C_TYPE_ENUM: case PROTOBUF_C_TYPE_UINT32: for (i = 0; i < count; i++) { unsigned len = uint32_pack(((uint32_t *) array)[i], scratch); buffer->append(buffer, len, scratch); rv += len; } break; case PROTOBUF_C_TYPE_SINT64: for (i = 0; i < count; i++) { unsigned len = sint64_pack(((int64_t *) array)[i], scratch); buffer->append(buffer, len, scratch); rv += len; } break; case PROTOBUF_C_TYPE_INT64: case PROTOBUF_C_TYPE_UINT64: for (i = 0; i < count; i++) { unsigned len = uint64_pack(((uint64_t *) array)[i], scratch); buffer->append(buffer, len, scratch); rv += len; } break; case PROTOBUF_C_TYPE_BOOL: for (i = 0; i < count; i++) { unsigned len = boolean_pack(((protobuf_c_boolean *) array)[i], scratch); buffer->append(buffer, len, scratch); rv += len; } return count; default: PROTOBUF_C__ASSERT_NOT_REACHED(); } return rv; no_packing_needed: buffer->append(buffer, rv, array); return rv; } static size_t repeated_field_pack_to_buffer(const ProtobufCFieldDescriptor *field, unsigned count, const void *member, ProtobufCBuffer *buffer) { char *array = *(char * const *) member; if (count == 0) return 0; if (0 != (field->flags & PROTOBUF_C_FIELD_FLAG_PACKED)) { uint8_t scratch[MAX_UINT64_ENCODED_SIZE * 2]; size_t rv = tag_pack(field->id, scratch); size_t payload_len = get_packed_payload_length(field, count, array); size_t tmp; scratch[0] |= PROTOBUF_C_WIRE_TYPE_LENGTH_PREFIXED; rv += uint32_pack(payload_len, scratch + rv); buffer->append(buffer, rv, scratch); tmp = pack_buffer_packed_payload(field, count, array, buffer); assert(tmp == payload_len); return rv + payload_len; } else { size_t siz; unsigned i; /* CONSIDER: optimize this case a bit (by putting the loop inside the switch) */ unsigned rv = 0; siz = sizeof_elt_in_repeated_array(field->type); for (i = 0; i < count; i++) { rv += required_field_pack_to_buffer(field, array, buffer); array += siz; } return rv; } } static size_t unknown_field_pack_to_buffer(const ProtobufCMessageUnknownField *field, ProtobufCBuffer *buffer) { uint8_t header[MAX_UINT64_ENCODED_SIZE]; size_t rv = tag_pack(field->tag, header); header[0] |= field->wire_type; buffer->append(buffer, rv, header); buffer->append(buffer, field->len, field->data); return rv + field->len; } /**@}*/ size_t protobuf_c_message_pack_to_buffer(const ProtobufCMessage *message, ProtobufCBuffer *buffer) { unsigned i; size_t rv = 0; ASSERT_IS_MESSAGE(message); for (i = 0; i < message->descriptor->n_fields; i++) { const ProtobufCFieldDescriptor *field = message->descriptor->fields + i; const void *member = ((const char *) message) + field->offset; const void *qmember = ((const char *) message) + field->quantifier_offset; if (field->label == PROTOBUF_C_LABEL_REQUIRED) { rv += required_field_pack_to_buffer(field, member, buffer); } else if (field->label == PROTOBUF_C_LABEL_OPTIONAL) { if (0 != (field->flags & PROTOBUF_C_FIELD_FLAG_ONEOF)) { rv += oneof_field_pack_to_buffer( field, qmember, member, buffer ); } else { rv += optional_field_pack_to_buffer( field, qmember, member, buffer ); } } else { rv += repeated_field_pack_to_buffer( field, *(const size_t *) qmember, member, buffer ); } } for (i = 0; i < message->n_unknown_fields; i++) rv += unknown_field_pack_to_buffer(&message->unknown_fields[i], buffer); return rv; } /** * \defgroup unpack unpacking implementation * * Routines mainly used by the unpacking functions. * * \ingroup internal * @{ */ static inline int int_range_lookup(unsigned n_ranges, const ProtobufCIntRange *ranges, int value) { unsigned n; unsigned start; if (n_ranges == 0) return -1; start = 0; n = n_ranges; while (n > 1) { unsigned mid = start + n / 2; if (value < ranges[mid].start_value) { n = mid - start; } else if (value >= ranges[mid].start_value + (int) (ranges[mid + 1].orig_index - ranges[mid].orig_index)) { unsigned new_start = mid + 1; n = start + n - new_start; start = new_start; } else return (value - ranges[mid].start_value) + ranges[mid].orig_index; } if (n > 0) { unsigned start_orig_index = ranges[start].orig_index; unsigned range_size = ranges[start + 1].orig_index - start_orig_index; if (ranges[start].start_value <= value && value < (int) (ranges[start].start_value + range_size)) { return (value - ranges[start].start_value) + start_orig_index; } } return -1; } static size_t parse_tag_and_wiretype(size_t len, const uint8_t *data, uint32_t *tag_out, ProtobufCWireType *wiretype_out) { unsigned max_rv = len > 5 ? 5 : len; uint32_t tag = (data[0] & 0x7f) >> 3; unsigned shift = 4; unsigned rv; *wiretype_out = data[0] & 7; if ((data[0] & 0x80) == 0) { *tag_out = tag; return 1; } for (rv = 1; rv < max_rv; rv++) { if (data[rv] & 0x80) { tag |= (data[rv] & 0x7f) << shift; shift += 7; } else { tag |= data[rv] << shift; *tag_out = tag; return rv + 1; } } return 0; /* error: bad header */ } /* sizeof(ScannedMember) must be <= (1< len) { PROTOBUF_C_UNPACK_ERROR("data too short after length-prefix of %u", val); return 0; } return hdr_len + val; } static size_t max_b128_numbers(size_t len, const uint8_t *data) { size_t rv = 0; while (len--) if ((*data++ & 0x80) == 0) ++rv; return rv; } /**@}*/ /** * Merge earlier message into a latter message. * * For numeric types and strings, if the same value appears multiple * times, the parser accepts the last value it sees. For embedded * message fields, the parser merges multiple instances of the same * field. That is, all singular scalar fields in the latter instance * replace those in the former, singular embedded messages are merged, * and repeated fields are concatenated. * * The earlier message should be freed after calling this function, as * some of its fields may have been reused and changed to their default * values during the merge. */ static protobuf_c_boolean merge_messages(ProtobufCMessage *earlier_msg, ProtobufCMessage *latter_msg, ProtobufCAllocator *allocator) { unsigned i; const ProtobufCFieldDescriptor *fields = latter_msg->descriptor->fields; for (i = 0; i < latter_msg->descriptor->n_fields; i++) { if (fields[i].label == PROTOBUF_C_LABEL_REPEATED) { size_t *n_earlier = STRUCT_MEMBER_PTR(size_t, earlier_msg, fields[i].quantifier_offset); uint8_t **p_earlier = STRUCT_MEMBER_PTR(uint8_t *, earlier_msg, fields[i].offset); size_t *n_latter = STRUCT_MEMBER_PTR(size_t, latter_msg, fields[i].quantifier_offset); uint8_t **p_latter = STRUCT_MEMBER_PTR(uint8_t *, latter_msg, fields[i].offset); if (*n_earlier > 0) { if (*n_latter > 0) { /* Concatenate the repeated field */ size_t el_size = sizeof_elt_in_repeated_array(fields[i].type); uint8_t *new_field; new_field = do_alloc(allocator, (*n_earlier + *n_latter) * el_size); if (!new_field) return FALSE; memcpy(new_field, *p_earlier, *n_earlier * el_size); memcpy(new_field + *n_earlier * el_size, *p_latter, *n_latter * el_size); do_free(allocator, *p_latter); do_free(allocator, *p_earlier); *p_latter = new_field; *n_latter = *n_earlier + *n_latter; } else { /* Zero copy the repeated field from the earlier message */ *n_latter = *n_earlier; *p_latter = *p_earlier; } /* Make sure the field does not get double freed */ *n_earlier = 0; *p_earlier = 0; } } else if (fields[i].label == PROTOBUF_C_LABEL_OPTIONAL) { const ProtobufCFieldDescriptor *field; uint32_t *earlier_case_p = STRUCT_MEMBER_PTR(uint32_t, earlier_msg, fields[i]. quantifier_offset); uint32_t *latter_case_p = STRUCT_MEMBER_PTR(uint32_t, latter_msg, fields[i]. quantifier_offset); protobuf_c_boolean need_to_merge = FALSE; void *earlier_elem; void *latter_elem; const void *def_val; if (fields[i].flags & PROTOBUF_C_FIELD_FLAG_ONEOF) { if (*latter_case_p == 0) { /* lookup correct oneof field */ int field_index = int_range_lookup( latter_msg->descriptor ->n_field_ranges, latter_msg->descriptor ->field_ranges, *earlier_case_p); field = latter_msg->descriptor->fields + field_index; } else { /* Oneof is present in the latter message, move on */ continue; } } else { field = &fields[i]; } earlier_elem = STRUCT_MEMBER_P(earlier_msg, field->offset); latter_elem = STRUCT_MEMBER_P(latter_msg, field->offset); def_val = field->default_value; switch (field->type) { case PROTOBUF_C_TYPE_MESSAGE: { ProtobufCMessage *em = *(ProtobufCMessage **) earlier_elem; ProtobufCMessage *lm = *(ProtobufCMessage **) latter_elem; if (em != NULL) { if (lm != NULL) { if (!merge_messages(em, lm, allocator)) return FALSE; /* Already merged */ need_to_merge = FALSE; } else { /* Zero copy the message */ need_to_merge = TRUE; } } break; } case PROTOBUF_C_TYPE_BYTES: { uint8_t *e_data = ((ProtobufCBinaryData *) earlier_elem)->data; uint8_t *l_data = ((ProtobufCBinaryData *) latter_elem)->data; const ProtobufCBinaryData *d_bd = (ProtobufCBinaryData *) def_val; need_to_merge = (e_data != NULL && (d_bd == NULL || e_data != d_bd->data)) && (l_data == NULL || (d_bd != NULL && l_data == d_bd->data)); break; } case PROTOBUF_C_TYPE_STRING: { char *e_str = *(char **) earlier_elem; char *l_str = *(char **) latter_elem; const char *d_str = def_val; need_to_merge = e_str != d_str && l_str == d_str; break; } default: { /* Could be has field or case enum, the logic is * equivalent, since 0 (FALSE) means not set for * oneof */ need_to_merge = (*earlier_case_p != 0) && (*latter_case_p == 0); break; } } if (need_to_merge) { size_t el_size = sizeof_elt_in_repeated_array(field->type); memcpy(latter_elem, earlier_elem, el_size); /* * Reset the element from the old message to 0 * to make sure earlier message deallocation * doesn't corrupt zero-copied data in the new * message, earlier message will be freed after * this function is called anyway */ memset(earlier_elem, 0, el_size); if (field->quantifier_offset != 0) { /* Set the has field or the case enum, * if applicable */ *latter_case_p = *earlier_case_p; *earlier_case_p = 0; } } } } return TRUE; } /** * Count packed elements. * * Given a raw slab of packed-repeated values, determine the number of * elements. This function detects certain kinds of errors but not * others; the remaining error checking is done by * parse_packed_repeated_member(). */ static protobuf_c_boolean count_packed_elements(ProtobufCType type, size_t len, const uint8_t *data, size_t *count_out) { switch (type) { case PROTOBUF_C_TYPE_SFIXED32: case PROTOBUF_C_TYPE_FIXED32: case PROTOBUF_C_TYPE_FLOAT: if (len % 4 != 0) { PROTOBUF_C_UNPACK_ERROR("length must be a multiple of 4 for fixed-length 32-bit types"); return FALSE; } *count_out = len / 4; return TRUE; case PROTOBUF_C_TYPE_SFIXED64: case PROTOBUF_C_TYPE_FIXED64: case PROTOBUF_C_TYPE_DOUBLE: if (len % 8 != 0) { PROTOBUF_C_UNPACK_ERROR("length must be a multiple of 8 for fixed-length 64-bit types"); return FALSE; } *count_out = len / 8; return TRUE; case PROTOBUF_C_TYPE_INT32: case PROTOBUF_C_TYPE_SINT32: case PROTOBUF_C_TYPE_ENUM: case PROTOBUF_C_TYPE_UINT32: case PROTOBUF_C_TYPE_INT64: case PROTOBUF_C_TYPE_SINT64: case PROTOBUF_C_TYPE_UINT64: *count_out = max_b128_numbers(len, data); return TRUE; case PROTOBUF_C_TYPE_BOOL: *count_out = len; return TRUE; case PROTOBUF_C_TYPE_STRING: case PROTOBUF_C_TYPE_BYTES: case PROTOBUF_C_TYPE_MESSAGE: default: PROTOBUF_C_UNPACK_ERROR("bad protobuf-c type %u for packed-repeated", type); return FALSE; } } static inline uint32_t parse_uint32(unsigned len, const uint8_t *data) { uint32_t rv = data[0] & 0x7f; if (len > 1) { rv |= ((uint32_t) (data[1] & 0x7f) << 7); if (len > 2) { rv |= ((uint32_t) (data[2] & 0x7f) << 14); if (len > 3) { rv |= ((uint32_t) (data[3] & 0x7f) << 21); if (len > 4) rv |= ((uint32_t) (data[4]) << 28); } } } return rv; } static inline uint32_t parse_int32(unsigned len, const uint8_t *data) { return parse_uint32(len, data); } static inline int32_t unzigzag32(uint32_t v) { if (v & 1) return -(v >> 1) - 1; else return v >> 1; } static inline uint32_t parse_fixed_uint32(const uint8_t *data) { #if !defined(WORDS_BIGENDIAN) uint32_t t; memcpy(&t, data, 4); return t; #else return data[0] | ((uint32_t) (data[1]) << 8) | ((uint32_t) (data[2]) << 16) | ((uint32_t) (data[3]) << 24); #endif } static uint64_t parse_uint64(unsigned len, const uint8_t *data) { unsigned shift, i; uint64_t rv; if (len < 5) return parse_uint32(len, data); rv = ((uint64_t) (data[0] & 0x7f)) | ((uint64_t) (data[1] & 0x7f) << 7) | ((uint64_t) (data[2] & 0x7f) << 14) | ((uint64_t) (data[3] & 0x7f) << 21); shift = 28; for (i = 4; i < len; i++) { rv |= (((uint64_t) (data[i] & 0x7f)) << shift); shift += 7; } return rv; } static inline int64_t unzigzag64(uint64_t v) { if (v & 1) return -(v >> 1) - 1; else return v >> 1; } static inline uint64_t parse_fixed_uint64(const uint8_t *data) { #if !defined(WORDS_BIGENDIAN) uint64_t t; memcpy(&t, data, 8); return t; #else return (uint64_t) parse_fixed_uint32(data) | (((uint64_t) parse_fixed_uint32(data + 4)) << 32); #endif } static protobuf_c_boolean parse_boolean(unsigned len, const uint8_t *data) { unsigned i; for (i = 0; i < len; i++) if (data[i] & 0x7f) return TRUE; return FALSE; } static protobuf_c_boolean parse_required_member(ScannedMember *scanned_member, void *member, ProtobufCAllocator *allocator, protobuf_c_boolean maybe_clear) { unsigned len = scanned_member->len; const uint8_t *data = scanned_member->data; ProtobufCWireType wire_type = scanned_member->wire_type; switch (scanned_member->field->type) { case PROTOBUF_C_TYPE_INT32: if (wire_type != PROTOBUF_C_WIRE_TYPE_VARINT) return FALSE; *(uint32_t *) member = parse_int32(len, data); return TRUE; case PROTOBUF_C_TYPE_UINT32: if (wire_type != PROTOBUF_C_WIRE_TYPE_VARINT) return FALSE; *(uint32_t *) member = parse_uint32(len, data); return TRUE; case PROTOBUF_C_TYPE_SINT32: if (wire_type != PROTOBUF_C_WIRE_TYPE_VARINT) return FALSE; *(int32_t *) member = unzigzag32(parse_uint32(len, data)); return TRUE; case PROTOBUF_C_TYPE_SFIXED32: case PROTOBUF_C_TYPE_FIXED32: case PROTOBUF_C_TYPE_FLOAT: if (wire_type != PROTOBUF_C_WIRE_TYPE_32BIT) return FALSE; *(uint32_t *) member = parse_fixed_uint32(data); return TRUE; case PROTOBUF_C_TYPE_INT64: case PROTOBUF_C_TYPE_UINT64: if (wire_type != PROTOBUF_C_WIRE_TYPE_VARINT) return FALSE; *(uint64_t *) member = parse_uint64(len, data); return TRUE; case PROTOBUF_C_TYPE_SINT64: if (wire_type != PROTOBUF_C_WIRE_TYPE_VARINT) return FALSE; *(int64_t *) member = unzigzag64(parse_uint64(len, data)); return TRUE; case PROTOBUF_C_TYPE_SFIXED64: case PROTOBUF_C_TYPE_FIXED64: case PROTOBUF_C_TYPE_DOUBLE: if (wire_type != PROTOBUF_C_WIRE_TYPE_64BIT) return FALSE; *(uint64_t *) member = parse_fixed_uint64(data); return TRUE; case PROTOBUF_C_TYPE_BOOL: *(protobuf_c_boolean *) member = parse_boolean(len, data); return TRUE; case PROTOBUF_C_TYPE_ENUM: if (wire_type != PROTOBUF_C_WIRE_TYPE_VARINT) return FALSE; *(uint32_t *) member = parse_uint32(len, data); return TRUE; case PROTOBUF_C_TYPE_STRING: { char **pstr = member; unsigned pref_len = scanned_member->length_prefix_len; if (wire_type != PROTOBUF_C_WIRE_TYPE_LENGTH_PREFIXED) return FALSE; if (maybe_clear && *pstr != NULL) { const char *def = scanned_member->field->default_value; if (*pstr != NULL && *pstr != def) do_free(allocator, *pstr); } *pstr = do_alloc(allocator, len - pref_len + 1); if (*pstr == NULL) return FALSE; memcpy(*pstr, data + pref_len, len - pref_len); (*pstr)[len - pref_len] = 0; return TRUE; } case PROTOBUF_C_TYPE_BYTES: { ProtobufCBinaryData *bd = member; const ProtobufCBinaryData *def_bd; unsigned pref_len = scanned_member->length_prefix_len; if (wire_type != PROTOBUF_C_WIRE_TYPE_LENGTH_PREFIXED) return FALSE; def_bd = scanned_member->field->default_value; if (maybe_clear && bd->data != NULL && (def_bd == NULL || bd->data != def_bd->data)) { do_free(allocator, bd->data); } if (len - pref_len > 0) { bd->data = do_alloc(allocator, len - pref_len); if (bd->data == NULL) return FALSE; memcpy(bd->data, data + pref_len, len - pref_len); } else { bd->data = NULL; } bd->len = len - pref_len; return TRUE; } case PROTOBUF_C_TYPE_MESSAGE: { ProtobufCMessage **pmessage = member; ProtobufCMessage *subm; const ProtobufCMessage *def_mess; protobuf_c_boolean merge_successful = TRUE; unsigned pref_len = scanned_member->length_prefix_len; if (wire_type != PROTOBUF_C_WIRE_TYPE_LENGTH_PREFIXED) return FALSE; def_mess = scanned_member->field->default_value; subm = protobuf_c_message_unpack(scanned_member->field->descriptor, allocator, len - pref_len, data + pref_len); if (maybe_clear && *pmessage != NULL && *pmessage != def_mess) { if (subm != NULL) merge_successful = merge_messages(*pmessage, subm, allocator); /* Delete the previous message */ protobuf_c_message_free_unpacked(*pmessage, allocator); } *pmessage = subm; if (subm == NULL || !merge_successful) return FALSE; return TRUE; } } return FALSE; } static protobuf_c_boolean parse_oneof_member (ScannedMember *scanned_member, void *member, ProtobufCMessage *message, ProtobufCAllocator *allocator) { uint32_t *oneof_case = STRUCT_MEMBER_PTR(uint32_t, message, scanned_member->field->quantifier_offset); /* If we have already parsed a member of this oneof, free it. */ if (*oneof_case != 0) { /* lookup field */ int field_index = int_range_lookup(message->descriptor->n_field_ranges, message->descriptor->field_ranges, *oneof_case); const ProtobufCFieldDescriptor *old_field = message->descriptor->fields + field_index; size_t el_size; switch (old_field->type) { case PROTOBUF_C_TYPE_STRING: { char **pstr = member; const char *def = old_field->default_value; if (*pstr != NULL && *pstr != def) do_free(allocator, *pstr); break; } case PROTOBUF_C_TYPE_BYTES: { ProtobufCBinaryData *bd = member; const ProtobufCBinaryData *def_bd = old_field->default_value; if (bd->data != NULL && (def_bd == NULL || bd->data != def_bd->data)) { do_free(allocator, bd->data); } break; } case PROTOBUF_C_TYPE_MESSAGE: { ProtobufCMessage **pmessage = member; const ProtobufCMessage *def_mess = old_field->default_value; if (*pmessage != NULL && *pmessage != def_mess) protobuf_c_message_free_unpacked(*pmessage, allocator); break; } default: break; } el_size = sizeof_elt_in_repeated_array(old_field->type); memset (member, 0, el_size); } if (!parse_required_member (scanned_member, member, allocator, TRUE)) return FALSE; *oneof_case = scanned_member->tag; return TRUE; } static protobuf_c_boolean parse_optional_member(ScannedMember *scanned_member, void *member, ProtobufCMessage *message, ProtobufCAllocator *allocator) { if (!parse_required_member(scanned_member, member, allocator, TRUE)) return FALSE; if (scanned_member->field->quantifier_offset != 0) STRUCT_MEMBER(protobuf_c_boolean, message, scanned_member->field->quantifier_offset) = TRUE; return TRUE; } static protobuf_c_boolean parse_repeated_member(ScannedMember *scanned_member, void *member, ProtobufCMessage *message, ProtobufCAllocator *allocator) { const ProtobufCFieldDescriptor *field = scanned_member->field; size_t *p_n = STRUCT_MEMBER_PTR(size_t, message, field->quantifier_offset); size_t siz = sizeof_elt_in_repeated_array(field->type); char *array = *(char **) member; if (!parse_required_member(scanned_member, array + siz * (*p_n), allocator, FALSE)) { return FALSE; } *p_n += 1; return TRUE; } static unsigned scan_varint(unsigned len, const uint8_t *data) { unsigned i; if (len > 10) len = 10; for (i = 0; i < len; i++) if ((data[i] & 0x80) == 0) break; if (i == len) return 0; return i + 1; } static protobuf_c_boolean parse_packed_repeated_member(ScannedMember *scanned_member, void *member, ProtobufCMessage *message) { const ProtobufCFieldDescriptor *field = scanned_member->field; size_t *p_n = STRUCT_MEMBER_PTR(size_t, message, field->quantifier_offset); size_t siz = sizeof_elt_in_repeated_array(field->type); void *array = *(char **) member + siz * (*p_n); const uint8_t *at = scanned_member->data + scanned_member->length_prefix_len; size_t rem = scanned_member->len - scanned_member->length_prefix_len; size_t count = 0; unsigned i; switch (field->type) { case PROTOBUF_C_TYPE_SFIXED32: case PROTOBUF_C_TYPE_FIXED32: case PROTOBUF_C_TYPE_FLOAT: count = (scanned_member->len - scanned_member->length_prefix_len) / 4; #if !defined(WORDS_BIGENDIAN) goto no_unpacking_needed; #else for (i = 0; i < count; i++) { ((uint32_t *) array)[i] = parse_fixed_uint32(at); at += 4; } break; #endif case PROTOBUF_C_TYPE_SFIXED64: case PROTOBUF_C_TYPE_FIXED64: case PROTOBUF_C_TYPE_DOUBLE: count = (scanned_member->len - scanned_member->length_prefix_len) / 8; #if !defined(WORDS_BIGENDIAN) goto no_unpacking_needed; #else for (i = 0; i < count; i++) { ((uint64_t *) array)[i] = parse_fixed_uint64(at); at += 8; } break; #endif case PROTOBUF_C_TYPE_INT32: while (rem > 0) { unsigned s = scan_varint(rem, at); if (s == 0) { PROTOBUF_C_UNPACK_ERROR("bad packed-repeated int32 value"); return FALSE; } ((int32_t *) array)[count++] = parse_int32(s, at); at += s; rem -= s; } break; case PROTOBUF_C_TYPE_SINT32: while (rem > 0) { unsigned s = scan_varint(rem, at); if (s == 0) { PROTOBUF_C_UNPACK_ERROR("bad packed-repeated sint32 value"); return FALSE; } ((int32_t *) array)[count++] = unzigzag32(parse_uint32(s, at)); at += s; rem -= s; } break; case PROTOBUF_C_TYPE_ENUM: case PROTOBUF_C_TYPE_UINT32: while (rem > 0) { unsigned s = scan_varint(rem, at); if (s == 0) { PROTOBUF_C_UNPACK_ERROR("bad packed-repeated enum or uint32 value"); return FALSE; } ((uint32_t *) array)[count++] = parse_uint32(s, at); at += s; rem -= s; } break; case PROTOBUF_C_TYPE_SINT64: while (rem > 0) { unsigned s = scan_varint(rem, at); if (s == 0) { PROTOBUF_C_UNPACK_ERROR("bad packed-repeated sint64 value"); return FALSE; } ((int64_t *) array)[count++] = unzigzag64(parse_uint64(s, at)); at += s; rem -= s; } break; case PROTOBUF_C_TYPE_INT64: case PROTOBUF_C_TYPE_UINT64: while (rem > 0) { unsigned s = scan_varint(rem, at); if (s == 0) { PROTOBUF_C_UNPACK_ERROR("bad packed-repeated int64/uint64 value"); return FALSE; } ((int64_t *) array)[count++] = parse_uint64(s, at); at += s; rem -= s; } break; case PROTOBUF_C_TYPE_BOOL: count = rem; for (i = 0; i < count; i++) { if (at[i] > 1) { PROTOBUF_C_UNPACK_ERROR("bad packed-repeated boolean value"); return FALSE; } ((protobuf_c_boolean *) array)[i] = at[i]; } break; default: PROTOBUF_C__ASSERT_NOT_REACHED(); } *p_n += count; return TRUE; #if !defined(WORDS_BIGENDIAN) no_unpacking_needed: memcpy(array, at, count * siz); *p_n += count; return TRUE; #endif } static protobuf_c_boolean is_packable_type(ProtobufCType type) { return type != PROTOBUF_C_TYPE_STRING && type != PROTOBUF_C_TYPE_BYTES && type != PROTOBUF_C_TYPE_MESSAGE; } static protobuf_c_boolean parse_member(ScannedMember *scanned_member, ProtobufCMessage *message, ProtobufCAllocator *allocator) { const ProtobufCFieldDescriptor *field = scanned_member->field; void *member; if (field == NULL) { ProtobufCMessageUnknownField *ufield = message->unknown_fields + (message->n_unknown_fields++); ufield->tag = scanned_member->tag; ufield->wire_type = scanned_member->wire_type; ufield->len = scanned_member->len; ufield->data = do_alloc(allocator, scanned_member->len); if (ufield->data == NULL) return FALSE; memcpy(ufield->data, scanned_member->data, ufield->len); return TRUE; } member = (char *) message + field->offset; switch (field->label) { case PROTOBUF_C_LABEL_REQUIRED: return parse_required_member(scanned_member, member, allocator, TRUE); case PROTOBUF_C_LABEL_OPTIONAL: if (0 != (field->flags & PROTOBUF_C_FIELD_FLAG_ONEOF)) { return parse_oneof_member(scanned_member, member, message, allocator); } else { return parse_optional_member(scanned_member, member, message, allocator); } case PROTOBUF_C_LABEL_REPEATED: if (scanned_member->wire_type == PROTOBUF_C_WIRE_TYPE_LENGTH_PREFIXED && (0 != (field->flags & PROTOBUF_C_FIELD_FLAG_PACKED) || is_packable_type(field->type))) { return parse_packed_repeated_member(scanned_member, member, message); } else { return parse_repeated_member(scanned_member, member, message, allocator); } } PROTOBUF_C__ASSERT_NOT_REACHED(); return 0; } /** * Initialise messages generated by old code. * * This function is used if desc->message_init == NULL (which occurs * for old code, and which would be useful to support allocating * descriptors dynamically). */ static void message_init_generic(const ProtobufCMessageDescriptor *desc, ProtobufCMessage *message) { unsigned i; memset(message, 0, desc->sizeof_message); message->descriptor = desc; for (i = 0; i < desc->n_fields; i++) { if (desc->fields[i].default_value != NULL && desc->fields[i].label != PROTOBUF_C_LABEL_REPEATED) { void *field = STRUCT_MEMBER_P(message, desc->fields[i].offset); const void *dv = desc->fields[i].default_value; switch (desc->fields[i].type) { case PROTOBUF_C_TYPE_INT32: case PROTOBUF_C_TYPE_SINT32: case PROTOBUF_C_TYPE_SFIXED32: case PROTOBUF_C_TYPE_UINT32: case PROTOBUF_C_TYPE_FIXED32: case PROTOBUF_C_TYPE_FLOAT: case PROTOBUF_C_TYPE_ENUM: memcpy(field, dv, 4); break; case PROTOBUF_C_TYPE_INT64: case PROTOBUF_C_TYPE_SINT64: case PROTOBUF_C_TYPE_SFIXED64: case PROTOBUF_C_TYPE_UINT64: case PROTOBUF_C_TYPE_FIXED64: case PROTOBUF_C_TYPE_DOUBLE: memcpy(field, dv, 8); break; case PROTOBUF_C_TYPE_BOOL: memcpy(field, dv, sizeof(protobuf_c_boolean)); break; case PROTOBUF_C_TYPE_BYTES: memcpy(field, dv, sizeof(ProtobufCBinaryData)); break; case PROTOBUF_C_TYPE_STRING: case PROTOBUF_C_TYPE_MESSAGE: /* * The next line essentially implements a cast * from const, which is totally unavoidable. */ *(const void **) field = dv; break; } } } } /**@}*/ /* * ScannedMember slabs (an unpacking implementation detail). Before doing real * unpacking, we first scan through the elements to see how many there are (for * repeated fields), and which field to use (for non-repeated fields given * twice). * * In order to avoid allocations for small messages, we keep a stack-allocated * slab of ScannedMembers of size FIRST_SCANNED_MEMBER_SLAB_SIZE (16). After we * fill that up, we allocate each slab twice as large as the previous one. */ #define FIRST_SCANNED_MEMBER_SLAB_SIZE_LOG2 4 /* * The number of slabs, including the stack-allocated ones; choose the number so * that we would overflow if we needed a slab larger than provided. */ #define MAX_SCANNED_MEMBER_SLAB \ (sizeof(unsigned int)*8 - 1 \ - BOUND_SIZEOF_SCANNED_MEMBER_LOG2 \ - FIRST_SCANNED_MEMBER_SLAB_SIZE_LOG2) #define REQUIRED_FIELD_BITMAP_SET(index) \ (required_fields_bitmap[(index)/8] |= (1<<((index)%8))) #define REQUIRED_FIELD_BITMAP_IS_SET(index) \ (required_fields_bitmap[(index)/8] & (1<<((index)%8))) ProtobufCMessage * protobuf_c_message_unpack(const ProtobufCMessageDescriptor *desc, ProtobufCAllocator *allocator, size_t len, const uint8_t *data) { ProtobufCMessage *rv; size_t rem = len; const uint8_t *at = data; const ProtobufCFieldDescriptor *last_field = desc->fields + 0; ScannedMember first_member_slab[1 << FIRST_SCANNED_MEMBER_SLAB_SIZE_LOG2]; /* * scanned_member_slabs[i] is an array of arrays of ScannedMember. * The first slab (scanned_member_slabs[0] is just a pointer to * first_member_slab), above. All subsequent slabs will be allocated * using the allocator. */ ScannedMember *scanned_member_slabs[MAX_SCANNED_MEMBER_SLAB + 1]; unsigned which_slab = 0; /* the slab we are currently populating */ unsigned in_slab_index = 0; /* number of members in the slab */ size_t n_unknown = 0; unsigned f; unsigned j; unsigned i_slab; unsigned last_field_index = 0; unsigned required_fields_bitmap_len; unsigned char required_fields_bitmap_stack[16]; unsigned char *required_fields_bitmap = required_fields_bitmap_stack; protobuf_c_boolean required_fields_bitmap_alloced = FALSE; ASSERT_IS_MESSAGE_DESCRIPTOR(desc); if (allocator == NULL) allocator = &protobuf_c__allocator; rv = do_alloc(allocator, desc->sizeof_message); if (!rv) return (NULL); scanned_member_slabs[0] = first_member_slab; required_fields_bitmap_len = (desc->n_fields + 7) / 8; if (required_fields_bitmap_len > sizeof(required_fields_bitmap_stack)) { required_fields_bitmap = do_alloc(allocator, required_fields_bitmap_len); if (!required_fields_bitmap) { do_free(allocator, rv); return (NULL); } required_fields_bitmap_alloced = TRUE; } memset(required_fields_bitmap, 0, required_fields_bitmap_len); /* * Generated code always defines "message_init". However, we provide a * fallback for (1) users of old protobuf-c generated-code that do not * provide the function, and (2) descriptors constructed from some other * source (most likely, direct construction from the .proto file). */ if (desc->message_init != NULL) protobuf_c_message_init(desc, rv); else message_init_generic(desc, rv); while (rem > 0) { uint32_t tag; ProtobufCWireType wire_type; size_t used = parse_tag_and_wiretype(rem, at, &tag, &wire_type); const ProtobufCFieldDescriptor *field; ScannedMember tmp; if (used == 0) { PROTOBUF_C_UNPACK_ERROR("error parsing tag/wiretype at offset %u", (unsigned) (at - data)); goto error_cleanup_during_scan; } /* * \todo Consider optimizing for field[1].id == tag, if field[1] * exists! */ if (last_field == NULL || last_field->id != tag) { /* lookup field */ int field_index = int_range_lookup(desc->n_field_ranges, desc->field_ranges, tag); if (field_index < 0) { field = NULL; n_unknown++; } else { field = desc->fields + field_index; last_field = field; last_field_index = field_index; } } else { field = last_field; } if (field != NULL && field->label == PROTOBUF_C_LABEL_REQUIRED) REQUIRED_FIELD_BITMAP_SET(last_field_index); at += used; rem -= used; tmp.tag = tag; tmp.wire_type = wire_type; tmp.field = field; tmp.data = at; tmp.length_prefix_len = 0; switch (wire_type) { case PROTOBUF_C_WIRE_TYPE_VARINT: { unsigned max_len = rem < 10 ? rem : 10; unsigned i; for (i = 0; i < max_len; i++) if ((at[i] & 0x80) == 0) break; if (i == max_len) { PROTOBUF_C_UNPACK_ERROR("unterminated varint at offset %u", (unsigned) (at - data)); goto error_cleanup_during_scan; } tmp.len = i + 1; break; } case PROTOBUF_C_WIRE_TYPE_64BIT: if (rem < 8) { PROTOBUF_C_UNPACK_ERROR("too short after 64bit wiretype at offset %u", (unsigned) (at - data)); goto error_cleanup_during_scan; } tmp.len = 8; break; case PROTOBUF_C_WIRE_TYPE_LENGTH_PREFIXED: { size_t pref_len; tmp.len = scan_length_prefixed_data(rem, at, &pref_len); if (tmp.len == 0) { /* NOTE: scan_length_prefixed_data calls UNPACK_ERROR */ goto error_cleanup_during_scan; } tmp.length_prefix_len = pref_len; break; } case PROTOBUF_C_WIRE_TYPE_32BIT: if (rem < 4) { PROTOBUF_C_UNPACK_ERROR("too short after 32bit wiretype at offset %u", (unsigned) (at - data)); goto error_cleanup_during_scan; } tmp.len = 4; break; default: PROTOBUF_C_UNPACK_ERROR("unsupported tag %u at offset %u", wire_type, (unsigned) (at - data)); goto error_cleanup_during_scan; } if (in_slab_index == (1U << (which_slab + FIRST_SCANNED_MEMBER_SLAB_SIZE_LOG2))) { size_t size; in_slab_index = 0; if (which_slab == MAX_SCANNED_MEMBER_SLAB) { PROTOBUF_C_UNPACK_ERROR("too many fields"); goto error_cleanup_during_scan; } which_slab++; size = sizeof(ScannedMember) << (which_slab + FIRST_SCANNED_MEMBER_SLAB_SIZE_LOG2); scanned_member_slabs[which_slab] = do_alloc(allocator, size); if (scanned_member_slabs[which_slab] == NULL) goto error_cleanup_during_scan; } scanned_member_slabs[which_slab][in_slab_index++] = tmp; if (field != NULL && field->label == PROTOBUF_C_LABEL_REPEATED) { size_t *n = STRUCT_MEMBER_PTR(size_t, rv, field->quantifier_offset); if (wire_type == PROTOBUF_C_WIRE_TYPE_LENGTH_PREFIXED && (0 != (field->flags & PROTOBUF_C_FIELD_FLAG_PACKED) || is_packable_type(field->type))) { size_t count; if (!count_packed_elements(field->type, tmp.len - tmp.length_prefix_len, tmp.data + tmp.length_prefix_len, &count)) { PROTOBUF_C_UNPACK_ERROR("counting packed elements"); goto error_cleanup_during_scan; } *n += count; } else { *n += 1; } } at += tmp.len; rem -= tmp.len; } /* allocate space for repeated fields, also check that all required fields have been set */ for (f = 0; f < desc->n_fields; f++) { const ProtobufCFieldDescriptor *field = desc->fields + f; if (field->label == PROTOBUF_C_LABEL_REPEATED) { size_t siz = sizeof_elt_in_repeated_array(field->type); size_t *n_ptr = STRUCT_MEMBER_PTR(size_t, rv, field->quantifier_offset); if (*n_ptr != 0) { void *a = 0; unsigned n = *n_ptr; *n_ptr = 0; assert(rv->descriptor != NULL); #define CLEAR_REMAINING_N_PTRS() \ for(f++;f < desc->n_fields; f++) \ { \ field = desc->fields + f; \ if (field->label == PROTOBUF_C_LABEL_REPEATED) \ STRUCT_MEMBER (size_t, rv, field->quantifier_offset) = 0; \ } a = do_alloc(allocator, siz * n); if (!a) { CLEAR_REMAINING_N_PTRS(); goto error_cleanup; } STRUCT_MEMBER(void *, rv, field->offset) = a; } } else if (field->label == PROTOBUF_C_LABEL_REQUIRED) { if (field->default_value == NULL && !REQUIRED_FIELD_BITMAP_IS_SET(f)) { CLEAR_REMAINING_N_PTRS(); PROTOBUF_C_UNPACK_ERROR("message '%s': missing required field '%s'", desc->name, field->name); goto error_cleanup; } } } #undef CLEAR_REMAINING_N_PTRS /* allocate space for unknown fields */ if (n_unknown) { rv->unknown_fields = do_alloc(allocator, n_unknown * sizeof(ProtobufCMessageUnknownField)); if (rv->unknown_fields == NULL) goto error_cleanup; } /* do real parsing */ for (i_slab = 0; i_slab <= which_slab; i_slab++) { unsigned max = (i_slab == which_slab) ? in_slab_index : (1U << (i_slab + 4)); ScannedMember *slab = scanned_member_slabs[i_slab]; unsigned j; for (j = 0; j < max; j++) { if (!parse_member(slab + j, rv, allocator)) { PROTOBUF_C_UNPACK_ERROR("error parsing member %s of %s", slab->field ? slab->field->name : "*unknown-field*", desc->name); goto error_cleanup; } } } /* cleanup */ for (j = 1; j <= which_slab; j++) do_free(allocator, scanned_member_slabs[j]); if (required_fields_bitmap_alloced) do_free(allocator, required_fields_bitmap); return rv; error_cleanup: protobuf_c_message_free_unpacked(rv, allocator); for (j = 1; j <= which_slab; j++) do_free(allocator, scanned_member_slabs[j]); if (required_fields_bitmap_alloced) do_free(allocator, required_fields_bitmap); return NULL; error_cleanup_during_scan: do_free(allocator, rv); for (j = 1; j <= which_slab; j++) do_free(allocator, scanned_member_slabs[j]); if (required_fields_bitmap_alloced) do_free(allocator, required_fields_bitmap); return NULL; } void protobuf_c_message_free_unpacked(ProtobufCMessage *message, ProtobufCAllocator *allocator) { const ProtobufCMessageDescriptor *desc; unsigned f; if (message == NULL) return; desc = message->descriptor; ASSERT_IS_MESSAGE(message); if (allocator == NULL) allocator = &protobuf_c__allocator; message->descriptor = NULL; for (f = 0; f < desc->n_fields; f++) { if (0 != (desc->fields[f].flags & PROTOBUF_C_FIELD_FLAG_ONEOF) && desc->fields[f].id != STRUCT_MEMBER(uint32_t, message, desc->fields[f].quantifier_offset)) { /* This is not the selected oneof, skip it */ continue; } if (desc->fields[f].label == PROTOBUF_C_LABEL_REPEATED) { size_t n = STRUCT_MEMBER(size_t, message, desc->fields[f].quantifier_offset); void *arr = STRUCT_MEMBER(void *, message, desc->fields[f].offset); if (arr != NULL) { if (desc->fields[f].type == PROTOBUF_C_TYPE_STRING) { unsigned i; for (i = 0; i < n; i++) do_free(allocator, ((char **) arr)[i]); } else if (desc->fields[f].type == PROTOBUF_C_TYPE_BYTES) { unsigned i; for (i = 0; i < n; i++) do_free(allocator, ((ProtobufCBinaryData *) arr)[i].data); } else if (desc->fields[f].type == PROTOBUF_C_TYPE_MESSAGE) { unsigned i; for (i = 0; i < n; i++) protobuf_c_message_free_unpacked( ((ProtobufCMessage **) arr)[i], allocator ); } do_free(allocator, arr); } } else if (desc->fields[f].type == PROTOBUF_C_TYPE_STRING) { char *str = STRUCT_MEMBER(char *, message, desc->fields[f].offset); if (str && str != desc->fields[f].default_value) do_free(allocator, str); } else if (desc->fields[f].type == PROTOBUF_C_TYPE_BYTES) { void *data = STRUCT_MEMBER(ProtobufCBinaryData, message, desc->fields[f].offset).data; const ProtobufCBinaryData *default_bd; default_bd = desc->fields[f].default_value; if (data != NULL && (default_bd == NULL || default_bd->data != data)) { do_free(allocator, data); } } else if (desc->fields[f].type == PROTOBUF_C_TYPE_MESSAGE) { ProtobufCMessage *sm; sm = STRUCT_MEMBER(ProtobufCMessage *, message, desc->fields[f].offset); if (sm && sm != desc->fields[f].default_value) protobuf_c_message_free_unpacked(sm, allocator); } } for (f = 0; f < message->n_unknown_fields; f++) do_free(allocator, message->unknown_fields[f].data); if (message->unknown_fields != NULL) do_free(allocator, message->unknown_fields); do_free(allocator, message); } void protobuf_c_message_init(const ProtobufCMessageDescriptor * descriptor, void *message) { descriptor->message_init((ProtobufCMessage *) (message)); } protobuf_c_boolean protobuf_c_message_check(const ProtobufCMessage *message) { unsigned i; if (!message || !message->descriptor || message->descriptor->magic != PROTOBUF_C__MESSAGE_DESCRIPTOR_MAGIC) { return FALSE; } for (i = 0; i < message->descriptor->n_fields; i++) { const ProtobufCFieldDescriptor *f = message->descriptor->fields + i; ProtobufCType type = f->type; ProtobufCLabel label = f->label; void *field = STRUCT_MEMBER_P (message, f->offset); if (label == PROTOBUF_C_LABEL_REPEATED) { size_t *quantity = STRUCT_MEMBER_P (message, f->quantifier_offset); if (*quantity > 0 && *(void **) field == NULL) { return FALSE; } if (type == PROTOBUF_C_TYPE_MESSAGE) { ProtobufCMessage **submessage = *(ProtobufCMessage ***) field; unsigned j; for (j = 0; j < *quantity; j++) { if (!protobuf_c_message_check(submessage[j])) return FALSE; } } else if (type == PROTOBUF_C_TYPE_STRING) { char **string = *(char ***) field; unsigned j; for (j = 0; j < *quantity; j++) { if (!string[j]) return FALSE; } } else if (type == PROTOBUF_C_TYPE_BYTES) { ProtobufCBinaryData *bd = *(ProtobufCBinaryData **) field; unsigned j; for (j = 0; j < *quantity; j++) { if (bd[j].len > 0 && bd[j].data == NULL) return FALSE; } } } else { /* PROTOBUF_C_LABEL_REQUIRED or PROTOBUF_C_LABEL_OPTIONAL */ if (type == PROTOBUF_C_TYPE_MESSAGE) { ProtobufCMessage *submessage = *(ProtobufCMessage **) field; if (label == PROTOBUF_C_LABEL_REQUIRED || submessage != NULL) { if (!protobuf_c_message_check(submessage)) return FALSE; } } else if (type == PROTOBUF_C_TYPE_STRING) { char *string = *(char **) field; if (label == PROTOBUF_C_LABEL_REQUIRED && string == NULL) return FALSE; } else if (type == PROTOBUF_C_TYPE_BYTES) { protobuf_c_boolean *has = STRUCT_MEMBER_P (message, f->quantifier_offset); ProtobufCBinaryData *bd = field; if (label == PROTOBUF_C_LABEL_REQUIRED || *has == TRUE) { if (bd->len > 0 && bd->data == NULL) return FALSE; } } } } return TRUE; } /* === services === */ typedef void (*GenericHandler) (void *service, const ProtobufCMessage *input, ProtobufCClosure closure, void *closure_data); void protobuf_c_service_invoke_internal(ProtobufCService *service, unsigned method_index, const ProtobufCMessage *input, ProtobufCClosure closure, void *closure_data) { GenericHandler *handlers; GenericHandler handler; /* * Verify that method_index is within range. If this fails, you are * likely invoking a newly added method on an old service. (Although * other memory corruption bugs can cause this assertion too.) */ assert(method_index < service->descriptor->n_methods); /* * Get the array of virtual methods (which are enumerated by the * generated code). */ handlers = (GenericHandler *) (service + 1); /* * Get our method and invoke it. * \todo Seems like handler == NULL is a situation that needs handling. */ handler = handlers[method_index]; (*handler)(service, input, closure, closure_data); } void protobuf_c_service_generated_init(ProtobufCService *service, const ProtobufCServiceDescriptor *descriptor, ProtobufCServiceDestroy destroy) { ASSERT_IS_SERVICE_DESCRIPTOR(descriptor); service->descriptor = descriptor; service->destroy = destroy; service->invoke = protobuf_c_service_invoke_internal; memset(service + 1, 0, descriptor->n_methods * sizeof(GenericHandler)); } void protobuf_c_service_destroy(ProtobufCService *service) { service->destroy(service); } /* --- querying the descriptors --- */ const ProtobufCEnumValue * protobuf_c_enum_descriptor_get_value_by_name(const ProtobufCEnumDescriptor *desc, const char *name) { unsigned start = 0; unsigned count = desc->n_value_names; while (count > 1) { unsigned mid = start + count / 2; int rv = strcmp(desc->values_by_name[mid].name, name); if (rv == 0) return desc->values + desc->values_by_name[mid].index; else if (rv < 0) { count = start + count - (mid + 1); start = mid + 1; } else count = mid - start; } if (count == 0) return NULL; if (strcmp(desc->values_by_name[start].name, name) == 0) return desc->values + desc->values_by_name[start].index; return NULL; } const ProtobufCEnumValue * protobuf_c_enum_descriptor_get_value(const ProtobufCEnumDescriptor *desc, int value) { int rv = int_range_lookup(desc->n_value_ranges, desc->value_ranges, value); if (rv < 0) return NULL; return desc->values + rv; } const ProtobufCFieldDescriptor * protobuf_c_message_descriptor_get_field_by_name(const ProtobufCMessageDescriptor *desc, const char *name) { unsigned start = 0; unsigned count = desc->n_fields; const ProtobufCFieldDescriptor *field; while (count > 1) { unsigned mid = start + count / 2; int rv; field = desc->fields + desc->fields_sorted_by_name[mid]; rv = strcmp(field->name, name); if (rv == 0) return field; else if (rv < 0) { count = start + count - (mid + 1); start = mid + 1; } else count = mid - start; } if (count == 0) return NULL; field = desc->fields + desc->fields_sorted_by_name[start]; if (strcmp(field->name, name) == 0) return field; return NULL; } const ProtobufCFieldDescriptor * protobuf_c_message_descriptor_get_field(const ProtobufCMessageDescriptor *desc, unsigned value) { int rv = int_range_lookup(desc->n_field_ranges,desc->field_ranges, value); if (rv < 0) return NULL; return desc->fields + rv; } const ProtobufCMethodDescriptor * protobuf_c_service_descriptor_get_method_by_name(const ProtobufCServiceDescriptor *desc, const char *name) { unsigned start = 0; unsigned count = desc->n_methods; while (count > 1) { unsigned mid = start + count / 2; unsigned mid_index = desc->method_indices_by_name[mid]; const char *mid_name = desc->methods[mid_index].name; int rv = strcmp(mid_name, name); if (rv == 0) return desc->methods + desc->method_indices_by_name[mid]; if (rv < 0) { count = start + count - (mid + 1); start = mid + 1; } else { count = mid - start; } } if (count == 0) return NULL; if (strcmp(desc->methods[desc->method_indices_by_name[start]].name, name) == 0) return desc->methods + desc->method_indices_by_name[start]; return NULL; } libsignal-protocol-c-2.3.3/src/protobuf-c/protobuf-c.h000066400000000000000000001004671363751346500226670ustar00rootroot00000000000000/* * Copyright (c) 2008-2014, Dave Benson and the protobuf-c authors. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are * met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * * Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the following disclaimer * in the documentation and/or other materials provided with the * distribution. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /*! \file * \mainpage Introduction * * This is [protobuf-c], a C implementation of [Protocol Buffers]. * * This file defines the public API for the `libprotobuf-c` support library. * This API includes interfaces that can be used directly by client code as well * as the interfaces used by the code generated by the `protoc-c` compiler. * * The `libprotobuf-c` support library performs the actual serialization and * deserialization of Protocol Buffers messages. It interacts with structures, * definitions, and metadata generated by the `protoc-c` compiler from .proto * files. * * \authors Dave Benson and the `protobuf-c` authors. * * \copyright 2008-2014. Licensed under the terms of the [BSD-2-Clause] license. * * [protobuf-c]: https://github.com/protobuf-c/protobuf-c * [Protocol Buffers]: https://developers.google.com/protocol-buffers/ * [BSD-2-Clause]: http://opensource.org/licenses/BSD-2-Clause * * \page gencode Generated Code * * For each enum, we generate a C enum. For each message, we generate a C * structure which can be cast to a `ProtobufCMessage`. * * For each enum and message, we generate a descriptor object that allows us to * implement a kind of reflection on the structures. * * First, some naming conventions: * * - The name of the type for enums and messages and services is camel case * (meaning WordsAreCrammedTogether) except that double underscores are used * to delimit scopes. For example, the following `.proto` file: * ~~~{.proto} package foo.bar; message BazBah { optional int32 val = 1; } ~~~ * * would generate a C type `Foo__Bar__BazBah`. * * - Identifiers for functions and globals are all lowercase, with camel case * words separated by single underscores. For example, one of the function * prototypes generated by `protoc-c` for the above example: * ~~~{.c} Foo__Bar__BazBah * foo__bar__baz_bah__unpack (ProtobufCAllocator *allocator, size_t len, const uint8_t *data); ~~~ * * - Identifiers for enum values contain an uppercase prefix which embeds the * package name and the enum type name. * * - A double underscore is used to separate further components of identifier * names. * * For example, in the name of the unpack function above, the package name * `foo.bar` has become `foo__bar`, the message name BazBah has become * `baz_bah`, and the method name is `unpack`. These are all joined with double * underscores to form the C identifier `foo__bar__baz_bah__unpack`. * * We also generate descriptor objects for messages and enums. These are * declared in the `.pb-c.h` files: * ~~~{.c} extern const ProtobufCMessageDescriptor foo__bar__baz_bah__descriptor; ~~~ * * The message structures all begin with `ProtobufCMessageDescriptor *` which is * sufficient to allow them to be cast to `ProtobufCMessage`. * * For each message defined in a `.proto` file, we generate a number of * functions and macros. Each function name contains a prefix based on the * package name and message name in order to make it a unique C identifier. * * - `INIT`. Statically initializes a message object, initializing its * descriptor and setting its fields to default values. Uninitialized * messages cannot be processed by the protobuf-c library. * ~~~{.c} #define FOO__BAR__BAZ_BAH__INIT \ { PROTOBUF_C_MESSAGE_INIT (&foo__bar__baz_bah__descriptor), 0 } ~~~ * - `init()`. Initializes a message object, initializing its descriptor and * setting its fields to default values. Uninitialized messages cannot be * processed by the protobuf-c library. * ~~~{.c} void foo__bar__baz_bah__init (Foo__Bar__BazBah *message); ~~~ * - `unpack()`. Unpacks data for a particular message format. Note that the * `allocator` parameter is usually `NULL` to indicate that the system's * `malloc()` and `free()` functions should be used for dynamically allocating * memory. * ~~~{.c} Foo__Bar__BazBah * foo__bar__baz_bah__unpack (ProtobufCAllocator *allocator, size_t len, const uint8_t *data); ~~~ * * - `free_unpacked()`. Frees a message object obtained with the `unpack()` * method. * ~~~{.c} void foo__bar__baz_bah__free_unpacked (Foo__Bar__BazBah *message, ProtobufCAllocator *allocator); ~~~ * * - `get_packed_size()`. Calculates the length in bytes of the serialized * representation of the message object. * ~~~{.c} size_t foo__bar__baz_bah__get_packed_size (const Foo__Bar__BazBah *message); ~~~ * * - `pack()`. Pack a message object into a preallocated buffer. Assumes that * the buffer is large enough. (Use `get_packed_size()` first.) * ~~~{.c} size_t foo__bar__baz_bah__pack (const Foo__Bar__BazBah *message, uint8_t *out); ~~~ * * - `pack_to_buffer()`. Packs a message into a "virtual buffer". This is an * object which defines an "append bytes" callback to consume data as it is * serialized. * ~~~{.c} size_t foo__bar__baz_bah__pack_to_buffer (const Foo__Bar__BazBah *message, ProtobufCBuffer *buffer); ~~~ * * \page pack Packing and unpacking messages * * To pack a message, first compute the packed size of the message with * protobuf_c_message_get_packed_size(), then allocate a buffer of at least * that size, then call protobuf_c_message_pack(). * * Alternatively, a message can be serialized without calculating the final size * first. Use the protobuf_c_message_pack_to_buffer() function and provide a * ProtobufCBuffer object which implements an "append" method that consumes * data. * * To unpack a message, call the protobuf_c_message_unpack() function. The * result can be cast to an object of the type that matches the descriptor for * the message. * * The result of unpacking a message should be freed with * protobuf_c_message_free_unpacked(). */ #ifndef PROTOBUF_C_H #define PROTOBUF_C_H #include #include #include #include #ifdef __cplusplus # define PROTOBUF_C__BEGIN_DECLS extern "C" { # define PROTOBUF_C__END_DECLS } #else # define PROTOBUF_C__BEGIN_DECLS # define PROTOBUF_C__END_DECLS #endif PROTOBUF_C__BEGIN_DECLS #if defined(_WIN32) && defined(PROTOBUF_C_USE_SHARED_LIB) # ifdef PROTOBUF_C_EXPORT # define PROTOBUF_C__API __declspec(dllexport) # else # define PROTOBUF_C__API __declspec(dllimport) # endif #else # define PROTOBUF_C__API #endif #if !defined(PROTOBUF_C__NO_DEPRECATED) && \ ((__GNUC__ > 3) || (__GNUC__ == 3 && __GNUC_MINOR__ >= 1)) # define PROTOBUF_C__DEPRECATED __attribute__((__deprecated__)) #else # define PROTOBUF_C__DEPRECATED #endif #ifndef PROTOBUF_C__FORCE_ENUM_TO_BE_INT_SIZE #define PROTOBUF_C__FORCE_ENUM_TO_BE_INT_SIZE(enum_name) \ , _##enum_name##_IS_INT_SIZE = INT_MAX #endif #define PROTOBUF_C__SERVICE_DESCRIPTOR_MAGIC 0x14159bc3 #define PROTOBUF_C__MESSAGE_DESCRIPTOR_MAGIC 0x28aaeef9 #define PROTOBUF_C__ENUM_DESCRIPTOR_MAGIC 0x114315af /** * \defgroup api Public API * * This is the public API for `libprotobuf-c`. These interfaces are stable and * subject to Semantic Versioning guarantees. * * @{ */ /** * Values for the `flags` word in `ProtobufCFieldDescriptor`. */ typedef enum { /** Set if the field is repeated and marked with the `packed` option. */ PROTOBUF_C_FIELD_FLAG_PACKED = (1 << 0), /** Set if the field is marked with the `deprecated` option. */ PROTOBUF_C_FIELD_FLAG_DEPRECATED = (1 << 1), /** Set if the field is a member of a oneof (union). */ PROTOBUF_C_FIELD_FLAG_ONEOF = (1 << 2), } ProtobufCFieldFlag; /** * Message field rules. * * \see [Defining A Message Type] in the Protocol Buffers documentation. * * [Defining A Message Type]: * https://developers.google.com/protocol-buffers/docs/proto#simple */ typedef enum { /** A well-formed message must have exactly one of this field. */ PROTOBUF_C_LABEL_REQUIRED, /** * A well-formed message can have zero or one of this field (but not * more than one). */ PROTOBUF_C_LABEL_OPTIONAL, /** * This field can be repeated any number of times (including zero) in a * well-formed message. The order of the repeated values will be * preserved. */ PROTOBUF_C_LABEL_REPEATED, } ProtobufCLabel; /** * Field value types. * * \see [Scalar Value Types] in the Protocol Buffers documentation. * * [Scalar Value Types]: * https://developers.google.com/protocol-buffers/docs/proto#scalar */ typedef enum { PROTOBUF_C_TYPE_INT32, /**< int32 */ PROTOBUF_C_TYPE_SINT32, /**< signed int32 */ PROTOBUF_C_TYPE_SFIXED32, /**< signed int32 (4 bytes) */ PROTOBUF_C_TYPE_INT64, /**< int64 */ PROTOBUF_C_TYPE_SINT64, /**< signed int64 */ PROTOBUF_C_TYPE_SFIXED64, /**< signed int64 (8 bytes) */ PROTOBUF_C_TYPE_UINT32, /**< unsigned int32 */ PROTOBUF_C_TYPE_FIXED32, /**< unsigned int32 (4 bytes) */ PROTOBUF_C_TYPE_UINT64, /**< unsigned int64 */ PROTOBUF_C_TYPE_FIXED64, /**< unsigned int64 (8 bytes) */ PROTOBUF_C_TYPE_FLOAT, /**< float */ PROTOBUF_C_TYPE_DOUBLE, /**< double */ PROTOBUF_C_TYPE_BOOL, /**< boolean */ PROTOBUF_C_TYPE_ENUM, /**< enumerated type */ PROTOBUF_C_TYPE_STRING, /**< UTF-8 or ASCII string */ PROTOBUF_C_TYPE_BYTES, /**< arbitrary byte sequence */ PROTOBUF_C_TYPE_MESSAGE, /**< nested message */ } ProtobufCType; /** * Field wire types. * * \see [Message Structure] in the Protocol Buffers documentation. * * [Message Structure]: * https://developers.google.com/protocol-buffers/docs/encoding#structure */ typedef enum { PROTOBUF_C_WIRE_TYPE_VARINT = 0, PROTOBUF_C_WIRE_TYPE_64BIT = 1, PROTOBUF_C_WIRE_TYPE_LENGTH_PREFIXED = 2, /* "Start group" and "end group" wire types are unsupported. */ PROTOBUF_C_WIRE_TYPE_32BIT = 5, } ProtobufCWireType; struct ProtobufCAllocator; struct ProtobufCBinaryData; struct ProtobufCBuffer; struct ProtobufCBufferSimple; struct ProtobufCEnumDescriptor; struct ProtobufCEnumValue; struct ProtobufCEnumValueIndex; struct ProtobufCFieldDescriptor; struct ProtobufCIntRange; struct ProtobufCMessage; struct ProtobufCMessageDescriptor; struct ProtobufCMessageUnknownField; struct ProtobufCMethodDescriptor; struct ProtobufCService; struct ProtobufCServiceDescriptor; typedef struct ProtobufCAllocator ProtobufCAllocator; typedef struct ProtobufCBinaryData ProtobufCBinaryData; typedef struct ProtobufCBuffer ProtobufCBuffer; typedef struct ProtobufCBufferSimple ProtobufCBufferSimple; typedef struct ProtobufCEnumDescriptor ProtobufCEnumDescriptor; typedef struct ProtobufCEnumValue ProtobufCEnumValue; typedef struct ProtobufCEnumValueIndex ProtobufCEnumValueIndex; typedef struct ProtobufCFieldDescriptor ProtobufCFieldDescriptor; typedef struct ProtobufCIntRange ProtobufCIntRange; typedef struct ProtobufCMessage ProtobufCMessage; typedef struct ProtobufCMessageDescriptor ProtobufCMessageDescriptor; typedef struct ProtobufCMessageUnknownField ProtobufCMessageUnknownField; typedef struct ProtobufCMethodDescriptor ProtobufCMethodDescriptor; typedef struct ProtobufCService ProtobufCService; typedef struct ProtobufCServiceDescriptor ProtobufCServiceDescriptor; /** Boolean type. */ typedef int protobuf_c_boolean; typedef void (*ProtobufCClosure)(const ProtobufCMessage *, void *closure_data); typedef void (*ProtobufCMessageInit)(ProtobufCMessage *); typedef void (*ProtobufCServiceDestroy)(ProtobufCService *); /** * Structure for defining a custom memory allocator. */ struct ProtobufCAllocator { /** Function to allocate memory. */ void *(*alloc)(void *allocator_data, size_t size); /** Function to free memory. */ void (*free)(void *allocator_data, void *pointer); /** Opaque pointer passed to `alloc` and `free` functions. */ void *allocator_data; }; /** * Structure for the protobuf `bytes` scalar type. * * The data contained in a `ProtobufCBinaryData` is an arbitrary sequence of * bytes. It may contain embedded `NUL` characters and is not required to be * `NUL`-terminated. */ struct ProtobufCBinaryData { size_t len; /**< Number of bytes in the `data` field. */ uint8_t *data; /**< Data bytes. */ }; /** * Structure for defining a virtual append-only buffer. Used by * protobuf_c_message_pack_to_buffer() to abstract the consumption of serialized * bytes. * * `ProtobufCBuffer` "subclasses" may be defined on the stack. For example, to * write to a `FILE` object: * ~~~{.c} typedef struct { ProtobufCBuffer base; FILE *fp; } BufferAppendToFile; static void my_buffer_file_append(ProtobufCBuffer *buffer, size_t len, const uint8_t *data) { BufferAppendToFile *file_buf = (BufferAppendToFile *) buffer; fwrite(data, len, 1, file_buf->fp); // XXX: No error handling! } ~~~ * * To use this new type of ProtobufCBuffer, it could be called as follows: * ~~~{.c} ... BufferAppendToFile tmp = {0}; tmp.base.append = my_buffer_file_append; tmp.fp = fp; protobuf_c_message_pack_to_buffer(&message, &tmp); ... ~~~ */ struct ProtobufCBuffer { /** Append function. Consumes the `len` bytes stored at `data`. */ void (*append)(ProtobufCBuffer *buffer, size_t len, const uint8_t *data); }; /** * Simple buffer "subclass" of `ProtobufCBuffer`. * * A `ProtobufCBufferSimple` object is declared on the stack and uses a * scratch buffer provided by the user for the initial allocation. It performs * exponential resizing, using dynamically allocated memory. A * `ProtobufCBufferSimple` object can be created and used as follows: * ~~~{.c} uint8_t pad[128]; ProtobufCBufferSimple simple = PROTOBUF_C_BUFFER_SIMPLE_INIT(pad); ProtobufCBuffer *buffer = (ProtobufCBuffer *) &simple; ~~~ * * `buffer` can now be used with `protobuf_c_message_pack_to_buffer()`. Once a * message has been serialized to a `ProtobufCBufferSimple` object, the * serialized data bytes can be accessed from the `.data` field. * * To free the memory allocated by a `ProtobufCBufferSimple` object, if any, * call PROTOBUF_C_BUFFER_SIMPLE_CLEAR() on the object, for example: * ~~~{.c} PROTOBUF_C_BUFFER_SIMPLE_CLEAR(&simple); ~~~ * * \see PROTOBUF_C_BUFFER_SIMPLE_INIT * \see PROTOBUF_C_BUFFER_SIMPLE_CLEAR */ struct ProtobufCBufferSimple { /** "Base class". */ ProtobufCBuffer base; /** Number of bytes allocated in `data`. */ size_t alloced; /** Number of bytes currently stored in `data`. */ size_t len; /** Data bytes. */ uint8_t *data; /** Whether `data` must be freed. */ protobuf_c_boolean must_free_data; /** Allocator to use. May be NULL to indicate the system allocator. */ ProtobufCAllocator *allocator; }; /** * Describes an enumeration as a whole, with all of its values. */ struct ProtobufCEnumDescriptor { /** Magic value checked to ensure that the API is used correctly. */ uint32_t magic; /** The qualified name (e.g., "namespace.Type"). */ const char *name; /** The unqualified name as given in the .proto file (e.g., "Type"). */ const char *short_name; /** Identifier used in generated C code. */ const char *c_name; /** The dot-separated namespace. */ const char *package_name; /** Number elements in `values`. */ unsigned n_values; /** Array of distinct values, sorted by numeric value. */ const ProtobufCEnumValue *values; /** Number of elements in `values_by_name`. */ unsigned n_value_names; /** Array of named values, including aliases, sorted by name. */ const ProtobufCEnumValueIndex *values_by_name; /** Number of elements in `value_ranges`. */ unsigned n_value_ranges; /** Value ranges, for faster lookups by numeric value. */ const ProtobufCIntRange *value_ranges; /** Reserved for future use. */ void *reserved1; /** Reserved for future use. */ void *reserved2; /** Reserved for future use. */ void *reserved3; /** Reserved for future use. */ void *reserved4; }; /** * Represents a single value of an enumeration. */ struct ProtobufCEnumValue { /** The string identifying this value in the .proto file. */ const char *name; /** The string identifying this value in generated C code. */ const char *c_name; /** The numeric value assigned in the .proto file. */ int value; }; /** * Used by `ProtobufCEnumDescriptor` to look up enum values. */ struct ProtobufCEnumValueIndex { /** Name of the enum value. */ const char *name; /** Index into values[] array. */ unsigned index; }; /** * Describes a single field in a message. */ struct ProtobufCFieldDescriptor { /** Name of the field as given in the .proto file. */ const char *name; /** Tag value of the field as given in the .proto file. */ uint32_t id; /** Whether the field is `REQUIRED`, `OPTIONAL`, or `REPEATED`. */ ProtobufCLabel label; /** The type of the field. */ ProtobufCType type; /** * The offset in bytes of the message's C structure's quantifier field * (the `has_MEMBER` field for optional members or the `n_MEMBER` field * for repeated members or the case enum for oneofs). */ unsigned quantifier_offset; /** * The offset in bytes into the message's C structure for the member * itself. */ unsigned offset; /** * A type-specific descriptor. * * If `type` is `PROTOBUF_C_TYPE_ENUM`, then `descriptor` points to the * corresponding `ProtobufCEnumDescriptor`. * * If `type` is `PROTOBUF_C_TYPE_MESSAGE`, then `descriptor` points to * the corresponding `ProtobufCMessageDescriptor`. * * Otherwise this field is NULL. */ const void *descriptor; /* for MESSAGE and ENUM types */ /** The default value for this field, if defined. May be NULL. */ const void *default_value; /** * A flag word. Zero or more of the bits defined in the * `ProtobufCFieldFlag` enum may be set. */ uint32_t flags; /** Reserved for future use. */ unsigned reserved_flags; /** Reserved for future use. */ void *reserved2; /** Reserved for future use. */ void *reserved3; }; /** * Helper structure for optimizing int => index lookups in the case * where the keys are mostly consecutive values, as they presumably are for * enums and fields. * * The data structures requires that the values in the original array are * sorted. */ struct ProtobufCIntRange { int start_value; unsigned orig_index; /* * NOTE: the number of values in the range can be inferred by looking * at the next element's orig_index. A dummy element is added to make * this simple. */ }; /** * An instance of a message. * * `ProtobufCMessage` is a light-weight "base class" for all messages. * * In particular, `ProtobufCMessage` doesn't have any allocation policy * associated with it. That's because it's common to create `ProtobufCMessage` * objects on the stack. In fact, that's what we recommend for sending messages. * If the object is allocated from the stack, you can't really have a memory * leak. * * This means that calls to functions like protobuf_c_message_unpack() which * return a `ProtobufCMessage` must be paired with a call to a free function, * like protobuf_c_message_free_unpacked(). */ struct ProtobufCMessage { /** The descriptor for this message type. */ const ProtobufCMessageDescriptor *descriptor; /** The number of elements in `unknown_fields`. */ unsigned n_unknown_fields; /** The fields that weren't recognized by the parser. */ ProtobufCMessageUnknownField *unknown_fields; }; /** * Describes a message. */ struct ProtobufCMessageDescriptor { /** Magic value checked to ensure that the API is used correctly. */ uint32_t magic; /** The qualified name (e.g., "namespace.Type"). */ const char *name; /** The unqualified name as given in the .proto file (e.g., "Type"). */ const char *short_name; /** Identifier used in generated C code. */ const char *c_name; /** The dot-separated namespace. */ const char *package_name; /** * Size in bytes of the C structure representing an instance of this * type of message. */ size_t sizeof_message; /** Number of elements in `fields`. */ unsigned n_fields; /** Field descriptors, sorted by tag number. */ const ProtobufCFieldDescriptor *fields; /** Used for looking up fields by name. */ const unsigned *fields_sorted_by_name; /** Number of elements in `field_ranges`. */ unsigned n_field_ranges; /** Used for looking up fields by id. */ const ProtobufCIntRange *field_ranges; /** Message initialisation function. */ ProtobufCMessageInit message_init; /** Reserved for future use. */ void *reserved1; /** Reserved for future use. */ void *reserved2; /** Reserved for future use. */ void *reserved3; }; /** * An unknown message field. */ struct ProtobufCMessageUnknownField { /** The tag number. */ uint32_t tag; /** The wire type of the field. */ ProtobufCWireType wire_type; /** Number of bytes in `data`. */ size_t len; /** Field data. */ uint8_t *data; }; /** * Method descriptor. */ struct ProtobufCMethodDescriptor { /** Method name. */ const char *name; /** Input message descriptor. */ const ProtobufCMessageDescriptor *input; /** Output message descriptor. */ const ProtobufCMessageDescriptor *output; }; /** * Service. */ struct ProtobufCService { /** Service descriptor. */ const ProtobufCServiceDescriptor *descriptor; /** Function to invoke the service. */ void (*invoke)(ProtobufCService *service, unsigned method_index, const ProtobufCMessage *input, ProtobufCClosure closure, void *closure_data); /** Function to destroy the service. */ void (*destroy)(ProtobufCService *service); }; /** * Service descriptor. */ struct ProtobufCServiceDescriptor { /** Magic value checked to ensure that the API is used correctly. */ uint32_t magic; /** Service name. */ const char *name; /** Short version of service name. */ const char *short_name; /** C identifier for the service name. */ const char *c_name; /** Package name. */ const char *package; /** Number of elements in `methods`. */ unsigned n_methods; /** Method descriptors, in the order defined in the .proto file. */ const ProtobufCMethodDescriptor *methods; /** Sort index of methods. */ const unsigned *method_indices_by_name; }; /** * Get the version of the protobuf-c library. Note that this is the version of * the library linked against, not the version of the headers compiled against. * * \return A string containing the version number of protobuf-c. */ PROTOBUF_C__API const char * protobuf_c_version(void); /** * Get the version of the protobuf-c library. Note that this is the version of * the library linked against, not the version of the headers compiled against. * * \return A 32 bit unsigned integer containing the version number of * protobuf-c, represented in base-10 as (MAJOR*1E6) + (MINOR*1E3) + PATCH. */ PROTOBUF_C__API uint32_t protobuf_c_version_number(void); /** * The version of the protobuf-c headers, represented as a string using the same * format as protobuf_c_version(). */ #define PROTOBUF_C_VERSION "1.1.1" /** * The version of the protobuf-c headers, represented as an integer using the * same format as protobuf_c_version_number(). */ #define PROTOBUF_C_VERSION_NUMBER 1001001 /** * The minimum protoc-c version which works with the current version of the * protobuf-c headers. */ #define PROTOBUF_C_MIN_COMPILER_VERSION 1000000 /** * Look up a `ProtobufCEnumValue` from a `ProtobufCEnumDescriptor` by name. * * \param desc * The `ProtobufCEnumDescriptor` object. * \param name * The `name` field from the corresponding `ProtobufCEnumValue` object to * match. * \return * A `ProtobufCEnumValue` object. * \retval NULL * If not found. */ PROTOBUF_C__API const ProtobufCEnumValue * protobuf_c_enum_descriptor_get_value_by_name( const ProtobufCEnumDescriptor *desc, const char *name); /** * Look up a `ProtobufCEnumValue` from a `ProtobufCEnumDescriptor` by numeric * value. * * \param desc * The `ProtobufCEnumDescriptor` object. * \param value * The `value` field from the corresponding `ProtobufCEnumValue` object to * match. * * \return * A `ProtobufCEnumValue` object. * \retval NULL * If not found. */ PROTOBUF_C__API const ProtobufCEnumValue * protobuf_c_enum_descriptor_get_value( const ProtobufCEnumDescriptor *desc, int value); /** * Look up a `ProtobufCFieldDescriptor` from a `ProtobufCMessageDescriptor` by * the name of the field. * * \param desc * The `ProtobufCMessageDescriptor` object. * \param name * The name of the field. * \return * A `ProtobufCFieldDescriptor` object. * \retval NULL * If not found. */ PROTOBUF_C__API const ProtobufCFieldDescriptor * protobuf_c_message_descriptor_get_field_by_name( const ProtobufCMessageDescriptor *desc, const char *name); /** * Look up a `ProtobufCFieldDescriptor` from a `ProtobufCMessageDescriptor` by * the tag value of the field. * * \param desc * The `ProtobufCMessageDescriptor` object. * \param value * The tag value of the field. * \return * A `ProtobufCFieldDescriptor` object. * \retval NULL * If not found. */ PROTOBUF_C__API const ProtobufCFieldDescriptor * protobuf_c_message_descriptor_get_field( const ProtobufCMessageDescriptor *desc, unsigned value); /** * Determine the number of bytes required to store the serialised message. * * \param message * The message object to serialise. * \return * Number of bytes. */ PROTOBUF_C__API size_t protobuf_c_message_get_packed_size(const ProtobufCMessage *message); /** * Serialise a message from its in-memory representation. * * This function stores the serialised bytes of the message in a pre-allocated * buffer. * * \param message * The message object to serialise. * \param[out] out * Buffer to store the bytes of the serialised message. This buffer must * have enough space to store the packed message. Use * protobuf_c_message_get_packed_size() to determine the number of bytes * required. * \return * Number of bytes stored in `out`. */ PROTOBUF_C__API size_t protobuf_c_message_pack(const ProtobufCMessage *message, uint8_t *out); /** * Serialise a message from its in-memory representation to a virtual buffer. * * This function calls the `append` method of a `ProtobufCBuffer` object to * consume the bytes generated by the serialiser. * * \param message * The message object to serialise. * \param buffer * The virtual buffer object. * \return * Number of bytes passed to the virtual buffer. */ PROTOBUF_C__API size_t protobuf_c_message_pack_to_buffer( const ProtobufCMessage *message, ProtobufCBuffer *buffer); /** * Unpack a serialised message into an in-memory representation. * * \param descriptor * The message descriptor. * \param allocator * `ProtobufCAllocator` to use for memory allocation. May be NULL to * specify the default allocator. * \param len * Length in bytes of the serialised message. * \param data * Pointer to the serialised message. * \return * An unpacked message object. * \retval NULL * If an error occurred during unpacking. */ PROTOBUF_C__API ProtobufCMessage * protobuf_c_message_unpack( const ProtobufCMessageDescriptor *descriptor, ProtobufCAllocator *allocator, size_t len, const uint8_t *data); /** * Free an unpacked message object. * * This function should be used to deallocate the memory used by a call to * protobuf_c_message_unpack(). * * \param message * The message object to free. * \param allocator * `ProtobufCAllocator` to use for memory deallocation. May be NULL to * specify the default allocator. */ PROTOBUF_C__API void protobuf_c_message_free_unpacked( ProtobufCMessage *message, ProtobufCAllocator *allocator); /** * Check the validity of a message object. * * Makes sure all required fields (`PROTOBUF_C_LABEL_REQUIRED`) are present. * Recursively checks nested messages. * * \retval TRUE * Message is valid. * \retval FALSE * Message is invalid. */ PROTOBUF_C__API protobuf_c_boolean protobuf_c_message_check(const ProtobufCMessage *); /** Message initialiser. */ #define PROTOBUF_C_MESSAGE_INIT(descriptor) { descriptor, 0, NULL } /** * Initialise a message object from a message descriptor. * * \param descriptor * Message descriptor. * \param message * Allocated block of memory of size `descriptor->sizeof_message`. */ PROTOBUF_C__API void protobuf_c_message_init( const ProtobufCMessageDescriptor *descriptor, void *message); /** * Free a service. * * \param service * The service object to free. */ PROTOBUF_C__API void protobuf_c_service_destroy(ProtobufCService *service); /** * Look up a `ProtobufCMethodDescriptor` by name. * * \param desc * Service descriptor. * \param name * Name of the method. * * \return * A `ProtobufCMethodDescriptor` object. * \retval NULL * If not found. */ PROTOBUF_C__API const ProtobufCMethodDescriptor * protobuf_c_service_descriptor_get_method_by_name( const ProtobufCServiceDescriptor *desc, const char *name); /** * Initialise a `ProtobufCBufferSimple` object. */ #define PROTOBUF_C_BUFFER_SIMPLE_INIT(array_of_bytes) \ { \ { protobuf_c_buffer_simple_append }, \ sizeof(array_of_bytes), \ 0, \ (array_of_bytes), \ 0, \ NULL \ } /** * Clear a `ProtobufCBufferSimple` object, freeing any allocated memory. */ #define PROTOBUF_C_BUFFER_SIMPLE_CLEAR(simp_buf) \ do { \ if ((simp_buf)->must_free_data) { \ if ((simp_buf)->allocator != NULL) \ (simp_buf)->allocator->free( \ (simp_buf)->allocator, \ (simp_buf)->data); \ else \ free((simp_buf)->data); \ } \ } while (0) /** * The `append` method for `ProtobufCBufferSimple`. * * \param buffer * The buffer object to append to. Must actually be a * `ProtobufCBufferSimple` object. * \param len * Number of bytes in `data`. * \param data * Data to append. */ PROTOBUF_C__API void protobuf_c_buffer_simple_append( ProtobufCBuffer *buffer, size_t len, const unsigned char *data); PROTOBUF_C__API void protobuf_c_service_generated_init( ProtobufCService *service, const ProtobufCServiceDescriptor *descriptor, ProtobufCServiceDestroy destroy); PROTOBUF_C__API void protobuf_c_service_invoke_internal( ProtobufCService *service, unsigned method_index, const ProtobufCMessage *input, ProtobufCClosure closure, void *closure_data); /**@}*/ PROTOBUF_C__END_DECLS #endif /* PROTOBUF_C_H */ libsignal-protocol-c-2.3.3/src/protocol.c000066400000000000000000001251421363751346500203600ustar00rootroot00000000000000#include "protocol.h" #include #include #include "curve.h" #include "signal_protocol_internal.h" #include "WhisperTextProtocol.pb-c.h" #define SIGNAL_MESSAGE_MAC_LENGTH 8 #define SIGNATURE_LENGTH 64 struct ciphertext_message { signal_type_base base; int message_type; signal_context *global_context; signal_buffer *serialized; }; struct signal_message { ciphertext_message base_message; uint8_t message_version; ec_public_key *sender_ratchet_key; uint32_t counter; uint32_t previous_counter; signal_buffer *ciphertext; }; struct pre_key_signal_message { ciphertext_message base_message; uint8_t version; uint32_t registration_id; int has_pre_key_id; uint32_t pre_key_id; uint32_t signed_pre_key_id; ec_public_key *base_key; ec_public_key *identity_key; signal_message *message; }; struct sender_key_message { ciphertext_message base_message; uint8_t message_version; uint32_t key_id; uint32_t iteration; signal_buffer *ciphertext; }; struct sender_key_distribution_message { ciphertext_message base_message; uint32_t id; uint32_t iteration; signal_buffer *chain_key; ec_public_key *signature_key; }; static int signal_message_serialize(signal_buffer **buffer, const signal_message *message); static int signal_message_get_mac(signal_buffer **buffer, uint8_t message_version, ec_public_key *sender_identity_key, ec_public_key *receiver_identity_key, const uint8_t *mac_key, size_t mac_key_len, const uint8_t *serialized, size_t serialized_len, signal_context *global_context); static int pre_key_signal_message_serialize(signal_buffer **buffer, const pre_key_signal_message *message); static int sender_key_message_serialize(signal_buffer **buffer, const sender_key_message *message, ec_private_key *signature_key, signal_context *global_context); static int sender_key_distribution_message_serialize(signal_buffer **buffer, const sender_key_distribution_message *message); /*------------------------------------------------------------------------*/ int ciphertext_message_get_type(const ciphertext_message *message) { assert(message); return message->message_type; } signal_buffer *ciphertext_message_get_serialized(const ciphertext_message *message) { assert(message); return message->serialized; } /*------------------------------------------------------------------------*/ int signal_message_create(signal_message **message, uint8_t message_version, const uint8_t *mac_key, size_t mac_key_len, ec_public_key *sender_ratchet_key, uint32_t counter, uint32_t previous_counter, const uint8_t *ciphertext, size_t ciphertext_len, ec_public_key *sender_identity_key, ec_public_key *receiver_identity_key, signal_context *global_context) { int result = 0; signal_buffer *message_buf = 0; signal_buffer *mac_buf = 0; signal_message *result_message = 0; assert(global_context); result_message = malloc(sizeof(signal_message)); if(!result_message) { return SG_ERR_NOMEM; } memset(result_message, 0, sizeof(signal_message)); SIGNAL_INIT(result_message, signal_message_destroy); result_message->base_message.message_type = CIPHERTEXT_SIGNAL_TYPE; result_message->base_message.global_context = global_context; SIGNAL_REF(sender_ratchet_key); result_message->sender_ratchet_key = sender_ratchet_key; result_message->counter = counter; result_message->previous_counter = previous_counter; result_message->ciphertext = signal_buffer_create(ciphertext, ciphertext_len); if(!result_message->ciphertext) { result = SG_ERR_NOMEM; goto complete; } result_message->message_version = message_version; result = signal_message_serialize(&message_buf, result_message); if(result < 0) { goto complete; } result = signal_message_get_mac(&mac_buf, message_version, sender_identity_key, receiver_identity_key, mac_key, mac_key_len, signal_buffer_data(message_buf), signal_buffer_len(message_buf), global_context); if(result < 0) { goto complete; } result_message->base_message.serialized = signal_buffer_append( message_buf, signal_buffer_data(mac_buf), signal_buffer_len(mac_buf)); if(result_message->base_message.serialized) { message_buf = 0; } else { result = SG_ERR_NOMEM; } complete: if(message_buf) { signal_buffer_free(message_buf); } if(mac_buf) { signal_buffer_free(mac_buf); } if(result >= 0) { result = 0; *message = result_message; } else { if(result_message) { SIGNAL_UNREF(result_message); } } return result; } static int signal_message_serialize(signal_buffer **buffer, const signal_message *message) { int result = 0; size_t result_size = 0; signal_buffer *result_buf = 0; Textsecure__SignalMessage message_structure = TEXTSECURE__SIGNAL_MESSAGE__INIT; size_t len = 0; uint8_t *data = 0; uint8_t version = (message->message_version << 4) | CIPHERTEXT_CURRENT_VERSION; result = ec_public_key_serialize_protobuf(&message_structure.ratchetkey, message->sender_ratchet_key); if(result < 0) { goto complete; } message_structure.has_ratchetkey = 1; message_structure.counter = message->counter; message_structure.has_counter = 1; message_structure.previouscounter = message->previous_counter; message_structure.has_previouscounter = 1; message_structure.ciphertext.data = signal_buffer_data(message->ciphertext); message_structure.ciphertext.len = signal_buffer_len(message->ciphertext); message_structure.has_ciphertext = 1; len = textsecure__signal_message__get_packed_size(&message_structure); result_buf = signal_buffer_alloc(len + 1); if(!result_buf) { result = SG_ERR_NOMEM; goto complete; } data = signal_buffer_data(result_buf); data[0] = version; result_size = textsecure__signal_message__pack(&message_structure, data + 1); if(result_size != len) { signal_buffer_free(result_buf); result = SG_ERR_INVALID_PROTO_BUF; result_buf = 0; goto complete; } complete: if(message_structure.ratchetkey.data) { free(message_structure.ratchetkey.data); } if(result >= 0) { *buffer = result_buf; } return result; } int signal_message_deserialize(signal_message **message, const uint8_t *data, size_t len, signal_context *global_context) { int result = 0; signal_message *result_message = 0; Textsecure__SignalMessage *message_structure = 0; uint8_t version = 0; uint8_t *ciphertext_data = 0; uint8_t *serialized_data = 0; const uint8_t *message_data = 0; size_t message_len = 0; assert(global_context); if(!data || len <= 1 + SIGNAL_MESSAGE_MAC_LENGTH) { result = SG_ERR_INVAL; goto complete; } version = (data[0] & 0xF0) >> 4; /* Set some pointers and lengths for the sections of the raw data */ message_data = data + 1; message_len = len - 1 - SIGNAL_MESSAGE_MAC_LENGTH; if(version <= CIPHERTEXT_UNSUPPORTED_VERSION) { signal_log(global_context, SG_LOG_WARNING, "Unsupported legacy version: %d", version); result = SG_ERR_LEGACY_MESSAGE; goto complete; } if(version > CIPHERTEXT_CURRENT_VERSION) { signal_log(global_context, SG_LOG_WARNING, "Unknown version: %d", version); result = SG_ERR_INVALID_MESSAGE; goto complete; } message_structure = textsecure__signal_message__unpack(0, message_len, message_data); if(!message_structure) { result = SG_ERR_INVALID_PROTO_BUF; goto complete; } if(!message_structure->has_ciphertext || !message_structure->has_counter || !message_structure->has_ratchetkey) { signal_log(global_context, SG_LOG_WARNING, "Incomplete message"); result = SG_ERR_INVALID_MESSAGE; goto complete; } result_message = malloc(sizeof(signal_message)); if(!result_message) { result = SG_ERR_NOMEM; goto complete; } memset(result_message, 0, sizeof(signal_message)); SIGNAL_INIT(result_message, signal_message_destroy); result_message->base_message.message_type = CIPHERTEXT_SIGNAL_TYPE; result_message->base_message.global_context = global_context; result = curve_decode_point(&result_message->sender_ratchet_key, message_structure->ratchetkey.data, message_structure->ratchetkey.len, global_context); if(result < 0) { goto complete; } result_message->message_version = version; result_message->counter = message_structure->counter; result_message->previous_counter = message_structure->previouscounter; result_message->ciphertext = signal_buffer_alloc(message_structure->ciphertext.len); if(!result_message->ciphertext) { result = SG_ERR_NOMEM; goto complete; } ciphertext_data = signal_buffer_data(result_message->ciphertext); memcpy(ciphertext_data, message_structure->ciphertext.data, message_structure->ciphertext.len); result_message->base_message.serialized = signal_buffer_alloc(len); if(!result_message->base_message.serialized) { result = SG_ERR_NOMEM; goto complete; } serialized_data = signal_buffer_data(result_message->base_message.serialized); memcpy(serialized_data, data, len); complete: if(message_structure) { textsecure__signal_message__free_unpacked(message_structure, 0); } if(result >= 0) { *message = result_message; } else { if(result_message) { SIGNAL_UNREF(result_message); } } return result; } int signal_message_copy(signal_message **message, signal_message *other_message, signal_context *global_context) { int result = 0; signal_message *result_message = 0; assert(other_message); assert(global_context); result = signal_message_deserialize( &result_message, signal_buffer_data(other_message->base_message.serialized), signal_buffer_len(other_message->base_message.serialized), global_context); if(result >= 0) { *message = result_message; } return result; } ec_public_key *signal_message_get_sender_ratchet_key(const signal_message *message) { assert(message); return message->sender_ratchet_key; } uint8_t signal_message_get_message_version(const signal_message *message) { assert(message); return message->message_version; } uint32_t signal_message_get_counter(const signal_message *message) { assert(message); return message->counter; } signal_buffer *signal_message_get_body(const signal_message *message) { assert(message); return message->ciphertext; } int signal_message_verify_mac(signal_message *message, ec_public_key *sender_identity_key, ec_public_key *receiver_identity_key, const uint8_t *mac_key, size_t mac_key_len, signal_context *global_context) { int result = 0; signal_buffer *our_mac_buffer = 0; uint8_t *serialized_data = 0; size_t serialized_len = 0; uint8_t *serialized_message_data = 0; size_t serialized_message_len = 0; uint8_t *their_mac_data = 0; const size_t their_mac_len = SIGNAL_MESSAGE_MAC_LENGTH; uint8_t *our_mac_data = 0; size_t our_mac_len = 0; assert(message); assert(message->base_message.serialized); /* Set some pointers and lengths for the sections of the raw data */ serialized_data = signal_buffer_data(message->base_message.serialized); serialized_len = signal_buffer_len(message->base_message.serialized); serialized_message_data = serialized_data; serialized_message_len = serialized_len - SIGNAL_MESSAGE_MAC_LENGTH; their_mac_data = serialized_data + serialized_message_len; result = signal_message_get_mac(&our_mac_buffer, message->message_version, sender_identity_key, receiver_identity_key, mac_key, mac_key_len, serialized_message_data, serialized_message_len, message->base_message.global_context); if(result < 0) { goto complete; } our_mac_data = signal_buffer_data(our_mac_buffer); our_mac_len = signal_buffer_len(our_mac_buffer); if(our_mac_len != their_mac_len) { signal_log(global_context, SG_LOG_WARNING, "MAC length mismatch: %d != %d", our_mac_len, their_mac_len); result = SG_ERR_UNKNOWN; goto complete; } if(signal_constant_memcmp(our_mac_data, their_mac_data, our_mac_len) == 0) { result = 1; } else { signal_log(global_context, SG_LOG_NOTICE, "Bad MAC"); result = 0; } complete: if(our_mac_buffer) { signal_buffer_free(our_mac_buffer); } return result; } static int signal_message_get_mac(signal_buffer **buffer, uint8_t message_version, ec_public_key *sender_identity_key, ec_public_key *receiver_identity_key, const uint8_t *mac_key, size_t mac_key_len, const uint8_t *serialized, size_t serialized_len, signal_context *global_context) { int result = 0; void *hmac_context; signal_buffer *sender_key_buffer = 0; signal_buffer *receiver_key_buffer = 0; signal_buffer *full_mac_buffer = 0; signal_buffer *result_buf = 0; uint8_t *result_data = 0; assert(global_context); result = signal_hmac_sha256_init(global_context, &hmac_context, mac_key, mac_key_len); if(result < 0) { goto complete; } if(message_version >= 3) { result = ec_public_key_serialize(&sender_key_buffer, sender_identity_key); if(result < 0) { goto complete; } result = signal_hmac_sha256_update(global_context, hmac_context, signal_buffer_data(sender_key_buffer), signal_buffer_len(sender_key_buffer)); if(result < 0) { goto complete; } result = ec_public_key_serialize(&receiver_key_buffer, receiver_identity_key); if(result < 0) { goto complete; } result = signal_hmac_sha256_update(global_context, hmac_context, signal_buffer_data(receiver_key_buffer), signal_buffer_len(receiver_key_buffer)); if(result < 0) { goto complete; } } result = signal_hmac_sha256_update(global_context, hmac_context, serialized, serialized_len); if(result < 0) { goto complete; } result = signal_hmac_sha256_final(global_context, hmac_context, &full_mac_buffer); if(result < 0 || signal_buffer_len(full_mac_buffer) < SIGNAL_MESSAGE_MAC_LENGTH) { if(result >= 0) { result = SG_ERR_UNKNOWN; } goto complete; } result_buf = signal_buffer_alloc(SIGNAL_MESSAGE_MAC_LENGTH); if(!result_buf) { result = SG_ERR_NOMEM; goto complete; } result_data = signal_buffer_data(result_buf); memcpy(result_data, signal_buffer_data(full_mac_buffer), SIGNAL_MESSAGE_MAC_LENGTH); complete: signal_hmac_sha256_cleanup(global_context, hmac_context); signal_buffer_free(sender_key_buffer); signal_buffer_free(receiver_key_buffer); signal_buffer_free(full_mac_buffer); if(result >= 0) { *buffer = result_buf; } return result; } int signal_message_is_legacy(const uint8_t *data, size_t len) { return data && len >= 1 && ((data[0] & 0xF0) >> 4) <= CIPHERTEXT_UNSUPPORTED_VERSION; } void signal_message_destroy(signal_type_base *type) { signal_message *message = (signal_message *)type; if(message->base_message.serialized) { signal_buffer_free(message->base_message.serialized); } SIGNAL_UNREF(message->sender_ratchet_key); if(message->ciphertext) { signal_buffer_free(message->ciphertext); } free(message); } /*------------------------------------------------------------------------*/ int pre_key_signal_message_create(pre_key_signal_message **pre_key_message, uint8_t message_version, uint32_t registration_id, const uint32_t *pre_key_id, uint32_t signed_pre_key_id, ec_public_key *base_key, ec_public_key *identity_key, signal_message *message, signal_context *global_context) { int result = 0; pre_key_signal_message *result_message = 0; assert(global_context); result_message = malloc(sizeof(pre_key_signal_message)); if(!result_message) { return SG_ERR_NOMEM; } memset(result_message, 0, sizeof(pre_key_signal_message)); SIGNAL_INIT(result_message, pre_key_signal_message_destroy); result_message->base_message.message_type = CIPHERTEXT_PREKEY_TYPE; result_message->base_message.global_context = global_context; result_message->version = message_version; result_message->registration_id = registration_id; if(pre_key_id) { result_message->has_pre_key_id = 1; result_message->pre_key_id = *pre_key_id; } result_message->signed_pre_key_id = signed_pre_key_id; SIGNAL_REF(base_key); result_message->base_key = base_key; SIGNAL_REF(identity_key); result_message->identity_key = identity_key; SIGNAL_REF(message); result_message->message = message; result = pre_key_signal_message_serialize(&result_message->base_message.serialized, result_message); if(result >= 0) { result = 0; *pre_key_message = result_message; } else { if(result_message) { SIGNAL_UNREF(result_message); } } return result; } static int pre_key_signal_message_serialize(signal_buffer **buffer, const pre_key_signal_message *message) { int result = 0; size_t result_size = 0; signal_buffer *result_buf = 0; Textsecure__PreKeySignalMessage message_structure = TEXTSECURE__PRE_KEY_SIGNAL_MESSAGE__INIT; signal_buffer *inner_message_buffer = 0; size_t len = 0; uint8_t *data = 0; uint8_t version = (message->version << 4) | CIPHERTEXT_CURRENT_VERSION; message_structure.registrationid = message->registration_id; message_structure.has_registrationid = 1; if(message->has_pre_key_id) { message_structure.prekeyid = message->pre_key_id; message_structure.has_prekeyid = 1; } message_structure.signedprekeyid = message->signed_pre_key_id; message_structure.has_signedprekeyid = 1; result = ec_public_key_serialize_protobuf(&message_structure.basekey, message->base_key); if(result < 0) { goto complete; } message_structure.has_basekey = 1; result = ec_public_key_serialize_protobuf(&message_structure.identitykey, message->identity_key); if(result < 0) { goto complete; } message_structure.has_identitykey = 1; inner_message_buffer = message->message->base_message.serialized; message_structure.message.data = signal_buffer_data(inner_message_buffer); message_structure.message.len = signal_buffer_len(inner_message_buffer); message_structure.has_message = 1; len = textsecure__pre_key_signal_message__get_packed_size(&message_structure); result_buf = signal_buffer_alloc(len + 1); if(!result_buf) { result = SG_ERR_NOMEM; goto complete; } data = signal_buffer_data(result_buf); data[0] = version; result_size = textsecure__pre_key_signal_message__pack(&message_structure, data + 1); if(result_size != len) { signal_buffer_free(result_buf); result = SG_ERR_INVALID_PROTO_BUF; result_buf = 0; goto complete; } complete: if(message_structure.basekey.data) { free(message_structure.basekey.data); } if(message_structure.identitykey.data) { free(message_structure.identitykey.data); } if(result >= 0) { *buffer = result_buf; } return result; } int pre_key_signal_message_deserialize(pre_key_signal_message **message, const uint8_t *data, size_t len, signal_context *global_context) { int result = 0; pre_key_signal_message *result_message = 0; Textsecure__PreKeySignalMessage *message_structure = 0; uint8_t version = 0; const uint8_t *message_data = 0; size_t message_len = 0; uint8_t *serialized_data = 0; assert(global_context); if(!data || len <= 1) { result = SG_ERR_INVAL; goto complete; } version = (data[0] & 0xF0) >> 4; /* Set some pointers and lengths for the sections of the raw data */ message_data = data + 1; message_len = len - 1; if(version < CIPHERTEXT_CURRENT_VERSION) { signal_log(global_context, SG_LOG_WARNING, "Unsupported legacy version: %d", version); result = SG_ERR_LEGACY_MESSAGE; goto complete; } if(version > CIPHERTEXT_CURRENT_VERSION) { signal_log(global_context, SG_LOG_WARNING, "Unknown version: %d", version); result = SG_ERR_INVALID_VERSION; goto complete; } message_structure = textsecure__pre_key_signal_message__unpack(0, message_len, message_data); if(!message_structure) { result = SG_ERR_INVALID_PROTO_BUF; goto complete; } if(!message_structure->has_signedprekeyid || !message_structure->has_basekey || !message_structure->has_identitykey || !message_structure->has_message) { signal_log(global_context, SG_LOG_WARNING, "Incomplete message"); result = SG_ERR_INVALID_MESSAGE; goto complete; } result_message = malloc(sizeof(pre_key_signal_message)); if(!result_message) { result = SG_ERR_NOMEM; goto complete; } memset(result_message, 0, sizeof(pre_key_signal_message)); SIGNAL_INIT(result_message, pre_key_signal_message_destroy); result_message->base_message.message_type = CIPHERTEXT_PREKEY_TYPE; result_message->base_message.global_context = global_context; result_message->version = version; if(message_structure->has_registrationid) { result_message->registration_id = message_structure->registrationid; } if(message_structure->has_prekeyid) { result_message->pre_key_id = message_structure->prekeyid; result_message->has_pre_key_id = 1; } if(message_structure->has_signedprekeyid) { result_message->signed_pre_key_id = message_structure->signedprekeyid; } if(message_structure->has_basekey) { result = curve_decode_point(&result_message->base_key, message_structure->basekey.data, message_structure->basekey.len, global_context); if(result < 0) { goto complete; } } if(message_structure->has_identitykey) { result = curve_decode_point(&result_message->identity_key, message_structure->identitykey.data, message_structure->identitykey.len, global_context); if(result < 0) { goto complete; } } if(message_structure->has_message) { result = signal_message_deserialize(&result_message->message, message_structure->message.data, message_structure->message.len, global_context); if(result < 0) { goto complete; } if(result_message->message->message_version != version) { signal_log(global_context, SG_LOG_WARNING, "Inner message version mismatch: %d != %d", result_message->message->message_version, version); result = SG_ERR_INVALID_VERSION; goto complete; } } result_message->base_message.serialized = signal_buffer_alloc(len); if(!result_message->base_message.serialized) { result = SG_ERR_NOMEM; goto complete; } serialized_data = signal_buffer_data(result_message->base_message.serialized); memcpy(serialized_data, data, len); complete: if(message_structure) { textsecure__pre_key_signal_message__free_unpacked(message_structure, 0); } if(result >= 0) { *message = result_message; } else { if(result_message) { SIGNAL_UNREF(result_message); } } return result; } int pre_key_signal_message_copy(pre_key_signal_message **message, pre_key_signal_message *other_message, signal_context *global_context) { int result = 0; pre_key_signal_message *result_message = 0; assert(other_message); assert(global_context); result = pre_key_signal_message_deserialize( &result_message, signal_buffer_data(other_message->base_message.serialized), signal_buffer_len(other_message->base_message.serialized), global_context); if(result >= 0) { *message = result_message; } return result; } uint8_t pre_key_signal_message_get_message_version(const pre_key_signal_message *message) { assert(message); return message->version; } ec_public_key *pre_key_signal_message_get_identity_key(const pre_key_signal_message *message) { assert(message); return message->identity_key; } uint32_t pre_key_signal_message_get_registration_id(const pre_key_signal_message *message) { assert(message); return message->registration_id; } int pre_key_signal_message_has_pre_key_id(const pre_key_signal_message *message) { assert(message); return message->has_pre_key_id; } uint32_t pre_key_signal_message_get_pre_key_id(const pre_key_signal_message *message) { assert(message); assert(message->has_pre_key_id); return message->pre_key_id; } uint32_t pre_key_signal_message_get_signed_pre_key_id(const pre_key_signal_message *message) { assert(message); return message->signed_pre_key_id; } ec_public_key *pre_key_signal_message_get_base_key(const pre_key_signal_message *message) { assert(message); return message->base_key; } signal_message *pre_key_signal_message_get_signal_message(const pre_key_signal_message *message) { assert(message); return message->message; } void pre_key_signal_message_destroy(signal_type_base *type) { pre_key_signal_message *message = (pre_key_signal_message *)type; if(message->base_message.serialized) { signal_buffer_free(message->base_message.serialized); } SIGNAL_UNREF(message->base_key); SIGNAL_UNREF(message->identity_key); SIGNAL_UNREF(message->message); free(message); } int sender_key_message_create(sender_key_message **message, uint32_t key_id, uint32_t iteration, const uint8_t *ciphertext, size_t ciphertext_len, ec_private_key *signature_key, signal_context *global_context) { int result = 0; sender_key_message *result_message = 0; signal_buffer *message_buf = 0; assert(global_context); result_message = malloc(sizeof(sender_key_message)); if(!result_message) { return SG_ERR_NOMEM; } memset(result_message, 0, sizeof(sender_key_message)); SIGNAL_INIT(result_message, sender_key_message_destroy); result_message->base_message.message_type = CIPHERTEXT_SENDERKEY_TYPE; result_message->base_message.global_context = global_context; result_message->message_version = CIPHERTEXT_CURRENT_VERSION; result_message->key_id = key_id; result_message->iteration = iteration; result_message->ciphertext = signal_buffer_create(ciphertext, ciphertext_len); if(!result_message->ciphertext) { result = SG_ERR_NOMEM; goto complete; } result = sender_key_message_serialize(&message_buf, result_message, signature_key, global_context); if(result < 0) { goto complete; } result_message->base_message.serialized = message_buf; complete: if(result >= 0) { result = 0; *message = result_message; } else { if(result_message) { SIGNAL_UNREF(result_message); } } return result; } int sender_key_message_serialize(signal_buffer **buffer, const sender_key_message *message, ec_private_key *signature_key, signal_context *global_context) { int result = 0; uint8_t version = (CIPHERTEXT_CURRENT_VERSION << 4) | CIPHERTEXT_CURRENT_VERSION; size_t result_size = 0; signal_buffer *result_buf = 0; signal_buffer *signature_buf = 0; Textsecure__SenderKeyMessage message_structure = TEXTSECURE__SENDER_KEY_MESSAGE__INIT; size_t len = 0; uint8_t *data = 0; message_structure.id = message->key_id; message_structure.has_id = 1; message_structure.iteration = message->iteration; message_structure.has_iteration = 1; message_structure.ciphertext.data = signal_buffer_data(message->ciphertext); message_structure.ciphertext.len = signal_buffer_len(message->ciphertext); message_structure.has_ciphertext = 1; len = textsecure__sender_key_message__get_packed_size(&message_structure); result_buf = signal_buffer_alloc(sizeof(version) + len + SIGNATURE_LENGTH); if(!result_buf) { result = SG_ERR_NOMEM; goto complete; } data = signal_buffer_data(result_buf); data[0] = version; result_size = textsecure__sender_key_message__pack(&message_structure, data + sizeof(version)); if(result_size != len) { signal_buffer_free(result_buf); result = SG_ERR_INVALID_PROTO_BUF; result_buf = 0; goto complete; } result = curve_calculate_signature(global_context, &signature_buf, signature_key, data, len + sizeof(version)); if(result < 0) { if(result == SG_ERR_INVALID_KEY) { result = SG_ERR_UNKNOWN; } goto complete; } else if(signal_buffer_len(signature_buf) != SIGNATURE_LENGTH) { result = SG_ERR_UNKNOWN; goto complete; } memcpy(data + sizeof(version) + len, signal_buffer_data(signature_buf), SIGNATURE_LENGTH); complete: signal_buffer_free(signature_buf); if(result >= 0) { *buffer = result_buf; } else { signal_buffer_free(result_buf); } return result; } int sender_key_message_deserialize(sender_key_message **message, const uint8_t *data, size_t len, signal_context *global_context) { int result = 0; sender_key_message *result_message = 0; uint8_t version = 0; const uint8_t *message_data = 0; size_t message_len = 0; Textsecure__SenderKeyMessage *message_structure = 0; assert(global_context); if(!data || len <= sizeof(uint8_t) + SIGNATURE_LENGTH) { result = SG_ERR_INVAL; goto complete; } version = (data[0] & 0xF0) >> 4; message_data = data + sizeof(uint8_t); message_len = len - sizeof(uint8_t) - SIGNATURE_LENGTH; if(version < CIPHERTEXT_CURRENT_VERSION) { signal_log(global_context, SG_LOG_WARNING, "Legacy message: %d", version); result = SG_ERR_LEGACY_MESSAGE; goto complete; } if(version > CIPHERTEXT_CURRENT_VERSION) { signal_log(global_context, SG_LOG_WARNING, "Unknown version: %d", version); result = SG_ERR_INVALID_VERSION; goto complete; } message_structure = textsecure__sender_key_message__unpack(0, message_len, message_data); if(!message_structure) { result = SG_ERR_INVALID_PROTO_BUF; goto complete; } if(!message_structure->has_id || !message_structure->has_iteration || !message_structure->has_ciphertext) { signal_log(global_context, SG_LOG_WARNING, "Incomplete message"); result = SG_ERR_INVALID_MESSAGE; goto complete; } result_message = malloc(sizeof(sender_key_message)); if(!result_message) { result = SG_ERR_NOMEM; goto complete; } memset(result_message, 0, sizeof(sender_key_message)); SIGNAL_INIT(result_message, sender_key_message_destroy); result_message->base_message.message_type = CIPHERTEXT_SENDERKEY_TYPE; result_message->base_message.global_context = global_context; result_message->key_id = message_structure->id; result_message->iteration = message_structure->iteration; result_message->message_version = version; result_message->ciphertext = signal_buffer_create( message_structure->ciphertext.data, message_structure->ciphertext.len); if(!result_message->ciphertext) { result = SG_ERR_NOMEM; goto complete; } result_message->base_message.serialized = signal_buffer_create(data, len); if(!result_message->base_message.serialized) { result = SG_ERR_NOMEM; goto complete; } complete: if(message_structure) { textsecure__sender_key_message__free_unpacked(message_structure, 0); } if(result >= 0) { *message = result_message; } else { if(result_message) { SIGNAL_UNREF(result_message); } } return result; } int sender_key_message_copy(sender_key_message **message, sender_key_message *other_message, signal_context *global_context) { int result = 0; sender_key_message *result_message = 0; assert(other_message); assert(global_context); result = sender_key_message_deserialize( &result_message, signal_buffer_data(other_message->base_message.serialized), signal_buffer_len(other_message->base_message.serialized), global_context); if(result >= 0) { *message = result_message; } return result; } uint32_t sender_key_message_get_key_id(sender_key_message *message) { assert(message); return message->key_id; } uint32_t sender_key_message_get_iteration(sender_key_message *message) { assert(message); return message->iteration; } signal_buffer *sender_key_message_get_ciphertext(sender_key_message *message) { assert(message); return message->ciphertext; } int sender_key_message_verify_signature(sender_key_message *message, ec_public_key *signature_key) { int result = 0; uint8_t *data; size_t data_len; assert(message); data = signal_buffer_data(message->base_message.serialized); data_len = signal_buffer_len(message->base_message.serialized) - SIGNATURE_LENGTH; result = curve_verify_signature(signature_key, data, data_len, data + data_len, SIGNATURE_LENGTH); if(result == 0) { signal_log(message->base_message.global_context, SG_LOG_ERROR, "Invalid signature!"); result = SG_ERR_INVALID_MESSAGE; } else if(result < 0) { result = SG_ERR_INVALID_MESSAGE; } else { result = 0; } return result; } void sender_key_message_destroy(signal_type_base *type) { sender_key_message *message = (sender_key_message *)type; if(message->base_message.serialized) { signal_buffer_free(message->base_message.serialized); } if(message->ciphertext) { signal_buffer_free(message->ciphertext); } free(message); } int sender_key_distribution_message_create(sender_key_distribution_message **message, uint32_t id, uint32_t iteration, const uint8_t *chain_key, size_t chain_key_len, ec_public_key *signature_key, signal_context *global_context) { int result = 0; sender_key_distribution_message *result_message = 0; signal_buffer *message_buf = 0; assert(global_context); result_message = malloc(sizeof(sender_key_distribution_message)); if(!result_message) { return SG_ERR_NOMEM; } memset(result_message, 0, sizeof(sender_key_distribution_message)); SIGNAL_INIT(result_message, sender_key_distribution_message_destroy); result_message->base_message.message_type = CIPHERTEXT_SENDERKEY_DISTRIBUTION_TYPE; result_message->base_message.global_context = global_context; result_message->id = id; result_message->iteration = iteration; result_message->chain_key = signal_buffer_create(chain_key, chain_key_len); if(!result_message->chain_key) { goto complete; } SIGNAL_REF(signature_key); result_message->signature_key = signature_key; result = sender_key_distribution_message_serialize(&message_buf, result_message); if(result < 0) { goto complete; } result_message->base_message.serialized = message_buf; complete: if(result >= 0) { result = 0; *message = result_message; } else { if(result_message) { SIGNAL_UNREF(result_message); } } return result; } int sender_key_distribution_message_serialize(signal_buffer **buffer, const sender_key_distribution_message *message) { int result = 0; uint8_t version = (CIPHERTEXT_CURRENT_VERSION << 4) | CIPHERTEXT_CURRENT_VERSION; size_t result_size = 0; signal_buffer *result_buf = 0; Textsecure__SenderKeyDistributionMessage message_structure = TEXTSECURE__SENDER_KEY_DISTRIBUTION_MESSAGE__INIT; size_t len = 0; uint8_t *data = 0; message_structure.id = message->id; message_structure.has_id = 1; message_structure.iteration = message->iteration; message_structure.has_iteration = 1; message_structure.chainkey.data = signal_buffer_data(message->chain_key); message_structure.chainkey.len = signal_buffer_len(message->chain_key); message_structure.has_chainkey = 1; result = ec_public_key_serialize_protobuf(&message_structure.signingkey, message->signature_key); if(result < 0) { goto complete; } message_structure.has_signingkey = 1; len = textsecure__sender_key_distribution_message__get_packed_size(&message_structure); result_buf = signal_buffer_alloc(sizeof(version) + len); if(!result_buf) { result = SG_ERR_NOMEM; goto complete; } data = signal_buffer_data(result_buf); data[0] = version; result_size = textsecure__sender_key_distribution_message__pack(&message_structure, data + sizeof(version)); if(result_size != len) { signal_buffer_free(result_buf); result = SG_ERR_INVALID_PROTO_BUF; result_buf = 0; goto complete; } complete: if(message_structure.has_signingkey) { free(message_structure.signingkey.data); } if(result >= 0) { *buffer = result_buf; } else { signal_buffer_free(result_buf); } return result; } int sender_key_distribution_message_deserialize(sender_key_distribution_message **message, const uint8_t *data, size_t len, signal_context *global_context) { int result = 0; sender_key_distribution_message *result_message = 0; uint8_t version = 0; const uint8_t *message_data = 0; size_t message_len = 0; Textsecure__SenderKeyDistributionMessage *message_structure = 0; assert(global_context); if(!data || len <= sizeof(uint8_t)) { result = SG_ERR_INVAL; goto complete; } version = (data[0] & 0xF0) >> 4; message_data = data + sizeof(uint8_t); message_len = len - sizeof(uint8_t); if(version < CIPHERTEXT_CURRENT_VERSION) { signal_log(global_context, SG_LOG_WARNING, "Legacy message: %d", version); result = SG_ERR_LEGACY_MESSAGE; goto complete; } if(version > CIPHERTEXT_CURRENT_VERSION) { signal_log(global_context, SG_LOG_WARNING, "Unknown version: %d", version); result = SG_ERR_INVALID_VERSION; goto complete; } message_structure = textsecure__sender_key_distribution_message__unpack(0, message_len, message_data); if(!message_structure) { result = SG_ERR_INVALID_PROTO_BUF; goto complete; } if(!message_structure->has_id || !message_structure->has_iteration || !message_structure->has_chainkey || !message_structure->has_signingkey) { signal_log(global_context, SG_LOG_WARNING, "Incomplete message"); result = SG_ERR_INVALID_MESSAGE; goto complete; } result_message = malloc(sizeof(sender_key_distribution_message)); if(!result_message) { result = SG_ERR_NOMEM; goto complete; } memset(result_message, 0, sizeof(sender_key_distribution_message)); SIGNAL_INIT(result_message, sender_key_distribution_message_destroy); result_message->base_message.message_type = CIPHERTEXT_SENDERKEY_DISTRIBUTION_TYPE; result_message->base_message.global_context = global_context; result_message->id = message_structure->id; result_message->iteration = message_structure->iteration; result_message->chain_key = signal_buffer_create( message_structure->chainkey.data, message_structure->chainkey.len); if(!result_message->chain_key) { result = SG_ERR_NOMEM; goto complete; } result = curve_decode_point(&result_message->signature_key, message_structure->signingkey.data, message_structure->signingkey.len, global_context); if(result < 0) { goto complete; } result_message->base_message.serialized = signal_buffer_create(data, len); if(!result_message->base_message.serialized) { result = SG_ERR_NOMEM; goto complete; } complete: if(message_structure) { textsecure__sender_key_distribution_message__free_unpacked(message_structure, 0); } if(result >= 0) { *message = result_message; } else { if(result_message) { SIGNAL_UNREF(result_message); } } return result; } int sender_key_distribution_message_copy(sender_key_distribution_message **message, sender_key_distribution_message *other_message, signal_context *global_context) { int result = 0; sender_key_distribution_message *result_message = 0; assert(other_message); assert(global_context); result = sender_key_distribution_message_deserialize( &result_message, signal_buffer_data(other_message->base_message.serialized), signal_buffer_len(other_message->base_message.serialized), global_context); if(result >= 0) { *message = result_message; } return result; } uint32_t sender_key_distribution_message_get_id(sender_key_distribution_message *message) { assert(message); return message->id; } uint32_t sender_key_distribution_message_get_iteration(sender_key_distribution_message *message) { assert(message); return message->iteration; } signal_buffer *sender_key_distribution_message_get_chain_key(sender_key_distribution_message *message) { assert(message); return message->chain_key; } ec_public_key *sender_key_distribution_message_get_signature_key(sender_key_distribution_message *message) { assert(message); return message->signature_key; } void sender_key_distribution_message_destroy(signal_type_base *type) { sender_key_distribution_message *message = (sender_key_distribution_message *)type; if(message->base_message.serialized) { signal_buffer_free(message->base_message.serialized); } if(message->chain_key) { signal_buffer_free(message->chain_key); } SIGNAL_UNREF(message->signature_key); free(message); } libsignal-protocol-c-2.3.3/src/protocol.h000066400000000000000000000131631363751346500203640ustar00rootroot00000000000000#ifndef PROTOCOL_H #define PROTOCOL_H #include #include #include "signal_protocol_types.h" #ifdef __cplusplus extern "C" { #endif #define KEY_EXCHANGE_INITIATE_FLAG 0x01 #define KEY_EXCHANGE_RESPONSE_FLAG 0X02 #define KEY_EXCHANGE_SIMULTAENOUS_INITIATE_FLAG 0x04 #define CIPHERTEXT_UNSUPPORTED_VERSION 1 #define CIPHERTEXT_CURRENT_VERSION 3 #define CIPHERTEXT_SIGNAL_TYPE 2 #define CIPHERTEXT_PREKEY_TYPE 3 #define CIPHERTEXT_SENDERKEY_TYPE 4 #define CIPHERTEXT_SENDERKEY_DISTRIBUTION_TYPE 5 /* Worst case overhead. Not always accurate, but good enough for padding. */ #define CIPHERTEXT_ENCRYPTED_MESSAGE_OVERHEAD 53 int ciphertext_message_get_type(const ciphertext_message *message); signal_buffer *ciphertext_message_get_serialized(const ciphertext_message *message); int signal_message_create(signal_message **message, uint8_t message_version, const uint8_t *mac_key, size_t mac_key_len, ec_public_key *sender_ratchet_key, uint32_t counter, uint32_t previous_counter, const uint8_t *ciphertext, size_t ciphertext_len, ec_public_key *sender_identity_key, ec_public_key *receiver_identity_key, signal_context *global_context); int signal_message_deserialize(signal_message **message, const uint8_t *data, size_t len, signal_context *global_context); int signal_message_copy(signal_message **message, signal_message *other_message, signal_context *global_context); ec_public_key *signal_message_get_sender_ratchet_key(const signal_message *message); uint8_t signal_message_get_message_version(const signal_message *message); uint32_t signal_message_get_counter(const signal_message *message); signal_buffer *signal_message_get_body(const signal_message *message); /** * Verify the MAC on the Signal message. * * @return 1 if verified, 0 if invalid, negative on error */ int signal_message_verify_mac(signal_message *message, ec_public_key *sender_identity_key, ec_public_key *receiver_identity_key, const uint8_t *mac_key, size_t mac_key_len, signal_context *global_context); int signal_message_is_legacy(const uint8_t *data, size_t len); void signal_message_destroy(signal_type_base *type); int pre_key_signal_message_create(pre_key_signal_message **pre_key_message, uint8_t message_version, uint32_t registration_id, const uint32_t *pre_key_id, uint32_t signed_pre_key_id, ec_public_key *base_key, ec_public_key *identity_key, signal_message *message, signal_context *global_context); int pre_key_signal_message_deserialize(pre_key_signal_message **message, const uint8_t *data, size_t len, signal_context *global_context); int pre_key_signal_message_copy(pre_key_signal_message **message, pre_key_signal_message *other_message, signal_context *global_context); uint8_t pre_key_signal_message_get_message_version(const pre_key_signal_message *message); ec_public_key *pre_key_signal_message_get_identity_key(const pre_key_signal_message *message); uint32_t pre_key_signal_message_get_registration_id(const pre_key_signal_message *message); int pre_key_signal_message_has_pre_key_id(const pre_key_signal_message *message); uint32_t pre_key_signal_message_get_pre_key_id(const pre_key_signal_message *message); uint32_t pre_key_signal_message_get_signed_pre_key_id(const pre_key_signal_message *message); ec_public_key *pre_key_signal_message_get_base_key(const pre_key_signal_message *message); signal_message *pre_key_signal_message_get_signal_message(const pre_key_signal_message *message); void pre_key_signal_message_destroy(signal_type_base *type); int sender_key_message_create(sender_key_message **message, uint32_t key_id, uint32_t iteration, const uint8_t *ciphertext, size_t ciphertext_len, ec_private_key *signature_key, signal_context *global_context); int sender_key_message_deserialize(sender_key_message **message, const uint8_t *data, size_t len, signal_context *global_context); int sender_key_message_copy(sender_key_message **message, sender_key_message *other_message, signal_context *global_context); uint32_t sender_key_message_get_key_id(sender_key_message *message); uint32_t sender_key_message_get_iteration(sender_key_message *message); signal_buffer *sender_key_message_get_ciphertext(sender_key_message *message); int sender_key_message_verify_signature(sender_key_message *message, ec_public_key *signature_key); void sender_key_message_destroy(signal_type_base *type); int sender_key_distribution_message_create(sender_key_distribution_message **message, uint32_t id, uint32_t iteration, const uint8_t *chain_key, size_t chain_key_len, ec_public_key *signature_key, signal_context *global_context); int sender_key_distribution_message_deserialize(sender_key_distribution_message **message, const uint8_t *data, size_t len, signal_context *global_context); int sender_key_distribution_message_copy(sender_key_distribution_message **message, sender_key_distribution_message *other_message, signal_context *global_context); uint32_t sender_key_distribution_message_get_id(sender_key_distribution_message *message); uint32_t sender_key_distribution_message_get_iteration(sender_key_distribution_message *message); signal_buffer *sender_key_distribution_message_get_chain_key(sender_key_distribution_message *message); ec_public_key *sender_key_distribution_message_get_signature_key(sender_key_distribution_message *message); void sender_key_distribution_message_destroy(signal_type_base *type); #ifdef __cplusplus } #endif #endif /* PROTOCOL_H */ libsignal-protocol-c-2.3.3/src/ratchet.c000066400000000000000000001076361363751346500201610ustar00rootroot00000000000000#include "ratchet.h" #include #include #include #include #include #include "hkdf.h" #include "curve.h" #include "session_state.h" #include "protocol.h" #include "vpool.h" #include "LocalStorageProtocol.pb-c.h" #include "signal_protocol_internal.h" #define HASH_OUTPUT_SIZE 32 #define DERIVED_MESSAGE_SECRETS_SIZE 80 #define DERIVED_ROOT_SECRETS_SIZE 64 struct ratchet_chain_key { signal_type_base base; signal_context *global_context; hkdf_context *kdf; uint8_t *key; size_t key_len; uint32_t index; }; struct ratchet_root_key { signal_type_base base; signal_context *global_context; hkdf_context *kdf; uint8_t *key; size_t key_len; }; struct ratchet_identity_key_pair { signal_type_base base; ec_public_key *public_key; ec_private_key *private_key; }; int ratchet_chain_key_create(ratchet_chain_key **chain_key, hkdf_context *kdf, const uint8_t *key, size_t key_len, uint32_t index, signal_context *global_context) { ratchet_chain_key *result = 0; if(!kdf || !key) { return SG_ERR_INVAL; } result = malloc(sizeof(ratchet_chain_key)); if(!result) { return SG_ERR_NOMEM; } SIGNAL_INIT(result, ratchet_chain_key_destroy); result->global_context = global_context; result->kdf = kdf; result->key = malloc(key_len); if(!result->key) { free(result); return SG_ERR_NOMEM; } memcpy(result->key, key, key_len); result->key_len = key_len; result->index = index; SIGNAL_REF(result->kdf); *chain_key = result; return 0; } int ratchet_chain_key_get_key(const ratchet_chain_key *chain_key, signal_buffer **buffer) { signal_buffer *buf = 0; uint8_t *data = 0; buf = signal_buffer_alloc(chain_key->key_len); if(!buf) { return SG_ERR_NOMEM; } data = signal_buffer_data(buf); memcpy(data, chain_key->key, chain_key->key_len); *buffer = buf; return 0; } int ratchet_chain_key_get_key_protobuf(const ratchet_chain_key *chain_key, ProtobufCBinaryData *buffer) { uint8_t *data = 0; assert(chain_key); assert(buffer); data = malloc(chain_key->key_len); if(!data) { return SG_ERR_NOMEM; } memcpy(data, chain_key->key, chain_key->key_len); buffer->data = data; buffer->len = chain_key->key_len; return 0; } uint32_t ratchet_chain_key_get_index(const ratchet_chain_key *chain_key) { return chain_key->index; } ssize_t ratchet_chain_key_get_base_material(const ratchet_chain_key *chain_key, uint8_t **material, const uint8_t *seed, size_t seed_len) { int result = 0; signal_buffer *output_buffer = 0; uint8_t *output = 0; size_t output_len = 0; void *hmac_context = 0; result = signal_hmac_sha256_init(chain_key->global_context, &hmac_context, chain_key->key, chain_key->key_len); if(result < 0) { goto complete; } result = signal_hmac_sha256_update(chain_key->global_context, hmac_context, seed, seed_len); if(result < 0) { goto complete; } result = signal_hmac_sha256_final(chain_key->global_context, hmac_context, &output_buffer); if(result < 0) { goto complete; } output_len = signal_buffer_len(output_buffer); output = malloc(output_len); if(!output) { result = SG_ERR_NOMEM; goto complete; } memcpy(output, signal_buffer_data(output_buffer), output_len); complete: signal_hmac_sha256_cleanup(chain_key->global_context, hmac_context); signal_buffer_free(output_buffer); if(result >= 0) { *material = output; return (ssize_t)output_len; } else { return result; } } int ratchet_chain_key_get_message_keys(ratchet_chain_key *chain_key, ratchet_message_keys *message_keys) { static const uint8_t message_key_seed = 0x01; static const char key_material_seed[] = "WhisperMessageKeys"; uint8_t salt[HASH_OUTPUT_SIZE]; int result = 0; ssize_t result_size = 0; uint8_t *input_key_material = 0; size_t input_key_material_len = 0; uint8_t *key_material_data = 0; size_t key_material_data_len = 0; memset(message_keys, 0, sizeof(ratchet_message_keys)); result_size = ratchet_chain_key_get_base_material(chain_key, &input_key_material, &message_key_seed, sizeof(message_key_seed)); if(result_size < 0) { result = (int)result_size; signal_log(chain_key->global_context, SG_LOG_WARNING, "ratchet_chain_key_get_base_material failed"); goto complete; } input_key_material_len = (size_t)result_size; memset(salt, 0, sizeof(salt)); result_size = hkdf_derive_secrets(chain_key->kdf, &key_material_data, input_key_material, input_key_material_len, salt, sizeof(salt), (uint8_t *)key_material_seed, sizeof(key_material_seed) - 1, DERIVED_MESSAGE_SECRETS_SIZE); if(result_size < 0) { result = (int)result_size; signal_log(chain_key->global_context, SG_LOG_WARNING, "hkdf_derive_secrets failed"); goto complete; } key_material_data_len = (size_t)result_size; if(key_material_data_len != RATCHET_CIPHER_KEY_LENGTH + RATCHET_MAC_KEY_LENGTH + RATCHET_IV_LENGTH) { signal_log(chain_key->global_context, SG_LOG_WARNING, "key_material_data length mismatch: %d != %d", key_material_data_len, (RATCHET_CIPHER_KEY_LENGTH + RATCHET_MAC_KEY_LENGTH + RATCHET_IV_LENGTH)); result = SG_ERR_UNKNOWN; goto complete; } memcpy(message_keys->cipher_key, key_material_data, RATCHET_CIPHER_KEY_LENGTH); memcpy(message_keys->mac_key, key_material_data + RATCHET_CIPHER_KEY_LENGTH, RATCHET_MAC_KEY_LENGTH); memcpy(message_keys->iv, key_material_data + RATCHET_CIPHER_KEY_LENGTH + RATCHET_MAC_KEY_LENGTH, RATCHET_IV_LENGTH); message_keys->counter = chain_key->index; complete: if(input_key_material) { free(input_key_material); } if(key_material_data) { free(key_material_data); } if(result < 0) { return result; } else { return 0; } } int ratchet_chain_key_create_next(const ratchet_chain_key *chain_key, ratchet_chain_key **next_chain_key) { static const uint8_t chain_key_seed = 0x02; int result = 0; ssize_t result_size = 0; uint8_t *next_key = 0; size_t next_key_len = 0; result_size = ratchet_chain_key_get_base_material(chain_key, &next_key, &chain_key_seed, sizeof(chain_key_seed)); if(result_size < 0) { result = (int)result_size; signal_log(chain_key->global_context, SG_LOG_WARNING, "ratchet_chain_key_get_base_material failed"); goto complete; } next_key_len = (size_t)result_size; result = ratchet_chain_key_create( next_chain_key, chain_key->kdf, next_key, next_key_len, chain_key->index + 1, chain_key->global_context); complete: if(next_key) { free(next_key); } return result; } void ratchet_chain_key_destroy(signal_type_base *type) { ratchet_chain_key *chain_key = (ratchet_chain_key *)type; SIGNAL_UNREF(chain_key->kdf); if(chain_key->key) { signal_explicit_bzero(chain_key->key, chain_key->key_len); free(chain_key->key); } free(chain_key); } int ratchet_root_key_create(ratchet_root_key **root_key, hkdf_context *kdf, const uint8_t *key, size_t key_len, signal_context *global_context) { ratchet_root_key *result = 0; if(!kdf || !key) { return SG_ERR_INVAL; } result = malloc(sizeof(ratchet_root_key)); if(!result) { return SG_ERR_NOMEM; } SIGNAL_INIT(result, ratchet_root_key_destroy); result->global_context = global_context; result->kdf = kdf; result->key = malloc(key_len); if(!result->key) { free(result); return SG_ERR_NOMEM; } memcpy(result->key, key, key_len); result->key_len = key_len; SIGNAL_REF(result->kdf); *root_key = result; return 0; } int ratchet_root_key_create_chain(ratchet_root_key *root_key, ratchet_root_key **new_root_key, ratchet_chain_key **new_chain_key, ec_public_key *their_ratchet_key, ec_private_key *our_ratchet_key_private) { static const char key_info[] = "WhisperRatchet"; int result = 0; ssize_t result_size = 0; uint8_t *shared_secret = 0; size_t shared_secret_len = 0; uint8_t *derived_secret = 0; ratchet_root_key *new_root_key_result = 0; ratchet_chain_key *new_chain_key_result = 0; if(!their_ratchet_key || !our_ratchet_key_private) { return SG_ERR_INVAL; } result = curve_calculate_agreement(&shared_secret, their_ratchet_key, our_ratchet_key_private); if(result < 0) { signal_log(root_key->global_context, SG_LOG_WARNING, "curve_calculate_agreement failed"); goto complete; } shared_secret_len = (size_t)result; result_size = hkdf_derive_secrets(root_key->kdf, &derived_secret, shared_secret, shared_secret_len, root_key->key, root_key->key_len, (uint8_t *)key_info, sizeof(key_info) - 1, DERIVED_ROOT_SECRETS_SIZE); if(result_size < 0) { result = (int)result_size; signal_log(root_key->global_context, SG_LOG_WARNING, "hkdf_derive_secrets failed"); goto complete; } else if(result_size != DERIVED_ROOT_SECRETS_SIZE) { result = SG_ERR_UNKNOWN; signal_log(root_key->global_context, SG_LOG_WARNING, "hkdf_derive_secrets size mismatch"); goto complete; } result = ratchet_root_key_create(&new_root_key_result, root_key->kdf, derived_secret, 32, root_key->global_context); if(result < 0) { signal_log(root_key->global_context, SG_LOG_WARNING, "ratchet_root_key_create failed"); goto complete; } result = ratchet_chain_key_create(&new_chain_key_result, root_key->kdf, derived_secret + 32, 32, 0, root_key->global_context); if(result < 0) { signal_log(root_key->global_context, SG_LOG_WARNING, "ratchet_chain_key_create failed"); goto complete; } complete: if(shared_secret) { free(shared_secret); } if(derived_secret) { free(derived_secret); } if(result < 0) { if(new_root_key_result) { SIGNAL_UNREF(new_root_key_result); } if(new_chain_key_result) { SIGNAL_UNREF(new_chain_key_result); } return result; } else { *new_root_key = new_root_key_result; *new_chain_key = new_chain_key_result; return 0; } } int ratchet_root_key_get_key(ratchet_root_key *root_key, signal_buffer **buffer) { signal_buffer *buf = 0; uint8_t *data = 0; assert(root_key); buf = signal_buffer_alloc(root_key->key_len); if(!buf) { return SG_ERR_NOMEM; } data = signal_buffer_data(buf); memcpy(data, root_key->key, root_key->key_len); *buffer = buf; return 0; } int ratchet_root_key_get_key_protobuf(const ratchet_root_key *root_key, ProtobufCBinaryData *buffer) { uint8_t *data = 0; assert(root_key); assert(buffer); data = malloc(root_key->key_len); if(!data) { return SG_ERR_NOMEM; } memcpy(data, root_key->key, root_key->key_len); buffer->data = data; buffer->len = root_key->key_len; return 0; } int ratchet_root_key_compare(const ratchet_root_key *key1, const ratchet_root_key *key2) { if(key1 == key2) { return 0; } else if(key1 == 0 && key2 != 0) { return -1; } else if(key1 != 0 && key2 == 0) { return 1; } else { int kdf_compare = hkdf_compare(key1->kdf, key2->kdf); if(kdf_compare != 0) { return kdf_compare; } else if(key1->key_len < key2->key_len) { return -1; } else if(key1->key_len > key2->key_len) { return 1; } else { return signal_constant_memcmp(key1->key, key2->key, key1->key_len); } } } void ratchet_root_key_destroy(signal_type_base *type) { ratchet_root_key *root_key = (ratchet_root_key *)type; SIGNAL_UNREF(root_key->kdf); if(root_key->key) { signal_explicit_bzero(root_key->key, root_key->key_len); free(root_key->key); } free(root_key); } int ratchet_identity_key_pair_create( ratchet_identity_key_pair **key_pair, ec_public_key *public_key, ec_private_key *private_key) { ratchet_identity_key_pair *result = malloc(sizeof(ratchet_identity_key_pair)); if(!result) { return SG_ERR_NOMEM; } SIGNAL_INIT(result, ratchet_identity_key_pair_destroy); SIGNAL_REF(public_key); SIGNAL_REF(private_key); result->public_key = public_key; result->private_key = private_key; *key_pair = result; return 0; } int ratchet_identity_key_pair_serialize(signal_buffer **buffer, const ratchet_identity_key_pair *key_pair) { int result = 0; size_t result_size = 0; signal_buffer *result_buf = 0; Textsecure__IdentityKeyPairStructure key_structure = TEXTSECURE__IDENTITY_KEY_PAIR_STRUCTURE__INIT; size_t len = 0; uint8_t *data = 0; if(!key_pair) { result = SG_ERR_INVAL; goto complete; } result = ec_public_key_serialize_protobuf(&key_structure.publickey, key_pair->public_key); if(result < 0) { goto complete; } key_structure.has_publickey = 1; result = ec_private_key_serialize_protobuf(&key_structure.privatekey, key_pair->private_key); if(result < 0) { goto complete; } key_structure.has_privatekey = 1; len = textsecure__identity_key_pair_structure__get_packed_size(&key_structure); result_buf = signal_buffer_alloc(len); if(!result_buf) { result = SG_ERR_NOMEM; goto complete; } data = signal_buffer_data(result_buf); result_size = textsecure__identity_key_pair_structure__pack(&key_structure, data); if(result_size != len) { signal_buffer_free(result_buf); result = SG_ERR_INVALID_PROTO_BUF; result_buf = 0; goto complete; } complete: if(key_structure.has_publickey) { free(key_structure.publickey.data); } if(key_structure.has_privatekey) { free(key_structure.privatekey.data); } if(result >= 0) { result = 0; *buffer = result_buf; } return result; } int ratchet_identity_key_pair_deserialize(ratchet_identity_key_pair **key_pair, const uint8_t *data, size_t len, signal_context *global_context) { int result = 0; ec_public_key *public_key = 0; ec_private_key *private_key = 0; ratchet_identity_key_pair *result_pair = 0; Textsecure__IdentityKeyPairStructure *key_structure = 0; key_structure = textsecure__identity_key_pair_structure__unpack(0, len, data); if(!key_structure) { result = SG_ERR_INVALID_PROTO_BUF; goto complete; } if(!key_structure->has_publickey || !key_structure->has_privatekey) { result = SG_ERR_INVALID_KEY; goto complete; } result = curve_decode_point( &public_key, key_structure->publickey.data, key_structure->publickey.len, global_context); if(result < 0) { goto complete; } result = curve_decode_private_point( &private_key, key_structure->privatekey.data, key_structure->privatekey.len, global_context); if(result < 0) { goto complete; } result = ratchet_identity_key_pair_create(&result_pair, public_key, private_key); complete: SIGNAL_UNREF(public_key); SIGNAL_UNREF(private_key); if(key_structure) { textsecure__identity_key_pair_structure__free_unpacked(key_structure, 0); } if(result >= 0) { *key_pair = result_pair; } return result; } ec_public_key *ratchet_identity_key_pair_get_public(const ratchet_identity_key_pair *key_pair) { assert(key_pair); assert(key_pair->public_key); return key_pair->public_key; } ec_private_key *ratchet_identity_key_pair_get_private(const ratchet_identity_key_pair *key_pair) { assert(key_pair); assert(key_pair->private_key); return key_pair->private_key; } void ratchet_identity_key_pair_destroy(signal_type_base *type) { ratchet_identity_key_pair *key_pair = (ratchet_identity_key_pair *)type; SIGNAL_UNREF(key_pair->public_key); SIGNAL_UNREF(key_pair->private_key); free(key_pair); } struct symmetric_signal_protocol_parameters { signal_type_base base; ratchet_identity_key_pair *our_identity_key; ec_key_pair *our_base_key; ec_key_pair *our_ratchet_key; ec_public_key *their_base_key; ec_public_key *their_ratchet_key; ec_public_key *their_identity_key; }; struct alice_signal_protocol_parameters { signal_type_base base; ratchet_identity_key_pair *our_identity_key; ec_key_pair *our_base_key; ec_public_key *their_identity_key; ec_public_key *their_signed_pre_key; ec_public_key *their_one_time_pre_key; /* optional */ ec_public_key *their_ratchet_key; }; struct bob_signal_protocol_parameters { signal_type_base base; ratchet_identity_key_pair *our_identity_key; ec_key_pair *our_signed_pre_key; ec_key_pair *our_one_time_pre_key; /* optional */ ec_key_pair *our_ratchet_key; ec_public_key *their_identity_key; ec_public_key *their_base_key; }; int symmetric_signal_protocol_parameters_create( symmetric_signal_protocol_parameters **parameters, ratchet_identity_key_pair *our_identity_key, ec_key_pair *our_base_key, ec_key_pair *our_ratchet_key, ec_public_key *their_base_key, ec_public_key *their_ratchet_key, ec_public_key *their_identity_key) { symmetric_signal_protocol_parameters *result = 0; if(!our_identity_key || !our_base_key || !our_ratchet_key || !their_base_key || !their_ratchet_key || !their_identity_key) { return SG_ERR_INVAL; } result = malloc(sizeof(symmetric_signal_protocol_parameters)); if(!result) { return SG_ERR_NOMEM; } memset(result, 0, sizeof(symmetric_signal_protocol_parameters)); SIGNAL_INIT(result, symmetric_signal_protocol_parameters_destroy); SIGNAL_REF(our_identity_key); SIGNAL_REF(our_base_key); SIGNAL_REF(our_ratchet_key); SIGNAL_REF(their_base_key); SIGNAL_REF(their_ratchet_key); SIGNAL_REF(their_identity_key); result->our_identity_key = our_identity_key; result->our_base_key = our_base_key; result->our_ratchet_key = our_ratchet_key; result->their_base_key = their_base_key; result->their_ratchet_key = their_ratchet_key; result->their_identity_key = their_identity_key; *parameters = result; return 0; } ratchet_identity_key_pair *symmetric_signal_protocol_parameters_get_our_identity_key(const symmetric_signal_protocol_parameters *parameters) { assert(parameters); return parameters->our_identity_key; } ec_key_pair *symmetric_signal_protocol_parameters_get_our_base_key(const symmetric_signal_protocol_parameters *parameters) { assert(parameters); return parameters->our_base_key; } ec_key_pair *symmetric_signal_protocol_parameters_get_our_ratchet_key(const symmetric_signal_protocol_parameters *parameters) { assert(parameters); return parameters->our_ratchet_key; } ec_public_key *symmetric_signal_protocol_parameters_get_their_base_key(const symmetric_signal_protocol_parameters *parameters) { assert(parameters); return parameters->their_base_key; } ec_public_key *symmetric_signal_protocol_parameters_get_their_ratchet_key(const symmetric_signal_protocol_parameters *parameters) { assert(parameters); return parameters->their_ratchet_key; } ec_public_key *symmetric_signal_protocol_parameters_get_their_identity_key(const symmetric_signal_protocol_parameters *parameters) { assert(parameters); return parameters->their_identity_key; } void symmetric_signal_protocol_parameters_destroy(signal_type_base *type) { symmetric_signal_protocol_parameters *parameters = (symmetric_signal_protocol_parameters *)type; SIGNAL_UNREF(parameters->our_identity_key); SIGNAL_UNREF(parameters->our_base_key); SIGNAL_UNREF(parameters->our_ratchet_key); SIGNAL_UNREF(parameters->their_base_key); SIGNAL_UNREF(parameters->their_ratchet_key); SIGNAL_UNREF(parameters->their_identity_key); free(parameters); } int alice_signal_protocol_parameters_create( alice_signal_protocol_parameters **parameters, ratchet_identity_key_pair *our_identity_key, ec_key_pair *our_base_key, ec_public_key *their_identity_key, ec_public_key *their_signed_pre_key, ec_public_key *their_one_time_pre_key, ec_public_key *their_ratchet_key) { alice_signal_protocol_parameters *result = 0; /* Only "their_one_time_pre_key" is allowed to be null */ if(!our_identity_key || !our_base_key || !their_identity_key || !their_signed_pre_key || !their_ratchet_key) { return SG_ERR_INVAL; } result = malloc(sizeof(alice_signal_protocol_parameters)); if(!result) { return SG_ERR_NOMEM; } memset(result, 0, sizeof(alice_signal_protocol_parameters)); SIGNAL_INIT(result, alice_signal_protocol_parameters_destroy); SIGNAL_REF(our_identity_key); SIGNAL_REF(our_base_key); SIGNAL_REF(their_identity_key); SIGNAL_REF(their_signed_pre_key); SIGNAL_REF(their_ratchet_key); result->our_identity_key = our_identity_key; result->our_base_key = our_base_key; result->their_identity_key = their_identity_key; result->their_signed_pre_key = their_signed_pre_key; result->their_ratchet_key = their_ratchet_key; if(their_one_time_pre_key) { SIGNAL_REF(their_one_time_pre_key); result->their_one_time_pre_key = their_one_time_pre_key; } *parameters = result; return 0; } void alice_signal_protocol_parameters_destroy(signal_type_base *type) { alice_signal_protocol_parameters *parameters = (alice_signal_protocol_parameters *)type; SIGNAL_UNREF(parameters->our_identity_key); SIGNAL_UNREF(parameters->our_base_key); SIGNAL_UNREF(parameters->their_identity_key); SIGNAL_UNREF(parameters->their_signed_pre_key); SIGNAL_UNREF(parameters->their_ratchet_key); if(parameters->their_one_time_pre_key) { SIGNAL_UNREF(parameters->their_one_time_pre_key); } free(parameters); } int bob_signal_protocol_parameters_create( bob_signal_protocol_parameters **parameters, ratchet_identity_key_pair *our_identity_key, ec_key_pair *our_signed_pre_key, ec_key_pair *our_one_time_pre_key, ec_key_pair *our_ratchet_key, ec_public_key *their_identity_key, ec_public_key *their_base_key) { bob_signal_protocol_parameters *result = 0; /* Only "our_one_time_pre_key" is allowed to be null */ if(!our_identity_key || !our_signed_pre_key || !our_ratchet_key || !their_identity_key || !their_base_key) { return SG_ERR_INVAL; } result = malloc(sizeof(bob_signal_protocol_parameters)); if(!result) { return SG_ERR_NOMEM; } memset(result, 0, sizeof(bob_signal_protocol_parameters)); SIGNAL_INIT(result, bob_signal_protocol_parameters_destroy); SIGNAL_REF(our_identity_key); SIGNAL_REF(our_signed_pre_key); SIGNAL_REF(our_ratchet_key); SIGNAL_REF(their_identity_key); SIGNAL_REF(their_base_key); result->our_identity_key = our_identity_key; result->our_signed_pre_key = our_signed_pre_key; result->our_ratchet_key = our_ratchet_key; result->their_identity_key = their_identity_key; result->their_base_key = their_base_key; if(our_one_time_pre_key) { SIGNAL_REF(our_one_time_pre_key); result->our_one_time_pre_key = our_one_time_pre_key; } *parameters = result; return 0; } void bob_signal_protocol_parameters_destroy(signal_type_base *type) { bob_signal_protocol_parameters *parameters = (bob_signal_protocol_parameters *)type; SIGNAL_UNREF(parameters->our_identity_key); SIGNAL_UNREF(parameters->our_signed_pre_key); SIGNAL_UNREF(parameters->our_ratchet_key); SIGNAL_UNREF(parameters->their_identity_key); SIGNAL_UNREF(parameters->their_base_key); if(parameters->our_one_time_pre_key) { SIGNAL_UNREF(parameters->our_one_time_pre_key); } free(parameters); } int ratcheting_session_calculate_derived_keys(ratchet_root_key **root_key, ratchet_chain_key **chain_key, uint8_t *secret, size_t secret_len, signal_context *global_context) { int result = 0; ssize_t result_size = 0; hkdf_context *kdf = 0; ratchet_root_key *root_key_result = 0; ratchet_chain_key *chain_key_result = 0; uint8_t *output = 0; uint8_t salt[HASH_OUTPUT_SIZE]; static const char key_info[] = "WhisperText"; result = hkdf_create(&kdf, 3, global_context); if(result < 0) { goto complete; } memset(salt, 0, sizeof(salt)); result_size = hkdf_derive_secrets(kdf, &output, secret, secret_len, salt, sizeof(salt), (uint8_t *)key_info, sizeof(key_info) - 1, 64); if(result_size != 64) { result = SG_ERR_UNKNOWN; goto complete; } result = ratchet_root_key_create(&root_key_result, kdf, output, 32, global_context); if(result < 0) { goto complete; } result = ratchet_chain_key_create(&chain_key_result, kdf, output + 32, 32, 0, global_context); if(result < 0) { goto complete; } complete: if(kdf) { SIGNAL_UNREF(kdf); } if(output) { free(output); } if(result < 0) { if(root_key_result) { SIGNAL_UNREF(root_key_result); } if(chain_key_result) { SIGNAL_UNREF(chain_key_result); } } else { *root_key = root_key_result; *chain_key = chain_key_result; } return result; } int ratcheting_session_symmetric_is_alice(symmetric_signal_protocol_parameters *parameters) { //FIXME Java code checks if our_base_key < their_base_key // This comparison may not return the same result. However, we should find // out whether the Java code was doing the right thing and why. return ec_public_key_memcmp( ec_key_pair_get_public(parameters->our_base_key), parameters->their_base_key) < 0; } int ratcheting_session_symmetric_initialize( session_state *state, symmetric_signal_protocol_parameters *parameters, signal_context *global_context) { int result = 0; assert(state); assert(parameters); assert(global_context); if(ratcheting_session_symmetric_is_alice(parameters)) { alice_signal_protocol_parameters *alice_parameters = 0; result = alice_signal_protocol_parameters_create(&alice_parameters, parameters->our_identity_key, parameters->our_base_key, parameters->their_identity_key, parameters->their_base_key, 0, parameters->their_ratchet_key); if(result >= 0) { result = ratcheting_session_alice_initialize(state, alice_parameters, global_context); } if(alice_parameters) { SIGNAL_UNREF(alice_parameters); } } else { bob_signal_protocol_parameters *bob_parameters = 0; result = bob_signal_protocol_parameters_create(&bob_parameters, parameters->our_identity_key, parameters->our_base_key, 0, parameters->our_ratchet_key, parameters->their_identity_key, parameters->their_base_key); if(result >= 0) { result = ratcheting_session_bob_initialize(state, bob_parameters, global_context); } if(bob_parameters) { SIGNAL_UNREF(bob_parameters); } } return result; } int ratcheting_session_alice_initialize( session_state *state, alice_signal_protocol_parameters *parameters, signal_context *global_context) { int result = 0; uint8_t *agreement = 0; int agreement_len = 0; ec_key_pair *sending_ratchet_key = 0; ratchet_root_key *derived_root = 0; ratchet_chain_key *derived_chain = 0; ratchet_root_key *sending_chain_root = 0; ratchet_chain_key *sending_chain_key = 0; struct vpool vp; uint8_t *secret = 0; size_t secret_len = 0; uint8_t discontinuity_data[32]; assert(state); assert(parameters); assert(global_context); vpool_init(&vp, 1024, 0); result = curve_generate_key_pair(global_context, &sending_ratchet_key); if(result < 0) { goto complete; } memset(discontinuity_data, 0xFF, sizeof(discontinuity_data)); if(!vpool_insert(&vp, vpool_get_length(&vp), discontinuity_data, sizeof(discontinuity_data))) { result = SG_ERR_NOMEM; goto complete; } agreement_len = curve_calculate_agreement(&agreement, parameters->their_signed_pre_key, parameters->our_identity_key->private_key); if(agreement_len < 0) { result = agreement_len; goto complete; } if(vpool_insert(&vp, vpool_get_length(&vp), agreement, (size_t)agreement_len)) { free(agreement); agreement = 0; agreement_len = 0; } else { result = SG_ERR_NOMEM; goto complete; } agreement_len = curve_calculate_agreement(&agreement, parameters->their_identity_key, ec_key_pair_get_private(parameters->our_base_key)); if(agreement_len < 0) { result = agreement_len; goto complete; } if(vpool_insert(&vp, vpool_get_length(&vp), agreement, (size_t)agreement_len)) { free(agreement); agreement = 0; agreement_len = 0; } else { result = SG_ERR_NOMEM; goto complete; } agreement_len = curve_calculate_agreement(&agreement, parameters->their_signed_pre_key, ec_key_pair_get_private(parameters->our_base_key)); if(agreement_len < 0) { result = agreement_len; goto complete; } if(vpool_insert(&vp, vpool_get_length(&vp), agreement, (size_t)agreement_len)) { free(agreement); agreement = 0; agreement_len = 0; } else { result = SG_ERR_NOMEM; goto complete; } if(parameters->their_one_time_pre_key) { agreement_len = curve_calculate_agreement(&agreement, parameters->their_one_time_pre_key, ec_key_pair_get_private(parameters->our_base_key)); if(agreement_len < 0) { result = agreement_len; goto complete; } if(vpool_insert(&vp, vpool_get_length(&vp), agreement, (size_t)agreement_len)) { free(agreement); agreement = 0; agreement_len = 0; } else { result = SG_ERR_NOMEM; goto complete; } } if(vpool_is_empty(&vp)) { result = SG_ERR_UNKNOWN; goto complete; } secret = vpool_get_buf(&vp); secret_len = vpool_get_length(&vp); result = ratcheting_session_calculate_derived_keys(&derived_root, &derived_chain, secret, secret_len, global_context); if(result < 0) { goto complete; } result = ratchet_root_key_create_chain(derived_root, &sending_chain_root, &sending_chain_key, parameters->their_ratchet_key, ec_key_pair_get_private(sending_ratchet_key)); if(result < 0) { goto complete; } result = session_state_add_receiver_chain(state, parameters->their_ratchet_key, derived_chain); if(result < 0) { goto complete; } session_state_set_session_version(state, CIPHERTEXT_CURRENT_VERSION); session_state_set_remote_identity_key(state, parameters->their_identity_key); session_state_set_local_identity_key(state, parameters->our_identity_key->public_key); session_state_set_sender_chain(state, sending_ratchet_key, sending_chain_key); session_state_set_root_key(state, sending_chain_root); complete: vpool_final(&vp); if(agreement) { free(agreement); } if(sending_ratchet_key) { SIGNAL_UNREF(sending_ratchet_key); } if(derived_root) { SIGNAL_UNREF(derived_root); } if(derived_chain) { SIGNAL_UNREF(derived_chain); } if(sending_chain_root) { SIGNAL_UNREF(sending_chain_root); } if(sending_chain_key) { SIGNAL_UNREF(sending_chain_key); } return result; } int ratcheting_session_bob_initialize( session_state *state, bob_signal_protocol_parameters *parameters, signal_context *global_context) { int result = 0; uint8_t *agreement = 0; int agreement_len = 0; ratchet_root_key *derived_root = 0; ratchet_chain_key *derived_chain = 0; struct vpool vp; uint8_t *secret = 0; size_t secret_len = 0; uint8_t discontinuity_data[32]; assert(state); assert(parameters); assert(global_context); vpool_init(&vp, 1024, 0); memset(discontinuity_data, 0xFF, sizeof(discontinuity_data)); if(!vpool_insert(&vp, vpool_get_length(&vp), discontinuity_data, sizeof(discontinuity_data))) { result = SG_ERR_NOMEM; goto complete; } agreement_len = curve_calculate_agreement(&agreement, parameters->their_identity_key, ec_key_pair_get_private(parameters->our_signed_pre_key)); if(agreement_len < 0) { result = agreement_len; goto complete; } if(vpool_insert(&vp, vpool_get_length(&vp), agreement, (size_t)agreement_len)) { free(agreement); agreement = 0; agreement_len = 0; } else { result = SG_ERR_NOMEM; goto complete; } agreement_len = curve_calculate_agreement(&agreement, parameters->their_base_key, parameters->our_identity_key->private_key); if(agreement_len < 0) { result = agreement_len; goto complete; } if(vpool_insert(&vp, vpool_get_length(&vp), agreement, (size_t)agreement_len)) { free(agreement); agreement = 0; agreement_len = 0; } else { result = SG_ERR_NOMEM; goto complete; } agreement_len = curve_calculate_agreement(&agreement, parameters->their_base_key, ec_key_pair_get_private(parameters->our_signed_pre_key)); if(agreement_len < 0) { result = agreement_len; goto complete; } if(vpool_insert(&vp, vpool_get_length(&vp), agreement, (size_t)agreement_len)) { free(agreement); agreement = 0; agreement_len = 0; } else { result = SG_ERR_NOMEM; goto complete; } if(parameters->our_one_time_pre_key) { agreement_len = curve_calculate_agreement(&agreement, parameters->their_base_key, ec_key_pair_get_private(parameters->our_one_time_pre_key)); if(agreement_len < 0) { result = agreement_len; goto complete; } if(vpool_insert(&vp, vpool_get_length(&vp), agreement, (size_t)agreement_len)) { free(agreement); agreement = 0; agreement_len = 0; } else { result = SG_ERR_NOMEM; goto complete; } } if(vpool_is_empty(&vp)) { result = SG_ERR_UNKNOWN; goto complete; } secret = vpool_get_buf(&vp); secret_len = vpool_get_length(&vp); result = ratcheting_session_calculate_derived_keys(&derived_root, &derived_chain, secret, secret_len, global_context); complete: if(result >= 0) { session_state_set_session_version(state, CIPHERTEXT_CURRENT_VERSION); session_state_set_remote_identity_key(state, parameters->their_identity_key); session_state_set_local_identity_key(state, parameters->our_identity_key->public_key); session_state_set_sender_chain(state, parameters->our_ratchet_key, derived_chain); session_state_set_root_key(state, derived_root); } vpool_final(&vp); if(agreement) { free(agreement); } if(derived_root) { SIGNAL_UNREF(derived_root); } if(derived_chain) { SIGNAL_UNREF(derived_chain); } return result; } libsignal-protocol-c-2.3.3/src/ratchet.h000066400000000000000000000114051363751346500201520ustar00rootroot00000000000000#ifndef RATCHET_H #define RATCHET_H #include #include #include "signal_protocol_types.h" #ifdef __cplusplus extern "C" { #endif int ratchet_chain_key_create(ratchet_chain_key **chain_key, hkdf_context *kdf, const uint8_t *key, size_t key_len, uint32_t index, signal_context *global_context); int ratchet_chain_key_get_key(const ratchet_chain_key *chain_key, signal_buffer **buffer); uint32_t ratchet_chain_key_get_index(const ratchet_chain_key *chain_key); int ratchet_chain_key_get_message_keys(ratchet_chain_key *chain_key, ratchet_message_keys *message_keys); int ratchet_chain_key_create_next(const ratchet_chain_key *chain_key, ratchet_chain_key **next_chain_key); void ratchet_chain_key_destroy(signal_type_base *type); int ratchet_root_key_create(ratchet_root_key **root_key, hkdf_context *kdf, const uint8_t *key, size_t key_len, signal_context *global_context); int ratchet_root_key_create_chain(ratchet_root_key *root_key, ratchet_root_key **new_root_key, ratchet_chain_key **new_chain_key, ec_public_key *their_ratchet_key, ec_private_key *our_ratchet_key_private); int ratchet_root_key_get_key(ratchet_root_key *root_key, signal_buffer **buffer); int ratchet_root_key_compare(const ratchet_root_key *key1, const ratchet_root_key *key2); void ratchet_root_key_destroy(signal_type_base *type); int ratchet_identity_key_pair_create( ratchet_identity_key_pair **key_pair, ec_public_key *public_key, ec_private_key *private_key); int ratchet_identity_key_pair_serialize(signal_buffer **buffer, const ratchet_identity_key_pair *key_pair); int ratchet_identity_key_pair_deserialize(ratchet_identity_key_pair **key_pair, const uint8_t *data, size_t len, signal_context *global_context); ec_public_key *ratchet_identity_key_pair_get_public(const ratchet_identity_key_pair *key_pair); ec_private_key *ratchet_identity_key_pair_get_private(const ratchet_identity_key_pair *key_pair); void ratchet_identity_key_pair_destroy(signal_type_base *type); typedef struct symmetric_signal_protocol_parameters symmetric_signal_protocol_parameters; typedef struct alice_signal_protocol_parameters alice_signal_protocol_parameters; typedef struct bob_signal_protocol_parameters bob_signal_protocol_parameters; int symmetric_signal_protocol_parameters_create( symmetric_signal_protocol_parameters **parameters, ratchet_identity_key_pair *our_identity_key, ec_key_pair *our_base_key, ec_key_pair *our_ratchet_key, ec_public_key *their_base_key, ec_public_key *their_ratchet_key, ec_public_key *their_identity_key); ratchet_identity_key_pair *symmetric_signal_protocol_parameters_get_our_identity_key(const symmetric_signal_protocol_parameters *parameters); ec_key_pair *symmetric_signal_protocol_parameters_get_our_base_key(const symmetric_signal_protocol_parameters *parameters); ec_key_pair *symmetric_signal_protocol_parameters_get_our_ratchet_key(const symmetric_signal_protocol_parameters *parameters); ec_public_key *symmetric_signal_protocol_parameters_get_their_base_key(const symmetric_signal_protocol_parameters *parameters); ec_public_key *symmetric_signal_protocol_parameters_get_their_ratchet_key(const symmetric_signal_protocol_parameters *parameters); ec_public_key *symmetric_signal_protocol_parameters_get_their_identity_key(const symmetric_signal_protocol_parameters *parameters); void symmetric_signal_protocol_parameters_destroy(signal_type_base *type); int alice_signal_protocol_parameters_create( alice_signal_protocol_parameters **parameters, ratchet_identity_key_pair *our_identity_key, ec_key_pair *our_base_key, ec_public_key *their_identity_key, ec_public_key *their_signed_pre_key, ec_public_key *their_one_time_pre_key, ec_public_key *their_ratchet_key); void alice_signal_protocol_parameters_destroy(signal_type_base *type); int bob_signal_protocol_parameters_create( bob_signal_protocol_parameters **parameters, ratchet_identity_key_pair *our_identity_key, ec_key_pair *our_signed_pre_key, ec_key_pair *our_one_time_pre_key, ec_key_pair *our_ratchet_key, ec_public_key *their_identity_key, ec_public_key *their_base_key); void bob_signal_protocol_parameters_destroy(signal_type_base *type); int ratcheting_session_symmetric_initialize(session_state *state, symmetric_signal_protocol_parameters *parameters, signal_context *global_context); int ratcheting_session_alice_initialize(session_state *state, alice_signal_protocol_parameters *parameters, signal_context *global_context); int ratcheting_session_bob_initialize(session_state *state, bob_signal_protocol_parameters *parameters, signal_context *global_context); #ifdef __cplusplus } #endif #endif /* RATCHET_H */ libsignal-protocol-c-2.3.3/src/sender_key.c000066400000000000000000000147451363751346500206550ustar00rootroot00000000000000#include "sender_key.h" #include #include #include "hkdf.h" #include "signal_protocol_internal.h" #define HASH_OUTPUT_SIZE 32 struct sender_message_key { signal_type_base base; uint32_t iteration; signal_buffer *iv; signal_buffer *cipher_key; signal_buffer *seed; signal_context *global_context; }; struct sender_chain_key { signal_type_base base; uint32_t iteration; signal_buffer *chain_key; signal_context *global_context; }; static int sender_chain_key_get_derivative(signal_buffer **derivative, uint8_t seed, signal_buffer *key, signal_context *global_context); int sender_message_key_create(sender_message_key **key, uint32_t iteration, signal_buffer *seed, signal_context *global_context) { sender_message_key *result = 0; int ret = 0; ssize_t ret_size = 0; hkdf_context *kdf = 0; static const char info_material[] = "WhisperGroup"; uint8_t salt[HASH_OUTPUT_SIZE]; uint8_t *derivative = 0; assert(global_context); if(!seed) { return SG_ERR_INVAL; } memset(salt, 0, sizeof(salt)); result = malloc(sizeof(sender_message_key)); if(!result) { return SG_ERR_NOMEM; } SIGNAL_INIT(result, sender_message_key_destroy); ret = hkdf_create(&kdf, 3, global_context); if(ret < 0) { goto complete; } ret_size = hkdf_derive_secrets(kdf, &derivative, signal_buffer_data(seed), signal_buffer_len(seed), salt, sizeof(salt), (uint8_t *)info_material, sizeof(info_material) - 1, 48); if(ret_size != 48) { ret = (ret_size < 0) ? (int)ret_size : SG_ERR_UNKNOWN; signal_log(global_context, SG_LOG_WARNING, "hkdf_derive_secrets failed"); goto complete; } result->iteration = iteration; result->seed = signal_buffer_copy(seed); if(!result->seed) { ret = SG_ERR_NOMEM; goto complete; } result->iv = signal_buffer_create(derivative, 16); if(!result->iv) { ret = SG_ERR_NOMEM; goto complete; } result->cipher_key = signal_buffer_create(derivative + 16, 32); if(!result->cipher_key) { ret = SG_ERR_NOMEM; goto complete; } result->global_context = global_context; complete: SIGNAL_UNREF(kdf); if(derivative) { free(derivative); } if(ret < 0) { SIGNAL_UNREF(result); } else { ret = 0; *key = result; } return ret; } uint32_t sender_message_key_get_iteration(sender_message_key *key) { assert(key); return key->iteration; } signal_buffer *sender_message_key_get_iv(sender_message_key *key) { assert(key); return key->iv; } signal_buffer *sender_message_key_get_cipher_key(sender_message_key *key) { assert(key); return key->cipher_key; } signal_buffer *sender_message_key_get_seed(sender_message_key *key) { assert(key); return key->seed; } void sender_message_key_destroy(signal_type_base *type) { sender_message_key *key = (sender_message_key *)type; signal_buffer_bzero_free(key->iv); signal_buffer_bzero_free(key->cipher_key); signal_buffer_bzero_free(key->seed); free(key); } int sender_chain_key_create(sender_chain_key **key, uint32_t iteration, signal_buffer *chain_key, signal_context *global_context) { sender_chain_key *result = 0; int ret = 0; assert(global_context); if(!chain_key) { return SG_ERR_INVAL; } result = malloc(sizeof(sender_chain_key)); if(!result) { return SG_ERR_NOMEM; } SIGNAL_INIT(result, sender_chain_key_destroy); result->iteration = iteration; result->chain_key = signal_buffer_copy(chain_key); if(!result->chain_key) { ret = SG_ERR_NOMEM; goto complete; } result->global_context = global_context; complete: if(ret < 0) { SIGNAL_UNREF(result); } else { ret = 0; *key = result; } return ret; } uint32_t sender_chain_key_get_iteration(sender_chain_key *key) { assert(key); return key->iteration; } int sender_chain_key_create_message_key(sender_chain_key *key, sender_message_key **message_key) { static const uint8_t MESSAGE_KEY_SEED = 0x01; int ret = 0; signal_buffer *derivative = 0; sender_message_key *result = 0; assert(key); ret = sender_chain_key_get_derivative(&derivative, MESSAGE_KEY_SEED, key->chain_key, key->global_context); if(ret < 0) { goto complete; } ret = sender_message_key_create(&result, key->iteration, derivative, key->global_context); complete: signal_buffer_free(derivative); if(ret >= 0) { ret = 0; *message_key = result; } return ret; } int sender_chain_key_create_next(sender_chain_key *key, sender_chain_key **next_key) { static const uint8_t CHAIN_KEY_SEED = 0x02; int ret = 0; signal_buffer *derivative = 0; sender_chain_key *result = 0; assert(key); ret = sender_chain_key_get_derivative(&derivative, CHAIN_KEY_SEED, key->chain_key, key->global_context); if(ret < 0) { goto complete; } ret = sender_chain_key_create(&result, key->iteration + 1, derivative, key->global_context); complete: signal_buffer_free(derivative); if(ret >= 0) { ret = 0; *next_key = result; } return ret; } signal_buffer *sender_chain_key_get_seed(sender_chain_key *key) { assert(key); return key->chain_key; } void sender_chain_key_destroy(signal_type_base *type) { sender_chain_key *key = (sender_chain_key *)type; signal_buffer_bzero_free(key->chain_key); free(key); } int sender_chain_key_get_derivative(signal_buffer **derivative, uint8_t seed, signal_buffer *key, signal_context *global_context) { int result = 0; signal_buffer *output_buffer = 0; void *hmac_context = 0; result = signal_hmac_sha256_init(global_context, &hmac_context, signal_buffer_data(key), signal_buffer_len(key)); if(result < 0) { goto complete; } result = signal_hmac_sha256_update(global_context, hmac_context, &seed, sizeof(seed)); if(result < 0) { goto complete; } result = signal_hmac_sha256_final(global_context, hmac_context, &output_buffer); if(result < 0) { goto complete; } complete: signal_hmac_sha256_cleanup(global_context, hmac_context); if(result < 0) { signal_buffer_free(output_buffer); } else { *derivative = output_buffer; } return result; } libsignal-protocol-c-2.3.3/src/sender_key.h000066400000000000000000000022671363751346500206560ustar00rootroot00000000000000#ifndef SENDER_KEY #define SENDER_KEY #include #include #include "signal_protocol_types.h" #ifdef __cplusplus extern "C" { #endif int sender_message_key_create(sender_message_key **key, uint32_t iteration, signal_buffer *seed, signal_context *global_context); uint32_t sender_message_key_get_iteration(sender_message_key *key); signal_buffer *sender_message_key_get_iv(sender_message_key *key); signal_buffer *sender_message_key_get_cipher_key(sender_message_key *key); signal_buffer *sender_message_key_get_seed(sender_message_key *key); void sender_message_key_destroy(signal_type_base *type); int sender_chain_key_create(sender_chain_key **key, uint32_t iteration, signal_buffer *chain_key, signal_context *global_context); uint32_t sender_chain_key_get_iteration(sender_chain_key *key); int sender_chain_key_create_message_key(sender_chain_key *key, sender_message_key **message_key); int sender_chain_key_create_next(sender_chain_key *key, sender_chain_key **next_key); signal_buffer *sender_chain_key_get_seed(sender_chain_key *key); void sender_chain_key_destroy(signal_type_base *type); #ifdef __cplusplus } #endif #endif /* SENDER_KEY */ libsignal-protocol-c-2.3.3/src/sender_key_record.c000066400000000000000000000252101363751346500222000ustar00rootroot00000000000000#include "sender_key_record.h" #include #include "sender_key_state.h" #include "sender_key.h" #include "utlist.h" #include "LocalStorageProtocol.pb-c.h" #include "signal_protocol_internal.h" #define MAX_STATES 5 typedef struct sender_key_state_node { sender_key_state *state; struct sender_key_state_node *prev, *next; } sender_key_state_node; struct sender_key_record { signal_type_base base; sender_key_state_node *sender_key_states_head; signal_buffer *user_record; signal_context *global_context; }; int sender_key_record_create(sender_key_record **record, signal_context *global_context) { sender_key_record *result = malloc(sizeof(sender_key_record)); if(!result) { return SG_ERR_NOMEM; } memset(result, 0, sizeof(sender_key_record)); SIGNAL_INIT(result, sender_key_record_destroy); result->global_context = global_context; *record = result; return 0; } int sender_key_record_serialize(signal_buffer **buffer, sender_key_record *record) { int result = 0; size_t result_size = 0; unsigned int i = 0; Textsecure__SenderKeyRecordStructure record_structure = TEXTSECURE__SENDER_KEY_RECORD_STRUCTURE__INIT; sender_key_state_node *cur_node = 0; signal_buffer *result_buf = 0; uint8_t *data; size_t len; if(record->sender_key_states_head) { size_t count; DL_COUNT(record->sender_key_states_head, cur_node, count); if(count > SIZE_MAX / sizeof(Textsecure__SenderKeyStateStructure *)) { result = SG_ERR_NOMEM; goto complete; } record_structure.senderkeystates = malloc(sizeof(Textsecure__SenderKeyStateStructure *) * count); if(!record_structure.senderkeystates) { result = SG_ERR_NOMEM; goto complete; } i = 0; DL_FOREACH(record->sender_key_states_head, cur_node) { record_structure.senderkeystates[i] = malloc(sizeof(Textsecure__SenderKeyStateStructure)); if(!record_structure.senderkeystates[i]) { result = SG_ERR_NOMEM; break; } textsecure__sender_key_state_structure__init(record_structure.senderkeystates[i]); result = sender_key_state_serialize_prepare(cur_node->state, record_structure.senderkeystates[i]); if(result < 0) { break; } i++; } record_structure.n_senderkeystates = i; if(result < 0) { goto complete; } } len = textsecure__sender_key_record_structure__get_packed_size(&record_structure); result_buf = signal_buffer_alloc(len); if(!result_buf) { result = SG_ERR_NOMEM; goto complete; } data = signal_buffer_data(result_buf); result_size = textsecure__sender_key_record_structure__pack(&record_structure, data); if(result_size != len) { signal_buffer_free(result_buf); result = SG_ERR_INVALID_PROTO_BUF; result_buf = 0; goto complete; } complete: if(record_structure.senderkeystates) { for(i = 0; i < record_structure.n_senderkeystates; i++) { if(record_structure.senderkeystates[i]) { sender_key_state_serialize_prepare_free(record_structure.senderkeystates[i]); } } free(record_structure.senderkeystates); } if(result >= 0) { *buffer = result_buf; } return result; } int sender_key_record_deserialize(sender_key_record **record, const uint8_t *data, size_t len, signal_context *global_context) { int result = 0; sender_key_record *result_record = 0; Textsecure__SenderKeyRecordStructure *record_structure = 0; record_structure = textsecure__sender_key_record_structure__unpack(0, len, data); if(!record_structure) { result = SG_ERR_INVALID_PROTO_BUF; goto complete; } result = sender_key_record_create(&result_record, global_context); if(result < 0) { goto complete; } if(record_structure->n_senderkeystates > 0) { unsigned int i; sender_key_state_node *state_node = 0; sender_key_state *state_element = 0; for(i = 0; i < record_structure->n_senderkeystates; i++) { result = sender_key_state_deserialize_protobuf(&state_element, record_structure->senderkeystates[i], global_context); if(result < 0) { goto complete; } state_node = malloc(sizeof(sender_key_state_node)); if(!state_node) { result = SG_ERR_NOMEM; goto complete; } state_node->state = state_element; DL_APPEND(result_record->sender_key_states_head, state_node); } } complete: if(record_structure) { textsecure__sender_key_record_structure__free_unpacked(record_structure, 0); } if(result_record) { if(result < 0) { SIGNAL_UNREF(result_record); } else { *record = result_record; } } return result; } int sender_key_record_copy(sender_key_record **record, sender_key_record *other_record, signal_context *global_context) { int result = 0; sender_key_record *result_record = 0; signal_buffer *buffer = 0; uint8_t *data; size_t len; assert(other_record); assert(global_context); result = sender_key_record_serialize(&buffer, other_record); if(result < 0) { goto complete; } data = signal_buffer_data(buffer); len = signal_buffer_len(buffer); result = sender_key_record_deserialize(&result_record, data, len, global_context); if(result < 0) { goto complete; } if(other_record->user_record) { result_record->user_record = signal_buffer_copy(other_record->user_record); if(!result_record->user_record) { result = SG_ERR_NOMEM; goto complete; } } complete: if(buffer) { signal_buffer_free(buffer); } if(result >= 0) { *record = result_record; } else { SIGNAL_UNREF(result_record); } return result; } int sender_key_record_is_empty(sender_key_record *record) { assert(record); if(record->sender_key_states_head) { return 0; } else { return 1; } } int sender_key_record_get_sender_key_state(sender_key_record *record, sender_key_state **state) { assert(record); if(record->sender_key_states_head) { *state = record->sender_key_states_head->state; return 0; } else { signal_log(record->global_context, SG_LOG_ERROR, "No key state in record!"); return SG_ERR_INVALID_KEY_ID; } } int sender_key_record_get_sender_key_state_by_id(sender_key_record *record, sender_key_state **state, uint32_t key_id) { sender_key_state_node *cur_node; assert(record); DL_FOREACH(record->sender_key_states_head, cur_node) { if(sender_key_state_get_key_id(cur_node->state) == key_id) { *state = cur_node->state; return 0; } } signal_log(record->global_context, SG_LOG_ERROR, "No keys for: %d", key_id); return SG_ERR_INVALID_KEY_ID; } static int sender_key_record_add_sender_key_state_impl(sender_key_record *record, uint32_t id, uint32_t iteration, signal_buffer *chain_key, ec_public_key *signature_public_key, ec_private_key *signature_private_key) { int result = 0; sender_chain_key *chain_key_element = 0; sender_key_state *state = 0; sender_key_state_node *state_node = 0; int count; assert(record); result = sender_chain_key_create(&chain_key_element, iteration, chain_key, record->global_context); if(result < 0) { goto complete; } result = sender_key_state_create(&state, id, chain_key_element, signature_public_key, signature_private_key, record->global_context); if(result < 0) { goto complete; } state_node = malloc(sizeof(sender_key_state_node)); if(!state_node) { result = SG_ERR_NOMEM; goto complete; } state_node->state = state; DL_PREPEND(record->sender_key_states_head, state_node); DL_COUNT(record->sender_key_states_head, state_node, count); while(count > MAX_STATES) { state_node = record->sender_key_states_head->prev; DL_DELETE(record->sender_key_states_head, state_node); if(state_node->state) { SIGNAL_UNREF(state_node->state); } free(state_node); --count; } complete: SIGNAL_UNREF(chain_key_element); if(result < 0) { SIGNAL_UNREF(state); } return result; } int sender_key_record_add_sender_key_state(sender_key_record *record, uint32_t id, uint32_t iteration, signal_buffer *chain_key, ec_public_key *signature_key) { int result = sender_key_record_add_sender_key_state_impl( record, id, iteration, chain_key, signature_key, 0); return result; } int sender_key_record_set_sender_key_state(sender_key_record *record, uint32_t id, uint32_t iteration, signal_buffer *chain_key, ec_key_pair *signature_key_pair) { int result = 0; sender_key_state_node *cur_node; sender_key_state_node *tmp_node; assert(record); DL_FOREACH_SAFE(record->sender_key_states_head, cur_node, tmp_node) { DL_DELETE(record->sender_key_states_head, cur_node); if(cur_node->state) { SIGNAL_UNREF(cur_node->state); } free(cur_node); } record->sender_key_states_head = 0; result = sender_key_record_add_sender_key_state_impl( record, id, iteration, chain_key, ec_key_pair_get_public(signature_key_pair), ec_key_pair_get_private(signature_key_pair)); return result; } signal_buffer *sender_key_record_get_user_record(const sender_key_record *record) { assert(record); return record->user_record; } void sender_key_record_set_user_record(sender_key_record *record, signal_buffer *user_record) { assert(record); if(record->user_record) { signal_buffer_free(record->user_record); } record->user_record = user_record; } void sender_key_record_destroy(signal_type_base *type) { sender_key_record *record = (sender_key_record *)type; sender_key_state_node *cur_node; sender_key_state_node *tmp_node; DL_FOREACH_SAFE(record->sender_key_states_head, cur_node, tmp_node) { DL_DELETE(record->sender_key_states_head, cur_node); if(cur_node->state) { SIGNAL_UNREF(cur_node->state); } free(cur_node); } record->sender_key_states_head = 0; if(record->user_record) { signal_buffer_free(record->user_record); } free(record); } libsignal-protocol-c-2.3.3/src/sender_key_record.h000066400000000000000000000027061363751346500222120ustar00rootroot00000000000000#ifndef SENDER_KEY_RECORD_H #define SENDER_KEY_RECORD_H #include "signal_protocol_types.h" #ifdef __cplusplus extern "C" { #endif int sender_key_record_create(sender_key_record **record, signal_context *global_context); int sender_key_record_serialize(signal_buffer **buffer, sender_key_record *record); int sender_key_record_deserialize(sender_key_record **record, const uint8_t *data, size_t len, signal_context *global_context); int sender_key_record_copy(sender_key_record **record, sender_key_record *other_state, signal_context *global_context); int sender_key_record_is_empty(sender_key_record *record); int sender_key_record_get_sender_key_state(sender_key_record *record, sender_key_state **state); int sender_key_record_get_sender_key_state_by_id(sender_key_record *record, sender_key_state **state, uint32_t key_id); int sender_key_record_add_sender_key_state(sender_key_record *record, uint32_t id, uint32_t iteration, signal_buffer *chain_key, ec_public_key *signature_key); int sender_key_record_set_sender_key_state(sender_key_record *record, uint32_t id, uint32_t iteration, signal_buffer *chain_key, ec_key_pair *signature_key_pair); signal_buffer *sender_key_record_get_user_record(const sender_key_record *record); void sender_key_record_set_user_record(sender_key_record *record, signal_buffer *user_record); void sender_key_record_destroy(signal_type_base *type); #ifdef __cplusplus } #endif #endif /* SENDER_KEY_RECORD_H */ libsignal-protocol-c-2.3.3/src/sender_key_state.c000066400000000000000000000405171363751346500220510ustar00rootroot00000000000000#include "sender_key_state.h" #include #include #include #include "sender_key.h" #include "utlist.h" #include "LocalStorageProtocol.pb-c.h" #include "signal_protocol_internal.h" #define MAX_MESSAGE_KEYS 2000 typedef struct sender_message_key_node { sender_message_key *key; struct sender_message_key_node *prev, *next; } sender_message_key_node; struct sender_key_state { signal_type_base base; uint32_t key_id; sender_chain_key *chain_key; ec_public_key *signature_public_key; ec_private_key *signature_private_key; sender_message_key_node *message_keys_head; signal_context *global_context; }; int sender_key_state_create(sender_key_state **state, uint32_t id, sender_chain_key *chain_key, ec_public_key *signature_public_key, ec_private_key *signature_private_key, signal_context *global_context) { sender_key_state *result = 0; if(!chain_key || !signature_public_key) { return SG_ERR_INVAL; } result = malloc(sizeof(sender_key_state)); if(!result) { return SG_ERR_NOMEM; } memset(result, 0, sizeof(sender_key_state)); SIGNAL_INIT(result, sender_key_state_destroy); result->key_id = id; SIGNAL_REF(chain_key); result->chain_key = chain_key; SIGNAL_REF(signature_public_key); result->signature_public_key = signature_public_key; if(signature_private_key) { SIGNAL_REF(signature_private_key); result->signature_private_key = signature_private_key; } result->global_context = global_context; *state = result; return 0; } int sender_key_state_serialize(signal_buffer **buffer, sender_key_state *state) { int result = 0; size_t result_size = 0; uint8_t *data; size_t len; Textsecure__SenderKeyStateStructure *state_structure = 0; signal_buffer *result_buf = 0; state_structure = malloc(sizeof(Textsecure__SenderKeyStateStructure)); if(!state_structure) { result = SG_ERR_NOMEM; goto complete; } textsecure__sender_key_state_structure__init(state_structure); result = sender_key_state_serialize_prepare(state, state_structure); if(result < 0) { goto complete; } len = textsecure__sender_key_state_structure__get_packed_size(state_structure); result_buf = signal_buffer_alloc(len); if(!result_buf) { result = SG_ERR_NOMEM; goto complete; } data = signal_buffer_data(result_buf); result_size = textsecure__sender_key_state_structure__pack(state_structure, data); if(result_size != len) { signal_buffer_free(result_buf); result = SG_ERR_INVALID_PROTO_BUF; result_buf = 0; goto complete; } complete: if(state_structure) { sender_key_state_serialize_prepare_free(state_structure); } if(result >= 0) { *buffer = result_buf; } return result; } int sender_key_state_deserialize(sender_key_state **state, const uint8_t *data, size_t len, signal_context *global_context) { int result = 0; Textsecure__SenderKeyStateStructure *state_structure = 0; sender_key_state *result_state = 0; state_structure = textsecure__sender_key_state_structure__unpack(0, len, data); if(!state_structure) { result = SG_ERR_INVALID_PROTO_BUF; goto complete; } result = sender_key_state_deserialize_protobuf(&result_state, state_structure, global_context); if(result < 0) { goto complete; } complete: if(state_structure) { textsecure__sender_key_state_structure__free_unpacked(state_structure, 0); } if(result_state) { if(result < 0) { SIGNAL_UNREF(result_state); } else { *state = result_state; } } return result; } int sender_key_state_serialize_prepare(sender_key_state *state, Textsecure__SenderKeyStateStructure *state_structure) { int result = 0; size_t i = 0; Textsecure__SenderKeyStateStructure__SenderChainKey *chain_key_structure = 0; Textsecure__SenderKeyStateStructure__SenderSigningKey *signing_key_structure = 0; sender_message_key_node *cur_node = 0; signal_buffer *chain_key_seed = 0; assert(state); assert(state_structure); /* Sender key ID */ state_structure->has_senderkeyid = 1; state_structure->senderkeyid = state->key_id; /* Sender chain key */ chain_key_structure = malloc(sizeof(Textsecure__SenderKeyStateStructure__SenderChainKey)); if(!chain_key_structure) { result = SG_ERR_NOMEM; goto complete; } textsecure__sender_key_state_structure__sender_chain_key__init(chain_key_structure); state_structure->senderchainkey = chain_key_structure; chain_key_structure->iteration = sender_chain_key_get_iteration(state->chain_key); chain_key_structure->has_iteration = 1; chain_key_seed = sender_chain_key_get_seed(state->chain_key); chain_key_structure->seed.data = signal_buffer_data(chain_key_seed); chain_key_structure->seed.len = signal_buffer_len(chain_key_seed); chain_key_structure->has_seed = 1; /* Sender signing key */ signing_key_structure = malloc(sizeof(Textsecure__SenderKeyStateStructure__SenderSigningKey)); if(!signing_key_structure) { result = SG_ERR_NOMEM; goto complete; } textsecure__sender_key_state_structure__sender_signing_key__init(signing_key_structure); state_structure->sendersigningkey = signing_key_structure; if(state->signature_public_key) { result = ec_public_key_serialize_protobuf(&(signing_key_structure->public_), state->signature_public_key); if(result < 0) { goto complete; } signing_key_structure->has_public_ = 1; } if(state->signature_private_key) { result = ec_private_key_serialize_protobuf(&(signing_key_structure->private_), state->signature_private_key); if(result < 0) { goto complete; } signing_key_structure->has_private_ = 1; } /* Sender message keys */ if(state->message_keys_head) { size_t count; DL_COUNT(state->message_keys_head, cur_node, count); if(count > SIZE_MAX / sizeof(Textsecure__SenderKeyStateStructure__SenderMessageKey *)) { result = SG_ERR_NOMEM; goto complete; } state_structure->sendermessagekeys = malloc(sizeof(Textsecure__SenderKeyStateStructure__SenderMessageKey *) * count); if(!state_structure->sendermessagekeys) { result = SG_ERR_NOMEM; goto complete; } i = 0; DL_FOREACH(state->message_keys_head, cur_node) { signal_buffer *seed = 0; state_structure->sendermessagekeys[i] = malloc(sizeof(Textsecure__SenderKeyStateStructure__SenderMessageKey)); if(!state_structure->sendermessagekeys[i]) { result = SG_ERR_NOMEM; break; } textsecure__sender_key_state_structure__sender_message_key__init(state_structure->sendermessagekeys[i]); state_structure->sendermessagekeys[i]->iteration = sender_message_key_get_iteration(cur_node->key); state_structure->sendermessagekeys[i]->has_iteration = 1; seed = sender_message_key_get_seed(cur_node->key); state_structure->sendermessagekeys[i]->seed.data = signal_buffer_data(seed); state_structure->sendermessagekeys[i]->seed.len = signal_buffer_len(seed); state_structure->sendermessagekeys[i]->has_seed = 1; if(result < 0) { break; } i++; } state_structure->n_sendermessagekeys = i; if(result < 0) { goto complete; } } complete: return result; } void sender_key_state_serialize_prepare_free(Textsecure__SenderKeyStateStructure *state_structure) { unsigned int i = 0; if(state_structure->senderchainkey) { free(state_structure->senderchainkey); } if(state_structure->sendersigningkey) { if(state_structure->sendersigningkey->public_.data) { free(state_structure->sendersigningkey->public_.data); } if(state_structure->sendersigningkey->private_.data) { free(state_structure->sendersigningkey->private_.data); } free(state_structure->sendersigningkey); } if(state_structure->sendermessagekeys) { for(i = 0; i < state_structure->n_sendermessagekeys; i++) { if(state_structure->sendermessagekeys[i]) { free(state_structure->sendermessagekeys[i]); } } free(state_structure->sendermessagekeys); } free(state_structure); } int sender_key_state_deserialize_protobuf(sender_key_state **state, Textsecure__SenderKeyStateStructure *state_structure, signal_context *global_context) { int result = 0; sender_key_state *result_state = 0; sender_chain_key *chain_key = 0; ec_public_key *signature_public_key = 0; ec_private_key *signature_private_key = 0; if(state_structure->senderchainkey && state_structure->senderchainkey->has_iteration && state_structure->senderchainkey->has_seed) { signal_buffer *seed_buffer = signal_buffer_create( state_structure->senderchainkey->seed.data, state_structure->senderchainkey->seed.len); if(!seed_buffer) { result = SG_ERR_NOMEM; goto complete; } result = sender_chain_key_create(&chain_key, state_structure->senderchainkey->iteration, seed_buffer, global_context); signal_buffer_free(seed_buffer); if(result < 0) { goto complete; } } if(state_structure->sendersigningkey) { if(state_structure->sendersigningkey->has_public_) { result = curve_decode_point(&signature_public_key, state_structure->sendersigningkey->public_.data, state_structure->sendersigningkey->public_.len, global_context); if(result < 0) { goto complete; } } if(state_structure->sendersigningkey->has_private_) { result = curve_decode_private_point(&signature_private_key, state_structure->sendersigningkey->private_.data, state_structure->sendersigningkey->private_.len, global_context); if(result < 0) { goto complete; } } } if(state_structure->has_senderkeyid && chain_key && signature_public_key) { unsigned int i; result = sender_key_state_create(&result_state, state_structure->senderkeyid, chain_key, signature_public_key, signature_private_key, global_context); if(result < 0) { goto complete; } if(state_structure->n_sendermessagekeys > 0) { for(i = 0; i < state_structure->n_sendermessagekeys; i++) { signal_buffer *seed_buffer; sender_message_key *message_key; Textsecure__SenderKeyStateStructure__SenderMessageKey *message_key_structure = state_structure->sendermessagekeys[i]; if(!message_key_structure->has_iteration || !message_key_structure->has_seed) { continue; } seed_buffer = signal_buffer_create( message_key_structure->seed.data, message_key_structure->seed.len); if(!seed_buffer) { result = SG_ERR_NOMEM; goto complete; } result = sender_message_key_create(&message_key, message_key_structure->iteration, seed_buffer, global_context); signal_buffer_free(seed_buffer); if(result < 0) { goto complete; } result = sender_key_state_add_sender_message_key(result_state, message_key); if(result < 0) { goto complete; } SIGNAL_UNREF(message_key); } } } else { result = SG_ERR_INVALID_PROTO_BUF; } complete: if(chain_key) { SIGNAL_UNREF(chain_key); } if(signature_public_key) { SIGNAL_UNREF(signature_public_key); } if(signature_private_key) { SIGNAL_UNREF(signature_private_key); } if(result >= 0) { *state = result_state; } else { if(result_state) { SIGNAL_UNREF(result_state); } } return result; } int sender_key_state_copy(sender_key_state **state, sender_key_state *other_state, signal_context *global_context) { int result = 0; signal_buffer *buffer = 0; uint8_t *data; size_t len; assert(other_state); assert(global_context); result = sender_key_state_serialize(&buffer, other_state); if(result < 0) { goto complete; } data = signal_buffer_data(buffer); len = signal_buffer_len(buffer); result = sender_key_state_deserialize(state, data, len, global_context); if(result < 0) { goto complete; } complete: if(buffer) { signal_buffer_free(buffer); } return result; } uint32_t sender_key_state_get_key_id(sender_key_state *state) { assert(state); return state->key_id; } sender_chain_key *sender_key_state_get_chain_key(sender_key_state *state) { assert(state); return state->chain_key; } void sender_key_state_set_chain_key(sender_key_state *state, sender_chain_key *chain_key) { assert(state); assert(chain_key); if(state->chain_key) { SIGNAL_UNREF(state->chain_key); } SIGNAL_REF(chain_key); state->chain_key = chain_key; } ec_public_key *sender_key_state_get_signing_key_public(sender_key_state *state) { assert(state); return state->signature_public_key; } ec_private_key *sender_key_state_get_signing_key_private(sender_key_state *state) { assert(state); return state->signature_private_key; } int sender_key_state_has_sender_message_key(sender_key_state *state, uint32_t iteration) { sender_message_key_node *cur_node = 0; assert(state); DL_FOREACH(state->message_keys_head, cur_node) { if(sender_message_key_get_iteration(cur_node->key) == iteration) { return 1; } } return 0; } int sender_key_state_add_sender_message_key(sender_key_state *state, sender_message_key *message_key) { int result = 0; sender_message_key_node *node = 0; int count; assert(state); assert(message_key); node = malloc(sizeof(sender_message_key_node)); if(!node) { result = SG_ERR_NOMEM; goto complete; } SIGNAL_REF(message_key); node->key = message_key; DL_APPEND(state->message_keys_head, node); DL_COUNT(state->message_keys_head, node, count); while(count > MAX_MESSAGE_KEYS) { node = state->message_keys_head; DL_DELETE(state->message_keys_head, node); if(node->key) { SIGNAL_UNREF(node->key); } free(node); --count; } complete: return result; } sender_message_key *sender_key_state_remove_sender_message_key(sender_key_state *state, uint32_t iteration) { sender_message_key *result = 0; sender_message_key_node *cur_node = 0; sender_message_key_node *tmp_node = 0; assert(state); DL_FOREACH_SAFE(state->message_keys_head, cur_node, tmp_node) { if(sender_message_key_get_iteration(cur_node->key) == iteration) { DL_DELETE(state->message_keys_head, cur_node); result = cur_node->key; free(cur_node); break; } } return result; } void sender_key_state_destroy(signal_type_base *type) { sender_key_state *state = (sender_key_state *)type; sender_message_key_node *cur_node; sender_message_key_node *tmp_node; SIGNAL_UNREF(state->chain_key); SIGNAL_UNREF(state->signature_public_key); SIGNAL_UNREF(state->signature_private_key); DL_FOREACH_SAFE(state->message_keys_head, cur_node, tmp_node) { DL_DELETE(state->message_keys_head, cur_node); if(cur_node->key) { SIGNAL_UNREF(cur_node->key); } free(cur_node); } state->message_keys_head = 0; free(state); } libsignal-protocol-c-2.3.3/src/sender_key_state.h000066400000000000000000000027541363751346500220570ustar00rootroot00000000000000#ifndef SENDER_KEY_STATE_H #define SENDER_KEY_STATE_H #include #include "signal_protocol_types.h" #ifdef __cplusplus extern "C" { #endif int sender_key_state_create(sender_key_state **state, uint32_t id, sender_chain_key *chain_key, ec_public_key *signature_public_key, ec_private_key *signature_private_key, signal_context *global_context); int sender_key_state_serialize(signal_buffer **buffer, sender_key_state *state); int sender_key_state_deserialize(sender_key_state **state, const uint8_t *data, size_t len, signal_context *global_context); int sender_key_state_copy(sender_key_state **state, sender_key_state *other_state, signal_context *global_context); uint32_t sender_key_state_get_key_id(sender_key_state *state); sender_chain_key *sender_key_state_get_chain_key(sender_key_state *state); void sender_key_state_set_chain_key(sender_key_state *state, sender_chain_key *chain_key); ec_public_key *sender_key_state_get_signing_key_public(sender_key_state *state); ec_private_key *sender_key_state_get_signing_key_private(sender_key_state *state); int sender_key_state_has_sender_message_key(sender_key_state *state, uint32_t iteration); int sender_key_state_add_sender_message_key(sender_key_state *state, sender_message_key *message_key); sender_message_key *sender_key_state_remove_sender_message_key(sender_key_state *state, uint32_t iteration); void sender_key_state_destroy(signal_type_base *type); #ifdef __cplusplus } #endif #endif /* SENDER_KEY_STATE_H */ libsignal-protocol-c-2.3.3/src/session_builder.c000066400000000000000000000257341363751346500217160ustar00rootroot00000000000000#include "session_builder.h" #include "session_builder_internal.h" #include #include #include "session_pre_key.h" #include "session_record.h" #include "session_state.h" #include "ratchet.h" #include "protocol.h" #include "key_helper.h" #include "signal_protocol_internal.h" struct session_builder { signal_protocol_store_context *store; const signal_protocol_address *remote_address; signal_context *global_context; }; static int session_builder_process_pre_key_signal_message_v3(session_builder *builder, session_record *record, pre_key_signal_message *message, uint32_t *unsigned_pre_key_id); int session_builder_create(session_builder **builder, signal_protocol_store_context *store, const signal_protocol_address *remote_address, signal_context *global_context) { session_builder *result = 0; assert(store); assert(global_context); result = malloc(sizeof(session_builder)); if(!result) { return SG_ERR_NOMEM; } memset(result, 0, sizeof(session_builder)); result->store = store; result->remote_address = remote_address; result->global_context = global_context; *builder = result; return 0; } int session_builder_process_pre_key_signal_message(session_builder *builder, session_record *record, pre_key_signal_message *message, uint32_t *unsigned_pre_key_id) { int result = 0; int has_unsigned_pre_key_id_result = 0; uint32_t unsigned_pre_key_id_result = 0; ec_public_key *their_identity_key = pre_key_signal_message_get_identity_key(message); result = signal_protocol_identity_is_trusted_identity(builder->store, builder->remote_address, their_identity_key); if(result < 0) { goto complete; } if(result == 0) { result = SG_ERR_UNTRUSTED_IDENTITY; goto complete; } result = session_builder_process_pre_key_signal_message_v3(builder, record, message, &unsigned_pre_key_id_result); if(result < 0) { goto complete; } has_unsigned_pre_key_id_result = result; result = signal_protocol_identity_save_identity(builder->store, builder->remote_address, their_identity_key); if(result < 0) { goto complete; } result = has_unsigned_pre_key_id_result; complete: if(result >= 0) { *unsigned_pre_key_id = unsigned_pre_key_id_result; } return result; } static int session_builder_process_pre_key_signal_message_v3(session_builder *builder, session_record *record, pre_key_signal_message *message, uint32_t *unsigned_pre_key_id) { int result = 0; uint32_t unsigned_pre_key_id_result = 0; session_signed_pre_key *our_signed_pre_key = 0; ratchet_identity_key_pair *our_identity_key = 0; bob_signal_protocol_parameters *parameters = 0; session_pre_key *session_our_one_time_pre_key = 0; ec_key_pair *our_one_time_pre_key = 0; session_state *state = 0; uint32_t local_registration_id = 0; int has_session_state = session_record_has_session_state(record, pre_key_signal_message_get_message_version(message), pre_key_signal_message_get_base_key(message)); if(has_session_state) { signal_log(builder->global_context, SG_LOG_INFO, "We've already setup a session for this V3 message, letting bundled message fall through..."); result = 0; goto complete; } result = signal_protocol_signed_pre_key_load_key(builder->store, &our_signed_pre_key, pre_key_signal_message_get_signed_pre_key_id(message)); if(result < 0) { goto complete; } result = signal_protocol_identity_get_key_pair(builder->store, &our_identity_key); if(result < 0) { goto complete; } if(pre_key_signal_message_has_pre_key_id(message)) { result = signal_protocol_pre_key_load_key(builder->store, &session_our_one_time_pre_key, pre_key_signal_message_get_pre_key_id(message)); if(result < 0) { goto complete; } our_one_time_pre_key = session_pre_key_get_key_pair(session_our_one_time_pre_key); } result = bob_signal_protocol_parameters_create( ¶meters, our_identity_key, session_signed_pre_key_get_key_pair(our_signed_pre_key), our_one_time_pre_key, session_signed_pre_key_get_key_pair(our_signed_pre_key), pre_key_signal_message_get_identity_key(message), pre_key_signal_message_get_base_key(message)); if(result < 0) { goto complete; } if(!session_record_is_fresh(record)) { result = session_record_archive_current_state(record); if(result < 0) { goto complete; } } state = session_record_get_state(record); result = ratcheting_session_bob_initialize( state, parameters, builder->global_context); if(result < 0) { goto complete; } result = signal_protocol_identity_get_local_registration_id(builder->store, &local_registration_id); if(result < 0) { goto complete; } session_state_set_local_registration_id(state, local_registration_id); session_state_set_remote_registration_id(state, pre_key_signal_message_get_registration_id(message)); session_state_set_alice_base_key(state, pre_key_signal_message_get_base_key(message));; if(pre_key_signal_message_has_pre_key_id(message) && pre_key_signal_message_get_pre_key_id(message) != PRE_KEY_MEDIUM_MAX_VALUE) { unsigned_pre_key_id_result = pre_key_signal_message_get_pre_key_id(message); result = 1; } else { result = 0; } complete: SIGNAL_UNREF(parameters); SIGNAL_UNREF(our_identity_key); SIGNAL_UNREF(our_signed_pre_key); SIGNAL_UNREF(session_our_one_time_pre_key); if(result >= 0) { *unsigned_pre_key_id = unsigned_pre_key_id_result; } return result; } int session_builder_process_pre_key_bundle(session_builder *builder, session_pre_key_bundle *bundle) { int result = 0; session_record *record = 0; ec_key_pair *our_base_key = 0; ratchet_identity_key_pair *our_identity_key = 0; alice_signal_protocol_parameters *parameters = 0; ec_public_key *signed_pre_key = 0; ec_public_key *pre_key = 0; ec_public_key *their_identity_key = 0; ec_public_key *their_signed_pre_key = 0; ec_public_key *their_one_time_pre_key = 0; int has_their_one_time_pre_key_id = 0; uint32_t their_one_time_pre_key_id = 0; session_state *state = 0; uint32_t local_registration_id = 0; assert(builder); assert(builder->store); assert(bundle); signal_lock(builder->global_context); result = signal_protocol_identity_is_trusted_identity(builder->store, builder->remote_address, session_pre_key_bundle_get_identity_key(bundle)); if(result < 0) { goto complete; } if(result == 0) { result = SG_ERR_UNTRUSTED_IDENTITY; goto complete; } signed_pre_key = session_pre_key_bundle_get_signed_pre_key(bundle); pre_key = session_pre_key_bundle_get_pre_key(bundle); if(signed_pre_key) { ec_public_key *identity_key = session_pre_key_bundle_get_identity_key(bundle); signal_buffer *signature = session_pre_key_bundle_get_signed_pre_key_signature(bundle); signal_buffer *serialized_signed_pre_key = 0; result = ec_public_key_serialize(&serialized_signed_pre_key, signed_pre_key); if(result < 0) { goto complete; } result = curve_verify_signature(identity_key, signal_buffer_data(serialized_signed_pre_key), signal_buffer_len(serialized_signed_pre_key), signal_buffer_data(signature), signal_buffer_len(signature)); signal_buffer_free(serialized_signed_pre_key); if(result == 0) { signal_log(builder->global_context, SG_LOG_WARNING, "invalid signature on device key!"); result = SG_ERR_INVALID_KEY; } if(result < 0) { goto complete; } } if(!signed_pre_key) { result = SG_ERR_INVALID_KEY; signal_log(builder->global_context, SG_LOG_WARNING, "no signed pre key!"); goto complete; } result = signal_protocol_session_load_session(builder->store, &record, builder->remote_address); if(result < 0) { goto complete; } result = curve_generate_key_pair(builder->global_context, &our_base_key); if(result < 0) { goto complete; } their_identity_key = session_pre_key_bundle_get_identity_key(bundle); their_signed_pre_key = signed_pre_key; their_one_time_pre_key = pre_key; if(their_one_time_pre_key) { has_their_one_time_pre_key_id = 1; their_one_time_pre_key_id = session_pre_key_bundle_get_pre_key_id(bundle); } result = signal_protocol_identity_get_key_pair(builder->store, &our_identity_key); if(result < 0) { goto complete; } result = alice_signal_protocol_parameters_create(¶meters, our_identity_key, our_base_key, their_identity_key, their_signed_pre_key, their_one_time_pre_key, their_signed_pre_key); if(result < 0) { goto complete; } if(!session_record_is_fresh(record)) { result = session_record_archive_current_state(record); if(result < 0) { goto complete; } } state = session_record_get_state(record); result = ratcheting_session_alice_initialize( state, parameters, builder->global_context); if(result < 0) { goto complete; } session_state_set_unacknowledged_pre_key_message(state, has_their_one_time_pre_key_id ? &their_one_time_pre_key_id : 0, session_pre_key_bundle_get_signed_pre_key_id(bundle), ec_key_pair_get_public(our_base_key)); result = signal_protocol_identity_get_local_registration_id(builder->store, &local_registration_id); if(result < 0) { goto complete; } session_state_set_local_registration_id(state, local_registration_id); session_state_set_remote_registration_id(state, session_pre_key_bundle_get_registration_id(bundle)); session_state_set_alice_base_key(state, ec_key_pair_get_public(our_base_key)); result = signal_protocol_session_store_session(builder->store, builder->remote_address, record); if(result < 0) { goto complete; } result = signal_protocol_identity_save_identity(builder->store, builder->remote_address, their_identity_key); if(result < 0) { goto complete; } complete: SIGNAL_UNREF(record); SIGNAL_UNREF(our_base_key); SIGNAL_UNREF(our_identity_key); SIGNAL_UNREF(parameters); signal_unlock(builder->global_context); return result; } void session_builder_free(session_builder *builder) { if(builder) { free(builder); } } libsignal-protocol-c-2.3.3/src/session_builder.h000066400000000000000000000040441363751346500217120ustar00rootroot00000000000000#ifndef SESSION_BUILDER_H #define SESSION_BUILDER_H #include #include "signal_protocol_types.h" #ifdef __cplusplus extern "C" { #endif /* * Session builder is responsible for setting up encrypted sessions. * Once a session has been established, session_cipher * can be used to encrypt/decrypt messages in that session. * * Sessions are built from one these different possible vectors: * - A session_pre_key_bundle retrieved from a server * - A pre_key_signal_message received from a client * * Sessions are constructed per Signal Protocol address * (recipient name + device ID tuple). Remote logical users are identified by * their recipient name, and each logical recipient can have multiple * physical devices. */ /** * Constructs a session builder. * * The store and global contexts must remain valid for the lifetime of the * session builder. * * When finished, free the returned instance by calling session_builder_free(). * * @param builder set to a freshly allocated session builder instance * @param store the signal_protocol_store_context to store all state information in * @param remote_address the address of the remote user to build a session with * @param global_context the global library context * @return 0 on success, or negative on failure */ int session_builder_create(session_builder **builder, signal_protocol_store_context *store, const signal_protocol_address *remote_address, signal_context *global_context); /** * Build a new session from a session_pre_key_bundle retrieved from a server. * * @param bundle A pre key bundle for the destination recipient, retrieved from a server. * @retval SG_SUCCESS Success * @retval SG_ERR_INVALID_KEY when the session_pre_key_bundle is badly formatted. * @retval SG_ERR_UNTRUSTED_IDENTITY when the sender's identity key is not trusted. */ int session_builder_process_pre_key_bundle(session_builder *builder, session_pre_key_bundle *bundle); void session_builder_free(session_builder *builder); #ifdef __cplusplus } #endif #endif /* SESSION_BUILDER_H */ libsignal-protocol-c-2.3.3/src/session_builder_internal.h000066400000000000000000000021671363751346500236120ustar00rootroot00000000000000#ifndef SESSION_BUILDER_INTERNAL_H #define SESSION_BUILDER_INTERNAL_H #include #include "signal_protocol_types.h" /** * Build a new session from a received pre_key_signal_message. * * After a session is constructed in this way, the embedded signal_message * can be decrypted. * * @param message The received pre_key_signal_message. * @param unsigned_pre_key_id set to the unsigned pre key ID, if available. * Return value indicates whether or not this value is available. * @retval 0 Success, no unsigned pre key value available * @retval 1 Success, an unsigned pre key is available * @retval SG_ERR_INVALID_KEY_ID when there is no local pre_key_record that * corresponds to the PreKey ID in the message. * @retval SG_ERR_INVALID_KEY when the message is formatted incorrectly. * @retval SG_ERR_UNTRUSTED_IDENTITY when the identity key of the sender is untrusted. */ int session_builder_process_pre_key_signal_message(session_builder *builder, session_record *record, pre_key_signal_message *message, uint32_t *unsigned_pre_key_id); #endif /* SESSION_BUILDER_INTERNAL_H */ libsignal-protocol-c-2.3.3/src/session_cipher.c000066400000000000000000000655201363751346500215370ustar00rootroot00000000000000#include "session_cipher.h" #include #include #include "session_builder.h" #include "session_builder_internal.h" #include "session_record.h" #include "session_state.h" #include "ratchet.h" #include "protocol.h" #include "signal_protocol_internal.h" struct session_cipher { signal_protocol_store_context *store; const signal_protocol_address *remote_address; session_builder *builder; signal_context *global_context; int (*decrypt_callback)(session_cipher *cipher, signal_buffer *plaintext, void *decrypt_context); int inside_callback; void *user_data; }; static int session_cipher_decrypt_from_record_and_signal_message(session_cipher *cipher, session_record *record, signal_message *ciphertext, signal_buffer **plaintext); static int session_cipher_decrypt_from_state_and_signal_message(session_cipher *cipher, session_state *state, signal_message *ciphertext, signal_buffer **plaintext); static int session_cipher_get_or_create_chain_key(session_cipher *cipher, ratchet_chain_key **chain_key, session_state *state, ec_public_key *their_ephemeral); static int session_cipher_get_or_create_message_keys(ratchet_message_keys *message_keys, session_state *state, ec_public_key *their_ephemeral, ratchet_chain_key *chain_key, uint32_t counter, signal_context *global_context); static int session_cipher_get_ciphertext(session_cipher *cipher, signal_buffer **ciphertext, uint32_t version, ratchet_message_keys *message_keys, const uint8_t *plaintext, size_t plaintext_len); static int session_cipher_get_plaintext(session_cipher *cipher, signal_buffer **plaintext, uint32_t version, ratchet_message_keys *message_keys, const uint8_t *ciphertext, size_t ciphertext_len); static int session_cipher_decrypt_callback(session_cipher *cipher, signal_buffer *plaintext, void *decrypt_context); int session_cipher_create(session_cipher **cipher, signal_protocol_store_context *store, const signal_protocol_address *remote_address, signal_context *global_context) { int result = 0; session_builder *builder = 0; session_cipher *result_cipher; assert(store); assert(global_context); result = session_builder_create(&builder, store, remote_address, global_context); if(result < 0) { return result; } result_cipher = malloc(sizeof(session_cipher)); if(!result_cipher) { return SG_ERR_NOMEM; } memset(result_cipher, 0, sizeof(session_cipher)); result_cipher->store = store; result_cipher->remote_address = remote_address; result_cipher->builder = builder; result_cipher->global_context = global_context; *cipher = result_cipher; return 0; } void session_cipher_set_user_data(session_cipher *cipher, void *user_data) { assert(cipher); cipher->user_data = user_data; } void *session_cipher_get_user_data(session_cipher *cipher) { assert(cipher); return cipher->user_data; } void session_cipher_set_decryption_callback(session_cipher *cipher, int (*callback)(session_cipher *cipher, signal_buffer *plaintext, void *decrypt_context)) { assert(cipher); cipher->decrypt_callback = callback; } int session_cipher_encrypt(session_cipher *cipher, const uint8_t *padded_message, size_t padded_message_len, ciphertext_message **encrypted_message) { int result = 0; session_record *record = 0; session_state *state = 0; ratchet_chain_key *chain_key = 0; ratchet_chain_key *next_chain_key = 0; ratchet_message_keys message_keys; ec_public_key *sender_ephemeral = 0; uint32_t previous_counter = 0; uint32_t session_version = 0; signal_buffer *ciphertext = 0; uint32_t chain_key_index = 0; ec_public_key *local_identity_key = 0; ec_public_key *remote_identity_key = 0; signal_message *message = 0; pre_key_signal_message *pre_key_message = 0; uint8_t *ciphertext_data = 0; size_t ciphertext_len = 0; assert(cipher); signal_lock(cipher->global_context); if(cipher->inside_callback == 1) { result = SG_ERR_INVAL; goto complete; } result = signal_protocol_session_load_session(cipher->store, &record, cipher->remote_address); if(result < 0) { goto complete; } state = session_record_get_state(record); if(!state) { result = SG_ERR_UNKNOWN; goto complete; } chain_key = session_state_get_sender_chain_key(state); if(!chain_key) { result = SG_ERR_UNKNOWN; goto complete; } result = ratchet_chain_key_get_message_keys(chain_key, &message_keys); if(result < 0) { goto complete; } sender_ephemeral = session_state_get_sender_ratchet_key(state); if(!sender_ephemeral) { result = SG_ERR_UNKNOWN; goto complete; } previous_counter = session_state_get_previous_counter(state); session_version = session_state_get_session_version(state); result = session_cipher_get_ciphertext(cipher, &ciphertext, session_version, &message_keys, padded_message, padded_message_len); if(result < 0) { goto complete; } ciphertext_data = signal_buffer_data(ciphertext); ciphertext_len = signal_buffer_len(ciphertext); chain_key_index = ratchet_chain_key_get_index(chain_key); local_identity_key = session_state_get_local_identity_key(state); if(!local_identity_key) { result = SG_ERR_UNKNOWN; goto complete; } remote_identity_key = session_state_get_remote_identity_key(state); if(!remote_identity_key) { result = SG_ERR_UNKNOWN; goto complete; } result = signal_message_create(&message, session_version, message_keys.mac_key, sizeof(message_keys.mac_key), sender_ephemeral, chain_key_index, previous_counter, ciphertext_data, ciphertext_len, local_identity_key, remote_identity_key, cipher->global_context); if(result < 0) { goto complete; } if(session_state_has_unacknowledged_pre_key_message(state) == 1) { uint32_t local_registration_id = session_state_get_local_registration_id(state); int has_pre_key_id = 0; uint32_t pre_key_id = 0; uint32_t signed_pre_key_id; ec_public_key *base_key; if(session_state_unacknowledged_pre_key_message_has_pre_key_id(state)) { has_pre_key_id = 1; pre_key_id = session_state_unacknowledged_pre_key_message_get_pre_key_id(state); } signed_pre_key_id = session_state_unacknowledged_pre_key_message_get_signed_pre_key_id(state); base_key = session_state_unacknowledged_pre_key_message_get_base_key(state); if(!base_key) { result = SG_ERR_UNKNOWN; goto complete; } result = pre_key_signal_message_create(&pre_key_message, session_version, local_registration_id, (has_pre_key_id ? &pre_key_id : 0), signed_pre_key_id, base_key, local_identity_key, message, cipher->global_context); if(result < 0) { goto complete; } SIGNAL_UNREF(message); message = 0; } result = ratchet_chain_key_create_next(chain_key, &next_chain_key); if(result < 0) { goto complete; } result = session_state_set_sender_chain_key(state, next_chain_key); if(result < 0) { goto complete; } result = signal_protocol_session_store_session(cipher->store, cipher->remote_address, record); complete: if(result >= 0) { if(pre_key_message) { *encrypted_message = (ciphertext_message *)pre_key_message; } else { *encrypted_message = (ciphertext_message *)message; } } else { SIGNAL_UNREF(pre_key_message); SIGNAL_UNREF(message); } signal_buffer_free(ciphertext); SIGNAL_UNREF(next_chain_key); SIGNAL_UNREF(record); signal_explicit_bzero(&message_keys, sizeof(ratchet_message_keys)); signal_unlock(cipher->global_context); return result; } int session_cipher_decrypt_pre_key_signal_message(session_cipher *cipher, pre_key_signal_message *ciphertext, void *decrypt_context, signal_buffer **plaintext) { int result = 0; signal_buffer *result_buf = 0; session_record *record = 0; int has_unsigned_pre_key_id = 0; uint32_t unsigned_pre_key_id = 0; assert(cipher); signal_lock(cipher->global_context); if(cipher->inside_callback == 1) { result = SG_ERR_INVAL; goto complete; } result = signal_protocol_session_load_session(cipher->store, &record, cipher->remote_address); if(result < 0) { goto complete; } result = session_builder_process_pre_key_signal_message(cipher->builder, record, ciphertext, &unsigned_pre_key_id); if(result < 0) { goto complete; } has_unsigned_pre_key_id = result; result = session_cipher_decrypt_from_record_and_signal_message(cipher, record, pre_key_signal_message_get_signal_message(ciphertext), &result_buf); if(result < 0) { goto complete; } result = session_cipher_decrypt_callback(cipher, result_buf, decrypt_context); if(result < 0) { goto complete; } result = signal_protocol_session_store_session(cipher->store, cipher->remote_address, record); if(result < 0) { goto complete; } if(has_unsigned_pre_key_id) { result = signal_protocol_pre_key_remove_key(cipher->store, unsigned_pre_key_id); if(result < 0) { goto complete; } } complete: SIGNAL_UNREF(record); if(result >= 0) { *plaintext = result_buf; } else { signal_buffer_free(result_buf); } signal_unlock(cipher->global_context); return result; } int session_cipher_decrypt_signal_message(session_cipher *cipher, signal_message *ciphertext, void *decrypt_context, signal_buffer **plaintext) { int result = 0; signal_buffer *result_buf = 0; session_record *record = 0; assert(cipher); signal_lock(cipher->global_context); if(cipher->inside_callback == 1) { result = SG_ERR_INVAL; goto complete; } result = signal_protocol_session_contains_session(cipher->store, cipher->remote_address); if(result == 0) { signal_log(cipher->global_context, SG_LOG_WARNING, "No session for: %s:%d", cipher->remote_address->name, cipher->remote_address->device_id); result = SG_ERR_NO_SESSION; goto complete; } else if(result < 0) { goto complete; } result = signal_protocol_session_load_session(cipher->store, &record, cipher->remote_address); if(result < 0) { goto complete; } result = session_cipher_decrypt_from_record_and_signal_message( cipher, record, ciphertext, &result_buf); if(result < 0) { goto complete; } result = session_cipher_decrypt_callback(cipher, result_buf, decrypt_context); if(result < 0) { goto complete; } result = signal_protocol_session_store_session(cipher->store, cipher->remote_address, record); complete: SIGNAL_UNREF(record); if(result >= 0) { *plaintext = result_buf; } else { signal_buffer_free(result_buf); } signal_unlock(cipher->global_context); return result; } static int session_cipher_decrypt_from_record_and_signal_message(session_cipher *cipher, session_record *record, signal_message *ciphertext, signal_buffer **plaintext) { int result = 0; signal_buffer *result_buf = 0; session_state *state = 0; session_state *state_copy = 0; session_record_state_node *previous_states_node = 0; assert(cipher); signal_lock(cipher->global_context); state = session_record_get_state(record); if(state) { result = session_state_copy(&state_copy, state, cipher->global_context); if(result < 0) { goto complete; } //TODO Collect and log invalid message errors if totally unsuccessful result = session_cipher_decrypt_from_state_and_signal_message(cipher, state_copy, ciphertext, &result_buf); if(result < 0 && result != SG_ERR_INVALID_MESSAGE) { goto complete; } if(result >= SG_SUCCESS) { session_record_set_state(record, state_copy); goto complete; } SIGNAL_UNREF(state_copy); } previous_states_node = session_record_get_previous_states_head(record); while(previous_states_node) { state = session_record_get_previous_states_element(previous_states_node); result = session_state_copy(&state_copy, state, cipher->global_context); if(result < 0) { goto complete; } result = session_cipher_decrypt_from_state_and_signal_message(cipher, state_copy, ciphertext, &result_buf); if(result < 0 && result != SG_ERR_INVALID_MESSAGE) { goto complete; } if(result >= SG_SUCCESS) { session_record_get_previous_states_remove(record, previous_states_node); result = session_record_promote_state(record, state_copy); goto complete; } SIGNAL_UNREF(state_copy); previous_states_node = session_record_get_previous_states_next(previous_states_node); } signal_log(cipher->global_context, SG_LOG_WARNING, "No valid sessions"); result = SG_ERR_INVALID_MESSAGE; complete: SIGNAL_UNREF(state_copy); if(result >= 0) { *plaintext = result_buf; } else { signal_buffer_free(result_buf); } signal_unlock(cipher->global_context); return result; } static int session_cipher_decrypt_from_state_and_signal_message(session_cipher *cipher, session_state *state, signal_message *ciphertext, signal_buffer **plaintext) { int result = 0; signal_buffer *result_buf = 0; ec_public_key *their_ephemeral = 0; uint32_t counter = 0; ratchet_chain_key *chain_key = 0; ratchet_message_keys message_keys; uint8_t message_version = 0; uint32_t session_version = 0; ec_public_key *remote_identity_key = 0; ec_public_key *local_identity_key = 0; signal_buffer *ciphertext_body = 0; if(!session_state_has_sender_chain(state)) { signal_log(cipher->global_context, SG_LOG_WARNING, "Uninitialized session!"); result = SG_ERR_INVALID_MESSAGE; goto complete; } message_version = signal_message_get_message_version(ciphertext); session_version = session_state_get_session_version(state); if(message_version != session_version) { signal_log(cipher->global_context, SG_LOG_WARNING, "Message version %d, but session version %d", message_version, session_version); result = SG_ERR_INVALID_MESSAGE; goto complete; } their_ephemeral = signal_message_get_sender_ratchet_key(ciphertext); if(!their_ephemeral) { result = SG_ERR_UNKNOWN; goto complete; } counter = signal_message_get_counter(ciphertext); result = session_cipher_get_or_create_chain_key(cipher, &chain_key, state, their_ephemeral); if(result < 0) { goto complete; } result = session_cipher_get_or_create_message_keys(&message_keys, state, their_ephemeral, chain_key, counter, cipher->global_context); if(result < 0) { goto complete; } remote_identity_key = session_state_get_remote_identity_key(state); if(!remote_identity_key) { result = SG_ERR_UNKNOWN; goto complete; } local_identity_key = session_state_get_local_identity_key(state); if(!local_identity_key) { result = SG_ERR_UNKNOWN; goto complete; } result = signal_message_verify_mac(ciphertext, remote_identity_key, local_identity_key, message_keys.mac_key, sizeof(message_keys.mac_key), cipher->global_context); if(result != 1) { if(result == 0) { signal_log(cipher->global_context, SG_LOG_WARNING, "Message mac not verified"); result = SG_ERR_INVALID_MESSAGE; } else if(result < 0) { signal_log(cipher->global_context, SG_LOG_WARNING, "Error attempting to verify message mac"); } goto complete; } ciphertext_body = signal_message_get_body(ciphertext); if(!ciphertext_body) { signal_log(cipher->global_context, SG_LOG_WARNING, "Message body does not exist"); result = SG_ERR_INVALID_MESSAGE; goto complete; } result = session_cipher_get_plaintext(cipher, &result_buf, message_version, &message_keys, signal_buffer_data(ciphertext_body), signal_buffer_len(ciphertext_body)); if(result < 0) { goto complete; } session_state_clear_unacknowledged_pre_key_message(state); complete: SIGNAL_UNREF(chain_key); if(result >= 0) { *plaintext = result_buf; } else { signal_buffer_free(result_buf); } signal_explicit_bzero(&message_keys, sizeof(ratchet_message_keys)); return result; } static int session_cipher_get_or_create_chain_key(session_cipher *cipher, ratchet_chain_key **chain_key, session_state *state, ec_public_key *their_ephemeral) { int result = 0; ratchet_chain_key *result_key = 0; ratchet_root_key *receiver_root_key = 0; ratchet_chain_key *receiver_chain_key = 0; ratchet_root_key *sender_root_key = 0; ratchet_chain_key *sender_chain_key = 0; ec_key_pair *our_new_ephemeral = 0; ratchet_root_key *root_key = 0; ec_key_pair *our_ephemeral = 0; ratchet_chain_key *previous_sender_chain_key = 0; uint32_t index = 0; result_key = session_state_get_receiver_chain_key(state, their_ephemeral); if(result_key) { SIGNAL_REF(result_key); goto complete; } root_key = session_state_get_root_key(state); if(!root_key) { result = SG_ERR_UNKNOWN; goto complete; } our_ephemeral = session_state_get_sender_ratchet_key_pair(state); if(!our_ephemeral) { result = SG_ERR_UNKNOWN; goto complete; } result = ratchet_root_key_create_chain(root_key, &receiver_root_key, &receiver_chain_key, their_ephemeral, ec_key_pair_get_private(our_ephemeral)); if(result < 0) { goto complete; } result = curve_generate_key_pair(cipher->global_context, &our_new_ephemeral); if(result < 0) { goto complete; } result = ratchet_root_key_create_chain(receiver_root_key, &sender_root_key, &sender_chain_key, their_ephemeral, ec_key_pair_get_private(our_new_ephemeral)); if(result < 0) { goto complete; } session_state_set_root_key(state, sender_root_key); result = session_state_add_receiver_chain(state, their_ephemeral, receiver_chain_key); if(result < 0) { goto complete; } previous_sender_chain_key = session_state_get_sender_chain_key(state); if(!previous_sender_chain_key) { result = SG_ERR_UNKNOWN; goto complete; } index = ratchet_chain_key_get_index(previous_sender_chain_key); if(index > 0) { --index; } session_state_set_previous_counter(state, index); session_state_set_sender_chain(state, our_new_ephemeral, sender_chain_key); result_key = receiver_chain_key; SIGNAL_REF(result_key); complete: SIGNAL_UNREF(receiver_root_key); SIGNAL_UNREF(receiver_chain_key); SIGNAL_UNREF(sender_root_key); SIGNAL_UNREF(sender_chain_key); SIGNAL_UNREF(our_new_ephemeral); if(result >= 0) { *chain_key = result_key; } else { SIGNAL_UNREF(result_key); } return result; } static int session_cipher_get_or_create_message_keys(ratchet_message_keys *message_keys, session_state *state, ec_public_key *their_ephemeral, ratchet_chain_key *chain_key, uint32_t counter, signal_context *global_context) { int result = 0; ratchet_chain_key *cur_chain_key = 0; ratchet_chain_key *next_chain_key = 0; ratchet_message_keys message_keys_result; if(ratchet_chain_key_get_index(chain_key) > counter) { result = session_state_remove_message_keys(state, &message_keys_result, their_ephemeral, counter); if(result == 1) { result = 0; goto complete; } signal_log(global_context, SG_LOG_WARNING, "Received message with old counter: %d, %d", ratchet_chain_key_get_index(chain_key), counter); result = SG_ERR_DUPLICATE_MESSAGE; goto complete; } if(counter - ratchet_chain_key_get_index(chain_key) > 2000) { signal_log(global_context, SG_LOG_WARNING, "Over 2000 messages into the future!"); result = SG_ERR_INVALID_MESSAGE; goto complete; } cur_chain_key = chain_key; SIGNAL_REF(cur_chain_key); while(ratchet_chain_key_get_index(cur_chain_key) < counter) { result = ratchet_chain_key_get_message_keys(cur_chain_key, &message_keys_result); if(result < 0) { goto complete; } result = session_state_set_message_keys(state, their_ephemeral, &message_keys_result); if(result < 0) { goto complete; } result = ratchet_chain_key_create_next(cur_chain_key, &next_chain_key); if(result < 0) { goto complete; } SIGNAL_UNREF(cur_chain_key); cur_chain_key = next_chain_key; next_chain_key = 0; } result = ratchet_chain_key_create_next(cur_chain_key, &next_chain_key); if(result < 0) { goto complete; } result = session_state_set_receiver_chain_key(state, their_ephemeral, next_chain_key); if(result < 0) { goto complete; } result = ratchet_chain_key_get_message_keys(cur_chain_key, &message_keys_result); if(result < 0) { goto complete; } complete: if(result >= 0) { memcpy(message_keys, &message_keys_result, sizeof(ratchet_message_keys)); } SIGNAL_UNREF(cur_chain_key); SIGNAL_UNREF(next_chain_key); signal_explicit_bzero(&message_keys_result, sizeof(ratchet_message_keys)); return result; } int session_cipher_get_remote_registration_id(session_cipher *cipher, uint32_t *remote_id) { int result = 0; uint32_t id_result = 0; session_record *record = 0; session_state *state = 0; assert(cipher); signal_lock(cipher->global_context); result = signal_protocol_session_load_session(cipher->store, &record, cipher->remote_address); if(result < 0) { goto complete; } state = session_record_get_state(record); if(!state) { result = SG_ERR_UNKNOWN; goto complete; } id_result = session_state_get_remote_registration_id(state); complete: SIGNAL_UNREF(record); if(result >= 0) { *remote_id = id_result; } signal_unlock(cipher->global_context); return result; } int session_cipher_get_session_version(session_cipher *cipher, uint32_t *version) { int result = 0; uint32_t version_result = 0; session_record *record = 0; session_state *state = 0; assert(cipher); signal_lock(cipher->global_context); result = signal_protocol_session_contains_session(cipher->store, cipher->remote_address); if(result != 1) { if(result == 0) { signal_log(cipher->global_context, SG_LOG_WARNING, "No session for: %s:%d", cipher->remote_address->name, cipher->remote_address->device_id); result = SG_ERR_NO_SESSION; } goto complete; } result = signal_protocol_session_load_session(cipher->store, &record, cipher->remote_address); if(result < 0) { goto complete; } state = session_record_get_state(record); if(!state) { result = SG_ERR_UNKNOWN; goto complete; } version_result = session_state_get_session_version(state); complete: SIGNAL_UNREF(record); if(result >= 0) { *version = version_result; } signal_unlock(cipher->global_context); return result; } static int session_cipher_get_ciphertext(session_cipher *cipher, signal_buffer **ciphertext, uint32_t version, ratchet_message_keys *message_keys, const uint8_t *plaintext, size_t plaintext_len) { int result = 0; signal_buffer *output = 0; if(version >= 3) { result = signal_encrypt(cipher->global_context, &output, SG_CIPHER_AES_CBC_PKCS5, message_keys->cipher_key, sizeof(message_keys->cipher_key), message_keys->iv, sizeof(message_keys->iv), plaintext, plaintext_len); } else { uint8_t iv[16]; memset(iv, 0, sizeof(iv)); iv[3] = (uint8_t)(message_keys->counter); iv[2] = (uint8_t)(message_keys->counter >> 8); iv[1] = (uint8_t)(message_keys->counter >> 16); iv[0] = (uint8_t)(message_keys->counter >> 24); result = signal_encrypt(cipher->global_context, &output, SG_CIPHER_AES_CTR_NOPADDING, message_keys->cipher_key, sizeof(message_keys->cipher_key), iv, sizeof(iv), plaintext, plaintext_len); } if(result >= 0) { *ciphertext = output; } return result; } static int session_cipher_get_plaintext(session_cipher *cipher, signal_buffer **plaintext, uint32_t version, ratchet_message_keys *message_keys, const uint8_t *ciphertext, size_t ciphertext_len) { int result = 0; signal_buffer *output = 0; if(version >= 3) { result = signal_decrypt(cipher->global_context, &output, SG_CIPHER_AES_CBC_PKCS5, message_keys->cipher_key, sizeof(message_keys->cipher_key), message_keys->iv, sizeof(message_keys->iv), ciphertext, ciphertext_len); } else { uint8_t iv[16]; memset(iv, 0, sizeof(iv)); iv[3] = (uint8_t)(message_keys->counter); iv[2] = (uint8_t)(message_keys->counter >> 8); iv[1] = (uint8_t)(message_keys->counter >> 16); iv[0] = (uint8_t)(message_keys->counter >> 24); result = signal_decrypt(cipher->global_context, &output, SG_CIPHER_AES_CTR_NOPADDING, message_keys->cipher_key, sizeof(message_keys->cipher_key), iv, sizeof(iv), ciphertext, ciphertext_len); } if(result >= 0) { *plaintext = output; } return result; } static int session_cipher_decrypt_callback(session_cipher *cipher, signal_buffer *plaintext, void *decrypt_context) { int result = 0; if(cipher->decrypt_callback) { cipher->inside_callback = 1; result = cipher->decrypt_callback(cipher, plaintext, decrypt_context); cipher->inside_callback = 0; } return result; } void session_cipher_free(session_cipher *cipher) { if(cipher) { session_builder_free(cipher->builder); free(cipher); } } libsignal-protocol-c-2.3.3/src/session_cipher.h000066400000000000000000000137201363751346500215370ustar00rootroot00000000000000#ifndef SESSION_CIPHER_H #define SESSION_CIPHER_H #include #include #include "signal_protocol_types.h" #ifdef __cplusplus extern "C" { #endif /** * The main entry point for Signal Protocol encrypt/decrypt operations. * * Once a session has been established with session_builder, * this class can be used for all encrypt/decrypt operations within * that session. */ /** * Construct a session cipher for encrypt/decrypt operations on a session. * In order to use session_cipher, a session must have already been created * and stored using session_builder. * * The store and global contexts must remain valid for the lifetime of the * session cipher. * * When finished, free the returned instance by calling session_cipher_free(). * * @param cipher set to a freshly allocated session cipher instance * @param store the signal_protocol_store_context to store all state information in * @param remote_address the remote address that messages will be encrypted to or decrypted from. * @param global_context the global library context * @return 0 on success, or negative on failure */ int session_cipher_create(session_cipher **cipher, signal_protocol_store_context *store, const signal_protocol_address *remote_address, signal_context *global_context); /** * Set the optional user data pointer for the session cipher. * * This is to give callback functions a way of accessing app specific * context information for this cipher. */ void session_cipher_set_user_data(session_cipher *cipher, void *user_data); /** * Get the optional user data pointer for the session cipher. * * This is to give callback functions a way of accessing app specific * context information for this cipher. */ void *session_cipher_get_user_data(session_cipher *cipher); /** * Set the callback function that is called during the decrypt process. * * The callback function is called from within * session_cipher_decrypt_pre_key_signal_message() and * session_cipher_decrypt_signal_message() after decryption is complete * but before the updated session state has been committed to the session * store. If the callback function returns a negative value, then the * decrypt function will immediately fail with an error. * * This a callback allows some implementations to store the committed plaintext * to their local message store first, in case they are concerned with a crash * or write error happening between the time the session state is updated but * before they're able to successfully store the plaintext to disk. * * @param callback the callback function to set */ void session_cipher_set_decryption_callback(session_cipher *cipher, int (*callback)(session_cipher *cipher, signal_buffer *plaintext, void *decrypt_context)); /** * Encrypt a message. * * @param padded_message The plaintext message bytes, optionally padded to a constant multiple. * @param padded_message_len The length of the data pointed to by padded_message * @param encrypted_message Set to a ciphertext message encrypted to the recipient+device tuple. * * @return SG_SUCCESS on success, negative on error */ int session_cipher_encrypt(session_cipher *cipher, const uint8_t *padded_message, size_t padded_message_len, ciphertext_message **encrypted_message); /** * Decrypt a message. * * @param ciphertext The pre_key_signal_message to decrypt. * @param decrypt_context Optional context pointer associated with the * ciphertext, which is passed to the decryption callback function * @param plaintext Set to a newly allocated buffer containing the plaintext. * * @retval SG_SUCCESS Success * @retval SG_ERR_INVALID_MESSAGE if the input is not valid ciphertext. * @retval SG_ERR_DUPLICATE_MESSAGE if the input is a message that has already been received. * @retval SG_ERR_LEGACY_MESSAGE if the input is a message formatted by a protocol version that * is no longer supported. * @retval SG_ERR_INVALID_KEY_ID when there is no local pre_key_record * that corresponds to the pre key ID in the message. * @retval SG_ERR_INVALID_KEY when the message is formatted incorrectly. * @retval SG_ERR_UNTRUSTED_IDENTITY when the identity key of the sender is untrusted. */ int session_cipher_decrypt_pre_key_signal_message(session_cipher *cipher, pre_key_signal_message *ciphertext, void *decrypt_context, signal_buffer **plaintext); /** * Decrypt a message. * * @param ciphertext The signal_message to decrypt. * @param decrypt_context Optional context pointer associated with the * ciphertext, which is passed to the decryption callback function * @param plaintext Set to a newly allocated buffer containing the plaintext. * * @retval SG_SUCCESS Success * @retval SG_ERR_INVALID_MESSAGE if the input is not valid ciphertext. * @retval SG_ERR_DUPLICATE_MESSAGE if the input is a message that has already been received. * @retval SG_ERR_LEGACY_MESSAGE if the input is a message formatted by a protocol version that * is no longer supported. * @retval SG_ERR_NO_SESSION if there is no established session for this contact. */ int session_cipher_decrypt_signal_message(session_cipher *cipher, signal_message *ciphertext, void *decrypt_context, signal_buffer **plaintext); /** * Gets the remote registration ID for this session cipher. * * @param remote_id Set to the value of the remote registration ID * * @return SG_SUCCESS on success, negative on error */ int session_cipher_get_remote_registration_id(session_cipher *cipher, uint32_t *remote_id); /** * Gets the version of the session associated with this session cipher. * * @param version Set to the value of the session version * * @retval SG_SUCCESS Success * @retval SG_ERR_NO_SESSION if no session could be found */ int session_cipher_get_session_version(session_cipher *cipher, uint32_t *version); void session_cipher_free(session_cipher *cipher); #ifdef __cplusplus } #endif #endif /* SESSION_CIPHER_H */ libsignal-protocol-c-2.3.3/src/session_pre_key.c000066400000000000000000000351631363751346500217230ustar00rootroot00000000000000#include "session_pre_key.h" #include #include #include #include "curve.h" #include "LocalStorageProtocol.pb-c.h" #include "signal_protocol_internal.h" struct session_pre_key { signal_type_base base; uint32_t id; ec_key_pair *key_pair; }; struct session_signed_pre_key { signal_type_base base; uint32_t id; ec_key_pair *key_pair; uint64_t timestamp; size_t signature_len; uint8_t signature[]; }; struct session_pre_key_bundle { signal_type_base base; uint32_t registration_id; int device_id; uint32_t pre_key_id; ec_public_key *pre_key_public; uint32_t signed_pre_key_id; ec_public_key *signed_pre_key_public; signal_buffer *signed_pre_key_signature; ec_public_key *identity_key; }; /*------------------------------------------------------------------------*/ int session_pre_key_create(session_pre_key **pre_key, uint32_t id, ec_key_pair *key_pair) { session_pre_key *result = 0; assert(key_pair); result = malloc(sizeof(session_pre_key)); if(!result) { return SG_ERR_NOMEM; } memset(result, 0, sizeof(session_pre_key)); SIGNAL_INIT(result, session_pre_key_destroy); result->id = id; SIGNAL_REF(key_pair); result->key_pair = key_pair; *pre_key = result; return 0; } int session_pre_key_serialize(signal_buffer **buffer, const session_pre_key *pre_key) { int result = 0; size_t result_size = 0; Textsecure__PreKeyRecordStructure record = TEXTSECURE__PRE_KEY_RECORD_STRUCTURE__INIT; signal_buffer *public_buf = 0; signal_buffer *private_buf = 0; signal_buffer *result_buf = 0; ec_public_key *public_key = 0; ec_private_key *private_key = 0; size_t len = 0; uint8_t *data = 0; if(!pre_key) { result = SG_ERR_INVAL; goto complete; } public_key = ec_key_pair_get_public(pre_key->key_pair); result = ec_public_key_serialize(&public_buf, public_key); if(result < 0) { goto complete; } private_key = ec_key_pair_get_private(pre_key->key_pair); result = ec_private_key_serialize(&private_buf, private_key); if(result < 0) { goto complete; } record.has_id = 1; record.id = pre_key->id; record.has_publickey = 1; record.publickey.data = signal_buffer_data(public_buf); record.publickey.len = signal_buffer_len(public_buf); record.has_privatekey = 1; record.privatekey.data = signal_buffer_data(private_buf); record.privatekey.len = signal_buffer_len(private_buf); len = textsecure__pre_key_record_structure__get_packed_size(&record); result_buf = signal_buffer_alloc(len); if(!result_buf) { result = SG_ERR_NOMEM; goto complete; } data = signal_buffer_data(result_buf); result_size = textsecure__pre_key_record_structure__pack(&record, data); if(result_size != len) { signal_buffer_free(result_buf); result = SG_ERR_INVALID_PROTO_BUF; result_buf = 0; goto complete; } complete: if(public_buf) { signal_buffer_free(public_buf); } if(private_buf) { signal_buffer_free(private_buf); } if(result >= 0) { *buffer = result_buf; } return result; } int session_pre_key_deserialize(session_pre_key **pre_key, const uint8_t *data, size_t len, signal_context *global_context) { int result = 0; Textsecure__PreKeyRecordStructure *record = 0; ec_public_key *public_key = 0; ec_private_key *private_key = 0; ec_key_pair *key_pair = 0; session_pre_key *result_pre_key = 0; record = textsecure__pre_key_record_structure__unpack(0, len, data); if(!record) { result = SG_ERR_INVALID_PROTO_BUF; goto complete; } if(!record->has_id || !record->has_publickey || !record->has_privatekey) { result = SG_ERR_INVALID_KEY; goto complete; } result = curve_decode_point(&public_key, record->publickey.data, record->publickey.len, global_context); if(result < 0) { goto complete; } result = curve_decode_private_point(&private_key, record->privatekey.data, record->privatekey.len, global_context); if(result < 0) { goto complete; } result = ec_key_pair_create(&key_pair, public_key, private_key); if(result < 0) { goto complete; } result = session_pre_key_create(&result_pre_key, record->id, key_pair); if(result < 0) { goto complete; } complete: if(record) { textsecure__pre_key_record_structure__free_unpacked(record, 0); } if(public_key) { SIGNAL_UNREF(public_key); } if(private_key) { SIGNAL_UNREF(private_key); } if(key_pair) { SIGNAL_UNREF(key_pair); } if(result >= 0) { *pre_key = result_pre_key; } return result; } uint32_t session_pre_key_get_id(const session_pre_key *pre_key) { return pre_key->id; } ec_key_pair *session_pre_key_get_key_pair(const session_pre_key *pre_key) { return pre_key->key_pair; } void session_pre_key_destroy(signal_type_base *type) { session_pre_key *pre_key = (session_pre_key *)type; if(pre_key->key_pair) { SIGNAL_UNREF(pre_key->key_pair); } free(pre_key); } /*------------------------------------------------------------------------*/ int session_signed_pre_key_create(session_signed_pre_key **pre_key, uint32_t id, uint64_t timestamp, ec_key_pair *key_pair, const uint8_t *signature, size_t signature_len) { session_signed_pre_key *result = 0; assert(key_pair); assert(signature); assert(signature_len > 0); if(signature_len > (SIZE_MAX - sizeof(session_signed_pre_key)) / sizeof(uint8_t)) { return SG_ERR_NOMEM; } result = malloc(sizeof(session_signed_pre_key) + (sizeof(uint8_t) * signature_len)); if(!result) { return SG_ERR_NOMEM; } memset(result, 0, sizeof(session_signed_pre_key)); SIGNAL_INIT(result, session_signed_pre_key_destroy); result->id = id; result->timestamp = timestamp; SIGNAL_REF(key_pair); result->key_pair = key_pair; result->signature_len = signature_len; memcpy(result->signature, signature, signature_len); *pre_key = result; return 0; } int session_signed_pre_key_serialize(signal_buffer **buffer, const session_signed_pre_key *pre_key) { int result = 0; size_t result_size = 0; Textsecure__SignedPreKeyRecordStructure record = TEXTSECURE__SIGNED_PRE_KEY_RECORD_STRUCTURE__INIT; signal_buffer *public_buf = 0; signal_buffer *private_buf = 0; signal_buffer *signature_buf = 0; signal_buffer *result_buf = 0; ec_public_key *public_key = 0; ec_private_key *private_key = 0; size_t len = 0; uint8_t *data = 0; public_key = ec_key_pair_get_public(pre_key->key_pair); result = ec_public_key_serialize(&public_buf, public_key); if(result < 0) { goto complete; } private_key = ec_key_pair_get_private(pre_key->key_pair); result = ec_private_key_serialize(&private_buf, private_key); if(result < 0) { goto complete; } signature_buf = signal_buffer_create(pre_key->signature, pre_key->signature_len); if(!signature_buf) { result = SG_ERR_NOMEM; goto complete; } record.has_id = 1; record.id = pre_key->id; record.has_timestamp = 1; record.timestamp = pre_key->timestamp; record.has_publickey = 1; record.publickey.data = signal_buffer_data(public_buf); record.publickey.len = signal_buffer_len(public_buf); record.has_privatekey = 1; record.privatekey.data = signal_buffer_data(private_buf); record.privatekey.len = signal_buffer_len(private_buf); record.has_signature = 1; record.signature.data = signal_buffer_data(signature_buf); record.signature.len = signal_buffer_len(signature_buf); len = textsecure__signed_pre_key_record_structure__get_packed_size(&record); result_buf = signal_buffer_alloc(len); if(!result_buf) { result = SG_ERR_NOMEM; goto complete; } data = signal_buffer_data(result_buf); result_size = textsecure__signed_pre_key_record_structure__pack(&record, data); if(result_size != len) { signal_buffer_free(result_buf); result = SG_ERR_INVALID_PROTO_BUF; result_buf = 0; goto complete; } complete: if(public_buf) { signal_buffer_free(public_buf); } if(private_buf) { signal_buffer_free(private_buf); } if(signature_buf) { signal_buffer_free(signature_buf); } if(result >= 0) { *buffer = result_buf; } return result; } int session_signed_pre_key_deserialize(session_signed_pre_key **pre_key, const uint8_t *data, size_t len, signal_context *global_context) { int result = 0; Textsecure__SignedPreKeyRecordStructure *record = 0; ec_public_key *public_key = 0; ec_private_key *private_key = 0; ec_key_pair *key_pair = 0; session_signed_pre_key *result_pre_key = 0; record = textsecure__signed_pre_key_record_structure__unpack(0, len, data); if(!record) { result = SG_ERR_INVALID_PROTO_BUF; goto complete; } if(!record->has_id || !record->has_timestamp || !record->has_publickey || !record->has_privatekey || !record->has_signature) { result = SG_ERR_INVALID_KEY; goto complete; } result = curve_decode_point(&public_key, record->publickey.data, record->publickey.len, global_context); if(result < 0) { goto complete; } result = curve_decode_private_point(&private_key, record->privatekey.data, record->privatekey.len, global_context); if(result < 0) { goto complete; } result = ec_key_pair_create(&key_pair, public_key, private_key); if(result < 0) { goto complete; } result = session_signed_pre_key_create(&result_pre_key, record->id, record->timestamp, key_pair, record->signature.data, record->signature.len); if(result < 0) { goto complete; } complete: if(record) { textsecure__signed_pre_key_record_structure__free_unpacked(record, 0); } if(public_key) { SIGNAL_UNREF(public_key); } if(private_key) { SIGNAL_UNREF(private_key); } if(key_pair) { SIGNAL_UNREF(key_pair); } if(result >= 0) { *pre_key = result_pre_key; } return result; } uint32_t session_signed_pre_key_get_id(const session_signed_pre_key *pre_key) { return pre_key->id; } uint64_t session_signed_pre_key_get_timestamp(const session_signed_pre_key *pre_key) { return pre_key->timestamp; } ec_key_pair *session_signed_pre_key_get_key_pair(const session_signed_pre_key *pre_key) { return pre_key->key_pair; } const uint8_t *session_signed_pre_key_get_signature(const session_signed_pre_key *pre_key) { return pre_key->signature; } size_t session_signed_pre_key_get_signature_len(const session_signed_pre_key *pre_key) { return pre_key->signature_len; } void session_signed_pre_key_destroy(signal_type_base *type) { session_signed_pre_key *pre_key = (session_signed_pre_key *)type; if(pre_key->key_pair) { SIGNAL_UNREF(pre_key->key_pair); } free(pre_key); } /*------------------------------------------------------------------------*/ int session_pre_key_bundle_create(session_pre_key_bundle **bundle, uint32_t registration_id, int device_id, uint32_t pre_key_id, ec_public_key *pre_key_public, uint32_t signed_pre_key_id, ec_public_key *signed_pre_key_public, const uint8_t *signed_pre_key_signature_data, size_t signed_pre_key_signature_len, ec_public_key *identity_key) { int result = 0; session_pre_key_bundle *result_bundle = 0; result_bundle = malloc(sizeof(session_pre_key_bundle)); if(!result_bundle) { result = SG_ERR_NOMEM; goto complete; } memset(result_bundle, 0, sizeof(session_pre_key_bundle)); SIGNAL_INIT(result_bundle, session_pre_key_bundle_destroy); result_bundle->registration_id = registration_id; result_bundle->device_id = device_id; result_bundle->pre_key_id = pre_key_id; if(pre_key_public) { SIGNAL_REF(pre_key_public); result_bundle->pre_key_public = pre_key_public; } result_bundle->signed_pre_key_id = signed_pre_key_id; if(signed_pre_key_public) { SIGNAL_REF(signed_pre_key_public); result_bundle->signed_pre_key_public = signed_pre_key_public; } if(signed_pre_key_signature_data && signed_pre_key_signature_len > 0) { result_bundle->signed_pre_key_signature = signal_buffer_create( signed_pre_key_signature_data, signed_pre_key_signature_len); } if(identity_key) { SIGNAL_REF(identity_key); result_bundle->identity_key = identity_key; } complete: if(result >= 0) { *bundle = result_bundle; } else { if(result_bundle) { SIGNAL_UNREF(result_bundle); } } return result; } uint32_t session_pre_key_bundle_get_registration_id(const session_pre_key_bundle *bundle) { assert(bundle); return bundle->registration_id; } int session_pre_key_bundle_get_device_id(const session_pre_key_bundle *bundle) { assert(bundle); return bundle->device_id; } uint32_t session_pre_key_bundle_get_pre_key_id(const session_pre_key_bundle *bundle) { assert(bundle); return bundle->pre_key_id; } ec_public_key *session_pre_key_bundle_get_pre_key(const session_pre_key_bundle *bundle) { assert(bundle); return bundle->pre_key_public; } uint32_t session_pre_key_bundle_get_signed_pre_key_id(const session_pre_key_bundle *bundle) { assert(bundle); return bundle->signed_pre_key_id; } ec_public_key *session_pre_key_bundle_get_signed_pre_key(const session_pre_key_bundle *bundle) { assert(bundle); return bundle->signed_pre_key_public; } signal_buffer *session_pre_key_bundle_get_signed_pre_key_signature(const session_pre_key_bundle *bundle) { assert(bundle); return bundle->signed_pre_key_signature; } ec_public_key *session_pre_key_bundle_get_identity_key(const session_pre_key_bundle *bundle) { assert(bundle); return bundle->identity_key; } void session_pre_key_bundle_destroy(signal_type_base *type) { session_pre_key_bundle *bundle = (session_pre_key_bundle *)type; if(bundle->pre_key_public) { SIGNAL_UNREF(bundle->pre_key_public); } if(bundle->signed_pre_key_public) { SIGNAL_UNREF(bundle->signed_pre_key_public); } if(bundle->signed_pre_key_signature) { signal_buffer_free(bundle->signed_pre_key_signature); } if(bundle->identity_key) { SIGNAL_UNREF(bundle->identity_key); } free(bundle); } libsignal-protocol-c-2.3.3/src/session_pre_key.h000066400000000000000000000060471363751346500217270ustar00rootroot00000000000000#ifndef SESSION_PRE_KEY_H #define SESSION_PRE_KEY_H #include #include #include "signal_protocol_types.h" #ifdef __cplusplus extern "C" { #endif #define PRE_KEY_MEDIUM_MAX_VALUE 0xFFFFFF /*------------------------------------------------------------------------*/ int session_pre_key_create(session_pre_key **pre_key, uint32_t id, ec_key_pair *key_pair); int session_pre_key_serialize(signal_buffer **buffer, const session_pre_key *pre_key); int session_pre_key_deserialize(session_pre_key **pre_key, const uint8_t *data, size_t len, signal_context *global_context); uint32_t session_pre_key_get_id(const session_pre_key *pre_key); ec_key_pair *session_pre_key_get_key_pair(const session_pre_key *pre_key); void session_pre_key_destroy(signal_type_base *type); /*------------------------------------------------------------------------*/ int session_signed_pre_key_create(session_signed_pre_key **pre_key, uint32_t id, uint64_t timestamp, ec_key_pair *key_pair, const uint8_t *signature, size_t signature_len); int session_signed_pre_key_serialize(signal_buffer **buffer, const session_signed_pre_key *pre_key); int session_signed_pre_key_deserialize(session_signed_pre_key **pre_key, const uint8_t *data, size_t len, signal_context *global_context); uint32_t session_signed_pre_key_get_id(const session_signed_pre_key *pre_key); uint64_t session_signed_pre_key_get_timestamp(const session_signed_pre_key *pre_key); ec_key_pair *session_signed_pre_key_get_key_pair(const session_signed_pre_key *pre_key); const uint8_t *session_signed_pre_key_get_signature(const session_signed_pre_key *pre_key); size_t session_signed_pre_key_get_signature_len(const session_signed_pre_key *pre_key); void session_signed_pre_key_destroy(signal_type_base *type); /*------------------------------------------------------------------------*/ int session_pre_key_bundle_create(session_pre_key_bundle **bundle, uint32_t registration_id, int device_id, uint32_t pre_key_id, ec_public_key *pre_key_public, uint32_t signed_pre_key_id, ec_public_key *signed_pre_key_public, const uint8_t *signed_pre_key_signature_data, size_t signed_pre_key_signature_len, ec_public_key *identity_key); uint32_t session_pre_key_bundle_get_registration_id(const session_pre_key_bundle *bundle); int session_pre_key_bundle_get_device_id(const session_pre_key_bundle *bundle); uint32_t session_pre_key_bundle_get_pre_key_id(const session_pre_key_bundle *bundle); ec_public_key *session_pre_key_bundle_get_pre_key(const session_pre_key_bundle *bundle); uint32_t session_pre_key_bundle_get_signed_pre_key_id(const session_pre_key_bundle *bundle); ec_public_key *session_pre_key_bundle_get_signed_pre_key(const session_pre_key_bundle *bundle); signal_buffer *session_pre_key_bundle_get_signed_pre_key_signature(const session_pre_key_bundle *bundle); ec_public_key *session_pre_key_bundle_get_identity_key(const session_pre_key_bundle *bundle); void session_pre_key_bundle_destroy(signal_type_base *type); #ifdef __cplusplus } #endif #endif /* SESSION_PRE_KEY_H */ libsignal-protocol-c-2.3.3/src/session_record.c000066400000000000000000000310621363751346500215350ustar00rootroot00000000000000#include "session_record.h" #include #include #include #include "session_state.h" #include "utlist.h" #include "LocalStorageProtocol.pb-c.h" #include "signal_protocol_internal.h" #define ARCHIVED_STATES_MAX_LENGTH 40 struct session_record_state_node { session_state *state; struct session_record_state_node *prev, *next; }; struct session_record { signal_type_base base; session_state *state; session_record_state_node *previous_states_head; int is_fresh; signal_buffer *user_record; signal_context *global_context; }; static void session_record_free_previous_states(session_record *record); int session_record_create(session_record **record, session_state *state, signal_context *global_context) { session_record *result = malloc(sizeof(session_record)); if(!result) { return SG_ERR_NOMEM; } memset(result, 0, sizeof(session_record)); SIGNAL_INIT(result, session_record_destroy); if(!state) { int ret = session_state_create(&result->state, global_context); if(ret < 0) { SIGNAL_UNREF(result); return ret; } result->is_fresh = 1; } else { SIGNAL_REF(state); result->state = state; result->is_fresh = 0; } result->global_context = global_context; *record = result; return 0; } int session_record_serialize(signal_buffer **buffer, const session_record *record) { int result = 0; size_t result_size = 0; unsigned int i = 0; Textsecure__RecordStructure record_structure = TEXTSECURE__RECORD_STRUCTURE__INIT; session_record_state_node *cur_node = 0; signal_buffer *result_buf = 0; size_t len = 0; uint8_t *data = 0; if(!record) { result = SG_ERR_INVAL; goto complete; } if(record->state) { record_structure.currentsession = malloc(sizeof(Textsecure__SessionStructure)); if(!record_structure.currentsession) { result = SG_ERR_NOMEM; goto complete; } textsecure__session_structure__init(record_structure.currentsession); result = session_state_serialize_prepare(record->state, record_structure.currentsession); if(result < 0) { goto complete; } } if(record->previous_states_head) { size_t count; DL_COUNT(record->previous_states_head, cur_node, count); if(count > SIZE_MAX / sizeof(Textsecure__SessionStructure *)) { result = SG_ERR_NOMEM; goto complete; } record_structure.previoussessions = malloc(sizeof(Textsecure__SessionStructure *) * count); if(!record_structure.previoussessions) { result = SG_ERR_NOMEM; goto complete; } i = 0; DL_FOREACH(record->previous_states_head, cur_node) { record_structure.previoussessions[i] = malloc(sizeof(Textsecure__SessionStructure)); if(!record_structure.previoussessions[i]) { result = SG_ERR_NOMEM; break; } textsecure__session_structure__init(record_structure.previoussessions[i]); result = session_state_serialize_prepare(cur_node->state, record_structure.previoussessions[i]); if(result < 0) { break; } i++; } record_structure.n_previoussessions = i; if(result < 0) { goto complete; } } len = textsecure__record_structure__get_packed_size(&record_structure); result_buf = signal_buffer_alloc(len); if(!result_buf) { result = SG_ERR_NOMEM; goto complete; } data = signal_buffer_data(result_buf); result_size = textsecure__record_structure__pack(&record_structure, data); if(result_size != len) { signal_buffer_free(result_buf); result = SG_ERR_INVALID_PROTO_BUF; result_buf = 0; goto complete; } complete: if(record_structure.currentsession) { session_state_serialize_prepare_free(record_structure.currentsession); } if(record_structure.previoussessions) { for(i = 0; i < record_structure.n_previoussessions; i++) { if(record_structure.previoussessions[i]) { session_state_serialize_prepare_free(record_structure.previoussessions[i]); } } free(record_structure.previoussessions); } if(result >= 0) { *buffer = result_buf; } return result; } int session_record_deserialize(session_record **record, const uint8_t *data, size_t len, signal_context *global_context) { int result = 0; session_record *result_record = 0; session_state *current_state = 0; session_record_state_node *previous_states_head = 0; Textsecure__RecordStructure *record_structure = 0; record_structure = textsecure__record_structure__unpack(0, len, data); if(!record_structure) { result = SG_ERR_INVALID_PROTO_BUF; goto complete; } if(record_structure->currentsession) { result = session_state_deserialize_protobuf(¤t_state, record_structure->currentsession, global_context); if(result < 0) { goto complete; } } result = session_record_create(&result_record, current_state, global_context); if(result < 0) { goto complete; } SIGNAL_UNREF(current_state); current_state = 0; result_record->is_fresh = 0; if(record_structure->n_previoussessions > 0) { unsigned int i; for(i = 0; i < record_structure->n_previoussessions; i++) { Textsecure__SessionStructure *session_structure = record_structure->previoussessions[i]; session_record_state_node *node = malloc(sizeof(session_record_state_node)); if(!node) { result = SG_ERR_NOMEM; goto complete; } result = session_state_deserialize_protobuf(&node->state, session_structure, global_context); if(result < 0) { free(node); goto complete; } DL_APPEND(previous_states_head, node); } } result_record->previous_states_head = previous_states_head; previous_states_head = 0; complete: if(record_structure) { textsecure__record_structure__free_unpacked(record_structure, 0); } if(current_state) { SIGNAL_UNREF(current_state); } if(previous_states_head) { session_record_state_node *cur_node; session_record_state_node *tmp_node; DL_FOREACH_SAFE(previous_states_head, cur_node, tmp_node) { DL_DELETE(previous_states_head, cur_node); free(cur_node); } } if(result_record) { if(result < 0) { SIGNAL_UNREF(result_record); } else { *record = result_record; } } return result; } int session_record_copy(session_record **record, session_record *other_record, signal_context *global_context) { int result = 0; session_record *result_record = 0; signal_buffer *buffer = 0; size_t len = 0; uint8_t *data = 0; assert(other_record); assert(global_context); result = session_record_serialize(&buffer, other_record); if(result < 0) { goto complete; } data = signal_buffer_data(buffer); len = signal_buffer_len(buffer); result = session_record_deserialize(&result_record, data, len, global_context); if(result < 0) { goto complete; } if(other_record->user_record) { result_record->user_record = signal_buffer_copy(other_record->user_record); if(!result_record->user_record) { result = SG_ERR_NOMEM; goto complete; } } complete: if(buffer) { signal_buffer_free(buffer); } if(result >= 0) { *record = result_record; } else { SIGNAL_UNREF(result_record); } return result; } int session_record_has_session_state(session_record *record, uint32_t version, const ec_public_key *alice_base_key) { session_record_state_node *cur_node = 0; assert(record); assert(record->state); if(session_state_get_session_version(record->state) == version && ec_public_key_compare( session_state_get_alice_base_key(record->state), alice_base_key) == 0) { return 1; } DL_FOREACH(record->previous_states_head, cur_node) { if(session_state_get_session_version(cur_node->state) == version && ec_public_key_compare( session_state_get_alice_base_key(cur_node->state), alice_base_key) == 0) { return 1; } } return 0; } session_state *session_record_get_state(session_record *record) { return record->state; } void session_record_set_state(session_record *record, session_state *state) { assert(record); assert(state); if(record->state) { SIGNAL_UNREF(record->state); } SIGNAL_REF(state); record->state = state; } session_record_state_node *session_record_get_previous_states_head(const session_record *record) { assert(record); return record->previous_states_head; } session_state *session_record_get_previous_states_element(const session_record_state_node *node) { assert(node); return node->state; } session_record_state_node *session_record_get_previous_states_next(const session_record_state_node *node) { assert(node); return node->next; } session_record_state_node *session_record_get_previous_states_remove(session_record *record, session_record_state_node *node) { session_record_state_node *next_node = 0; assert(record); assert(node); next_node = node->next; DL_DELETE(record->previous_states_head, node); SIGNAL_UNREF(node->state); free(node); return next_node; } int session_record_is_fresh(session_record *record) { assert(record); return record->is_fresh; } int session_record_archive_current_state(session_record *record) { int result = 0; session_state *new_state = 0; assert(record); result = session_state_create(&new_state, record->global_context); if(result < 0) { goto complete; } result = session_record_promote_state(record, new_state); complete: SIGNAL_UNREF(new_state); return result; } int session_record_promote_state(session_record *record, session_state *promoted_state) { int count = 0; session_record_state_node *cur_node = 0; session_record_state_node *tmp_node = 0; assert(record); assert(promoted_state); // Move the previously current state to the list of previous states if(record->state) { session_record_state_node *node = malloc(sizeof(session_record_state_node)); if(!node) { return SG_ERR_NOMEM; } node->state = record->state; DL_PREPEND(record->previous_states_head, node); record->state = 0; } // Make the promoted state the current state SIGNAL_REF(promoted_state); record->state = promoted_state; // Remove any previous nodes beyond the maximum length DL_FOREACH_SAFE(record->previous_states_head, cur_node, tmp_node) { count++; if(count > ARCHIVED_STATES_MAX_LENGTH) { DL_DELETE(record->previous_states_head, cur_node); if(cur_node->state) { SIGNAL_UNREF(cur_node->state); } free(cur_node); } } return 0; } static void session_record_free_previous_states(session_record *record) { session_record_state_node *cur_node; session_record_state_node *tmp_node; DL_FOREACH_SAFE(record->previous_states_head, cur_node, tmp_node) { DL_DELETE(record->previous_states_head, cur_node); if(cur_node->state) { SIGNAL_UNREF(cur_node->state); } free(cur_node); } record->previous_states_head = 0; } signal_buffer *session_record_get_user_record(const session_record *record) { assert(record); return record->user_record; } void session_record_set_user_record(session_record *record, signal_buffer *user_record) { assert(record); if(record->user_record) { signal_buffer_free(record->user_record); } record->user_record = user_record; } void session_record_destroy(signal_type_base *type) { session_record *record = (session_record *)type; if(record->state) { SIGNAL_UNREF(record->state); } session_record_free_previous_states(record); if(record->user_record) { signal_buffer_free(record->user_record); } free(record); } libsignal-protocol-c-2.3.3/src/session_record.h000066400000000000000000000041761363751346500215500ustar00rootroot00000000000000#ifndef SESSION_RECORD_H #define SESSION_RECORD_H #include #include #include "signal_protocol_types.h" #ifdef __cplusplus extern "C" { #endif int session_record_create(session_record **record, session_state *state, signal_context *global_context); int session_record_serialize(signal_buffer **buffer, const session_record *record); int session_record_deserialize(session_record **record, const uint8_t *data, size_t len, signal_context *global_context); int session_record_copy(session_record **record, session_record *other_record, signal_context *global_context); int session_record_has_session_state(session_record *record, uint32_t version, const ec_public_key *alice_base_key); session_state *session_record_get_state(session_record *record); void session_record_set_state(session_record *record, session_state *state); session_record_state_node *session_record_get_previous_states_head(const session_record *record); session_state *session_record_get_previous_states_element(const session_record_state_node *node); session_record_state_node *session_record_get_previous_states_next(const session_record_state_node *node); /** * Removes the specified node in the previous states list. * @param node the node to remove * @return the node immediately following the removed node, or null if at the end of the list */ session_record_state_node *session_record_get_previous_states_remove(session_record *record, session_record_state_node *node); int session_record_is_fresh(session_record *record); /** * Move the current session_state into the list of "previous" session states, * and replace the current session_state with a fresh reset instance. * * @return 0 on success, negative on failure */ int session_record_archive_current_state(session_record *record); int session_record_promote_state(session_record *record, session_state *promoted_state); signal_buffer *session_record_get_user_record(const session_record *record); void session_record_set_user_record(session_record *record, signal_buffer *user_record); void session_record_destroy(signal_type_base *type); #ifdef __cplusplus } #endif #endif /* SESSION_RECORD_H */ libsignal-protocol-c-2.3.3/src/session_state.c000066400000000000000000001616241363751346500214070ustar00rootroot00000000000000#include "session_state.h" #include #include #include #include "hkdf.h" #include "curve.h" #include "ratchet.h" #include "LocalStorageProtocol.pb-c.h" #include "signal_protocol_internal.h" #include "utlist.h" #define MAX_MESSAGE_KEYS 2000 typedef struct message_keys_node { ratchet_message_keys message_key; struct message_keys_node *prev, *next; } message_keys_node; typedef struct session_state_sender_chain { ec_key_pair *sender_ratchet_key_pair; ratchet_chain_key *chain_key; } session_state_sender_chain; typedef struct session_state_receiver_chain { ec_public_key *sender_ratchet_key; ratchet_chain_key *chain_key; message_keys_node *message_keys_head; struct session_state_receiver_chain *prev, *next; } session_state_receiver_chain; typedef struct session_pending_key_exchange { uint32_t sequence; ec_key_pair *local_base_key; ec_key_pair *local_ratchet_key; ratchet_identity_key_pair *local_identity_key; } session_pending_key_exchange; typedef struct session_pending_pre_key { int has_pre_key_id; uint32_t pre_key_id; uint32_t signed_pre_key_id; ec_public_key *base_key; } session_pending_pre_key; struct session_state { signal_type_base base; uint32_t session_version; ec_public_key *local_identity_public; ec_public_key *remote_identity_public; ratchet_root_key *root_key; uint32_t previous_counter; int has_sender_chain; session_state_sender_chain sender_chain; session_state_receiver_chain *receiver_chain_head; int has_pending_key_exchange; session_pending_key_exchange pending_key_exchange; int has_pending_pre_key; session_pending_pre_key pending_pre_key; uint32_t remote_registration_id; uint32_t local_registration_id; int needs_refresh; ec_public_key *alice_base_key; signal_context *global_context; }; static int session_state_serialize_prepare_sender_chain( session_state_sender_chain *chain, Textsecure__SessionStructure__Chain *chain_structure); static int session_state_serialize_prepare_receiver_chain( session_state_receiver_chain *chain, Textsecure__SessionStructure__Chain *chain_structure); static void session_state_serialize_prepare_chain_free( Textsecure__SessionStructure__Chain *chain_structure); static int session_state_serialize_prepare_chain_chain_key( ratchet_chain_key *chain_key, Textsecure__SessionStructure__Chain *chain_structure); static int session_state_serialize_prepare_chain_message_keys_list( message_keys_node *message_keys_head, Textsecure__SessionStructure__Chain *chain_structure); static int session_state_serialize_prepare_message_keys( ratchet_message_keys *message_key, Textsecure__SessionStructure__Chain__MessageKey *message_key_structure); static void session_state_serialize_prepare_message_keys_free( Textsecure__SessionStructure__Chain__MessageKey *message_key_structure); static int session_state_serialize_prepare_pending_key_exchange( session_pending_key_exchange *exchange, Textsecure__SessionStructure__PendingKeyExchange *exchange_structure); static void session_state_serialize_prepare_pending_key_exchange_free( Textsecure__SessionStructure__PendingKeyExchange *exchange_structure); static int session_state_serialize_prepare_pending_pre_key( session_pending_pre_key *pre_key, Textsecure__SessionStructure__PendingPreKey *pre_key_structure); static void session_state_serialize_prepare_pending_pre_key_free( Textsecure__SessionStructure__PendingPreKey *pre_key_structure); static int session_state_deserialize_protobuf_pending_key_exchange( session_pending_key_exchange *result_exchange, Textsecure__SessionStructure__PendingKeyExchange *exchange_structure, signal_context *global_context); static int session_state_deserialize_protobuf_pending_pre_key( session_pending_pre_key *result_pre_key, Textsecure__SessionStructure__PendingPreKey *pre_key_structure, signal_context *global_context); static int session_state_deserialize_protobuf_sender_chain( uint32_t session_version, session_state_sender_chain *chain, Textsecure__SessionStructure__Chain *chain_structure, signal_context *global_context); static int session_state_deserialize_protobuf_receiver_chain( uint32_t session_version, session_state_receiver_chain *chain, Textsecure__SessionStructure__Chain *chain_structure, signal_context *global_context); static void session_state_free_sender_chain(session_state *state); static void session_state_free_receiver_chain_node(session_state_receiver_chain *node); static void session_state_free_receiver_chain(session_state *state); static session_state_receiver_chain *session_state_find_receiver_chain(const session_state *state, const ec_public_key *sender_ephemeral); int session_state_create(session_state **state, signal_context *global_context) { session_state *result = malloc(sizeof(session_state)); if(!result) { return SG_ERR_NOMEM; } memset(result, 0, sizeof(session_state)); SIGNAL_INIT(result, session_state_destroy); result->session_version = 2; result->global_context = global_context; *state = result; return 0; } int session_state_serialize(signal_buffer **buffer, session_state *state) { int result = 0; size_t result_size = 0; Textsecure__SessionStructure *state_structure = 0; signal_buffer *result_buf = 0; size_t len = 0; uint8_t *data = 0; state_structure = malloc(sizeof(Textsecure__SessionStructure)); if(!state_structure) { result = SG_ERR_NOMEM; goto complete; } textsecure__session_structure__init(state_structure); result = session_state_serialize_prepare(state, state_structure); if(result < 0) { goto complete; } len = textsecure__session_structure__get_packed_size(state_structure); result_buf = signal_buffer_alloc(len); if(!result_buf) { result = SG_ERR_NOMEM; goto complete; } data = signal_buffer_data(result_buf); result_size = textsecure__session_structure__pack(state_structure, data); if(result_size != len) { signal_buffer_free(result_buf); result = SG_ERR_INVALID_PROTO_BUF; result_buf = 0; goto complete; } complete: if(state_structure) { session_state_serialize_prepare_free(state_structure); } if(result >= 0) { *buffer = result_buf; } return result; } int session_state_deserialize(session_state **state, const uint8_t *data, size_t len, signal_context *global_context) { int result = 0; session_state *result_state = 0; Textsecure__SessionStructure *session_structure = 0; session_structure = textsecure__session_structure__unpack(0, len, data); if(!session_structure) { result = SG_ERR_INVALID_PROTO_BUF; goto complete; } result = session_state_deserialize_protobuf(&result_state, session_structure, global_context); if(result < 0) { goto complete; } complete: if(session_structure) { textsecure__session_structure__free_unpacked(session_structure, 0); } if(result_state) { if(result < 0) { SIGNAL_UNREF(result_state); } else { *state = result_state; } } return result; } int session_state_serialize_prepare(session_state *state, Textsecure__SessionStructure *session_structure) { int result = 0; assert(state); assert(session_structure); session_structure->has_sessionversion = 1; session_structure->sessionversion = state->session_version; if(state->local_identity_public) { result = ec_public_key_serialize_protobuf( &session_structure->localidentitypublic, state->local_identity_public); if(result < 0) { goto complete; } session_structure->has_localidentitypublic = 1; } if(state->remote_identity_public) { result = ec_public_key_serialize_protobuf( &session_structure->remoteidentitypublic, state->remote_identity_public); if(result < 0) { goto complete; } session_structure->has_remoteidentitypublic = 1; } if(state->root_key) { result = ratchet_root_key_get_key_protobuf( state->root_key, &session_structure->rootkey); if(result < 0) { goto complete; } session_structure->has_rootkey = 1; } session_structure->has_previouscounter = 1; session_structure->previouscounter = state->previous_counter; if(state->has_sender_chain) { session_structure->senderchain = malloc(sizeof(Textsecure__SessionStructure__Chain)); if(!session_structure->senderchain) { result = SG_ERR_NOMEM; goto complete; } textsecure__session_structure__chain__init(session_structure->senderchain); result = session_state_serialize_prepare_sender_chain( &state->sender_chain, session_structure->senderchain); if(result < 0) { goto complete; } } if(state->receiver_chain_head) { size_t count, i = 0; session_state_receiver_chain *cur_node; DL_COUNT(state->receiver_chain_head, cur_node, count); if(count > SIZE_MAX / sizeof(Textsecure__SessionStructure__Chain *)) { result = SG_ERR_NOMEM; goto complete; } session_structure->receiverchains = malloc(sizeof(Textsecure__SessionStructure__Chain *) * count); if(!session_structure->receiverchains) { result = SG_ERR_NOMEM; goto complete; } DL_FOREACH(state->receiver_chain_head, cur_node) { session_structure->receiverchains[i] = malloc(sizeof(Textsecure__SessionStructure__Chain)); if(!session_structure->receiverchains[i]) { result = SG_ERR_NOMEM; break; } textsecure__session_structure__chain__init(session_structure->receiverchains[i]); result = session_state_serialize_prepare_receiver_chain(cur_node, session_structure->receiverchains[i]); if(result < 0) { break; } i++; } session_structure->n_receiverchains = i; if(result < 0) { goto complete; } } if(state->has_pending_key_exchange) { session_structure->pendingkeyexchange = malloc(sizeof(Textsecure__SessionStructure__PendingKeyExchange)); if(!session_structure->pendingkeyexchange) { result = SG_ERR_NOMEM; goto complete; } textsecure__session_structure__pending_key_exchange__init(session_structure->pendingkeyexchange); result = session_state_serialize_prepare_pending_key_exchange( &state->pending_key_exchange, session_structure->pendingkeyexchange); if(result < 0) { goto complete; } } if(state->has_pending_pre_key) { session_structure->pendingprekey = malloc(sizeof(Textsecure__SessionStructure__PendingPreKey)); if(!session_structure->pendingprekey) { result = SG_ERR_NOMEM; goto complete; } textsecure__session_structure__pending_pre_key__init(session_structure->pendingprekey); result = session_state_serialize_prepare_pending_pre_key( &state->pending_pre_key, session_structure->pendingprekey); if(result < 0) { goto complete; } } session_structure->has_remoteregistrationid = 1; session_structure->remoteregistrationid = state->remote_registration_id; session_structure->has_localregistrationid = 1; session_structure->localregistrationid = state->local_registration_id; session_structure->has_needsrefresh = 1; session_structure->needsrefresh = state->needs_refresh; if(state->alice_base_key) { result = ec_public_key_serialize_protobuf( &session_structure->alicebasekey, state->alice_base_key); if(result < 0) { goto complete; } session_structure->has_alicebasekey = 1; } complete: return result; } static int session_state_serialize_prepare_sender_chain( session_state_sender_chain *chain, Textsecure__SessionStructure__Chain *chain_structure) { int result = 0; if(chain->sender_ratchet_key_pair) { ec_public_key *public_key = 0; ec_private_key *private_key = 0; public_key = ec_key_pair_get_public(chain->sender_ratchet_key_pair); result = ec_public_key_serialize_protobuf(&chain_structure->senderratchetkey, public_key); if(result < 0) { goto complete; } chain_structure->has_senderratchetkey = 1; private_key = ec_key_pair_get_private(chain->sender_ratchet_key_pair); result = ec_private_key_serialize_protobuf(&chain_structure->senderratchetkeyprivate, private_key); if(result < 0) { goto complete; } chain_structure->has_senderratchetkeyprivate = 1; } if(chain->chain_key) { result = session_state_serialize_prepare_chain_chain_key(chain->chain_key, chain_structure); if(result < 0) { goto complete; } } complete: return result; } static int session_state_serialize_prepare_receiver_chain( session_state_receiver_chain *chain, Textsecure__SessionStructure__Chain *chain_structure) { int result = 0; if(chain->sender_ratchet_key) { result = ec_public_key_serialize_protobuf(&chain_structure->senderratchetkey, chain->sender_ratchet_key); if(result < 0) { goto complete; } chain_structure->has_senderratchetkey = 1; } if(chain->chain_key) { result = session_state_serialize_prepare_chain_chain_key(chain->chain_key, chain_structure); if(result < 0) { goto complete; } } if(chain->message_keys_head) { result = session_state_serialize_prepare_chain_message_keys_list(chain->message_keys_head, chain_structure); if(result < 0) { goto complete; } } complete: return result; } static int session_state_serialize_prepare_chain_chain_key( ratchet_chain_key *chain_key, Textsecure__SessionStructure__Chain *chain_structure) { int result = 0; chain_structure->chainkey = malloc(sizeof(Textsecure__SessionStructure__Chain__ChainKey)); if(!chain_structure->chainkey) { result = SG_ERR_NOMEM; goto complete; } textsecure__session_structure__chain__chain_key__init(chain_structure->chainkey); chain_structure->chainkey->has_index = 1; chain_structure->chainkey->index = ratchet_chain_key_get_index(chain_key); result = ratchet_chain_key_get_key_protobuf(chain_key, &chain_structure->chainkey->key); if(result < 0) { goto complete; } chain_structure->chainkey->has_key = 1; complete: return result; } static int session_state_serialize_prepare_chain_message_keys_list( message_keys_node *message_keys_head, Textsecure__SessionStructure__Chain *chain_structure) { int result = 0; size_t count, i = 0; message_keys_node *cur_node; DL_COUNT(message_keys_head, cur_node, count); if(count == 0) { goto complete; } if(count > SIZE_MAX / sizeof(Textsecure__SessionStructure__Chain__MessageKey *)) { result = SG_ERR_NOMEM; goto complete; } chain_structure->messagekeys = malloc(sizeof(Textsecure__SessionStructure__Chain__MessageKey *) * count); if(!chain_structure->messagekeys) { result = SG_ERR_NOMEM; goto complete; } DL_FOREACH(message_keys_head, cur_node) { chain_structure->messagekeys[i] = malloc(sizeof(Textsecure__SessionStructure__Chain__MessageKey)); if(!chain_structure->messagekeys[i]) { result = SG_ERR_NOMEM; break; } textsecure__session_structure__chain__message_key__init(chain_structure->messagekeys[i]); result = session_state_serialize_prepare_message_keys(&cur_node->message_key, chain_structure->messagekeys[i]); if(result < 0) { break; } i++; } chain_structure->n_messagekeys = i; if(result < 0) { goto complete; } complete: return result; } static int session_state_serialize_prepare_message_keys( ratchet_message_keys *message_key, Textsecure__SessionStructure__Chain__MessageKey *message_key_structure) { int result = 0; message_key_structure->has_index = 1; message_key_structure->index = message_key->counter; message_key_structure->cipherkey.data = malloc(sizeof(message_key->cipher_key)); if(!message_key_structure->cipherkey.data) { result = SG_ERR_NOMEM; goto complete; } memcpy(message_key_structure->cipherkey.data, message_key->cipher_key, sizeof(message_key->cipher_key)); message_key_structure->cipherkey.len = sizeof(message_key->cipher_key); message_key_structure->has_cipherkey = 1; message_key_structure->mackey.data = malloc(sizeof(message_key->mac_key)); if(!message_key_structure->mackey.data) { result = SG_ERR_NOMEM; goto complete; } memcpy(message_key_structure->mackey.data, message_key->mac_key, sizeof(message_key->mac_key)); message_key_structure->mackey.len = sizeof(message_key->mac_key); message_key_structure->has_mackey = 1; message_key_structure->iv.data = malloc(sizeof(message_key->iv)); if(!message_key_structure->iv.data) { result = SG_ERR_NOMEM; goto complete; } memcpy(message_key_structure->iv.data, message_key->iv, sizeof(message_key->iv)); message_key_structure->iv.len = sizeof(message_key->iv); message_key_structure->has_iv = 1; complete: return result; } static void session_state_serialize_prepare_message_keys_free( Textsecure__SessionStructure__Chain__MessageKey *message_key_structure) { if(message_key_structure->has_cipherkey) { free(message_key_structure->cipherkey.data); } if(message_key_structure->has_mackey) { free(message_key_structure->mackey.data); } if(message_key_structure->has_iv) { free(message_key_structure->iv.data); } free(message_key_structure); } static int session_state_serialize_prepare_pending_key_exchange( session_pending_key_exchange *exchange, Textsecure__SessionStructure__PendingKeyExchange *exchange_structure) { int result = 0; exchange_structure->has_sequence = 1; exchange_structure->sequence = exchange->sequence; if(exchange->local_base_key) { ec_public_key *public_key = 0; ec_private_key *private_key = 0; public_key = ec_key_pair_get_public(exchange->local_base_key); result = ec_public_key_serialize_protobuf(&exchange_structure->localbasekey, public_key); if(result < 0) { goto complete; } exchange_structure->has_localbasekey = 1; private_key = ec_key_pair_get_private(exchange->local_base_key); result = ec_private_key_serialize_protobuf(&exchange_structure->localbasekeyprivate, private_key); if(result < 0) { goto complete; } exchange_structure->has_localbasekeyprivate = 1; } if(exchange->local_ratchet_key) { ec_public_key *public_key; ec_private_key *private_key; public_key = ec_key_pair_get_public(exchange->local_ratchet_key); result = ec_public_key_serialize_protobuf(&exchange_structure->localratchetkey, public_key); if(result < 0) { goto complete; } exchange_structure->has_localratchetkey = 1; private_key = ec_key_pair_get_private(exchange->local_ratchet_key); result = ec_private_key_serialize_protobuf(&exchange_structure->localratchetkeyprivate, private_key); if(result < 0) { goto complete; } exchange_structure->has_localratchetkeyprivate = 1; } if(exchange->local_identity_key) { ec_public_key *public_key; ec_private_key *private_key; public_key = ratchet_identity_key_pair_get_public(exchange->local_identity_key); result = ec_public_key_serialize_protobuf(&exchange_structure->localidentitykey, public_key); if(result < 0) { goto complete; } exchange_structure->has_localidentitykey = 1; private_key = ratchet_identity_key_pair_get_private(exchange->local_identity_key); result = ec_private_key_serialize_protobuf(&exchange_structure->localidentitykeyprivate, private_key); if(result < 0) { goto complete; } exchange_structure->has_localidentitykeyprivate = 1; } complete: return result; } static int session_state_serialize_prepare_pending_pre_key( session_pending_pre_key *pre_key, Textsecure__SessionStructure__PendingPreKey *pre_key_structure) { int result = 0; if(pre_key->has_pre_key_id) { pre_key_structure->has_prekeyid = 1; pre_key_structure->prekeyid = pre_key->pre_key_id; } pre_key_structure->has_signedprekeyid = 1; pre_key_structure->signedprekeyid = (int32_t)pre_key->signed_pre_key_id; if(pre_key->base_key) { result = ec_public_key_serialize_protobuf(&pre_key_structure->basekey, pre_key->base_key); if(result < 0) { goto complete; } pre_key_structure->has_basekey = 1; } complete: return result; } void session_state_serialize_prepare_free(Textsecure__SessionStructure *session_structure) { assert(session_structure); if(session_structure->has_localidentitypublic) { free(session_structure->localidentitypublic.data); } if(session_structure->has_remoteidentitypublic) { free(session_structure->remoteidentitypublic.data); } if(session_structure->has_rootkey) { free(session_structure->rootkey.data); } if(session_structure->senderchain) { session_state_serialize_prepare_chain_free(session_structure->senderchain); } if(session_structure->receiverchains) { unsigned int i; for(i = 0; i < session_structure->n_receiverchains; i++) { if(session_structure->receiverchains[i]) { session_state_serialize_prepare_chain_free(session_structure->receiverchains[i]); } } free(session_structure->receiverchains); } if(session_structure->pendingkeyexchange) { session_state_serialize_prepare_pending_key_exchange_free(session_structure->pendingkeyexchange); } if(session_structure->pendingprekey) { session_state_serialize_prepare_pending_pre_key_free(session_structure->pendingprekey); } if(session_structure->has_alicebasekey) { free(session_structure->alicebasekey.data); } free(session_structure); } static void session_state_serialize_prepare_chain_free( Textsecure__SessionStructure__Chain *chain_structure) { if(chain_structure->has_senderratchetkey) { free(chain_structure->senderratchetkey.data); } if(chain_structure->has_senderratchetkeyprivate) { free(chain_structure->senderratchetkeyprivate.data); } if(chain_structure->chainkey) { if(chain_structure->chainkey->has_key) { free(chain_structure->chainkey->key.data); } free(chain_structure->chainkey); } if(chain_structure->messagekeys) { unsigned int i; for(i = 0; i < chain_structure->n_messagekeys; i++) { if(chain_structure->messagekeys[i]) { session_state_serialize_prepare_message_keys_free(chain_structure->messagekeys[i]); } } free(chain_structure->messagekeys); } free(chain_structure); } static void session_state_serialize_prepare_pending_key_exchange_free( Textsecure__SessionStructure__PendingKeyExchange *exchange_structure) { if(exchange_structure->has_localbasekey) { free(exchange_structure->localbasekey.data); } if(exchange_structure->has_localbasekeyprivate) { free(exchange_structure->localbasekeyprivate.data); } if(exchange_structure->has_localratchetkey) { free(exchange_structure->localratchetkey.data); } if(exchange_structure->has_localratchetkeyprivate) { free(exchange_structure->localratchetkeyprivate.data); } if(exchange_structure->has_localidentitykey) { free(exchange_structure->localidentitykey.data); } if(exchange_structure->has_localidentitykeyprivate) { free(exchange_structure->localidentitykeyprivate.data); } free(exchange_structure); } static void session_state_serialize_prepare_pending_pre_key_free( Textsecure__SessionStructure__PendingPreKey *pre_key_structure) { if(pre_key_structure->has_basekey) { free(pre_key_structure->basekey.data); } free(pre_key_structure); } int session_state_deserialize_protobuf(session_state **state, Textsecure__SessionStructure *session_structure, signal_context *global_context) { int result = 0; session_state *result_state = 0; result = session_state_create(&result_state, global_context); if(result < 0) { goto complete; } if(session_structure->has_sessionversion) { result_state->session_version = session_structure->sessionversion; } if(session_structure->has_localidentitypublic) { result = curve_decode_point( &result_state->local_identity_public, session_structure->localidentitypublic.data, session_structure->localidentitypublic.len, global_context); if(result < 0) { goto complete; } } if(session_structure->has_remoteidentitypublic) { result = curve_decode_point( &result_state->remote_identity_public, session_structure->remoteidentitypublic.data, session_structure->remoteidentitypublic.len, global_context); if(result < 0) { goto complete; } } if(session_structure->has_rootkey) { hkdf_context *kdf = 0; result = hkdf_create(&kdf, (int)result_state->session_version, global_context); if(result < 0) { goto complete; } result = ratchet_root_key_create( &result_state->root_key, kdf, session_structure->rootkey.data, session_structure->rootkey.len, global_context); SIGNAL_UNREF(kdf); if(result < 0) { goto complete; } } if(session_structure->has_previouscounter) { result_state->previous_counter = session_structure->previouscounter; } if(session_structure->senderchain) { session_state_deserialize_protobuf_sender_chain( result_state->session_version, &result_state->sender_chain, session_structure->senderchain, global_context); if(result < 0) { goto complete; } result_state->has_sender_chain = 1; } if(session_structure->n_receiverchains > 0) { unsigned int i; for(i = 0; i < session_structure->n_receiverchains; i++) { session_state_receiver_chain *node = malloc(sizeof(session_state_receiver_chain)); if(!node) { result = SG_ERR_NOMEM; goto complete; } memset(node, 0, sizeof(session_state_receiver_chain)); result = session_state_deserialize_protobuf_receiver_chain( result_state->session_version, node, session_structure->receiverchains[i], global_context); if(result < 0) { free(node); goto complete; } DL_APPEND(result_state->receiver_chain_head, node); } } if(session_structure->pendingkeyexchange) { result = session_state_deserialize_protobuf_pending_key_exchange( &result_state->pending_key_exchange, session_structure->pendingkeyexchange, global_context); if(result < 0) { goto complete; } result_state->has_pending_key_exchange = 1; } if(session_structure->pendingprekey) { result = session_state_deserialize_protobuf_pending_pre_key( &result_state->pending_pre_key, session_structure->pendingprekey, global_context); if(result < 0) { goto complete; } result_state->has_pending_pre_key = 1; } if(session_structure->has_remoteregistrationid) { result_state->remote_registration_id = session_structure->remoteregistrationid; } if(session_structure->has_localregistrationid) { result_state->local_registration_id = session_structure->localregistrationid; } if(session_structure->has_needsrefresh) { result_state->needs_refresh = session_structure->needsrefresh; } if(session_structure->has_alicebasekey) { result = curve_decode_point( &result_state->alice_base_key, session_structure->alicebasekey.data, session_structure->alicebasekey.len, global_context); if(result < 0) { goto complete; } } complete: if(result >= 0) { *state = result_state; } else { if(result_state) { SIGNAL_UNREF(result_state); } } return result; } static int session_state_deserialize_protobuf_pending_key_exchange( session_pending_key_exchange *result_exchange, Textsecure__SessionStructure__PendingKeyExchange *exchange_structure, signal_context *global_context) { int result = 0; ec_key_pair *local_base_key = 0; ec_public_key *local_base_key_public = 0; ec_private_key *local_base_key_private = 0; ec_key_pair *local_ratchet_key = 0; ec_public_key *local_ratchet_key_public = 0; ec_private_key *local_ratchet_key_private = 0; ratchet_identity_key_pair *local_identity_key = 0; ec_public_key *local_identity_key_public = 0; ec_private_key *local_identity_key_private = 0; if(exchange_structure->has_localbasekey && exchange_structure->has_localbasekeyprivate) { result = curve_decode_point(&local_base_key_public, exchange_structure->localbasekey.data, exchange_structure->localbasekey.len, global_context); if(result < 0) { goto complete; } result = curve_decode_private_point(&local_base_key_private, exchange_structure->localbasekeyprivate.data, exchange_structure->localbasekeyprivate.len, global_context); if(result < 0) { goto complete; } result = ec_key_pair_create(&local_base_key, local_base_key_public, local_base_key_private); if(result < 0) { goto complete; } } if(exchange_structure->has_localratchetkey && exchange_structure->has_localratchetkeyprivate) { result = curve_decode_point(&local_ratchet_key_public, exchange_structure->localratchetkey.data, exchange_structure->localratchetkey.len, global_context); if(result < 0) { goto complete; } result = curve_decode_private_point(&local_ratchet_key_private, exchange_structure->localratchetkeyprivate.data, exchange_structure->localratchetkeyprivate.len, global_context); if(result < 0) { goto complete; } result = ec_key_pair_create(&local_ratchet_key, local_ratchet_key_public, local_ratchet_key_private); if(result < 0) { goto complete; } } if(exchange_structure->has_localidentitykey && exchange_structure->has_localidentitykeyprivate) { result = curve_decode_point(&local_identity_key_public, exchange_structure->localidentitykey.data, exchange_structure->localidentitykey.len, global_context); if(result < 0) { goto complete; } result = curve_decode_private_point(&local_identity_key_private, exchange_structure->localidentitykeyprivate.data, exchange_structure->localidentitykeyprivate.len, global_context); if(result < 0) { goto complete; } result = ratchet_identity_key_pair_create(&local_identity_key, local_identity_key_public, local_identity_key_private); if(result < 0) { goto complete; } } result_exchange->sequence = exchange_structure->sequence; result_exchange->local_base_key = local_base_key; result_exchange->local_ratchet_key = local_ratchet_key; result_exchange->local_identity_key = local_identity_key; complete: SIGNAL_UNREF(local_base_key_public); SIGNAL_UNREF(local_base_key_private); SIGNAL_UNREF(local_ratchet_key_public); SIGNAL_UNREF(local_ratchet_key_private); SIGNAL_UNREF(local_identity_key_public); SIGNAL_UNREF(local_identity_key_private); if(result < 0) { SIGNAL_UNREF(local_base_key); SIGNAL_UNREF(local_ratchet_key); SIGNAL_UNREF(local_identity_key); } return result; } static int session_state_deserialize_protobuf_pending_pre_key( session_pending_pre_key *result_pre_key, Textsecure__SessionStructure__PendingPreKey *pre_key_structure, signal_context *global_context) { int result = 0; if(pre_key_structure->has_basekey) { ec_public_key *base_key = 0; result = curve_decode_point(&base_key, pre_key_structure->basekey.data, pre_key_structure->basekey.len, global_context); if(result < 0) { goto complete; } result_pre_key->base_key = base_key; } if(pre_key_structure->has_prekeyid) { result_pre_key->has_pre_key_id = 1; result_pre_key->pre_key_id = pre_key_structure->prekeyid; } if(pre_key_structure->has_signedprekeyid) { result_pre_key->signed_pre_key_id = (uint32_t)pre_key_structure->signedprekeyid; } complete: return result; } static int session_state_deserialize_protobuf_sender_chain( uint32_t session_version, session_state_sender_chain *chain, Textsecure__SessionStructure__Chain *chain_structure, signal_context *global_context) { int result = 0; hkdf_context *kdf = 0; ec_key_pair *sender_ratchet_key_pair = 0; ec_public_key *sender_ratchet_key_public = 0; ec_private_key *sender_ratchet_key_private = 0; ratchet_chain_key *sender_chain_key = 0; if(chain_structure->has_senderratchetkey && chain_structure->has_senderratchetkeyprivate) { result = curve_decode_point(&sender_ratchet_key_public, chain_structure->senderratchetkey.data, chain_structure->senderratchetkey.len, global_context); if(result < 0) { goto complete; } result = curve_decode_private_point(&sender_ratchet_key_private, chain_structure->senderratchetkeyprivate.data, chain_structure->senderratchetkeyprivate.len, global_context); if(result < 0) { goto complete; } result = ec_key_pair_create(&sender_ratchet_key_pair, sender_ratchet_key_public, sender_ratchet_key_private); if(result < 0) { goto complete; } } if(chain_structure->chainkey && chain_structure->chainkey->has_key && chain_structure->chainkey->has_index) { result = hkdf_create(&kdf, (int)session_version, global_context); if(result < 0) { goto complete; } result = ratchet_chain_key_create( &sender_chain_key, kdf, chain_structure->chainkey->key.data, chain_structure->chainkey->key.len, chain_structure->chainkey->index, global_context); if(result < 0) { goto complete; } } chain->sender_ratchet_key_pair = sender_ratchet_key_pair; chain->chain_key = sender_chain_key; complete: SIGNAL_UNREF(kdf); SIGNAL_UNREF(sender_ratchet_key_public); SIGNAL_UNREF(sender_ratchet_key_private); if(result < 0) { SIGNAL_UNREF(sender_ratchet_key_pair); SIGNAL_UNREF(sender_chain_key); } return result; } static int session_state_deserialize_protobuf_receiver_chain( uint32_t session_version, session_state_receiver_chain *chain, Textsecure__SessionStructure__Chain *chain_structure, signal_context *global_context) { int result = 0; hkdf_context *kdf = 0; ec_public_key *sender_ratchet_key = 0; ratchet_chain_key *chain_key = 0; message_keys_node *message_keys_head = 0; if(chain_structure->has_senderratchetkey) { result = curve_decode_point(&sender_ratchet_key, chain_structure->senderratchetkey.data, chain_structure->senderratchetkey.len, global_context); if(result < 0) { goto complete; } } if(chain_structure->chainkey && chain_structure->chainkey->has_key && chain_structure->chainkey->has_index) { result = hkdf_create(&kdf, (int)session_version, global_context); if(result < 0) { goto complete; } result = ratchet_chain_key_create( &chain_key, kdf, chain_structure->chainkey->key.data, chain_structure->chainkey->key.len, chain_structure->chainkey->index, global_context); if(result < 0) { goto complete; } } if(chain_structure->n_messagekeys > 0) { unsigned int i; for(i = 0; i < chain_structure->n_messagekeys; i++) { Textsecure__SessionStructure__Chain__MessageKey *key_structure = chain_structure->messagekeys[i]; message_keys_node *node = malloc(sizeof(message_keys_node)); if(!node) { result = SG_ERR_NOMEM; goto complete; } memset(node, 0, sizeof(message_keys_node)); if(key_structure->has_index) { node->message_key.counter = key_structure->index; } if(key_structure->has_cipherkey && key_structure->cipherkey.len == sizeof(node->message_key.cipher_key)) { memcpy(node->message_key.cipher_key, key_structure->cipherkey.data, key_structure->cipherkey.len); } if(key_structure->has_mackey && key_structure->mackey.len == sizeof(node->message_key.mac_key)) { memcpy(node->message_key.mac_key, key_structure->mackey.data, key_structure->mackey.len); } if(key_structure->has_iv && key_structure->iv.len == sizeof(node->message_key.iv)) { memcpy(node->message_key.iv, key_structure->iv.data, key_structure->iv.len); } DL_APPEND(message_keys_head, node); } } chain->sender_ratchet_key = sender_ratchet_key; chain->chain_key = chain_key; chain->message_keys_head = message_keys_head; complete: SIGNAL_UNREF(kdf); if(result < 0) { SIGNAL_UNREF(sender_ratchet_key); SIGNAL_UNREF(chain_key); if(message_keys_head) { message_keys_node *cur_node; message_keys_node *tmp_node; DL_FOREACH_SAFE(message_keys_head, cur_node, tmp_node) { DL_DELETE(message_keys_head, cur_node); signal_explicit_bzero(&cur_node->message_key, sizeof(ratchet_message_keys)); free(cur_node); } } } return result; } int session_state_copy(session_state **state, session_state *other_state, signal_context *global_context) { int result = 0; signal_buffer *buffer = 0; size_t len = 0; uint8_t *data = 0; assert(other_state); assert(global_context); result = session_state_serialize(&buffer, other_state); if(result < 0) { goto complete; } data = signal_buffer_data(buffer); len = signal_buffer_len(buffer); result = session_state_deserialize(state, data, len, global_context); if(result < 0) { goto complete; } complete: if(buffer) { signal_buffer_free(buffer); } return result; } void session_state_set_session_version(session_state *state, uint32_t version) { assert(state); state->session_version = version; } uint32_t session_state_get_session_version(const session_state *state) { assert(state); return state->session_version; } void session_state_set_local_identity_key(session_state *state, ec_public_key *identity_key) { assert(state); assert(identity_key); if(state->local_identity_public) { SIGNAL_UNREF(state->local_identity_public); } SIGNAL_REF(identity_key); state->local_identity_public = identity_key; } ec_public_key *session_state_get_local_identity_key(const session_state *state) { assert(state); return state->local_identity_public; } void session_state_set_remote_identity_key(session_state *state, ec_public_key *identity_key) { assert(state); assert(identity_key); if(state->remote_identity_public) { SIGNAL_UNREF(state->remote_identity_public); } SIGNAL_REF(identity_key); state->remote_identity_public = identity_key; } ec_public_key *session_state_get_remote_identity_key(const session_state *state) { assert(state); return state->remote_identity_public; } void session_state_set_root_key(session_state *state, ratchet_root_key *root_key) { assert(state); assert(root_key); if(state->root_key) { SIGNAL_UNREF(state->root_key); } SIGNAL_REF(root_key); state->root_key = root_key; } ratchet_root_key *session_state_get_root_key(const session_state *state) { assert(state); return state->root_key; } void session_state_set_previous_counter(session_state *state, uint32_t counter) { assert(state); state->previous_counter = counter; } uint32_t session_state_get_previous_counter(const session_state *state) { assert(state); return state->previous_counter; } void session_state_set_sender_chain(session_state *state, ec_key_pair *sender_ratchet_key_pair, ratchet_chain_key *chain_key) { assert(state); assert(sender_ratchet_key_pair); assert(chain_key); state->has_sender_chain = 1; if(state->sender_chain.sender_ratchet_key_pair) { SIGNAL_UNREF(state->sender_chain.sender_ratchet_key_pair); } SIGNAL_REF(sender_ratchet_key_pair); state->sender_chain.sender_ratchet_key_pair = sender_ratchet_key_pair; if(state->sender_chain.chain_key) { SIGNAL_UNREF(state->sender_chain.chain_key); } SIGNAL_REF(chain_key); state->sender_chain.chain_key = chain_key; } ec_public_key *session_state_get_sender_ratchet_key(const session_state *state) { assert(state); if(state->sender_chain.sender_ratchet_key_pair) { return ec_key_pair_get_public(state->sender_chain.sender_ratchet_key_pair); } else { return 0; } } ec_key_pair *session_state_get_sender_ratchet_key_pair(const session_state *state) { assert(state); return state->sender_chain.sender_ratchet_key_pair; } ratchet_chain_key *session_state_get_sender_chain_key(const session_state *state) { assert(state); return state->sender_chain.chain_key; } int session_state_set_sender_chain_key(session_state *state, ratchet_chain_key *chain_key) { assert(state); if(state->has_sender_chain) { if(state->sender_chain.chain_key) { SIGNAL_UNREF(state->sender_chain.chain_key); } SIGNAL_REF(chain_key); state->sender_chain.chain_key = chain_key; return 0; } else { return SG_ERR_UNKNOWN; } } int session_state_has_sender_chain(const session_state *state) { assert(state); return state->has_sender_chain; } int session_state_has_message_keys(session_state *state, ec_public_key *sender_ephemeral, uint32_t counter) { session_state_receiver_chain *chain = 0; message_keys_node *cur_node = 0; assert(state); assert(sender_ephemeral); chain = session_state_find_receiver_chain(state, sender_ephemeral); if(!chain) { return 0; } DL_FOREACH(chain->message_keys_head, cur_node) { if(cur_node->message_key.counter == counter) { return 1; } } return 0; } int session_state_remove_message_keys(session_state *state, ratchet_message_keys *message_keys_result, ec_public_key *sender_ephemeral, uint32_t counter) { session_state_receiver_chain *chain = 0; message_keys_node *cur_node = 0; message_keys_node *tmp_node = 0; assert(state); assert(message_keys_result); assert(sender_ephemeral); chain = session_state_find_receiver_chain(state, sender_ephemeral); if(!chain) { return 0; } DL_FOREACH_SAFE(chain->message_keys_head, cur_node, tmp_node) { if(cur_node->message_key.counter == counter) { memcpy(message_keys_result, &(cur_node->message_key), sizeof(ratchet_message_keys)); DL_DELETE(chain->message_keys_head, cur_node); signal_explicit_bzero(&cur_node->message_key, sizeof(ratchet_message_keys)); free(cur_node); return 1; } } return 0; } int session_state_set_message_keys(session_state *state, ec_public_key *sender_ephemeral, ratchet_message_keys *message_keys) { session_state_receiver_chain *chain = 0; message_keys_node *node = 0; int count; assert(state); assert(sender_ephemeral); assert(message_keys); chain = session_state_find_receiver_chain(state, sender_ephemeral); if(!chain) { return 0; } node = malloc(sizeof(message_keys_node)); if(!node) { return SG_ERR_NOMEM; } memcpy(&(node->message_key), message_keys, sizeof(ratchet_message_keys)); node->prev = 0; node->next = 0; DL_APPEND(chain->message_keys_head, node); DL_COUNT(chain->message_keys_head, node, count); while(count > MAX_MESSAGE_KEYS) { node = chain->message_keys_head; DL_DELETE(chain->message_keys_head, node); signal_explicit_bzero(&node->message_key, sizeof(ratchet_message_keys)); free(node); --count; } return 0; } int session_state_add_receiver_chain(session_state *state, ec_public_key *sender_ratchet_key, ratchet_chain_key *chain_key) { session_state_receiver_chain *node; int count; assert(state); assert(sender_ratchet_key); assert(chain_key); node = malloc(sizeof(session_state_receiver_chain)); if(!node) { return SG_ERR_NOMEM; } memset(node, 0, sizeof(session_state_receiver_chain)); SIGNAL_REF(sender_ratchet_key); node->sender_ratchet_key = sender_ratchet_key; SIGNAL_REF(chain_key); node->chain_key = chain_key; DL_APPEND(state->receiver_chain_head, node); DL_COUNT(state->receiver_chain_head, node, count); while(count > 5) { node = state->receiver_chain_head; DL_DELETE(state->receiver_chain_head, node); session_state_free_receiver_chain_node(node); --count; } return 0; } int session_state_set_receiver_chain_key(session_state *state, ec_public_key *sender_ephemeral, ratchet_chain_key *chain_key) { int result = 0; session_state_receiver_chain *node; assert(state); assert(sender_ephemeral); assert(chain_key); node = session_state_find_receiver_chain(state, sender_ephemeral); if(!node) { signal_log(state->global_context, SG_LOG_WARNING, "Couldn't find receiver chain to set chain key on"); result = SG_ERR_UNKNOWN; goto complete; } SIGNAL_UNREF(node->chain_key); SIGNAL_REF(chain_key); node->chain_key = chain_key; complete: return result; } static session_state_receiver_chain *session_state_find_receiver_chain(const session_state *state, const ec_public_key *sender_ephemeral) { session_state_receiver_chain *result = 0; session_state_receiver_chain *cur_node; DL_FOREACH(state->receiver_chain_head, cur_node) { if(ec_public_key_compare(cur_node->sender_ratchet_key, sender_ephemeral) == 0) { result = cur_node; break; } } return result; } ratchet_chain_key *session_state_get_receiver_chain_key(session_state *state, ec_public_key *sender_ephemeral) { ratchet_chain_key *result = 0; session_state_receiver_chain *node = session_state_find_receiver_chain(state, sender_ephemeral); if(node) { result = node->chain_key; } return result; } void session_state_set_pending_key_exchange(session_state *state, uint32_t sequence, ec_key_pair *our_base_key, ec_key_pair *our_ratchet_key, ratchet_identity_key_pair *our_identity_key) { assert(state); assert(our_base_key); assert(our_ratchet_key); assert(our_identity_key); if(state->pending_key_exchange.local_base_key) { SIGNAL_UNREF(state->pending_key_exchange.local_base_key); state->pending_key_exchange.local_base_key = 0; } if(state->pending_key_exchange.local_ratchet_key) { SIGNAL_UNREF(state->pending_key_exchange.local_ratchet_key); state->pending_key_exchange.local_ratchet_key = 0; } if(state->pending_key_exchange.local_identity_key) { SIGNAL_UNREF(state->pending_key_exchange.local_identity_key); state->pending_key_exchange.local_identity_key = 0; } SIGNAL_REF(our_base_key); SIGNAL_REF(our_ratchet_key); SIGNAL_REF(our_identity_key); state->has_pending_key_exchange = 1; state->pending_key_exchange.sequence = sequence; state->pending_key_exchange.local_base_key = our_base_key; state->pending_key_exchange.local_ratchet_key = our_ratchet_key; state->pending_key_exchange.local_identity_key = our_identity_key; } uint32_t session_state_get_pending_key_exchange_sequence(session_state *state) { assert(state); if(state->has_pending_key_exchange) { return state->pending_key_exchange.sequence; } else { return 0; } } ec_key_pair *session_state_get_pending_key_exchange_base_key(const session_state *state) { assert(state); if(state->has_pending_key_exchange) { return state->pending_key_exchange.local_base_key; } else { return 0; } } ec_key_pair *session_state_get_pending_key_exchange_ratchet_key(const session_state *state) { assert(state); if(state->has_pending_key_exchange) { return state->pending_key_exchange.local_ratchet_key; } else { return 0; } } ratchet_identity_key_pair *session_state_get_pending_key_exchange_identity_key(const session_state *state) { assert(state); if(state->has_pending_key_exchange) { return state->pending_key_exchange.local_identity_key; } else { return 0; } } int session_state_has_pending_key_exchange(const session_state *state) { assert(state); return state->has_pending_key_exchange; } void session_state_set_unacknowledged_pre_key_message(session_state *state, const uint32_t *pre_key_id, uint32_t signed_pre_key_id, ec_public_key *base_key) { assert(state); assert(base_key); if(state->pending_pre_key.base_key) { SIGNAL_UNREF(state->pending_pre_key.base_key); state->pending_pre_key.base_key = 0; } SIGNAL_REF(base_key); state->has_pending_pre_key = 1; if(pre_key_id) { state->pending_pre_key.has_pre_key_id = 1; state->pending_pre_key.pre_key_id = *pre_key_id; } else { state->pending_pre_key.has_pre_key_id = 0; state->pending_pre_key.pre_key_id = 0; } state->pending_pre_key.signed_pre_key_id = signed_pre_key_id; state->pending_pre_key.base_key = base_key; } int session_state_unacknowledged_pre_key_message_has_pre_key_id(const session_state *state) { assert(state); return state->pending_pre_key.has_pre_key_id; } uint32_t session_state_unacknowledged_pre_key_message_get_pre_key_id(const session_state *state) { assert(state); assert(state->pending_pre_key.has_pre_key_id); return state->pending_pre_key.pre_key_id; } uint32_t session_state_unacknowledged_pre_key_message_get_signed_pre_key_id(const session_state *state) { assert(state); return state->pending_pre_key.signed_pre_key_id; } ec_public_key *session_state_unacknowledged_pre_key_message_get_base_key(const session_state *state) { assert(state); return state->pending_pre_key.base_key; } int session_state_has_unacknowledged_pre_key_message(const session_state *state) { assert(state); return state->has_pending_pre_key; } void session_state_clear_unacknowledged_pre_key_message(session_state *state) { assert(state); if(state->pending_pre_key.base_key) { SIGNAL_UNREF(state->pending_pre_key.base_key); } memset(&state->pending_pre_key, 0, sizeof(state->pending_pre_key)); state->has_pending_pre_key = 0; } void session_state_set_remote_registration_id(session_state *state, uint32_t id) { assert(state); state->remote_registration_id = id; } uint32_t session_state_get_remote_registration_id(const session_state *state) { assert(state); return state->remote_registration_id; } void session_state_set_local_registration_id(session_state *state, uint32_t id) { assert(state); state->local_registration_id = id; } uint32_t session_state_get_local_registration_id(const session_state *state) { assert(state); return state->local_registration_id; } void session_state_set_needs_refresh(session_state *state, int value) { assert(state); assert(value == 0 || value == 1); state->needs_refresh = value; } int session_state_get_needs_refresh(const session_state *state) { assert(state); return state->needs_refresh; } void session_state_set_alice_base_key(session_state *state, ec_public_key *key) { assert(state); assert(key); if(state->alice_base_key) { SIGNAL_UNREF(state->alice_base_key); } SIGNAL_REF(key); state->alice_base_key = key; } ec_public_key *session_state_get_alice_base_key(const session_state *state) { assert(state); return state->alice_base_key; } static void session_state_free_sender_chain(session_state *state) { if(state->sender_chain.sender_ratchet_key_pair) { SIGNAL_UNREF(state->sender_chain.sender_ratchet_key_pair); state->sender_chain.sender_ratchet_key_pair = 0; } if(state->sender_chain.chain_key) { SIGNAL_UNREF(state->sender_chain.chain_key); state->sender_chain.chain_key = 0; } } static void session_state_free_receiver_chain_node(session_state_receiver_chain *node) { if(node->sender_ratchet_key) { SIGNAL_UNREF(node->sender_ratchet_key); } if(node->chain_key) { SIGNAL_UNREF(node->chain_key); } if(node->message_keys_head) { message_keys_node *cur_node; message_keys_node *tmp_node; DL_FOREACH_SAFE(node->message_keys_head, cur_node, tmp_node) { DL_DELETE(node->message_keys_head, cur_node); signal_explicit_bzero(&cur_node->message_key, sizeof(ratchet_message_keys)); free(cur_node); } node->message_keys_head = 0; } free(node); } static void session_state_free_receiver_chain(session_state *state) { session_state_receiver_chain *cur_node; session_state_receiver_chain *tmp_node; DL_FOREACH_SAFE(state->receiver_chain_head, cur_node, tmp_node) { DL_DELETE(state->receiver_chain_head, cur_node); session_state_free_receiver_chain_node(cur_node); } state->receiver_chain_head = 0; } void session_state_destroy(signal_type_base *type) { session_state *state = (session_state *)type; if(state->local_identity_public) { SIGNAL_UNREF(state->local_identity_public); } if(state->remote_identity_public) { SIGNAL_UNREF(state->remote_identity_public); } if(state->root_key) { SIGNAL_UNREF(state->root_key); } session_state_free_sender_chain(state); session_state_free_receiver_chain(state); if(state->has_pending_key_exchange) { if(state->pending_key_exchange.local_base_key) { SIGNAL_UNREF(state->pending_key_exchange.local_base_key); } if(state->pending_key_exchange.local_ratchet_key) { SIGNAL_UNREF(state->pending_key_exchange.local_ratchet_key); } if(state->pending_key_exchange.local_identity_key) { SIGNAL_UNREF(state->pending_key_exchange.local_identity_key); } } if(state->has_pending_pre_key) { if(state->pending_pre_key.base_key) { SIGNAL_UNREF(state->pending_pre_key.base_key); } } if(state->alice_base_key) { SIGNAL_UNREF(state->alice_base_key); } free(state); } libsignal-protocol-c-2.3.3/src/session_state.h000066400000000000000000000114061363751346500214040ustar00rootroot00000000000000#ifndef SESSION_STATE_H #define SESSION_STATE_H #include #include #include "signal_protocol_types.h" #ifdef __cplusplus extern "C" { #endif /*------------------------------------------------------------------------*/ int session_state_create(session_state **state, signal_context *global_context); int session_state_serialize(signal_buffer **buffer, session_state *state); int session_state_deserialize(session_state **state, const uint8_t *data, size_t len, signal_context *global_context); int session_state_copy(session_state **state, session_state *other_state, signal_context *global_context); void session_state_set_session_version(session_state *state, uint32_t version); uint32_t session_state_get_session_version(const session_state *state); void session_state_set_local_identity_key(session_state *state, ec_public_key *identity_key); ec_public_key *session_state_get_local_identity_key(const session_state *state); void session_state_set_remote_identity_key(session_state *state, ec_public_key *identity_key); ec_public_key *session_state_get_remote_identity_key(const session_state *state); void session_state_set_root_key(session_state *state, ratchet_root_key *root_key); ratchet_root_key *session_state_get_root_key(const session_state *state); void session_state_set_previous_counter(session_state *state, uint32_t counter); uint32_t session_state_get_previous_counter(const session_state *state); void session_state_set_sender_chain(session_state *state, ec_key_pair *sender_ratchet_key_pair, ratchet_chain_key *chain_key); ec_public_key *session_state_get_sender_ratchet_key(const session_state *state); ec_key_pair *session_state_get_sender_ratchet_key_pair(const session_state *state); ratchet_chain_key *session_state_get_sender_chain_key(const session_state *state); int session_state_set_sender_chain_key(session_state *state, ratchet_chain_key *chain_key); int session_state_has_sender_chain(const session_state *state); int session_state_has_message_keys(session_state *state, ec_public_key *sender_ephemeral, uint32_t counter); int session_state_remove_message_keys(session_state *state, ratchet_message_keys *message_keys_result, ec_public_key *sender_ephemeral, uint32_t counter); int session_state_set_message_keys(session_state *state, ec_public_key *sender_ephemeral, ratchet_message_keys *message_keys); int session_state_add_receiver_chain(session_state *state, ec_public_key *sender_ratchet_key, ratchet_chain_key *chain_key); int session_state_set_receiver_chain_key(session_state *state, ec_public_key *sender_ephemeral, ratchet_chain_key *chain_key); ratchet_chain_key *session_state_get_receiver_chain_key(session_state *state, ec_public_key *sender_ephemeral); void session_state_set_pending_key_exchange(session_state *state, uint32_t sequence, ec_key_pair *our_base_key, ec_key_pair *our_ratchet_key, ratchet_identity_key_pair *our_identity_key); uint32_t session_state_get_pending_key_exchange_sequence(session_state *state); ec_key_pair *session_state_get_pending_key_exchange_base_key(const session_state *state); ec_key_pair *session_state_get_pending_key_exchange_ratchet_key(const session_state *state); ratchet_identity_key_pair *session_state_get_pending_key_exchange_identity_key(const session_state *state); int session_state_has_pending_key_exchange(const session_state *state); void session_state_set_unacknowledged_pre_key_message(session_state *state, const uint32_t *pre_key_id, uint32_t signed_pre_key_id, ec_public_key *base_key); int session_state_unacknowledged_pre_key_message_has_pre_key_id(const session_state *state); uint32_t session_state_unacknowledged_pre_key_message_get_pre_key_id(const session_state *state); uint32_t session_state_unacknowledged_pre_key_message_get_signed_pre_key_id(const session_state *state); ec_public_key *session_state_unacknowledged_pre_key_message_get_base_key(const session_state *state); int session_state_has_unacknowledged_pre_key_message(const session_state *state); void session_state_clear_unacknowledged_pre_key_message(session_state *state); void session_state_set_remote_registration_id(session_state *state, uint32_t id); uint32_t session_state_get_remote_registration_id(const session_state *state); void session_state_set_local_registration_id(session_state *state, uint32_t id); uint32_t session_state_get_local_registration_id(const session_state *state); void session_state_set_needs_refresh(session_state *state, int value); int session_state_get_needs_refresh(const session_state *state); void session_state_set_alice_base_key(session_state *state, ec_public_key *key); ec_public_key *session_state_get_alice_base_key(const session_state *state); void session_state_destroy(signal_type_base *type); #ifdef __cplusplus } #endif #endif /* SESSION_STATE_H */ libsignal-protocol-c-2.3.3/src/signal_protocol.c000066400000000000000000001006221363751346500217110ustar00rootroot00000000000000#include "signal_protocol.h" #include #include #include #include #include #include #include "signal_protocol_internal.h" #include "signal_utarray.h" #ifdef _WINDOWS #include "Windows.h" #include "WinBase.h" #endif #ifdef DEBUG_REFCOUNT int type_ref_count = 0; int type_unref_count = 0; #endif #define MIN(a,b) (((a)<(b))?(a):(b)) struct signal_protocol_store_context { signal_context *global_context; signal_protocol_session_store session_store; signal_protocol_pre_key_store pre_key_store; signal_protocol_signed_pre_key_store signed_pre_key_store; signal_protocol_identity_key_store identity_key_store; signal_protocol_sender_key_store sender_key_store; }; void signal_type_init(signal_type_base *instance, void (*destroy_func)(signal_type_base *instance)) { instance->ref_count = 1; instance->destroy = destroy_func; #ifdef DEBUG_REFCOUNT type_ref_count++; #endif } void signal_type_ref(signal_type_base *instance) { #ifdef DEBUG_REFCOUNT type_ref_count++; #endif assert(instance); assert(instance->ref_count > 0); instance->ref_count++; } void signal_type_unref(signal_type_base *instance) { if(instance) { #ifdef DEBUG_REFCOUNT type_unref_count++; #endif assert(instance->ref_count > 0); if(instance->ref_count > 1) { instance->ref_count--; } else { instance->destroy(instance); } } } #ifdef DEBUG_REFCOUNT int signal_type_ref_count(signal_type_base *instance) { if(!instance) { return 0; } return instance->ref_count; } #endif /*------------------------------------------------------------------------*/ signal_buffer *signal_buffer_alloc(size_t len) { signal_buffer *buffer; if(len > (SIZE_MAX - sizeof(struct signal_buffer)) / sizeof(uint8_t)) { return 0; } buffer = malloc(sizeof(struct signal_buffer) + (sizeof(uint8_t) * len)); if(buffer) { buffer->len = len; } return buffer; } signal_buffer *signal_buffer_create(const uint8_t *data, size_t len) { signal_buffer *buffer = signal_buffer_alloc(len); if(!buffer) { return 0; } memcpy(buffer->data, data, len); return buffer; } signal_buffer *signal_buffer_copy(const signal_buffer *buffer) { return signal_buffer_create(buffer->data, buffer->len); } signal_buffer *signal_buffer_n_copy(const signal_buffer *buffer, size_t n) { size_t len = MIN(buffer->len, n); return signal_buffer_create(buffer->data, len); } signal_buffer *signal_buffer_append(signal_buffer *buffer, const uint8_t *data, size_t len) { signal_buffer *tmp_buffer; size_t previous_size = buffer->len; size_t previous_alloc = sizeof(struct signal_buffer) + (sizeof(uint8_t) * previous_size); if(len > (SIZE_MAX - previous_alloc)) { return 0; } tmp_buffer = realloc(buffer, previous_alloc + (sizeof(uint8_t) * len)); if(!tmp_buffer) { return 0; } memcpy(tmp_buffer->data + previous_size, data, len); tmp_buffer->len = previous_size + len; return tmp_buffer; } uint8_t *signal_buffer_data(signal_buffer *buffer) { return buffer->data; } const uint8_t *signal_buffer_const_data(const signal_buffer *buffer) { return buffer->data; } size_t signal_buffer_len(const signal_buffer *buffer) { return buffer->len; } int signal_buffer_compare(signal_buffer *buffer1, signal_buffer *buffer2) { if(buffer1 == buffer2) { return 0; } else if(buffer1 == 0 && buffer2 != 0) { return -1; } else if(buffer1 != 0 && buffer2 == 0) { return 1; } else { if(buffer1->len < buffer2->len) { return -1; } else if(buffer1->len > buffer2->len) { return 1; } else { return signal_constant_memcmp(buffer1->data, buffer2->data, buffer1->len); } } } void signal_buffer_free(signal_buffer *buffer) { if(buffer) { free(buffer); } } void signal_buffer_bzero_free(signal_buffer *buffer) { if(buffer) { signal_explicit_bzero(buffer->data, buffer->len); free(buffer); } } /*------------------------------------------------------------------------*/ struct signal_buffer_list { UT_array *values; }; signal_buffer_list *signal_buffer_list_alloc(void) { int result = 0; signal_buffer_list *list = malloc(sizeof(signal_buffer_list)); if(!list) { result = SG_ERR_NOMEM; goto complete; } memset(list, 0, sizeof(signal_buffer_list)); utarray_new(list->values, &ut_ptr_icd); complete: if(result < 0) { if(list) { free(list); } return 0; } else { return list; } } signal_buffer_list *signal_buffer_list_copy(const signal_buffer_list *list) { int result = 0; signal_buffer_list *result_list = 0; signal_buffer *buffer_copy = 0; unsigned int list_size; unsigned int i; result_list = signal_buffer_list_alloc(); if(!result_list) { result = SG_ERR_NOMEM; goto complete; } list_size = utarray_len(list->values); utarray_reserve(result_list->values, list_size); for(i = 0; i < list_size; i++) { signal_buffer **buffer = (signal_buffer**)utarray_eltptr(list->values, i); buffer_copy = signal_buffer_copy(*buffer); utarray_push_back(result_list->values, &buffer_copy); buffer_copy = 0; } complete: if(result < 0) { signal_buffer_free(buffer_copy); signal_buffer_list_free(result_list); return 0; } else { return result_list; } } int signal_buffer_list_push_back(signal_buffer_list *list, signal_buffer *buffer) { int result = 0; assert(list); utarray_push_back(list->values, &buffer); complete: return result; } unsigned int signal_buffer_list_size(signal_buffer_list *list) { assert(list); return utarray_len(list->values); } signal_buffer *signal_buffer_list_at(signal_buffer_list *list, unsigned int index) { signal_buffer **value = 0; assert(list); assert(index < utarray_len(list->values)); value = (signal_buffer**)utarray_eltptr(list->values, index); assert(*value); return *value; } void signal_buffer_list_free(signal_buffer_list *list) { unsigned int size; unsigned int i; signal_buffer **p; if(list) { size = utarray_len(list->values); for (i = 0; i < size; i++) { p = (signal_buffer **)utarray_eltptr(list->values, i); signal_buffer_free(*p); } utarray_free(list->values); free(list); } } void signal_buffer_list_bzero_free(signal_buffer_list *list) { unsigned int size; unsigned int i; signal_buffer **p; if(list) { size = utarray_len(list->values); for (i = 0; i < size; i++) { p = (signal_buffer **)utarray_eltptr(list->values, i); signal_buffer_bzero_free(*p); } utarray_free(list->values); free(list); } } /*------------------------------------------------------------------------*/ struct signal_int_list { UT_array *values; }; signal_int_list *signal_int_list_alloc() { int result = 0; signal_int_list *list = malloc(sizeof(signal_int_list)); if(!list) { result = SG_ERR_NOMEM; goto complete; } memset(list, 0, sizeof(signal_int_list)); utarray_new(list->values, &ut_int_icd); complete: if(result < 0) { if(list) { free(list); } return 0; } else { return list; } } int signal_int_list_push_back(signal_int_list *list, int value) { int result = 0; assert(list); utarray_push_back(list->values, &value); complete: return result; } unsigned int signal_int_list_size(signal_int_list *list) { assert(list); return utarray_len(list->values); } int signal_int_list_at(signal_int_list *list, unsigned int index) { int *value = 0; assert(list); assert(index < utarray_len(list->values)); value = (int *)utarray_eltptr(list->values, index); assert(value); return *value; } void signal_int_list_free(signal_int_list *list) { if(list) { utarray_free(list->values); free(list); } } /*------------------------------------------------------------------------*/ int signal_context_create(signal_context **context, void *user_data) { *context = malloc(sizeof(signal_context)); if(!(*context)) { return SG_ERR_NOMEM; } memset(*context, 0, sizeof(signal_context)); (*context)->user_data = user_data; #ifdef DEBUG_REFCOUNT type_ref_count = 0; type_unref_count = 0; #endif return 0; } int signal_context_set_crypto_provider(signal_context *context, const signal_crypto_provider *crypto_provider) { assert(context); if(!crypto_provider || !crypto_provider->hmac_sha256_init_func || !crypto_provider->hmac_sha256_update_func || !crypto_provider->hmac_sha256_final_func || !crypto_provider->hmac_sha256_cleanup_func) { return SG_ERR_INVAL; } memcpy(&(context->crypto_provider), crypto_provider, sizeof(signal_crypto_provider)); return 0; } int signal_context_set_locking_functions(signal_context *context, void (*lock)(void *user_data), void (*unlock)(void *user_data)) { assert(context); if((lock && !unlock) || (!lock && unlock)) { return SG_ERR_INVAL; } context->lock = lock; context->unlock = unlock; return 0; } int signal_context_set_log_function(signal_context *context, void (*log)(int level, const char *message, size_t len, void *user_data)) { assert(context); context->log = log; return 0; } void signal_context_destroy(signal_context *context) { #ifdef DEBUG_REFCOUNT fprintf(stderr, "Global REF count: %d\n", type_ref_count); fprintf(stderr, "Global UNREF count: %d\n", type_unref_count); #endif if(context) { free(context); } } /*------------------------------------------------------------------------*/ int signal_crypto_random(signal_context *context, uint8_t *data, size_t len) { assert(context); assert(context->crypto_provider.random_func); return context->crypto_provider.random_func(data, len, context->crypto_provider.user_data); } int signal_hmac_sha256_init(signal_context *context, void **hmac_context, const uint8_t *key, size_t key_len) { assert(context); assert(context->crypto_provider.hmac_sha256_init_func); return context->crypto_provider.hmac_sha256_init_func(hmac_context, key, key_len, context->crypto_provider.user_data); } int signal_hmac_sha256_update(signal_context *context, void *hmac_context, const uint8_t *data, size_t data_len) { assert(context); assert(context->crypto_provider.hmac_sha256_update_func); return context->crypto_provider.hmac_sha256_update_func(hmac_context, data, data_len, context->crypto_provider.user_data); } int signal_hmac_sha256_final(signal_context *context, void *hmac_context, signal_buffer **output) { assert(context); assert(context->crypto_provider.hmac_sha256_final_func); return context->crypto_provider.hmac_sha256_final_func(hmac_context, output, context->crypto_provider.user_data); } void signal_hmac_sha256_cleanup(signal_context *context, void *hmac_context) { assert(context); assert(context->crypto_provider.hmac_sha256_cleanup_func); context->crypto_provider.hmac_sha256_cleanup_func(hmac_context, context->crypto_provider.user_data); } int signal_sha512_digest_init(signal_context *context, void **digest_context) { assert(context); assert(context->crypto_provider.sha512_digest_init_func); return context->crypto_provider.sha512_digest_init_func(digest_context, context->crypto_provider.user_data); } int signal_sha512_digest_update(signal_context *context, void *digest_context, const uint8_t *data, size_t data_len) { assert(context); assert(context->crypto_provider.sha512_digest_update_func); return context->crypto_provider.sha512_digest_update_func(digest_context, data, data_len, context->crypto_provider.user_data); } int signal_sha512_digest_final(signal_context *context, void *digest_context, signal_buffer **output) { assert(context); assert(context->crypto_provider.sha512_digest_final_func); return context->crypto_provider.sha512_digest_final_func(digest_context, output, context->crypto_provider.user_data); } void signal_sha512_digest_cleanup(signal_context *context, void *digest_context) { assert(context); assert(context->crypto_provider.sha512_digest_cleanup_func); return context->crypto_provider.sha512_digest_cleanup_func(digest_context, context->crypto_provider.user_data); } int signal_encrypt(signal_context *context, signal_buffer **output, int cipher, const uint8_t *key, size_t key_len, const uint8_t *iv, size_t iv_len, const uint8_t *plaintext, size_t plaintext_len) { assert(context); assert(context->crypto_provider.encrypt_func); return context->crypto_provider.encrypt_func( output, cipher, key, key_len, iv, iv_len, plaintext, plaintext_len, context->crypto_provider.user_data); } int signal_decrypt(signal_context *context, signal_buffer **output, int cipher, const uint8_t *key, size_t key_len, const uint8_t *iv, size_t iv_len, const uint8_t *ciphertext, size_t ciphertext_len) { assert(context); assert(context->crypto_provider.decrypt_func); return context->crypto_provider.decrypt_func( output, cipher, key, key_len, iv, iv_len, ciphertext, ciphertext_len, context->crypto_provider.user_data); } void signal_lock(signal_context *context) { if(context->lock) { context->lock(context->user_data); } } void signal_unlock(signal_context *context) { if(context->unlock) { context->unlock(context->user_data); } } void signal_log(signal_context *context, int level, const char *format, ...) { char buf[256]; int n; if(context && context->log) { va_list args; va_start(args, format); n = vsnprintf(buf, sizeof(buf), format, args); va_end(args); if(n > 0) { context->log(level, buf, strlen(buf), context->user_data); } } } void signal_explicit_bzero(void *v, size_t n) { #ifdef HAVE_SECUREZEROMEMORY SecureZeroMemory(v, n); #elif HAVE_MEMSET_S memset_s(v, n, 0, n); #else volatile unsigned char *p = v; while(n--) *p++ = 0; #endif } int signal_constant_memcmp(const void *s1, const void *s2, size_t n) { size_t i; const unsigned char *c1 = (const unsigned char *) s1; const unsigned char *c2 = (const unsigned char *) s2; unsigned char result = 0; for (i = 0; i < n; i++) { result |= c1[i] ^ c2[i]; } return result; } void signal_protocol_str_serialize_protobuf(ProtobufCBinaryData *buffer, const char *str) { assert(buffer); assert(str); buffer->data = (uint8_t *)str; buffer->len = strlen(str); } char *signal_protocol_str_deserialize_protobuf(ProtobufCBinaryData *buffer) { char *str = 0; assert(buffer); str = malloc(buffer->len + 1); if(!str) { return 0; } memcpy(str, buffer->data, buffer->len); str[buffer->len] = '\0'; return str; } /*------------------------------------------------------------------------*/ int signal_protocol_store_context_create(signal_protocol_store_context **context, signal_context *global_context) { assert(global_context); *context = malloc(sizeof(signal_protocol_store_context)); if(!(*context)) { return SG_ERR_NOMEM; } memset(*context, 0, sizeof(signal_protocol_store_context)); (*context)->global_context = global_context; return 0; } int signal_protocol_store_context_set_session_store(signal_protocol_store_context *context, const signal_protocol_session_store *store) { if(!store) { return SG_ERR_INVAL; } memcpy(&(context->session_store), store, sizeof(signal_protocol_session_store)); return 0; } int signal_protocol_store_context_set_pre_key_store(signal_protocol_store_context *context, const signal_protocol_pre_key_store *store) { if(!store) { return SG_ERR_INVAL; } memcpy(&(context->pre_key_store), store, sizeof(signal_protocol_pre_key_store)); return 0; } int signal_protocol_store_context_set_signed_pre_key_store(signal_protocol_store_context *context, const signal_protocol_signed_pre_key_store *store) { if(!store) { return SG_ERR_INVAL; } memcpy(&(context->signed_pre_key_store), store, sizeof(signal_protocol_signed_pre_key_store)); return 0; } int signal_protocol_store_context_set_identity_key_store(signal_protocol_store_context *context, const signal_protocol_identity_key_store *store) { if(!store) { return SG_ERR_INVAL; } memcpy(&(context->identity_key_store), store, sizeof(signal_protocol_identity_key_store)); return 0; } int signal_protocol_store_context_set_sender_key_store(signal_protocol_store_context *context, const signal_protocol_sender_key_store *store) { if(!store) { return SG_ERR_INVAL; } memcpy(&(context->sender_key_store), store, sizeof(signal_protocol_sender_key_store)); return 0; } void signal_protocol_store_context_destroy(signal_protocol_store_context *context) { if(context) { if(context->session_store.destroy_func) { context->session_store.destroy_func(context->session_store.user_data); } if(context->pre_key_store.destroy_func) { context->pre_key_store.destroy_func(context->pre_key_store.user_data); } if(context->signed_pre_key_store.destroy_func) { context->signed_pre_key_store.destroy_func(context->signed_pre_key_store.user_data); } if(context->identity_key_store.destroy_func) { context->identity_key_store.destroy_func(context->identity_key_store.user_data); } if(context->sender_key_store.destroy_func) { context->sender_key_store.destroy_func(context->sender_key_store.user_data); } free(context); } } /*------------------------------------------------------------------------*/ int signal_protocol_session_load_session(signal_protocol_store_context *context, session_record **record, const signal_protocol_address *address) { int result = 0; signal_buffer *buffer = 0; signal_buffer *user_buffer = 0; session_record *result_record = 0; assert(context); assert(context->session_store.load_session_func); result = context->session_store.load_session_func( &buffer, &user_buffer, address, context->session_store.user_data); if(result < 0) { goto complete; } if(result == 0) { if(buffer) { result = SG_ERR_UNKNOWN; goto complete; } result = session_record_create(&result_record, 0, context->global_context); } else if(result == 1) { if(!buffer) { result = -1; goto complete; } result = session_record_deserialize(&result_record, signal_buffer_data(buffer), signal_buffer_len(buffer), context->global_context); } else { result = SG_ERR_UNKNOWN; } complete: if(buffer) { signal_buffer_free(buffer); } if(result >= 0) { if(user_buffer) { session_record_set_user_record(result_record, user_buffer); } *record = result_record; } else { signal_buffer_free(user_buffer); } return result; } int signal_protocol_session_get_sub_device_sessions(signal_protocol_store_context *context, signal_int_list **sessions, const char *name, size_t name_len) { assert(context); assert(context->session_store.get_sub_device_sessions_func); return context->session_store.get_sub_device_sessions_func( sessions, name, name_len, context->session_store.user_data); } int signal_protocol_session_store_session(signal_protocol_store_context *context, const signal_protocol_address *address, session_record *record) { int result = 0; signal_buffer *buffer = 0; signal_buffer *user_buffer = 0; uint8_t *user_buffer_data = 0; size_t user_buffer_len = 0; assert(context); assert(context->session_store.store_session_func); assert(record); result = session_record_serialize(&buffer, record); if(result < 0) { goto complete; } user_buffer = session_record_get_user_record(record); if(user_buffer) { user_buffer_data = signal_buffer_data(user_buffer); user_buffer_len = signal_buffer_len(user_buffer); } result = context->session_store.store_session_func( address, signal_buffer_data(buffer), signal_buffer_len(buffer), user_buffer_data, user_buffer_len, context->session_store.user_data); complete: if(buffer) { signal_buffer_free(buffer); } return result; } int signal_protocol_session_contains_session(signal_protocol_store_context *context, const signal_protocol_address *address) { assert(context); assert(context->session_store.contains_session_func); return context->session_store.contains_session_func( address, context->session_store.user_data); } int signal_protocol_session_delete_session(signal_protocol_store_context *context, const signal_protocol_address *address) { assert(context); assert(context->session_store.delete_session_func); return context->session_store.delete_session_func( address, context->session_store.user_data); } int signal_protocol_session_delete_all_sessions(signal_protocol_store_context *context, const char *name, size_t name_len) { assert(context); assert(context->session_store.delete_all_sessions_func); return context->session_store.delete_all_sessions_func( name, name_len, context->session_store.user_data); } /*------------------------------------------------------------------------*/ int signal_protocol_pre_key_load_key(signal_protocol_store_context *context, session_pre_key **pre_key, uint32_t pre_key_id) { int result = 0; signal_buffer *buffer = 0; session_pre_key *result_key = 0; assert(context); assert(context->pre_key_store.load_pre_key); result = context->pre_key_store.load_pre_key( &buffer, pre_key_id, context->pre_key_store.user_data); if(result < 0) { goto complete; } result = session_pre_key_deserialize(&result_key, signal_buffer_data(buffer), signal_buffer_len(buffer), context->global_context); complete: if(buffer) { signal_buffer_free(buffer); } if(result >= 0) { *pre_key = result_key; } return result; } int signal_protocol_pre_key_store_key(signal_protocol_store_context *context, session_pre_key *pre_key) { int result = 0; signal_buffer *buffer = 0; uint32_t id = 0; assert(context); assert(context->pre_key_store.store_pre_key); assert(pre_key); id = session_pre_key_get_id(pre_key); result = session_pre_key_serialize(&buffer, pre_key); if(result < 0) { goto complete; } result = context->pre_key_store.store_pre_key( id, signal_buffer_data(buffer), signal_buffer_len(buffer), context->pre_key_store.user_data); complete: if(buffer) { signal_buffer_free(buffer); } return result; } int signal_protocol_pre_key_contains_key(signal_protocol_store_context *context, uint32_t pre_key_id) { int result = 0; assert(context); assert(context->pre_key_store.contains_pre_key); result = context->pre_key_store.contains_pre_key( pre_key_id, context->pre_key_store.user_data); return result; } int signal_protocol_pre_key_remove_key(signal_protocol_store_context *context, uint32_t pre_key_id) { int result = 0; assert(context); assert(context->pre_key_store.remove_pre_key); result = context->pre_key_store.remove_pre_key( pre_key_id, context->pre_key_store.user_data); return result; } /*------------------------------------------------------------------------*/ int signal_protocol_signed_pre_key_load_key(signal_protocol_store_context *context, session_signed_pre_key **pre_key, uint32_t signed_pre_key_id) { int result = 0; signal_buffer *buffer = 0; session_signed_pre_key *result_key = 0; assert(context); assert(context->signed_pre_key_store.load_signed_pre_key); result = context->signed_pre_key_store.load_signed_pre_key( &buffer, signed_pre_key_id, context->signed_pre_key_store.user_data); if(result < 0) { goto complete; } result = session_signed_pre_key_deserialize(&result_key, signal_buffer_data(buffer), signal_buffer_len(buffer), context->global_context); complete: if(buffer) { signal_buffer_free(buffer); } if(result >= 0) { *pre_key = result_key; } return result; } int signal_protocol_signed_pre_key_store_key(signal_protocol_store_context *context, session_signed_pre_key *pre_key) { int result = 0; signal_buffer *buffer = 0; uint32_t id = 0; assert(context); assert(context->signed_pre_key_store.store_signed_pre_key); assert(pre_key); id = session_signed_pre_key_get_id(pre_key); result = session_signed_pre_key_serialize(&buffer, pre_key); if(result < 0) { goto complete; } result = context->signed_pre_key_store.store_signed_pre_key( id, signal_buffer_data(buffer), signal_buffer_len(buffer), context->signed_pre_key_store.user_data); complete: if(buffer) { signal_buffer_free(buffer); } return result; } int signal_protocol_signed_pre_key_contains_key(signal_protocol_store_context *context, uint32_t signed_pre_key_id) { int result = 0; assert(context); assert(context->signed_pre_key_store.contains_signed_pre_key); result = context->signed_pre_key_store.contains_signed_pre_key( signed_pre_key_id, context->signed_pre_key_store.user_data); return result; } int signal_protocol_signed_pre_key_remove_key(signal_protocol_store_context *context, uint32_t signed_pre_key_id) { int result = 0; assert(context); assert(context->signed_pre_key_store.remove_signed_pre_key); result = context->signed_pre_key_store.remove_signed_pre_key( signed_pre_key_id, context->signed_pre_key_store.user_data); return result; } /*------------------------------------------------------------------------*/ int signal_protocol_identity_get_key_pair(signal_protocol_store_context *context, ratchet_identity_key_pair **key_pair) { int result = 0; signal_buffer *public_buf = 0; signal_buffer *private_buf = 0; ec_public_key *public_key = 0; ec_private_key *private_key = 0; ratchet_identity_key_pair *result_key = 0; assert(context); assert(context->identity_key_store.get_identity_key_pair); result = context->identity_key_store.get_identity_key_pair( &public_buf, &private_buf, context->identity_key_store.user_data); if(result < 0) { goto complete; } result = curve_decode_point(&public_key, public_buf->data, public_buf->len, context->global_context); if(result < 0) { goto complete; } result = curve_decode_private_point(&private_key, private_buf->data, private_buf->len, context->global_context); if(result < 0) { goto complete; } result = ratchet_identity_key_pair_create(&result_key, public_key, private_key); if(result < 0) { goto complete; } complete: if(public_buf) { signal_buffer_free(public_buf); } if(private_buf) { signal_buffer_free(private_buf); } if(public_key) { SIGNAL_UNREF(public_key); } if(private_key) { SIGNAL_UNREF(private_key); } if(result >= 0) { *key_pair = result_key; } return result; } int signal_protocol_identity_get_local_registration_id(signal_protocol_store_context *context, uint32_t *registration_id) { int result = 0; assert(context); assert(context->identity_key_store.get_local_registration_id); result = context->identity_key_store.get_local_registration_id( context->identity_key_store.user_data, registration_id); return result; } int signal_protocol_identity_save_identity(signal_protocol_store_context *context, const signal_protocol_address *address, ec_public_key *identity_key) { int result = 0; signal_buffer *buffer = 0; assert(context); assert(context->identity_key_store.save_identity); if(identity_key) { result = ec_public_key_serialize(&buffer, identity_key); if(result < 0) { goto complete; } result = context->identity_key_store.save_identity( address, signal_buffer_data(buffer), signal_buffer_len(buffer), context->identity_key_store.user_data); } else { result = context->identity_key_store.save_identity( address, 0, 0, context->identity_key_store.user_data); } complete: if(buffer) { signal_buffer_free(buffer); } return result; } int signal_protocol_identity_is_trusted_identity(signal_protocol_store_context *context, const signal_protocol_address *address, ec_public_key *identity_key) { int result = 0; signal_buffer *buffer = 0; assert(context); assert(context->identity_key_store.is_trusted_identity); result = ec_public_key_serialize(&buffer, identity_key); if(result < 0) { goto complete; } result = context->identity_key_store.is_trusted_identity( address, signal_buffer_data(buffer), signal_buffer_len(buffer), context->identity_key_store.user_data); complete: if(buffer) { signal_buffer_free(buffer); } return result; } int signal_protocol_sender_key_store_key(signal_protocol_store_context *context, const signal_protocol_sender_key_name *sender_key_name, sender_key_record *record) { int result = 0; signal_buffer *buffer = 0; signal_buffer *user_buffer = 0; uint8_t *user_buffer_data = 0; size_t user_buffer_len = 0; assert(context); assert(context->sender_key_store.store_sender_key); assert(record); result = sender_key_record_serialize(&buffer, record); if(result < 0) { goto complete; } user_buffer = sender_key_record_get_user_record(record); if(user_buffer) { user_buffer_data = signal_buffer_data(user_buffer); user_buffer_len = signal_buffer_len(user_buffer); } result = context->sender_key_store.store_sender_key( sender_key_name, signal_buffer_data(buffer), signal_buffer_len(buffer), user_buffer_data, user_buffer_len, context->sender_key_store.user_data); complete: if(buffer) { signal_buffer_free(buffer); } return result; } int signal_protocol_sender_key_load_key(signal_protocol_store_context *context, sender_key_record **record, const signal_protocol_sender_key_name *sender_key_name) { int result = 0; signal_buffer *buffer = 0; signal_buffer *user_buffer = 0; sender_key_record *result_record = 0; assert(context); assert(context->sender_key_store.load_sender_key); result = context->sender_key_store.load_sender_key( &buffer, &user_buffer, sender_key_name, context->sender_key_store.user_data); if(result < 0) { goto complete; } if(result == 0) { if(buffer) { result = SG_ERR_UNKNOWN; goto complete; } result = sender_key_record_create(&result_record, context->global_context); } else if(result == 1) { if(!buffer) { result = -1; goto complete; } result = sender_key_record_deserialize(&result_record, signal_buffer_data(buffer), signal_buffer_len(buffer), context->global_context); } else { result = SG_ERR_UNKNOWN; } complete: if(buffer) { signal_buffer_free(buffer); } if(result >= 0) { if(user_buffer) { sender_key_record_set_user_record(result_record, user_buffer); } *record = result_record; } else { signal_buffer_free(user_buffer); } return result; } libsignal-protocol-c-2.3.3/src/signal_protocol.h000066400000000000000000000767001363751346500217270ustar00rootroot00000000000000#ifndef SIGNAL_PROTOCOL_H #define SIGNAL_PROTOCOL_H #include #include #include #include "ratchet.h" #include "curve.h" #include "session_record.h" #include "session_pre_key.h" #include "sender_key_record.h" #include "signal_protocol_types.h" #ifdef __cplusplus extern "C" { #endif #define SG_SUCCESS 0 /* Standard error codes with values that match errno.h equivalents */ #define SG_ERR_NOMEM -12 /* Not enough space */ #define SG_ERR_INVAL -22 /* Invalid argument */ /* Custom error codes for error conditions specific to the library */ #define SG_ERR_UNKNOWN -1000 #define SG_ERR_DUPLICATE_MESSAGE -1001 #define SG_ERR_INVALID_KEY -1002 #define SG_ERR_INVALID_KEY_ID -1003 #define SG_ERR_INVALID_MAC -1004 #define SG_ERR_INVALID_MESSAGE -1005 #define SG_ERR_INVALID_VERSION -1006 #define SG_ERR_LEGACY_MESSAGE -1007 #define SG_ERR_NO_SESSION -1008 #define SG_ERR_STALE_KEY_EXCHANGE -1009 #define SG_ERR_UNTRUSTED_IDENTITY -1010 #define SG_ERR_VRF_SIG_VERIF_FAILED -1011 #define SG_ERR_INVALID_PROTO_BUF -1100 #define SG_ERR_FP_VERSION_MISMATCH -1200 #define SG_ERR_FP_IDENT_MISMATCH -1201 /* * Minimum negative error code value that this library may use. * When implementing library callback functions, using values * less than this constant will ensure that application-specific * errors can be distinguished from library errors. */ #define SG_ERR_MINIMUM -9999 /* Log levels */ #define SG_LOG_ERROR 0 #define SG_LOG_WARNING 1 #define SG_LOG_NOTICE 2 #define SG_LOG_INFO 3 #define SG_LOG_DEBUG 4 /* Mode settings for the crypto callbacks */ #define SG_CIPHER_AES_CTR_NOPADDING 1 #define SG_CIPHER_AES_CBC_PKCS5 2 void signal_type_ref(signal_type_base *instance); void signal_type_unref(signal_type_base *instance); #ifdef DEBUG_REFCOUNT int signal_type_ref_count(signal_type_base *instance); #define SIGNAL_REF(instance) do { \ signal_type_ref((signal_type_base *)instance); \ fprintf(stderr, "REF: " #instance " = %d\n", signal_type_ref_count((signal_type_base *)instance)); \ } while (0) #define SIGNAL_UNREF(instance) do { \ fprintf(stderr, "UNREF: " #instance " = %d\n", signal_type_ref_count((signal_type_base *)instance)); \ signal_type_unref((signal_type_base *)instance); \ instance = 0; \ } while(0) #else #define SIGNAL_REF(instance) signal_type_ref((signal_type_base *)instance) #define SIGNAL_UNREF(instance) do { signal_type_unref((signal_type_base *)instance); instance = 0; } while(0) #endif /** * Allocate a new buffer to store data of the provided length. * * @param len length of the buffer to allocate * @return pointer to the allocated buffer, or 0 on failure */ signal_buffer *signal_buffer_alloc(size_t len); /** * Create a new buffer and copy the provided data into it. * * @param data pointer to the start of the data * @param len length of the data * @return pointer to the allocated buffer, or 0 on failure */ signal_buffer *signal_buffer_create(const uint8_t *data, size_t len); /** * Create a copy of an existing buffer. * * @param buffer the existing buffer to copy * @return pointer to the updated buffer, or 0 on failure */ signal_buffer *signal_buffer_copy(const signal_buffer *buffer); /** * Create a copy of an existing buffer. * * @param buffer the existing buffer to copy * @param n the maximum number of bytes to copy * @return pointer to the updated buffer, or 0 on failure */ signal_buffer *signal_buffer_n_copy(const signal_buffer *buffer, size_t n); /** * Append the provided data to an existing buffer. * Note: The underlying buffer is only expanded by an amount sufficient * to hold the data being appended. There is no additional reserved space * to reduce the need for memory allocations. * * @param buffer the existing buffer to append to * @param data pointer to the start of the data * @param len length of the data * @return pointer to the updated buffer, or 0 on failure */ signal_buffer *signal_buffer_append(signal_buffer *buffer, const uint8_t *data, size_t len); /** * Gets the data pointer for the buffer. * This can be used to read and write data stored in the buffer. * * @param buffer pointer to the buffer instance * @return data pointer */ uint8_t *signal_buffer_data(signal_buffer *buffer); /** * Gets the data pointer for the buffer. * This can be used to read and write data stored in the buffer. * * @param buffer pointer to the buffer instance * @return data pointer */ const uint8_t *signal_buffer_const_data(const signal_buffer *buffer); /** * Gets the length of the data stored within the buffer. * * @param buffer pointer to the buffer instance * @return data length */ size_t signal_buffer_len(const signal_buffer *buffer); /** * Compare two buffers. * * @param buffer1 first buffer to compare * @param buffer2 second buffer to compare * @return 0 if the two buffers are equal, negative or positive otherwise */ int signal_buffer_compare(signal_buffer *buffer1, signal_buffer *buffer2); /** * Free the data buffer. * * @param buffer pointer to the buffer instance to free */ void signal_buffer_free(signal_buffer *buffer); /** * Zero and free the data buffer. * This function should be used when the buffer contains sensitive * data, to make sure the memory is cleared before being freed. * * @param buffer pointer to the buffer instance to free */ void signal_buffer_bzero_free(signal_buffer *buffer); /** * Allocate a new buffer list. * * @return pointer to the allocated buffer, or 0 on failure */ signal_buffer_list *signal_buffer_list_alloc(void); /** * Create a copy of an existing buffer list. * * @param list the existing buffer list to copy * @return pointer to the updated buffer, or 0 on failure */ signal_buffer_list *signal_buffer_list_copy(const signal_buffer_list *list); /** * Push the provided buffer onto the end of the list. * The list will take ownership of the buffer, and free it when the list is * freed. * * @param list the buffer list * @param buffer the buffer to push * @return 0 on success, or negative on failure */ int signal_buffer_list_push_back(signal_buffer_list *list, signal_buffer *buffer); /** * Gets the size of the buffer list. * * @param list the buffer list * @return the size of the list */ unsigned int signal_buffer_list_size(signal_buffer_list *list); /** * Gets the value of the element at a particular index in the list * * @param list the list * @param index the index within the list * @return the value */ signal_buffer *signal_buffer_list_at(signal_buffer_list *list, unsigned int index); /** * Free the buffer list, including all the buffers added to it. * * @param list the buffer list */ void signal_buffer_list_free(signal_buffer_list *list); /** * Free the buffer list, including all the buffers added to it. * This function should be used when the buffer list contains sensitive * data, to make sure the memory is cleared before being freed. * * @param list the buffer list */ void signal_buffer_list_bzero_free(signal_buffer_list *list); /** * Allocate a new int list * * @return pointer to the allocated buffer, or 0 on failure */ signal_int_list *signal_int_list_alloc(void); /** * Push a new value onto the end of the list * * @param list the list * @param value the value to push * @return 0 on success, or negative on failure */ int signal_int_list_push_back(signal_int_list *list, int value); /** * Gets the size of the list. * * @param list the list * @return the size of the list */ unsigned int signal_int_list_size(signal_int_list *list); /** * Gets the value of the element at a particular index in the list * * @param list the list * @param index the index within the list * @return the value */ int signal_int_list_at(signal_int_list *list, unsigned int index); /** * Free the int list * @param list the list to free */ void signal_int_list_free(signal_int_list *list); typedef struct signal_crypto_provider { /** * Callback for a secure random number generator. * This function shall fill the provided buffer with random bytes. * * @param data pointer to the output buffer * @param len size of the output buffer * @return 0 on success, negative on failure */ int (*random_func)(uint8_t *data, size_t len, void *user_data); /** * Callback for an HMAC-SHA256 implementation. * This function shall initialize an HMAC context with the provided key. * * @param hmac_context private HMAC context pointer * @param key pointer to the key * @param key_len length of the key * @return 0 on success, negative on failure */ int (*hmac_sha256_init_func)(void **hmac_context, const uint8_t *key, size_t key_len, void *user_data); /** * Callback for an HMAC-SHA256 implementation. * This function shall update the HMAC context with the provided data * * @param hmac_context private HMAC context pointer * @param data pointer to the data * @param data_len length of the data * @return 0 on success, negative on failure */ int (*hmac_sha256_update_func)(void *hmac_context, const uint8_t *data, size_t data_len, void *user_data); /** * Callback for an HMAC-SHA256 implementation. * This function shall finalize an HMAC calculation and populate the output * buffer with the result. * * @param hmac_context private HMAC context pointer * @param output buffer to be allocated and populated with the result * @return 0 on success, negative on failure */ int (*hmac_sha256_final_func)(void *hmac_context, signal_buffer **output, void *user_data); /** * Callback for an HMAC-SHA256 implementation. * This function shall free the private context allocated in * hmac_sha256_init_func. * * @param hmac_context private HMAC context pointer */ void (*hmac_sha256_cleanup_func)(void *hmac_context, void *user_data); /** * Callback for a SHA512 message digest implementation. * This function shall initialize a digest context. * * @param digest_context private digest context pointer * @return 0 on success, negative on failure */ int (*sha512_digest_init_func)(void **digest_context, void *user_data); /** * Callback for a SHA512 message digest implementation. * This function shall update the digest context with the provided data. * * @param digest_context private digest context pointer * @param data pointer to the data * @param data_len length of the data * @return 0 on success, negative on failure */ int (*sha512_digest_update_func)(void *digest_context, const uint8_t *data, size_t data_len, void *user_data); /** * Callback for a SHA512 message digest implementation. * This function shall finalize the digest calculation, populate the * output buffer with the result, and prepare the context for reuse. * * @param digest_context private digest context pointer * @param output buffer to be allocated and populated with the result * @return 0 on success, negative on failure */ int (*sha512_digest_final_func)(void *digest_context, signal_buffer **output, void *user_data); /** * Callback for a SHA512 message digest implementation. * This function shall free the private context allocated in * sha512_digest_init_func. * * @param digest_context private digest context pointer */ void (*sha512_digest_cleanup_func)(void *digest_context, void *user_data); /** * Callback for an AES encryption implementation. * * @param output buffer to be allocated and populated with the ciphertext * @param cipher specific cipher variant to use, either SG_CIPHER_AES_CTR_NOPADDING or SG_CIPHER_AES_CBC_PKCS5 * @param key the encryption key * @param key_len length of the encryption key * @param iv the initialization vector * @param iv_len length of the initialization vector * @param plaintext the plaintext to encrypt * @param plaintext_len length of the plaintext * @return 0 on success, negative on failure */ int (*encrypt_func)(signal_buffer **output, int cipher, const uint8_t *key, size_t key_len, const uint8_t *iv, size_t iv_len, const uint8_t *plaintext, size_t plaintext_len, void *user_data); /** * Callback for an AES decryption implementation. * * @param output buffer to be allocated and populated with the plaintext * @param cipher specific cipher variant to use, either SG_CIPHER_AES_CTR_NOPADDING or SG_CIPHER_AES_CBC_PKCS5 * @param key the encryption key * @param key_len length of the encryption key * @param iv the initialization vector * @param iv_len length of the initialization vector * @param ciphertext the ciphertext to decrypt * @param ciphertext_len length of the ciphertext * @return 0 on success, negative on failure */ int (*decrypt_func)(signal_buffer **output, int cipher, const uint8_t *key, size_t key_len, const uint8_t *iv, size_t iv_len, const uint8_t *ciphertext, size_t ciphertext_len, void *user_data); /** User data pointer */ void *user_data; } signal_crypto_provider; typedef struct signal_protocol_session_store { /** * Returns a copy of the serialized session record corresponding to the * provided recipient ID + device ID tuple. * * @param record pointer to a freshly allocated buffer containing the * serialized session record. Unset if no record was found. * The Signal Protocol library is responsible for freeing this buffer. * @param user_record pointer to a freshly allocated buffer containing * application specific data stored alongside the serialized session * record. If no such data exists, then this pointer may be left unset. * The Signal Protocol library is responsible for freeing this buffer. * @param address the address of the remote client * @return 1 if the session was loaded, 0 if the session was not found, negative on failure */ int (*load_session_func)(signal_buffer **record, signal_buffer **user_record, const signal_protocol_address *address, void *user_data); /** * Returns all known devices with active sessions for a recipient * * @param pointer to an array that will be allocated and populated with the result * @param name the name of the remote client * @param name_len the length of the name * @return size of the sessions array, or negative on failure */ int (*get_sub_device_sessions_func)(signal_int_list **sessions, const char *name, size_t name_len, void *user_data); /** * Commit to storage the session record for a given * recipient ID + device ID tuple. * * @param address the address of the remote client * @param record pointer to a buffer containing the serialized session * record for the remote client * @param record_len length of the serialized session record * @param user_record pointer to a buffer containing application specific * data to be stored alongside the serialized session record for the * remote client. If no such data exists, then this pointer will be null. * @param user_record_len length of the application specific data * @return 0 on success, negative on failure */ int (*store_session_func)(const signal_protocol_address *address, uint8_t *record, size_t record_len, uint8_t *user_record, size_t user_record_len, void *user_data); /** * Determine whether there is a committed session record for a * recipient ID + device ID tuple. * * @param address the address of the remote client * @return 1 if a session record exists, 0 otherwise. */ int (*contains_session_func)(const signal_protocol_address *address, void *user_data); /** * Remove a session record for a recipient ID + device ID tuple. * * @param address the address of the remote client * @return 1 if a session was deleted, 0 if a session was not deleted, negative on error */ int (*delete_session_func)(const signal_protocol_address *address, void *user_data); /** * Remove the session records corresponding to all devices of a recipient ID. * * @param name the name of the remote client * @param name_len the length of the name * @return the number of deleted sessions on success, negative on failure */ int (*delete_all_sessions_func)(const char *name, size_t name_len, void *user_data); /** * Function called to perform cleanup when the data store context is being * destroyed. */ void (*destroy_func)(void *user_data); /** User data pointer */ void *user_data; } signal_protocol_session_store; typedef struct signal_protocol_pre_key_store { /** * Load a local serialized PreKey record. * * @param record pointer to a newly allocated buffer containing the record, * if found. Unset if no record was found. * The Signal Protocol library is responsible for freeing this buffer. * @param pre_key_id the ID of the local serialized PreKey record * @retval SG_SUCCESS if the key was found * @retval SG_ERR_INVALID_KEY_ID if the key could not be found */ int (*load_pre_key)(signal_buffer **record, uint32_t pre_key_id, void *user_data); /** * Store a local serialized PreKey record. * * @param pre_key_id the ID of the PreKey record to store. * @param record pointer to a buffer containing the serialized record * @param record_len length of the serialized record * @return 0 on success, negative on failure */ int (*store_pre_key)(uint32_t pre_key_id, uint8_t *record, size_t record_len, void *user_data); /** * Determine whether there is a committed PreKey record matching the * provided ID. * * @param pre_key_id A PreKey record ID. * @return 1 if the store has a record for the PreKey ID, 0 otherwise */ int (*contains_pre_key)(uint32_t pre_key_id, void *user_data); /** * Delete a PreKey record from local storage. * * @param pre_key_id The ID of the PreKey record to remove. * @return 0 on success, negative on failure */ int (*remove_pre_key)(uint32_t pre_key_id, void *user_data); /** * Function called to perform cleanup when the data store context is being * destroyed. */ void (*destroy_func)(void *user_data); /** User data pointer */ void *user_data; } signal_protocol_pre_key_store; typedef struct signal_protocol_signed_pre_key_store { /** * Load a local serialized signed PreKey record. * * @param record pointer to a newly allocated buffer containing the record, * if found. Unset if no record was found. * The Signal Protocol library is responsible for freeing this buffer. * @param signed_pre_key_id the ID of the local signed PreKey record * @retval SG_SUCCESS if the key was found * @retval SG_ERR_INVALID_KEY_ID if the key could not be found */ int (*load_signed_pre_key)(signal_buffer **record, uint32_t signed_pre_key_id, void *user_data); /** * Store a local serialized signed PreKey record. * * @param signed_pre_key_id the ID of the signed PreKey record to store * @param record pointer to a buffer containing the serialized record * @param record_len length of the serialized record * @return 0 on success, negative on failure */ int (*store_signed_pre_key)(uint32_t signed_pre_key_id, uint8_t *record, size_t record_len, void *user_data); /** * Determine whether there is a committed signed PreKey record matching * the provided ID. * * @param signed_pre_key_id A signed PreKey record ID. * @return 1 if the store has a record for the signed PreKey ID, 0 otherwise */ int (*contains_signed_pre_key)(uint32_t signed_pre_key_id, void *user_data); /** * Delete a SignedPreKeyRecord from local storage. * * @param signed_pre_key_id The ID of the signed PreKey record to remove. * @return 0 on success, negative on failure */ int (*remove_signed_pre_key)(uint32_t signed_pre_key_id, void *user_data); /** * Function called to perform cleanup when the data store context is being * destroyed. */ void (*destroy_func)(void *user_data); /** User data pointer */ void *user_data; } signal_protocol_signed_pre_key_store; typedef struct signal_protocol_identity_key_store { /** * Get the local client's identity key pair. * * @param public_data pointer to a newly allocated buffer containing the * public key, if found. Unset if no record was found. * The Signal Protocol library is responsible for freeing this buffer. * @param private_data pointer to a newly allocated buffer containing the * private key, if found. Unset if no record was found. * The Signal Protocol library is responsible for freeing this buffer. * @return 0 on success, negative on failure */ int (*get_identity_key_pair)(signal_buffer **public_data, signal_buffer **private_data, void *user_data); /** * Return the local client's registration ID. * * Clients should maintain a registration ID, a random number * between 1 and 16380 that's generated once at install time. * * @param registration_id pointer to be set to the local client's * registration ID, if it was successfully retrieved. * @return 0 on success, negative on failure */ int (*get_local_registration_id)(void *user_data, uint32_t *registration_id); /** * Save a remote client's identity key *

* Store a remote client's identity key as trusted. * The value of key_data may be null. In this case remove the key data * from the identity store, but retain any metadata that may be kept * alongside it. * * @param address the address of the remote client * @param key_data Pointer to the remote client's identity key, may be null * @param key_len Length of the remote client's identity key * @return 0 on success, negative on failure */ int (*save_identity)(const signal_protocol_address *address, uint8_t *key_data, size_t key_len, void *user_data); /** * Verify a remote client's identity key. * * Determine whether a remote client's identity is trusted. Convention is * that the TextSecure protocol is 'trust on first use.' This means that * an identity key is considered 'trusted' if there is no entry for the recipient * in the local store, or if it matches the saved key for a recipient in the local * store. Only if it mismatches an entry in the local store is it considered * 'untrusted.' * * @param address the address of the remote client * @param identityKey The identity key to verify. * @param key_data Pointer to the identity key to verify * @param key_len Length of the identity key to verify * @return 1 if trusted, 0 if untrusted, negative on failure */ int (*is_trusted_identity)(const signal_protocol_address *address, uint8_t *key_data, size_t key_len, void *user_data); /** * Function called to perform cleanup when the data store context is being * destroyed. */ void (*destroy_func)(void *user_data); /** User data pointer */ void *user_data; } signal_protocol_identity_key_store; typedef struct signal_protocol_sender_key_store { /** * Store a serialized sender key record for a given * (groupId + senderId + deviceId) tuple. * * @param sender_key_name the (groupId + senderId + deviceId) tuple * @param record pointer to a buffer containing the serialized record * @param record_len length of the serialized record * @param user_record pointer to a buffer containing application specific * data to be stored alongside the serialized record. If no such * data exists, then this pointer will be null. * @param user_record_len length of the application specific data * @return 0 on success, negative on failure */ int (*store_sender_key)(const signal_protocol_sender_key_name *sender_key_name, uint8_t *record, size_t record_len, uint8_t *user_record, size_t user_record_len, void *user_data); /** * Returns a copy of the sender key record corresponding to the * (groupId + senderId + deviceId) tuple. * * @param record pointer to a newly allocated buffer containing the record, * if found. Unset if no record was found. * The Signal Protocol library is responsible for freeing this buffer. * @param user_record pointer to a newly allocated buffer containing * application-specific data stored alongside the record. If no such * data exists, then this pointer may be left unset. * The Signal Protocol library is responsible for freeing this buffer. * @param sender_key_name the (groupId + senderId + deviceId) tuple * @return 1 if the record was loaded, 0 if the record was not found, negative on failure */ int (*load_sender_key)(signal_buffer **record, signal_buffer **user_record, const signal_protocol_sender_key_name *sender_key_name, void *user_data); /** * Function called to perform cleanup when the data store context is being * destroyed. */ void (*destroy_func)(void *user_data); /** User data pointer */ void *user_data; } signal_protocol_sender_key_store; /** * Create a new instance of the global library context. */ int signal_context_create(signal_context **context, void *user_data); /** * Set the crypto provider to be used by the Signal Protocol library. * * @param crypto_provider Populated structure of crypto provider function * pointers. The contents of this structure are copied, so the caller * does not need to maintain its instance. * @return 0 on success, negative on failure */ int signal_context_set_crypto_provider(signal_context *context, const signal_crypto_provider *crypto_provider); /** * Set the locking functions to be used by the Signal Protocol library for * synchronization. * * Note: These functions must allow recursive locking (e.g. PTHREAD_MUTEX_RECURSIVE) * * @param lock function to lock a mutex * @param unlock function to unlock a mutex * @return 0 on success, negative on failure */ int signal_context_set_locking_functions(signal_context *context, void (*lock)(void *user_data), void (*unlock)(void *user_data)); /** * Set the log function to be used by the Signal Protocol library for logging. * * @return 0 on success, negative on failure */ int signal_context_set_log_function(signal_context *context, void (*log)(int level, const char *message, size_t len, void *user_data)); void signal_context_destroy(signal_context *context); /** * Create a new instance of the Signal Protocol data store interface. */ int signal_protocol_store_context_create(signal_protocol_store_context **context, signal_context *global_context); int signal_protocol_store_context_set_session_store(signal_protocol_store_context *context, const signal_protocol_session_store *store); int signal_protocol_store_context_set_pre_key_store(signal_protocol_store_context *context, const signal_protocol_pre_key_store *store); int signal_protocol_store_context_set_signed_pre_key_store(signal_protocol_store_context *context, const signal_protocol_signed_pre_key_store *store); int signal_protocol_store_context_set_identity_key_store(signal_protocol_store_context *context, const signal_protocol_identity_key_store *store); int signal_protocol_store_context_set_sender_key_store(signal_protocol_store_context *context, const signal_protocol_sender_key_store *store); void signal_protocol_store_context_destroy(signal_protocol_store_context *context); /* * Interface to the session store. * These functions will use the callbacks in the provided * signal_protocol_store_context instance and operate in terms of higher level * library data structures. */ int signal_protocol_session_load_session(signal_protocol_store_context *context, session_record **record, const signal_protocol_address *address); int signal_protocol_session_get_sub_device_sessions(signal_protocol_store_context *context, signal_int_list **sessions, const char *name, size_t name_len); int signal_protocol_session_store_session(signal_protocol_store_context *context, const signal_protocol_address *address, session_record *record); int signal_protocol_session_contains_session(signal_protocol_store_context *context, const signal_protocol_address *address); int signal_protocol_session_delete_session(signal_protocol_store_context *context, const signal_protocol_address *address); int signal_protocol_session_delete_all_sessions(signal_protocol_store_context *context, const char *name, size_t name_len); /* * Interface to the pre-key store. * These functions will use the callbacks in the provided * signal_protocol_store_context instance and operate in terms of higher level * library data structures. */ int signal_protocol_pre_key_load_key(signal_protocol_store_context *context, session_pre_key **pre_key, uint32_t pre_key_id); int signal_protocol_pre_key_store_key(signal_protocol_store_context *context, session_pre_key *pre_key); int signal_protocol_pre_key_contains_key(signal_protocol_store_context *context, uint32_t pre_key_id); int signal_protocol_pre_key_remove_key(signal_protocol_store_context *context, uint32_t pre_key_id); /* * Interface to the signed pre-key store. * These functions will use the callbacks in the provided * signal_protocol_store_context instance and operate in terms of higher level * library data structures. */ int signal_protocol_signed_pre_key_load_key(signal_protocol_store_context *context, session_signed_pre_key **pre_key, uint32_t signed_pre_key_id); int signal_protocol_signed_pre_key_store_key(signal_protocol_store_context *context, session_signed_pre_key *pre_key); int signal_protocol_signed_pre_key_contains_key(signal_protocol_store_context *context, uint32_t signed_pre_key_id); int signal_protocol_signed_pre_key_remove_key(signal_protocol_store_context *context, uint32_t signed_pre_key_id); /* * Interface to the identity key store. * These functions will use the callbacks in the provided * signal_protocol_store_context instance and operate in terms of higher level * library data structures. */ int signal_protocol_identity_get_key_pair(signal_protocol_store_context *context, ratchet_identity_key_pair **key_pair); int signal_protocol_identity_get_local_registration_id(signal_protocol_store_context *context, uint32_t *registration_id); int signal_protocol_identity_save_identity(signal_protocol_store_context *context, const signal_protocol_address *address, ec_public_key *identity_key); int signal_protocol_identity_is_trusted_identity(signal_protocol_store_context *context, const signal_protocol_address *address, ec_public_key *identity_key); /* * Interface to the sender key store. * These functions will use the callbacks in the provided * signal_protocol_store_context instance and operate in terms of higher level * library data structures. */ int signal_protocol_sender_key_store_key(signal_protocol_store_context *context, const signal_protocol_sender_key_name *sender_key_name, sender_key_record *record); int signal_protocol_sender_key_load_key(signal_protocol_store_context *context, sender_key_record **record, const signal_protocol_sender_key_name *sender_key_name); #ifdef __cplusplus } #endif #endif /* SIGNAL_PROTOCOL_H */ libsignal-protocol-c-2.3.3/src/signal_protocol_internal.h000066400000000000000000000075171363751346500236230ustar00rootroot00000000000000#ifndef SIGNAL_PROTOCOL_INTERNAL_H #define SIGNAL_PROTOCOL_INTERNAL_H #include #include "LocalStorageProtocol.pb-c.h" #include "signal_protocol.h" struct signal_type_base { unsigned int ref_count; void (*destroy)(signal_type_base *instance); }; void signal_type_init(signal_type_base *instance, void (*destroy_func)(signal_type_base *instance)); #define SIGNAL_INIT(instance, destroy_func) signal_type_init((signal_type_base *)instance, destroy_func) struct signal_buffer { size_t len; uint8_t data[]; }; struct signal_context { signal_crypto_provider crypto_provider; void (*lock)(void *user_data); void (*unlock)(void *user_data); void (*log)(int level, const char *message, size_t len, void *user_data); void *user_data; }; int signal_crypto_random(signal_context *context, uint8_t *data, size_t len); int signal_hmac_sha256_init(signal_context *context, void **hmac_context, const uint8_t *key, size_t key_len); int signal_hmac_sha256_update(signal_context *context, void *hmac_context, const uint8_t *data, size_t data_len); int signal_hmac_sha256_final(signal_context *context, void *hmac_context, signal_buffer **output); void signal_hmac_sha256_cleanup(signal_context *context, void *hmac_context); int signal_sha512_digest_init(signal_context *context, void **digest_context); int signal_sha512_digest_update(signal_context *context, void *digest_context, const uint8_t *data, size_t data_len); int signal_sha512_digest_final(signal_context *context, void *digest_context, signal_buffer **output); void signal_sha512_digest_cleanup(signal_context *context, void *digest_context); int signal_encrypt(signal_context *context, signal_buffer **output, int cipher, const uint8_t *key, size_t key_len, const uint8_t *iv, size_t iv_len, const uint8_t *plaintext, size_t plaintext_len); int signal_decrypt(signal_context *context, signal_buffer **output, int cipher, const uint8_t *key, size_t key_len, const uint8_t *iv, size_t iv_len, const uint8_t *ciphertext, size_t ciphertext_len); void signal_lock(signal_context *context); void signal_unlock(signal_context *context); void signal_log(signal_context *context, int level, const char *format, ...); void signal_explicit_bzero(void *v, size_t n); int signal_constant_memcmp(const void *s1, const void *s2, size_t n); /*------------------------------------------------------------------------*/ /* * Functions used for internal protocol buffers serialization support. */ int ec_public_key_serialize_protobuf(ProtobufCBinaryData *buffer, const ec_public_key *key); int ec_private_key_serialize_protobuf(ProtobufCBinaryData *buffer, const ec_private_key *key); int ratchet_chain_key_get_key_protobuf(const ratchet_chain_key *chain_key, ProtobufCBinaryData *buffer); int ratchet_root_key_get_key_protobuf(const ratchet_root_key *root_key, ProtobufCBinaryData *buffer); int session_state_serialize_prepare(session_state *state, Textsecure__SessionStructure *session_structure); void session_state_serialize_prepare_free(Textsecure__SessionStructure *session_structure); int session_state_deserialize_protobuf(session_state **state, Textsecure__SessionStructure *session_structure, signal_context *global_context); int sender_key_state_serialize_prepare(sender_key_state *state, Textsecure__SenderKeyStateStructure *state_structure); void sender_key_state_serialize_prepare_free(Textsecure__SenderKeyStateStructure *state_structure); int sender_key_state_deserialize_protobuf(sender_key_state **state, Textsecure__SenderKeyStateStructure *state_structure, signal_context *global_context); void signal_protocol_str_serialize_protobuf(ProtobufCBinaryData *buffer, const char *str); char *signal_protocol_str_deserialize_protobuf(ProtobufCBinaryData *buffer); #endif /* SIGNAL_PROTOCOL_INTERNAL_H */ libsignal-protocol-c-2.3.3/src/signal_protocol_types.h000066400000000000000000000073651363751346500231540ustar00rootroot00000000000000#ifndef SIGNAL_PROTOCOL_TYPES_H #define SIGNAL_PROTOCOL_TYPES_H #include #include #ifndef _WINDOWS #include #else #include typedef SSIZE_T ssize_t; #endif #ifdef __cplusplus extern "C" { #endif /* * Base library types */ typedef struct signal_type_base signal_type_base; typedef struct signal_buffer signal_buffer; typedef struct signal_buffer_list signal_buffer_list; typedef struct signal_int_list signal_int_list; /* * Global context for the Signal Protocol library */ typedef struct signal_context signal_context; /* * Context for the Signal Protocol data store implementation */ typedef struct signal_protocol_store_context signal_protocol_store_context; /* * Address of an Signal Protocol message recipient */ typedef struct signal_protocol_address { const char *name; size_t name_len; int32_t device_id; } signal_protocol_address; /* * A representation of a (group + sender + device) tuple */ typedef struct signal_protocol_sender_key_name { const char *group_id; size_t group_id_len; signal_protocol_address sender; } signal_protocol_sender_key_name; /* * Curve key types */ typedef struct ec_public_key ec_public_key; typedef struct ec_private_key ec_private_key; typedef struct ec_key_pair ec_key_pair; typedef struct ec_public_key_list ec_public_key_list; /* * HKDF types */ typedef struct hkdf_context hkdf_context; /* * Key helper types */ typedef struct signal_protocol_key_helper_pre_key_list_node signal_protocol_key_helper_pre_key_list_node; /* * Protocol types */ typedef struct ciphertext_message ciphertext_message; typedef struct signal_message signal_message; typedef struct pre_key_signal_message pre_key_signal_message; typedef struct sender_key_message sender_key_message; typedef struct sender_key_distribution_message sender_key_distribution_message; /* * Ratchet types */ #define RATCHET_CIPHER_KEY_LENGTH 32 #define RATCHET_MAC_KEY_LENGTH 32 #define RATCHET_IV_LENGTH 16 typedef struct ratchet_chain_key ratchet_chain_key; typedef struct ratchet_root_key ratchet_root_key; typedef struct ratchet_identity_key_pair ratchet_identity_key_pair; typedef struct ratchet_message_keys { uint8_t cipher_key[RATCHET_CIPHER_KEY_LENGTH]; uint8_t mac_key[RATCHET_MAC_KEY_LENGTH]; uint8_t iv[RATCHET_IV_LENGTH]; uint32_t counter; } ratchet_message_keys; /* * Session types */ typedef struct session_pre_key session_pre_key; typedef struct session_signed_pre_key session_signed_pre_key; typedef struct session_pre_key_bundle session_pre_key_bundle; typedef struct session_builder session_builder; typedef struct session_record session_record; typedef struct session_record_state_node session_record_state_node; typedef struct session_state session_state; typedef struct session_cipher session_cipher; /* * Group types */ typedef struct sender_message_key sender_message_key; typedef struct sender_chain_key sender_chain_key; typedef struct sender_key_state sender_key_state; typedef struct sender_key_record sender_key_record; typedef struct group_session_builder group_session_builder; typedef struct group_cipher group_cipher; /* * Fingerprint types */ typedef struct fingerprint fingerprint; typedef struct displayable_fingerprint displayable_fingerprint; typedef struct scannable_fingerprint scannable_fingerprint; typedef struct fingerprint_generator fingerprint_generator; /* * Device consistency types */ typedef struct device_consistency_signature device_consistency_signature; typedef struct device_consistency_commitment device_consistency_commitment; typedef struct device_consistency_message device_consistency_message; typedef struct device_consistency_signature_list device_consistency_signature_list; #ifdef __cplusplus } #endif #endif /* SIGNAL_PROTOCOL_TYPES_H */ libsignal-protocol-c-2.3.3/src/signal_utarray.h000066400000000000000000000006011363751346500215400ustar00rootroot00000000000000#ifndef SIGNAL_UTARRAY_H #define SIGNAL_UTARRAY_H #include "signal_protocol.h" #define oom() do { \ result = SG_ERR_NOMEM; \ goto complete; \ } while(0) #include "utarray.h" #endif /* SIGNAL_UTARRAY_H */ libsignal-protocol-c-2.3.3/src/utarray.h000066400000000000000000000312331363751346500202100ustar00rootroot00000000000000/* Copyright (c) 2008-2016, Troy D. Hanson http://troydhanson.github.com/uthash/ All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /* a dynamic array implementation using macros */ #ifndef UTARRAY_H #define UTARRAY_H #define UTARRAY_VERSION 2.0.1 #ifdef __GNUC__ #define _UNUSED_ __attribute__ ((__unused__)) #else #define _UNUSED_ #endif #include /* size_t */ #include /* memset, etc */ #include /* exit */ #ifndef oom #define oom() exit(-1) #endif typedef void (ctor_f)(void *dst, const void *src); typedef void (dtor_f)(void *elt); typedef void (init_f)(void *elt); typedef struct { size_t sz; init_f *init; ctor_f *copy; dtor_f *dtor; } UT_icd; typedef struct { unsigned i,n;/* i: index of next available slot, n: num slots */ UT_icd icd; /* initializer, copy and destructor functions */ char *d; /* n slots of size icd->sz*/ } UT_array; #define utarray_init(a,_icd) do { \ memset(a,0,sizeof(UT_array)); \ (a)->icd = *(_icd); \ } while(0) #define utarray_done(a) do { \ if ((a)->n) { \ if ((a)->icd.dtor) { \ unsigned _ut_i; \ for(_ut_i=0; _ut_i < (a)->i; _ut_i++) { \ (a)->icd.dtor(utarray_eltptr(a,_ut_i)); \ } \ } \ free((a)->d); \ } \ (a)->n=0; \ } while(0) #define utarray_new(a,_icd) do { \ (a) = (UT_array*)malloc(sizeof(UT_array)); \ if ((a) == NULL) oom(); \ utarray_init(a,_icd); \ } while(0) #define utarray_free(a) do { \ utarray_done(a); \ free(a); \ } while(0) #define utarray_reserve(a,by) do { \ if (((a)->i+(by)) > (a)->n) { \ char *utarray_tmp; \ while (((a)->i+(by)) > (a)->n) { (a)->n = ((a)->n ? (2*(a)->n) : 8); } \ utarray_tmp=(char*)realloc((a)->d, (a)->n*(a)->icd.sz); \ if (utarray_tmp == NULL) oom(); \ (a)->d=utarray_tmp; \ } \ } while(0) #define utarray_push_back(a,p) do { \ utarray_reserve(a,1); \ if ((a)->icd.copy) { (a)->icd.copy( _utarray_eltptr(a,(a)->i++), p); } \ else { memcpy(_utarray_eltptr(a,(a)->i++), p, (a)->icd.sz); }; \ } while(0) #define utarray_pop_back(a) do { \ if ((a)->icd.dtor) { (a)->icd.dtor( _utarray_eltptr(a,--((a)->i))); } \ else { (a)->i--; } \ } while(0) #define utarray_extend_back(a) do { \ utarray_reserve(a,1); \ if ((a)->icd.init) { (a)->icd.init(_utarray_eltptr(a,(a)->i)); } \ else { memset(_utarray_eltptr(a,(a)->i),0,(a)->icd.sz); } \ (a)->i++; \ } while(0) #define utarray_len(a) ((a)->i) #define utarray_eltptr(a,j) (((j) < (a)->i) ? _utarray_eltptr(a,j) : NULL) #define _utarray_eltptr(a,j) ((a)->d + ((a)->icd.sz * (j))) #define utarray_insert(a,p,j) do { \ if ((j) > (a)->i) utarray_resize(a,j); \ utarray_reserve(a,1); \ if ((j) < (a)->i) { \ memmove( _utarray_eltptr(a,(j)+1), _utarray_eltptr(a,j), \ ((a)->i - (j))*((a)->icd.sz)); \ } \ if ((a)->icd.copy) { (a)->icd.copy( _utarray_eltptr(a,j), p); } \ else { memcpy(_utarray_eltptr(a,j), p, (a)->icd.sz); }; \ (a)->i++; \ } while(0) #define utarray_inserta(a,w,j) do { \ if (utarray_len(w) == 0) break; \ if ((j) > (a)->i) utarray_resize(a,j); \ utarray_reserve(a,utarray_len(w)); \ if ((j) < (a)->i) { \ memmove(_utarray_eltptr(a,(j)+utarray_len(w)), \ _utarray_eltptr(a,j), \ ((a)->i - (j))*((a)->icd.sz)); \ } \ if ((a)->icd.copy) { \ unsigned _ut_i; \ for(_ut_i=0;_ut_i<(w)->i;_ut_i++) { \ (a)->icd.copy(_utarray_eltptr(a, (j) + _ut_i), _utarray_eltptr(w, _ut_i)); \ } \ } else { \ memcpy(_utarray_eltptr(a,j), _utarray_eltptr(w,0), \ utarray_len(w)*((a)->icd.sz)); \ } \ (a)->i += utarray_len(w); \ } while(0) #define utarray_resize(dst,num) do { \ unsigned _ut_i; \ if ((dst)->i > (unsigned)(num)) { \ if ((dst)->icd.dtor) { \ for (_ut_i = (num); _ut_i < (dst)->i; ++_ut_i) { \ (dst)->icd.dtor(_utarray_eltptr(dst, _ut_i)); \ } \ } \ } else if ((dst)->i < (unsigned)(num)) { \ utarray_reserve(dst, (num) - (dst)->i); \ if ((dst)->icd.init) { \ for (_ut_i = (dst)->i; _ut_i < (unsigned)(num); ++_ut_i) { \ (dst)->icd.init(_utarray_eltptr(dst, _ut_i)); \ } \ } else { \ memset(_utarray_eltptr(dst, (dst)->i), 0, (dst)->icd.sz*((num) - (dst)->i)); \ } \ } \ (dst)->i = (num); \ } while(0) #define utarray_concat(dst,src) do { \ utarray_inserta(dst, src, utarray_len(dst)); \ } while(0) #define utarray_erase(a,pos,len) do { \ if ((a)->icd.dtor) { \ unsigned _ut_i; \ for (_ut_i = 0; _ut_i < (len); _ut_i++) { \ (a)->icd.dtor(utarray_eltptr(a, (pos) + _ut_i)); \ } \ } \ if ((a)->i > ((pos) + (len))) { \ memmove(_utarray_eltptr(a, pos), _utarray_eltptr(a, (pos) + (len)), \ ((a)->i - ((pos) + (len))) * (a)->icd.sz); \ } \ (a)->i -= (len); \ } while(0) #define utarray_renew(a,u) do { \ if (a) utarray_clear(a); \ else utarray_new(a, u); \ } while(0) #define utarray_clear(a) do { \ if ((a)->i > 0) { \ if ((a)->icd.dtor) { \ unsigned _ut_i; \ for(_ut_i=0; _ut_i < (a)->i; _ut_i++) { \ (a)->icd.dtor(_utarray_eltptr(a, _ut_i)); \ } \ } \ (a)->i = 0; \ } \ } while(0) #define utarray_sort(a,cmp) do { \ qsort((a)->d, (a)->i, (a)->icd.sz, cmp); \ } while(0) #define utarray_find(a,v,cmp) bsearch((v),(a)->d,(a)->i,(a)->icd.sz,cmp) #define utarray_front(a) (((a)->i) ? (_utarray_eltptr(a,0)) : NULL) #define utarray_next(a,e) (((e)==NULL) ? utarray_front(a) : ((((a)->i) > (utarray_eltidx(a,e)+1)) ? _utarray_eltptr(a,utarray_eltidx(a,e)+1) : NULL)) #define utarray_prev(a,e) (((e)==NULL) ? utarray_back(a) : ((utarray_eltidx(a,e) > 0) ? _utarray_eltptr(a,utarray_eltidx(a,e)-1) : NULL)) #define utarray_back(a) (((a)->i) ? (_utarray_eltptr(a,(a)->i-1)) : NULL) #define utarray_eltidx(a,e) (((char*)(e) >= (a)->d) ? (((char*)(e) - (a)->d)/(a)->icd.sz) : -1) /* last we pre-define a few icd for common utarrays of ints and strings */ static void utarray_str_cpy(void *dst, const void *src) { char **_src = (char**)src, **_dst = (char**)dst; *_dst = (*_src == NULL) ? NULL : strdup(*_src); } static void utarray_str_dtor(void *elt) { char **eltc = (char**)elt; if (*eltc != NULL) free(*eltc); } static const UT_icd ut_str_icd _UNUSED_ = {sizeof(char*),NULL,utarray_str_cpy,utarray_str_dtor}; static const UT_icd ut_int_icd _UNUSED_ = {sizeof(int),NULL,NULL,NULL}; static const UT_icd ut_ptr_icd _UNUSED_ = {sizeof(void*),NULL,NULL,NULL}; #endif /* UTARRAY_H */ libsignal-protocol-c-2.3.3/src/uthash.h000066400000000000000000002075531363751346500200270ustar00rootroot00000000000000/* Copyright (c) 2003-2016, Troy D. Hanson http://troydhanson.github.com/uthash/ All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #ifndef UTHASH_H #define UTHASH_H #define UTHASH_VERSION 2.0.1 #include /* memcmp,strlen */ #include /* ptrdiff_t */ #include /* exit() */ /* These macros use decltype or the earlier __typeof GNU extension. As decltype is only available in newer compilers (VS2010 or gcc 4.3+ when compiling c++ source) this code uses whatever method is needed or, for VS2008 where neither is available, uses casting workarounds. */ #if defined(_MSC_VER) /* MS compiler */ #if _MSC_VER >= 1600 && defined(__cplusplus) /* VS2010 or newer in C++ mode */ #define DECLTYPE(x) (decltype(x)) #else /* VS2008 or older (or VS2010 in C mode) */ #define NO_DECLTYPE #define DECLTYPE(x) #endif #elif defined(__BORLANDC__) || defined(__LCC__) || defined(__WATCOMC__) #define NO_DECLTYPE #define DECLTYPE(x) #else /* GNU, Sun and other compilers */ #define DECLTYPE(x) (__typeof(x)) #endif #ifdef NO_DECLTYPE #define DECLTYPE_ASSIGN(dst,src) \ do { \ char **_da_dst = (char**)(&(dst)); \ *_da_dst = (char*)(src); \ } while (0) #else #define DECLTYPE_ASSIGN(dst,src) \ do { \ (dst) = DECLTYPE(dst)(src); \ } while (0) #endif /* a number of the hash function use uint32_t which isn't defined on Pre VS2010 */ #if defined(_WIN32) #if defined(_MSC_VER) && _MSC_VER >= 1600 #include #elif defined(__WATCOMC__) || defined(__MINGW32__) || defined(__CYGWIN__) #include #else typedef unsigned int uint32_t; typedef unsigned char uint8_t; #endif #elif defined(__GNUC__) && !defined(__VXWORKS__) #include #else typedef unsigned int uint32_t; typedef unsigned char uint8_t; #endif #ifndef uthash_fatal #define uthash_fatal(msg) exit(-1) /* fatal error (out of memory,etc) */ #endif #ifndef uthash_malloc #define uthash_malloc(sz) malloc(sz) /* malloc fcn */ #endif #ifndef uthash_free #define uthash_free(ptr,sz) free(ptr) /* free fcn */ #endif #ifndef uthash_strlen #define uthash_strlen(s) strlen(s) #endif #ifndef uthash_memcmp #define uthash_memcmp(a,b,n) memcmp(a,b,n) #endif #ifndef uthash_noexpand_fyi #define uthash_noexpand_fyi(tbl) /* can be defined to log noexpand */ #endif #ifndef uthash_expand_fyi #define uthash_expand_fyi(tbl) /* can be defined to log expands */ #endif /* initial number of buckets */ #define HASH_INITIAL_NUM_BUCKETS 32U /* initial number of buckets */ #define HASH_INITIAL_NUM_BUCKETS_LOG2 5U /* lg2 of initial number of buckets */ #define HASH_BKT_CAPACITY_THRESH 10U /* expand when bucket count reaches */ /* calculate the element whose hash handle address is hhp */ #define ELMT_FROM_HH(tbl,hhp) ((void*)(((char*)(hhp)) - ((tbl)->hho))) /* calculate the hash handle from element address elp */ #define HH_FROM_ELMT(tbl,elp) ((UT_hash_handle *)(((char*)(elp)) + ((tbl)->hho))) #define HASH_VALUE(keyptr,keylen,hashv) \ do { \ HASH_FCN(keyptr, keylen, hashv); \ } while (0) #define HASH_FIND_BYHASHVALUE(hh,head,keyptr,keylen,hashval,out) \ do { \ (out) = NULL; \ if (head) { \ unsigned _hf_bkt; \ HASH_TO_BKT(hashval, (head)->hh.tbl->num_buckets, _hf_bkt); \ if (HASH_BLOOM_TEST((head)->hh.tbl, hashval) != 0) { \ HASH_FIND_IN_BKT((head)->hh.tbl, hh, (head)->hh.tbl->buckets[ _hf_bkt ], keyptr, keylen, hashval, out); \ } \ } \ } while (0) #define HASH_FIND(hh,head,keyptr,keylen,out) \ do { \ unsigned _hf_hashv; \ HASH_VALUE(keyptr, keylen, _hf_hashv); \ HASH_FIND_BYHASHVALUE(hh, head, keyptr, keylen, _hf_hashv, out); \ } while (0) #ifdef HASH_BLOOM #define HASH_BLOOM_BITLEN (1UL << HASH_BLOOM) #define HASH_BLOOM_BYTELEN (HASH_BLOOM_BITLEN/8UL) + (((HASH_BLOOM_BITLEN%8UL)!=0UL) ? 1UL : 0UL) #define HASH_BLOOM_MAKE(tbl) \ do { \ (tbl)->bloom_nbits = HASH_BLOOM; \ (tbl)->bloom_bv = (uint8_t*)uthash_malloc(HASH_BLOOM_BYTELEN); \ if (!((tbl)->bloom_bv)) { uthash_fatal( "out of memory"); } \ memset((tbl)->bloom_bv, 0, HASH_BLOOM_BYTELEN); \ (tbl)->bloom_sig = HASH_BLOOM_SIGNATURE; \ } while (0) #define HASH_BLOOM_FREE(tbl) \ do { \ uthash_free((tbl)->bloom_bv, HASH_BLOOM_BYTELEN); \ } while (0) #define HASH_BLOOM_BITSET(bv,idx) (bv[(idx)/8U] |= (1U << ((idx)%8U))) #define HASH_BLOOM_BITTEST(bv,idx) (bv[(idx)/8U] & (1U << ((idx)%8U))) #define HASH_BLOOM_ADD(tbl,hashv) \ HASH_BLOOM_BITSET((tbl)->bloom_bv, (hashv & (uint32_t)((1ULL << (tbl)->bloom_nbits) - 1U))) #define HASH_BLOOM_TEST(tbl,hashv) \ HASH_BLOOM_BITTEST((tbl)->bloom_bv, (hashv & (uint32_t)((1ULL << (tbl)->bloom_nbits) - 1U))) #else #define HASH_BLOOM_MAKE(tbl) #define HASH_BLOOM_FREE(tbl) #define HASH_BLOOM_ADD(tbl,hashv) #define HASH_BLOOM_TEST(tbl,hashv) (1) #define HASH_BLOOM_BYTELEN 0U #endif #define HASH_MAKE_TABLE(hh,head) \ do { \ (head)->hh.tbl = (UT_hash_table*)uthash_malloc( \ sizeof(UT_hash_table)); \ if (!((head)->hh.tbl)) { uthash_fatal( "out of memory"); } \ memset((head)->hh.tbl, 0, sizeof(UT_hash_table)); \ (head)->hh.tbl->tail = &((head)->hh); \ (head)->hh.tbl->num_buckets = HASH_INITIAL_NUM_BUCKETS; \ (head)->hh.tbl->log2_num_buckets = HASH_INITIAL_NUM_BUCKETS_LOG2; \ (head)->hh.tbl->hho = (char*)(&(head)->hh) - (char*)(head); \ (head)->hh.tbl->buckets = (UT_hash_bucket*)uthash_malloc( \ HASH_INITIAL_NUM_BUCKETS*sizeof(struct UT_hash_bucket)); \ if (! (head)->hh.tbl->buckets) { uthash_fatal( "out of memory"); } \ memset((head)->hh.tbl->buckets, 0, \ HASH_INITIAL_NUM_BUCKETS*sizeof(struct UT_hash_bucket)); \ HASH_BLOOM_MAKE((head)->hh.tbl); \ (head)->hh.tbl->signature = HASH_SIGNATURE; \ } while (0) #define HASH_REPLACE_BYHASHVALUE_INORDER(hh,head,fieldname,keylen_in,hashval,add,replaced,cmpfcn) \ do { \ (replaced) = NULL; \ HASH_FIND_BYHASHVALUE(hh, head, &((add)->fieldname), keylen_in, hashval, replaced); \ if (replaced) { \ HASH_DELETE(hh, head, replaced); \ } \ HASH_ADD_KEYPTR_BYHASHVALUE_INORDER(hh, head, &((add)->fieldname), keylen_in, hashval, add, cmpfcn); \ } while (0) #define HASH_REPLACE_BYHASHVALUE(hh,head,fieldname,keylen_in,hashval,add,replaced) \ do { \ (replaced) = NULL; \ HASH_FIND_BYHASHVALUE(hh, head, &((add)->fieldname), keylen_in, hashval, replaced); \ if (replaced) { \ HASH_DELETE(hh, head, replaced); \ } \ HASH_ADD_KEYPTR_BYHASHVALUE(hh, head, &((add)->fieldname), keylen_in, hashval, add); \ } while (0) #define HASH_REPLACE(hh,head,fieldname,keylen_in,add,replaced) \ do { \ unsigned _hr_hashv; \ HASH_VALUE(&((add)->fieldname), keylen_in, _hr_hashv); \ HASH_REPLACE_BYHASHVALUE(hh, head, fieldname, keylen_in, _hr_hashv, add, replaced); \ } while (0) #define HASH_REPLACE_INORDER(hh,head,fieldname,keylen_in,add,replaced,cmpfcn) \ do { \ unsigned _hr_hashv; \ HASH_VALUE(&((add)->fieldname), keylen_in, _hr_hashv); \ HASH_REPLACE_BYHASHVALUE_INORDER(hh, head, fieldname, keylen_in, _hr_hashv, add, replaced, cmpfcn); \ } while (0) #define HASH_APPEND_LIST(hh, head, add) \ do { \ (add)->hh.next = NULL; \ (add)->hh.prev = ELMT_FROM_HH((head)->hh.tbl, (head)->hh.tbl->tail); \ (head)->hh.tbl->tail->next = (add); \ (head)->hh.tbl->tail = &((add)->hh); \ } while (0) #define HASH_ADD_KEYPTR_BYHASHVALUE_INORDER(hh,head,keyptr,keylen_in,hashval,add,cmpfcn) \ do { \ unsigned _ha_bkt; \ (add)->hh.hashv = (hashval); \ (add)->hh.key = (char*) (keyptr); \ (add)->hh.keylen = (unsigned) (keylen_in); \ if (!(head)) { \ (add)->hh.next = NULL; \ (add)->hh.prev = NULL; \ (head) = (add); \ HASH_MAKE_TABLE(hh, head); \ } else { \ void *_hs_iter = (head); \ (add)->hh.tbl = (head)->hh.tbl; \ do { \ if (cmpfcn(DECLTYPE(head)(_hs_iter), add) > 0) \ break; \ } while ((_hs_iter = HH_FROM_ELMT((head)->hh.tbl, _hs_iter)->next)); \ if (_hs_iter) { \ (add)->hh.next = _hs_iter; \ if (((add)->hh.prev = HH_FROM_ELMT((head)->hh.tbl, _hs_iter)->prev)) { \ HH_FROM_ELMT((head)->hh.tbl, (add)->hh.prev)->next = (add); \ } else { \ (head) = (add); \ } \ HH_FROM_ELMT((head)->hh.tbl, _hs_iter)->prev = (add); \ } else { \ HASH_APPEND_LIST(hh, head, add); \ } \ } \ (head)->hh.tbl->num_items++; \ HASH_TO_BKT(hashval, (head)->hh.tbl->num_buckets, _ha_bkt); \ HASH_ADD_TO_BKT((head)->hh.tbl->buckets[_ha_bkt], &(add)->hh); \ HASH_BLOOM_ADD((head)->hh.tbl, hashval); \ HASH_EMIT_KEY(hh, head, keyptr, keylen_in); \ HASH_FSCK(hh, head); \ } while (0) #define HASH_ADD_KEYPTR_INORDER(hh,head,keyptr,keylen_in,add,cmpfcn) \ do { \ unsigned _hs_hashv; \ HASH_VALUE(keyptr, keylen_in, _hs_hashv); \ HASH_ADD_KEYPTR_BYHASHVALUE_INORDER(hh, head, keyptr, keylen_in, _hs_hashv, add, cmpfcn); \ } while (0) #define HASH_ADD_BYHASHVALUE_INORDER(hh,head,fieldname,keylen_in,hashval,add,cmpfcn) \ HASH_ADD_KEYPTR_BYHASHVALUE_INORDER(hh, head, &((add)->fieldname), keylen_in, hashval, add, cmpfcn) #define HASH_ADD_INORDER(hh,head,fieldname,keylen_in,add,cmpfcn) \ HASH_ADD_KEYPTR_INORDER(hh, head, &((add)->fieldname), keylen_in, add, cmpfcn) #define HASH_ADD_KEYPTR_BYHASHVALUE(hh,head,keyptr,keylen_in,hashval,add) \ do { \ unsigned _ha_bkt; \ (add)->hh.hashv = (hashval); \ (add)->hh.key = (char*) (keyptr); \ (add)->hh.keylen = (unsigned) (keylen_in); \ if (!(head)) { \ (add)->hh.next = NULL; \ (add)->hh.prev = NULL; \ (head) = (add); \ HASH_MAKE_TABLE(hh, head); \ } else { \ (add)->hh.tbl = (head)->hh.tbl; \ HASH_APPEND_LIST(hh, head, add); \ } \ (head)->hh.tbl->num_items++; \ HASH_TO_BKT(hashval, (head)->hh.tbl->num_buckets, _ha_bkt); \ HASH_ADD_TO_BKT((head)->hh.tbl->buckets[_ha_bkt], &(add)->hh); \ HASH_BLOOM_ADD((head)->hh.tbl, hashval); \ HASH_EMIT_KEY(hh, head, keyptr, keylen_in); \ HASH_FSCK(hh, head); \ } while (0) #define HASH_ADD_KEYPTR(hh,head,keyptr,keylen_in,add) \ do { \ unsigned _ha_hashv; \ HASH_VALUE(keyptr, keylen_in, _ha_hashv); \ HASH_ADD_KEYPTR_BYHASHVALUE(hh, head, keyptr, keylen_in, _ha_hashv, add); \ } while (0) #define HASH_ADD_BYHASHVALUE(hh,head,fieldname,keylen_in,hashval,add) \ HASH_ADD_KEYPTR_BYHASHVALUE(hh, head, &((add)->fieldname), keylen_in, hashval, add) #define HASH_ADD(hh,head,fieldname,keylen_in,add) \ HASH_ADD_KEYPTR(hh, head, &((add)->fieldname), keylen_in, add) #define HASH_TO_BKT(hashv,num_bkts,bkt) \ do { \ bkt = ((hashv) & ((num_bkts) - 1U)); \ } while (0) /* delete "delptr" from the hash table. * "the usual" patch-up process for the app-order doubly-linked-list. * The use of _hd_hh_del below deserves special explanation. * These used to be expressed using (delptr) but that led to a bug * if someone used the same symbol for the head and deletee, like * HASH_DELETE(hh,users,users); * We want that to work, but by changing the head (users) below * we were forfeiting our ability to further refer to the deletee (users) * in the patch-up process. Solution: use scratch space to * copy the deletee pointer, then the latter references are via that * scratch pointer rather than through the repointed (users) symbol. */ #define HASH_DELETE(hh,head,delptr) \ do { \ struct UT_hash_handle *_hd_hh_del; \ if ( ((delptr)->hh.prev == NULL) && ((delptr)->hh.next == NULL) ) { \ uthash_free((head)->hh.tbl->buckets, \ (head)->hh.tbl->num_buckets*sizeof(struct UT_hash_bucket) ); \ HASH_BLOOM_FREE((head)->hh.tbl); \ uthash_free((head)->hh.tbl, sizeof(UT_hash_table)); \ head = NULL; \ } else { \ unsigned _hd_bkt; \ _hd_hh_del = &((delptr)->hh); \ if ((delptr) == ELMT_FROM_HH((head)->hh.tbl,(head)->hh.tbl->tail)) { \ (head)->hh.tbl->tail = \ (UT_hash_handle*)((ptrdiff_t)((delptr)->hh.prev) + \ (head)->hh.tbl->hho); \ } \ if ((delptr)->hh.prev != NULL) { \ ((UT_hash_handle*)((ptrdiff_t)((delptr)->hh.prev) + \ (head)->hh.tbl->hho))->next = (delptr)->hh.next; \ } else { \ DECLTYPE_ASSIGN(head,(delptr)->hh.next); \ } \ if (_hd_hh_del->next != NULL) { \ ((UT_hash_handle*)((ptrdiff_t)_hd_hh_del->next + \ (head)->hh.tbl->hho))->prev = \ _hd_hh_del->prev; \ } \ HASH_TO_BKT( _hd_hh_del->hashv, (head)->hh.tbl->num_buckets, _hd_bkt); \ HASH_DEL_IN_BKT(hh,(head)->hh.tbl->buckets[_hd_bkt], _hd_hh_del); \ (head)->hh.tbl->num_items--; \ } \ HASH_FSCK(hh,head); \ } while (0) /* convenience forms of HASH_FIND/HASH_ADD/HASH_DEL */ #define HASH_FIND_STR(head,findstr,out) \ HASH_FIND(hh,head,findstr,(unsigned)uthash_strlen(findstr),out) #define HASH_ADD_STR(head,strfield,add) \ HASH_ADD(hh,head,strfield[0],(unsigned)uthash_strlen(add->strfield),add) #define HASH_REPLACE_STR(head,strfield,add,replaced) \ HASH_REPLACE(hh,head,strfield[0],(unsigned)uthash_strlen(add->strfield),add,replaced) #define HASH_FIND_INT(head,findint,out) \ HASH_FIND(hh,head,findint,sizeof(int),out) #define HASH_ADD_INT(head,intfield,add) \ HASH_ADD(hh,head,intfield,sizeof(int),add) #define HASH_REPLACE_INT(head,intfield,add,replaced) \ HASH_REPLACE(hh,head,intfield,sizeof(int),add,replaced) #define HASH_FIND_PTR(head,findptr,out) \ HASH_FIND(hh,head,findptr,sizeof(void *),out) #define HASH_ADD_PTR(head,ptrfield,add) \ HASH_ADD(hh,head,ptrfield,sizeof(void *),add) #define HASH_REPLACE_PTR(head,ptrfield,add,replaced) \ HASH_REPLACE(hh,head,ptrfield,sizeof(void *),add,replaced) #define HASH_DEL(head,delptr) \ HASH_DELETE(hh,head,delptr) /* HASH_FSCK checks hash integrity on every add/delete when HASH_DEBUG is defined. * This is for uthash developer only; it compiles away if HASH_DEBUG isn't defined. */ #ifdef HASH_DEBUG #define HASH_OOPS(...) do { fprintf(stderr,__VA_ARGS__); exit(-1); } while (0) #define HASH_FSCK(hh,head) \ do { \ struct UT_hash_handle *_thh; \ if (head) { \ unsigned _bkt_i; \ unsigned _count; \ char *_prev; \ _count = 0; \ for( _bkt_i = 0; _bkt_i < (head)->hh.tbl->num_buckets; _bkt_i++) { \ unsigned _bkt_count = 0; \ _thh = (head)->hh.tbl->buckets[_bkt_i].hh_head; \ _prev = NULL; \ while (_thh) { \ if (_prev != (char*)(_thh->hh_prev)) { \ HASH_OOPS("invalid hh_prev %p, actual %p\n", \ _thh->hh_prev, _prev ); \ } \ _bkt_count++; \ _prev = (char*)(_thh); \ _thh = _thh->hh_next; \ } \ _count += _bkt_count; \ if ((head)->hh.tbl->buckets[_bkt_i].count != _bkt_count) { \ HASH_OOPS("invalid bucket count %u, actual %u\n", \ (head)->hh.tbl->buckets[_bkt_i].count, _bkt_count); \ } \ } \ if (_count != (head)->hh.tbl->num_items) { \ HASH_OOPS("invalid hh item count %u, actual %u\n", \ (head)->hh.tbl->num_items, _count ); \ } \ /* traverse hh in app order; check next/prev integrity, count */ \ _count = 0; \ _prev = NULL; \ _thh = &(head)->hh; \ while (_thh) { \ _count++; \ if (_prev !=(char*)(_thh->prev)) { \ HASH_OOPS("invalid prev %p, actual %p\n", \ _thh->prev, _prev ); \ } \ _prev = (char*)ELMT_FROM_HH((head)->hh.tbl, _thh); \ _thh = ( _thh->next ? (UT_hash_handle*)((char*)(_thh->next) + \ (head)->hh.tbl->hho) : NULL ); \ } \ if (_count != (head)->hh.tbl->num_items) { \ HASH_OOPS("invalid app item count %u, actual %u\n", \ (head)->hh.tbl->num_items, _count ); \ } \ } \ } while (0) #else #define HASH_FSCK(hh,head) #endif /* When compiled with -DHASH_EMIT_KEYS, length-prefixed keys are emitted to * the descriptor to which this macro is defined for tuning the hash function. * The app can #include to get the prototype for write(2). */ #ifdef HASH_EMIT_KEYS #define HASH_EMIT_KEY(hh,head,keyptr,fieldlen) \ do { \ unsigned _klen = fieldlen; \ write(HASH_EMIT_KEYS, &_klen, sizeof(_klen)); \ write(HASH_EMIT_KEYS, keyptr, (unsigned long)fieldlen); \ } while (0) #else #define HASH_EMIT_KEY(hh,head,keyptr,fieldlen) #endif /* default to Jenkin's hash unless overridden e.g. DHASH_FUNCTION=HASH_SAX */ #ifdef HASH_FUNCTION #define HASH_FCN HASH_FUNCTION #else #define HASH_FCN HASH_JEN #endif /* The Bernstein hash function, used in Perl prior to v5.6. Note (x<<5+x)=x*33. */ #define HASH_BER(key,keylen,hashv) \ do { \ unsigned _hb_keylen=(unsigned)keylen; \ const unsigned char *_hb_key=(const unsigned char*)(key); \ (hashv) = 0; \ while (_hb_keylen-- != 0U) { \ (hashv) = (((hashv) << 5) + (hashv)) + *_hb_key++; \ } \ } while (0) /* SAX/FNV/OAT/JEN hash functions are macro variants of those listed at * http://eternallyconfuzzled.com/tuts/algorithms/jsw_tut_hashing.aspx */ #define HASH_SAX(key,keylen,hashv) \ do { \ unsigned _sx_i; \ const unsigned char *_hs_key=(const unsigned char*)(key); \ hashv = 0; \ for(_sx_i=0; _sx_i < keylen; _sx_i++) { \ hashv ^= (hashv << 5) + (hashv >> 2) + _hs_key[_sx_i]; \ } \ } while (0) /* FNV-1a variation */ #define HASH_FNV(key,keylen,hashv) \ do { \ unsigned _fn_i; \ const unsigned char *_hf_key=(const unsigned char*)(key); \ hashv = 2166136261U; \ for(_fn_i=0; _fn_i < keylen; _fn_i++) { \ hashv = hashv ^ _hf_key[_fn_i]; \ hashv = hashv * 16777619U; \ } \ } while (0) #define HASH_OAT(key,keylen,hashv) \ do { \ unsigned _ho_i; \ const unsigned char *_ho_key=(const unsigned char*)(key); \ hashv = 0; \ for(_ho_i=0; _ho_i < keylen; _ho_i++) { \ hashv += _ho_key[_ho_i]; \ hashv += (hashv << 10); \ hashv ^= (hashv >> 6); \ } \ hashv += (hashv << 3); \ hashv ^= (hashv >> 11); \ hashv += (hashv << 15); \ } while (0) #define HASH_JEN_MIX(a,b,c) \ do { \ a -= b; a -= c; a ^= ( c >> 13 ); \ b -= c; b -= a; b ^= ( a << 8 ); \ c -= a; c -= b; c ^= ( b >> 13 ); \ a -= b; a -= c; a ^= ( c >> 12 ); \ b -= c; b -= a; b ^= ( a << 16 ); \ c -= a; c -= b; c ^= ( b >> 5 ); \ a -= b; a -= c; a ^= ( c >> 3 ); \ b -= c; b -= a; b ^= ( a << 10 ); \ c -= a; c -= b; c ^= ( b >> 15 ); \ } while (0) #define HASH_JEN(key,keylen,hashv) \ do { \ unsigned _hj_i,_hj_j,_hj_k; \ unsigned const char *_hj_key=(unsigned const char*)(key); \ hashv = 0xfeedbeefu; \ _hj_i = _hj_j = 0x9e3779b9u; \ _hj_k = (unsigned)(keylen); \ while (_hj_k >= 12U) { \ _hj_i += (_hj_key[0] + ( (unsigned)_hj_key[1] << 8 ) \ + ( (unsigned)_hj_key[2] << 16 ) \ + ( (unsigned)_hj_key[3] << 24 ) ); \ _hj_j += (_hj_key[4] + ( (unsigned)_hj_key[5] << 8 ) \ + ( (unsigned)_hj_key[6] << 16 ) \ + ( (unsigned)_hj_key[7] << 24 ) ); \ hashv += (_hj_key[8] + ( (unsigned)_hj_key[9] << 8 ) \ + ( (unsigned)_hj_key[10] << 16 ) \ + ( (unsigned)_hj_key[11] << 24 ) ); \ \ HASH_JEN_MIX(_hj_i, _hj_j, hashv); \ \ _hj_key += 12; \ _hj_k -= 12U; \ } \ hashv += (unsigned)(keylen); \ switch ( _hj_k ) { \ case 11: hashv += ( (unsigned)_hj_key[10] << 24 ); /* FALLTHROUGH */ \ case 10: hashv += ( (unsigned)_hj_key[9] << 16 ); /* FALLTHROUGH */ \ case 9: hashv += ( (unsigned)_hj_key[8] << 8 ); /* FALLTHROUGH */ \ case 8: _hj_j += ( (unsigned)_hj_key[7] << 24 ); /* FALLTHROUGH */ \ case 7: _hj_j += ( (unsigned)_hj_key[6] << 16 ); /* FALLTHROUGH */ \ case 6: _hj_j += ( (unsigned)_hj_key[5] << 8 ); /* FALLTHROUGH */ \ case 5: _hj_j += _hj_key[4]; /* FALLTHROUGH */ \ case 4: _hj_i += ( (unsigned)_hj_key[3] << 24 ); /* FALLTHROUGH */ \ case 3: _hj_i += ( (unsigned)_hj_key[2] << 16 ); /* FALLTHROUGH */ \ case 2: _hj_i += ( (unsigned)_hj_key[1] << 8 ); /* FALLTHROUGH */ \ case 1: _hj_i += _hj_key[0]; \ } \ HASH_JEN_MIX(_hj_i, _hj_j, hashv); \ } while (0) /* The Paul Hsieh hash function */ #undef get16bits #if (defined(__GNUC__) && defined(__i386__)) || defined(__WATCOMC__) \ || defined(_MSC_VER) || defined (__BORLANDC__) || defined (__TURBOC__) #define get16bits(d) (*((const uint16_t *) (d))) #endif #if !defined (get16bits) #define get16bits(d) ((((uint32_t)(((const uint8_t *)(d))[1])) << 8) \ +(uint32_t)(((const uint8_t *)(d))[0]) ) #endif #define HASH_SFH(key,keylen,hashv) \ do { \ unsigned const char *_sfh_key=(unsigned const char*)(key); \ uint32_t _sfh_tmp, _sfh_len = (uint32_t)keylen; \ \ unsigned _sfh_rem = _sfh_len & 3U; \ _sfh_len >>= 2; \ hashv = 0xcafebabeu; \ \ /* Main loop */ \ for (;_sfh_len > 0U; _sfh_len--) { \ hashv += get16bits (_sfh_key); \ _sfh_tmp = ((uint32_t)(get16bits (_sfh_key+2)) << 11) ^ hashv; \ hashv = (hashv << 16) ^ _sfh_tmp; \ _sfh_key += 2U*sizeof (uint16_t); \ hashv += hashv >> 11; \ } \ \ /* Handle end cases */ \ switch (_sfh_rem) { \ case 3: hashv += get16bits (_sfh_key); \ hashv ^= hashv << 16; \ hashv ^= (uint32_t)(_sfh_key[sizeof (uint16_t)]) << 18; \ hashv += hashv >> 11; \ break; \ case 2: hashv += get16bits (_sfh_key); \ hashv ^= hashv << 11; \ hashv += hashv >> 17; \ break; \ case 1: hashv += *_sfh_key; \ hashv ^= hashv << 10; \ hashv += hashv >> 1; \ } \ \ /* Force "avalanching" of final 127 bits */ \ hashv ^= hashv << 3; \ hashv += hashv >> 5; \ hashv ^= hashv << 4; \ hashv += hashv >> 17; \ hashv ^= hashv << 25; \ hashv += hashv >> 6; \ } while (0) #ifdef HASH_USING_NO_STRICT_ALIASING /* The MurmurHash exploits some CPU's (x86,x86_64) tolerance for unaligned reads. * For other types of CPU's (e.g. Sparc) an unaligned read causes a bus error. * MurmurHash uses the faster approach only on CPU's where we know it's safe. * * Note the preprocessor built-in defines can be emitted using: * * gcc -m64 -dM -E - < /dev/null (on gcc) * cc -## a.c (where a.c is a simple test file) (Sun Studio) */ #if (defined(__i386__) || defined(__x86_64__) || defined(_M_IX86)) #define MUR_GETBLOCK(p,i) p[i] #else /* non intel */ #define MUR_PLUS0_ALIGNED(p) (((unsigned long)p & 3UL) == 0UL) #define MUR_PLUS1_ALIGNED(p) (((unsigned long)p & 3UL) == 1UL) #define MUR_PLUS2_ALIGNED(p) (((unsigned long)p & 3UL) == 2UL) #define MUR_PLUS3_ALIGNED(p) (((unsigned long)p & 3UL) == 3UL) #define WP(p) ((uint32_t*)((unsigned long)(p) & ~3UL)) #if (defined(__BIG_ENDIAN__) || defined(SPARC) || defined(__ppc__) || defined(__ppc64__)) #define MUR_THREE_ONE(p) ((((*WP(p))&0x00ffffff) << 8) | (((*(WP(p)+1))&0xff000000) >> 24)) #define MUR_TWO_TWO(p) ((((*WP(p))&0x0000ffff) <<16) | (((*(WP(p)+1))&0xffff0000) >> 16)) #define MUR_ONE_THREE(p) ((((*WP(p))&0x000000ff) <<24) | (((*(WP(p)+1))&0xffffff00) >> 8)) #else /* assume little endian non-intel */ #define MUR_THREE_ONE(p) ((((*WP(p))&0xffffff00) >> 8) | (((*(WP(p)+1))&0x000000ff) << 24)) #define MUR_TWO_TWO(p) ((((*WP(p))&0xffff0000) >>16) | (((*(WP(p)+1))&0x0000ffff) << 16)) #define MUR_ONE_THREE(p) ((((*WP(p))&0xff000000) >>24) | (((*(WP(p)+1))&0x00ffffff) << 8)) #endif #define MUR_GETBLOCK(p,i) (MUR_PLUS0_ALIGNED(p) ? ((p)[i]) : \ (MUR_PLUS1_ALIGNED(p) ? MUR_THREE_ONE(p) : \ (MUR_PLUS2_ALIGNED(p) ? MUR_TWO_TWO(p) : \ MUR_ONE_THREE(p)))) #endif #define MUR_ROTL32(x,r) (((x) << (r)) | ((x) >> (32 - (r)))) #define MUR_FMIX(_h) \ do { \ _h ^= _h >> 16; \ _h *= 0x85ebca6bu; \ _h ^= _h >> 13; \ _h *= 0xc2b2ae35u; \ _h ^= _h >> 16; \ } while (0) #define HASH_MUR(key,keylen,hashv) \ do { \ const uint8_t *_mur_data = (const uint8_t*)(key); \ const int _mur_nblocks = (int)(keylen) / 4; \ uint32_t _mur_h1 = 0xf88D5353u; \ uint32_t _mur_c1 = 0xcc9e2d51u; \ uint32_t _mur_c2 = 0x1b873593u; \ uint32_t _mur_k1 = 0; \ const uint8_t *_mur_tail; \ const uint32_t *_mur_blocks = (const uint32_t*)(_mur_data+(_mur_nblocks*4)); \ int _mur_i; \ for(_mur_i = -_mur_nblocks; _mur_i!=0; _mur_i++) { \ _mur_k1 = MUR_GETBLOCK(_mur_blocks,_mur_i); \ _mur_k1 *= _mur_c1; \ _mur_k1 = MUR_ROTL32(_mur_k1,15); \ _mur_k1 *= _mur_c2; \ \ _mur_h1 ^= _mur_k1; \ _mur_h1 = MUR_ROTL32(_mur_h1,13); \ _mur_h1 = (_mur_h1*5U) + 0xe6546b64u; \ } \ _mur_tail = (const uint8_t*)(_mur_data + (_mur_nblocks*4)); \ _mur_k1=0; \ switch((keylen) & 3U) { \ case 3: _mur_k1 ^= (uint32_t)_mur_tail[2] << 16; /* FALLTHROUGH */ \ case 2: _mur_k1 ^= (uint32_t)_mur_tail[1] << 8; /* FALLTHROUGH */ \ case 1: _mur_k1 ^= (uint32_t)_mur_tail[0]; \ _mur_k1 *= _mur_c1; \ _mur_k1 = MUR_ROTL32(_mur_k1,15); \ _mur_k1 *= _mur_c2; \ _mur_h1 ^= _mur_k1; \ } \ _mur_h1 ^= (uint32_t)(keylen); \ MUR_FMIX(_mur_h1); \ hashv = _mur_h1; \ } while (0) #endif /* HASH_USING_NO_STRICT_ALIASING */ /* iterate over items in a known bucket to find desired item */ #define HASH_FIND_IN_BKT(tbl,hh,head,keyptr,keylen_in,hashval,out) \ do { \ if ((head).hh_head != NULL) { \ DECLTYPE_ASSIGN(out, ELMT_FROM_HH(tbl, (head).hh_head)); \ } else { \ (out) = NULL; \ } \ while ((out) != NULL) { \ if ((out)->hh.hashv == (hashval) && (out)->hh.keylen == (keylen_in)) { \ if (uthash_memcmp((out)->hh.key, keyptr, keylen_in) == 0) { \ break; \ } \ } \ if ((out)->hh.hh_next != NULL) { \ DECLTYPE_ASSIGN(out, ELMT_FROM_HH(tbl, (out)->hh.hh_next)); \ } else { \ (out) = NULL; \ } \ } \ } while (0) /* add an item to a bucket */ #define HASH_ADD_TO_BKT(head,addhh) \ do { \ head.count++; \ (addhh)->hh_next = head.hh_head; \ (addhh)->hh_prev = NULL; \ if (head.hh_head != NULL) { (head).hh_head->hh_prev = (addhh); } \ (head).hh_head=addhh; \ if ((head.count >= ((head.expand_mult+1U) * HASH_BKT_CAPACITY_THRESH)) \ && ((addhh)->tbl->noexpand != 1U)) { \ HASH_EXPAND_BUCKETS((addhh)->tbl); \ } \ } while (0) /* remove an item from a given bucket */ #define HASH_DEL_IN_BKT(hh,head,hh_del) \ (head).count--; \ if ((head).hh_head == hh_del) { \ (head).hh_head = hh_del->hh_next; \ } \ if (hh_del->hh_prev) { \ hh_del->hh_prev->hh_next = hh_del->hh_next; \ } \ if (hh_del->hh_next) { \ hh_del->hh_next->hh_prev = hh_del->hh_prev; \ } /* Bucket expansion has the effect of doubling the number of buckets * and redistributing the items into the new buckets. Ideally the * items will distribute more or less evenly into the new buckets * (the extent to which this is true is a measure of the quality of * the hash function as it applies to the key domain). * * With the items distributed into more buckets, the chain length * (item count) in each bucket is reduced. Thus by expanding buckets * the hash keeps a bound on the chain length. This bounded chain * length is the essence of how a hash provides constant time lookup. * * The calculation of tbl->ideal_chain_maxlen below deserves some * explanation. First, keep in mind that we're calculating the ideal * maximum chain length based on the *new* (doubled) bucket count. * In fractions this is just n/b (n=number of items,b=new num buckets). * Since the ideal chain length is an integer, we want to calculate * ceil(n/b). We don't depend on floating point arithmetic in this * hash, so to calculate ceil(n/b) with integers we could write * * ceil(n/b) = (n/b) + ((n%b)?1:0) * * and in fact a previous version of this hash did just that. * But now we have improved things a bit by recognizing that b is * always a power of two. We keep its base 2 log handy (call it lb), * so now we can write this with a bit shift and logical AND: * * ceil(n/b) = (n>>lb) + ( (n & (b-1)) ? 1:0) * */ #define HASH_EXPAND_BUCKETS(tbl) \ do { \ unsigned _he_bkt; \ unsigned _he_bkt_i; \ struct UT_hash_handle *_he_thh, *_he_hh_nxt; \ UT_hash_bucket *_he_new_buckets, *_he_newbkt; \ _he_new_buckets = (UT_hash_bucket*)uthash_malloc( \ 2UL * tbl->num_buckets * sizeof(struct UT_hash_bucket)); \ if (!_he_new_buckets) { uthash_fatal( "out of memory"); } \ memset(_he_new_buckets, 0, \ 2UL * tbl->num_buckets * sizeof(struct UT_hash_bucket)); \ tbl->ideal_chain_maxlen = \ (tbl->num_items >> (tbl->log2_num_buckets+1U)) + \ (((tbl->num_items & ((tbl->num_buckets*2U)-1U)) != 0U) ? 1U : 0U); \ tbl->nonideal_items = 0; \ for(_he_bkt_i = 0; _he_bkt_i < tbl->num_buckets; _he_bkt_i++) \ { \ _he_thh = tbl->buckets[ _he_bkt_i ].hh_head; \ while (_he_thh != NULL) { \ _he_hh_nxt = _he_thh->hh_next; \ HASH_TO_BKT( _he_thh->hashv, tbl->num_buckets*2U, _he_bkt); \ _he_newbkt = &(_he_new_buckets[ _he_bkt ]); \ if (++(_he_newbkt->count) > tbl->ideal_chain_maxlen) { \ tbl->nonideal_items++; \ _he_newbkt->expand_mult = _he_newbkt->count / \ tbl->ideal_chain_maxlen; \ } \ _he_thh->hh_prev = NULL; \ _he_thh->hh_next = _he_newbkt->hh_head; \ if (_he_newbkt->hh_head != NULL) { _he_newbkt->hh_head->hh_prev = \ _he_thh; } \ _he_newbkt->hh_head = _he_thh; \ _he_thh = _he_hh_nxt; \ } \ } \ uthash_free( tbl->buckets, tbl->num_buckets*sizeof(struct UT_hash_bucket) ); \ tbl->num_buckets *= 2U; \ tbl->log2_num_buckets++; \ tbl->buckets = _he_new_buckets; \ tbl->ineff_expands = (tbl->nonideal_items > (tbl->num_items >> 1)) ? \ (tbl->ineff_expands+1U) : 0U; \ if (tbl->ineff_expands > 1U) { \ tbl->noexpand=1; \ uthash_noexpand_fyi(tbl); \ } \ uthash_expand_fyi(tbl); \ } while (0) /* This is an adaptation of Simon Tatham's O(n log(n)) mergesort */ /* Note that HASH_SORT assumes the hash handle name to be hh. * HASH_SRT was added to allow the hash handle name to be passed in. */ #define HASH_SORT(head,cmpfcn) HASH_SRT(hh,head,cmpfcn) #define HASH_SRT(hh,head,cmpfcn) \ do { \ unsigned _hs_i; \ unsigned _hs_looping,_hs_nmerges,_hs_insize,_hs_psize,_hs_qsize; \ struct UT_hash_handle *_hs_p, *_hs_q, *_hs_e, *_hs_list, *_hs_tail; \ if (head != NULL) { \ _hs_insize = 1; \ _hs_looping = 1; \ _hs_list = &((head)->hh); \ while (_hs_looping != 0U) { \ _hs_p = _hs_list; \ _hs_list = NULL; \ _hs_tail = NULL; \ _hs_nmerges = 0; \ while (_hs_p != NULL) { \ _hs_nmerges++; \ _hs_q = _hs_p; \ _hs_psize = 0; \ for ( _hs_i = 0; _hs_i < _hs_insize; _hs_i++ ) { \ _hs_psize++; \ _hs_q = (UT_hash_handle*)((_hs_q->next != NULL) ? \ ((void*)((char*)(_hs_q->next) + \ (head)->hh.tbl->hho)) : NULL); \ if (! (_hs_q) ) { break; } \ } \ _hs_qsize = _hs_insize; \ while ((_hs_psize > 0U) || ((_hs_qsize > 0U) && (_hs_q != NULL))) {\ if (_hs_psize == 0U) { \ _hs_e = _hs_q; \ _hs_q = (UT_hash_handle*)((_hs_q->next != NULL) ? \ ((void*)((char*)(_hs_q->next) + \ (head)->hh.tbl->hho)) : NULL); \ _hs_qsize--; \ } else if ( (_hs_qsize == 0U) || (_hs_q == NULL) ) { \ _hs_e = _hs_p; \ if (_hs_p != NULL){ \ _hs_p = (UT_hash_handle*)((_hs_p->next != NULL) ? \ ((void*)((char*)(_hs_p->next) + \ (head)->hh.tbl->hho)) : NULL); \ } \ _hs_psize--; \ } else if (( \ cmpfcn(DECLTYPE(head)(ELMT_FROM_HH((head)->hh.tbl,_hs_p)), \ DECLTYPE(head)(ELMT_FROM_HH((head)->hh.tbl,_hs_q))) \ ) <= 0) { \ _hs_e = _hs_p; \ if (_hs_p != NULL){ \ _hs_p = (UT_hash_handle*)((_hs_p->next != NULL) ? \ ((void*)((char*)(_hs_p->next) + \ (head)->hh.tbl->hho)) : NULL); \ } \ _hs_psize--; \ } else { \ _hs_e = _hs_q; \ _hs_q = (UT_hash_handle*)((_hs_q->next != NULL) ? \ ((void*)((char*)(_hs_q->next) + \ (head)->hh.tbl->hho)) : NULL); \ _hs_qsize--; \ } \ if ( _hs_tail != NULL ) { \ _hs_tail->next = ((_hs_e != NULL) ? \ ELMT_FROM_HH((head)->hh.tbl,_hs_e) : NULL); \ } else { \ _hs_list = _hs_e; \ } \ if (_hs_e != NULL) { \ _hs_e->prev = ((_hs_tail != NULL) ? \ ELMT_FROM_HH((head)->hh.tbl,_hs_tail) : NULL); \ } \ _hs_tail = _hs_e; \ } \ _hs_p = _hs_q; \ } \ if (_hs_tail != NULL){ \ _hs_tail->next = NULL; \ } \ if ( _hs_nmerges <= 1U ) { \ _hs_looping=0; \ (head)->hh.tbl->tail = _hs_tail; \ DECLTYPE_ASSIGN(head,ELMT_FROM_HH((head)->hh.tbl, _hs_list)); \ } \ _hs_insize *= 2U; \ } \ HASH_FSCK(hh,head); \ } \ } while (0) /* This function selects items from one hash into another hash. * The end result is that the selected items have dual presence * in both hashes. There is no copy of the items made; rather * they are added into the new hash through a secondary hash * hash handle that must be present in the structure. */ #define HASH_SELECT(hh_dst, dst, hh_src, src, cond) \ do { \ unsigned _src_bkt, _dst_bkt; \ void *_last_elt=NULL, *_elt; \ UT_hash_handle *_src_hh, *_dst_hh, *_last_elt_hh=NULL; \ ptrdiff_t _dst_hho = ((char*)(&(dst)->hh_dst) - (char*)(dst)); \ if (src != NULL) { \ for(_src_bkt=0; _src_bkt < (src)->hh_src.tbl->num_buckets; _src_bkt++) { \ for(_src_hh = (src)->hh_src.tbl->buckets[_src_bkt].hh_head; \ _src_hh != NULL; \ _src_hh = _src_hh->hh_next) { \ _elt = ELMT_FROM_HH((src)->hh_src.tbl, _src_hh); \ if (cond(_elt)) { \ _dst_hh = (UT_hash_handle*)(((char*)_elt) + _dst_hho); \ _dst_hh->key = _src_hh->key; \ _dst_hh->keylen = _src_hh->keylen; \ _dst_hh->hashv = _src_hh->hashv; \ _dst_hh->prev = _last_elt; \ _dst_hh->next = NULL; \ if (_last_elt_hh != NULL) { _last_elt_hh->next = _elt; } \ if (dst == NULL) { \ DECLTYPE_ASSIGN(dst,_elt); \ HASH_MAKE_TABLE(hh_dst,dst); \ } else { \ _dst_hh->tbl = (dst)->hh_dst.tbl; \ } \ HASH_TO_BKT(_dst_hh->hashv, _dst_hh->tbl->num_buckets, _dst_bkt); \ HASH_ADD_TO_BKT(_dst_hh->tbl->buckets[_dst_bkt],_dst_hh); \ (dst)->hh_dst.tbl->num_items++; \ _last_elt = _elt; \ _last_elt_hh = _dst_hh; \ } \ } \ } \ } \ HASH_FSCK(hh_dst,dst); \ } while (0) #define HASH_CLEAR(hh,head) \ do { \ if (head != NULL) { \ uthash_free((head)->hh.tbl->buckets, \ (head)->hh.tbl->num_buckets*sizeof(struct UT_hash_bucket)); \ HASH_BLOOM_FREE((head)->hh.tbl); \ uthash_free((head)->hh.tbl, sizeof(UT_hash_table)); \ (head)=NULL; \ } \ } while (0) #define HASH_OVERHEAD(hh,head) \ ((head != NULL) ? ( \ (size_t)(((head)->hh.tbl->num_items * sizeof(UT_hash_handle)) + \ ((head)->hh.tbl->num_buckets * sizeof(UT_hash_bucket)) + \ sizeof(UT_hash_table) + \ (HASH_BLOOM_BYTELEN))) : 0U) #ifdef NO_DECLTYPE #define HASH_ITER(hh,head,el,tmp) \ for(((el)=(head)), ((*(char**)(&(tmp)))=(char*)((head!=NULL)?(head)->hh.next:NULL)); \ (el) != NULL; ((el)=(tmp)), ((*(char**)(&(tmp)))=(char*)((tmp!=NULL)?(tmp)->hh.next:NULL))) #else #define HASH_ITER(hh,head,el,tmp) \ for(((el)=(head)), ((tmp)=DECLTYPE(el)((head!=NULL)?(head)->hh.next:NULL)); \ (el) != NULL; ((el)=(tmp)), ((tmp)=DECLTYPE(el)((tmp!=NULL)?(tmp)->hh.next:NULL))) #endif /* obtain a count of items in the hash */ #define HASH_COUNT(head) HASH_CNT(hh,head) #define HASH_CNT(hh,head) ((head != NULL)?((head)->hh.tbl->num_items):0U) typedef struct UT_hash_bucket { struct UT_hash_handle *hh_head; unsigned count; /* expand_mult is normally set to 0. In this situation, the max chain length * threshold is enforced at its default value, HASH_BKT_CAPACITY_THRESH. (If * the bucket's chain exceeds this length, bucket expansion is triggered). * However, setting expand_mult to a non-zero value delays bucket expansion * (that would be triggered by additions to this particular bucket) * until its chain length reaches a *multiple* of HASH_BKT_CAPACITY_THRESH. * (The multiplier is simply expand_mult+1). The whole idea of this * multiplier is to reduce bucket expansions, since they are expensive, in * situations where we know that a particular bucket tends to be overused. * It is better to let its chain length grow to a longer yet-still-bounded * value, than to do an O(n) bucket expansion too often. */ unsigned expand_mult; } UT_hash_bucket; /* random signature used only to find hash tables in external analysis */ #define HASH_SIGNATURE 0xa0111fe1u #define HASH_BLOOM_SIGNATURE 0xb12220f2u typedef struct UT_hash_table { UT_hash_bucket *buckets; unsigned num_buckets, log2_num_buckets; unsigned num_items; struct UT_hash_handle *tail; /* tail hh in app order, for fast append */ ptrdiff_t hho; /* hash handle offset (byte pos of hash handle in element */ /* in an ideal situation (all buckets used equally), no bucket would have * more than ceil(#items/#buckets) items. that's the ideal chain length. */ unsigned ideal_chain_maxlen; /* nonideal_items is the number of items in the hash whose chain position * exceeds the ideal chain maxlen. these items pay the penalty for an uneven * hash distribution; reaching them in a chain traversal takes >ideal steps */ unsigned nonideal_items; /* ineffective expands occur when a bucket doubling was performed, but * afterward, more than half the items in the hash had nonideal chain * positions. If this happens on two consecutive expansions we inhibit any * further expansion, as it's not helping; this happens when the hash * function isn't a good fit for the key domain. When expansion is inhibited * the hash will still work, albeit no longer in constant time. */ unsigned ineff_expands, noexpand; uint32_t signature; /* used only to find hash tables in external analysis */ #ifdef HASH_BLOOM uint32_t bloom_sig; /* used only to test bloom exists in external analysis */ uint8_t *bloom_bv; uint8_t bloom_nbits; #endif } UT_hash_table; typedef struct UT_hash_handle { struct UT_hash_table *tbl; void *prev; /* prev element in app order */ void *next; /* next element in app order */ struct UT_hash_handle *hh_prev; /* previous hh in bucket order */ struct UT_hash_handle *hh_next; /* next hh in bucket order */ void *key; /* ptr to enclosing struct's key */ unsigned keylen; /* enclosing struct's key len */ unsigned hashv; /* result of hash-fcn(key) */ } UT_hash_handle; #endif /* UTHASH_H */ libsignal-protocol-c-2.3.3/src/utlist.h000066400000000000000000002036501363751346500200510ustar00rootroot00000000000000/* Copyright (c) 2007-2016, Troy D. Hanson http://troydhanson.github.com/uthash/ All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #ifndef UTLIST_H #define UTLIST_H #define UTLIST_VERSION 2.0.1 #include /* * This file contains macros to manipulate singly and doubly-linked lists. * * 1. LL_ macros: singly-linked lists. * 2. DL_ macros: doubly-linked lists. * 3. CDL_ macros: circular doubly-linked lists. * * To use singly-linked lists, your structure must have a "next" pointer. * To use doubly-linked lists, your structure must "prev" and "next" pointers. * Either way, the pointer to the head of the list must be initialized to NULL. * * ----------------.EXAMPLE ------------------------- * struct item { * int id; * struct item *prev, *next; * } * * struct item *list = NULL: * * int main() { * struct item *item; * ... allocate and populate item ... * DL_APPEND(list, item); * } * -------------------------------------------------- * * For doubly-linked lists, the append and delete macros are O(1) * For singly-linked lists, append and delete are O(n) but prepend is O(1) * The sort macro is O(n log(n)) for all types of single/double/circular lists. */ /* These macros use decltype or the earlier __typeof GNU extension. As decltype is only available in newer compilers (VS2010 or gcc 4.3+ when compiling c++ code), this code uses whatever method is needed or, for VS2008 where neither is available, uses casting workarounds. */ #ifdef _MSC_VER /* MS compiler */ #if _MSC_VER >= 1600 && defined(__cplusplus) /* VS2010 or newer in C++ mode */ #define LDECLTYPE(x) decltype(x) #else /* VS2008 or older (or VS2010 in C mode) */ #define NO_DECLTYPE #endif #elif defined(__ICCARM__) #define NO_DECLTYPE #else /* GNU, Sun and other compilers */ #define LDECLTYPE(x) __typeof(x) #endif /* for VS2008 we use some workarounds to get around the lack of decltype, * namely, we always reassign our tmp variable to the list head if we need * to dereference its prev/next pointers, and save/restore the real head.*/ #ifdef NO_DECLTYPE #define IF_NO_DECLTYPE(x) x #define LDECLTYPE(x) char* #define _SV(elt,list) _tmp = (char*)(list); {char **_alias = (char**)&(list); *_alias = (elt); } #define _NEXT(elt,list,next) ((char*)((list)->next)) #define _NEXTASGN(elt,list,to,next) { char **_alias = (char**)&((list)->next); *_alias=(char*)(to); } /* #define _PREV(elt,list,prev) ((char*)((list)->prev)) */ #define _PREVASGN(elt,list,to,prev) { char **_alias = (char**)&((list)->prev); *_alias=(char*)(to); } #define _RS(list) { char **_alias = (char**)&(list); *_alias=_tmp; } #define _CASTASGN(a,b) { char **_alias = (char**)&(a); *_alias=(char*)(b); } #else #define IF_NO_DECLTYPE(x) #define _SV(elt,list) #define _NEXT(elt,list,next) ((elt)->next) #define _NEXTASGN(elt,list,to,next) ((elt)->next)=(to) /* #define _PREV(elt,list,prev) ((elt)->prev) */ #define _PREVASGN(elt,list,to,prev) ((elt)->prev)=(to) #define _RS(list) #define _CASTASGN(a,b) (a)=(b) #endif /****************************************************************************** * The sort macro is an adaptation of Simon Tatham's O(n log(n)) mergesort * * Unwieldy variable names used here to avoid shadowing passed-in variables. * *****************************************************************************/ #define LL_SORT(list, cmp) \ LL_SORT2(list, cmp, next) #define LL_SORT2(list, cmp, next) \ do { \ LDECLTYPE(list) _ls_p; \ LDECLTYPE(list) _ls_q; \ LDECLTYPE(list) _ls_e; \ LDECLTYPE(list) _ls_tail; \ IF_NO_DECLTYPE(LDECLTYPE(list) _tmp;) \ int _ls_insize, _ls_nmerges, _ls_psize, _ls_qsize, _ls_i, _ls_looping; \ if (list) { \ _ls_insize = 1; \ _ls_looping = 1; \ while (_ls_looping) { \ _CASTASGN(_ls_p,list); \ (list) = NULL; \ _ls_tail = NULL; \ _ls_nmerges = 0; \ while (_ls_p) { \ _ls_nmerges++; \ _ls_q = _ls_p; \ _ls_psize = 0; \ for (_ls_i = 0; _ls_i < _ls_insize; _ls_i++) { \ _ls_psize++; \ _SV(_ls_q,list); _ls_q = _NEXT(_ls_q,list,next); _RS(list); \ if (!_ls_q) break; \ } \ _ls_qsize = _ls_insize; \ while (_ls_psize > 0 || (_ls_qsize > 0 && _ls_q)) { \ if (_ls_psize == 0) { \ _ls_e = _ls_q; _SV(_ls_q,list); _ls_q = \ _NEXT(_ls_q,list,next); _RS(list); _ls_qsize--; \ } else if (_ls_qsize == 0 || !_ls_q) { \ _ls_e = _ls_p; _SV(_ls_p,list); _ls_p = \ _NEXT(_ls_p,list,next); _RS(list); _ls_psize--; \ } else if (cmp(_ls_p,_ls_q) <= 0) { \ _ls_e = _ls_p; _SV(_ls_p,list); _ls_p = \ _NEXT(_ls_p,list,next); _RS(list); _ls_psize--; \ } else { \ _ls_e = _ls_q; _SV(_ls_q,list); _ls_q = \ _NEXT(_ls_q,list,next); _RS(list); _ls_qsize--; \ } \ if (_ls_tail) { \ _SV(_ls_tail,list); _NEXTASGN(_ls_tail,list,_ls_e,next); _RS(list); \ } else { \ _CASTASGN(list,_ls_e); \ } \ _ls_tail = _ls_e; \ } \ _ls_p = _ls_q; \ } \ if (_ls_tail) { \ _SV(_ls_tail,list); _NEXTASGN(_ls_tail,list,NULL,next); _RS(list); \ } \ if (_ls_nmerges <= 1) { \ _ls_looping=0; \ } \ _ls_insize *= 2; \ } \ } \ } while (0) #define DL_SORT(list, cmp) \ DL_SORT2(list, cmp, prev, next) #define DL_SORT2(list, cmp, prev, next) \ do { \ LDECLTYPE(list) _ls_p; \ LDECLTYPE(list) _ls_q; \ LDECLTYPE(list) _ls_e; \ LDECLTYPE(list) _ls_tail; \ IF_NO_DECLTYPE(LDECLTYPE(list) _tmp;) \ int _ls_insize, _ls_nmerges, _ls_psize, _ls_qsize, _ls_i, _ls_looping; \ if (list) { \ _ls_insize = 1; \ _ls_looping = 1; \ while (_ls_looping) { \ _CASTASGN(_ls_p,list); \ (list) = NULL; \ _ls_tail = NULL; \ _ls_nmerges = 0; \ while (_ls_p) { \ _ls_nmerges++; \ _ls_q = _ls_p; \ _ls_psize = 0; \ for (_ls_i = 0; _ls_i < _ls_insize; _ls_i++) { \ _ls_psize++; \ _SV(_ls_q,list); _ls_q = _NEXT(_ls_q,list,next); _RS(list); \ if (!_ls_q) break; \ } \ _ls_qsize = _ls_insize; \ while ((_ls_psize > 0) || ((_ls_qsize > 0) && _ls_q)) { \ if (_ls_psize == 0) { \ _ls_e = _ls_q; _SV(_ls_q,list); _ls_q = \ _NEXT(_ls_q,list,next); _RS(list); _ls_qsize--; \ } else if ((_ls_qsize == 0) || (!_ls_q)) { \ _ls_e = _ls_p; _SV(_ls_p,list); _ls_p = \ _NEXT(_ls_p,list,next); _RS(list); _ls_psize--; \ } else if (cmp(_ls_p,_ls_q) <= 0) { \ _ls_e = _ls_p; _SV(_ls_p,list); _ls_p = \ _NEXT(_ls_p,list,next); _RS(list); _ls_psize--; \ } else { \ _ls_e = _ls_q; _SV(_ls_q,list); _ls_q = \ _NEXT(_ls_q,list,next); _RS(list); _ls_qsize--; \ } \ if (_ls_tail) { \ _SV(_ls_tail,list); _NEXTASGN(_ls_tail,list,_ls_e,next); _RS(list); \ } else { \ _CASTASGN(list,_ls_e); \ } \ _SV(_ls_e,list); _PREVASGN(_ls_e,list,_ls_tail,prev); _RS(list); \ _ls_tail = _ls_e; \ } \ _ls_p = _ls_q; \ } \ _CASTASGN((list)->prev, _ls_tail); \ _SV(_ls_tail,list); _NEXTASGN(_ls_tail,list,NULL,next); _RS(list); \ if (_ls_nmerges <= 1) { \ _ls_looping=0; \ } \ _ls_insize *= 2; \ } \ } \ } while (0) #define CDL_SORT(list, cmp) \ CDL_SORT2(list, cmp, prev, next) #define CDL_SORT2(list, cmp, prev, next) \ do { \ LDECLTYPE(list) _ls_p; \ LDECLTYPE(list) _ls_q; \ LDECLTYPE(list) _ls_e; \ LDECLTYPE(list) _ls_tail; \ LDECLTYPE(list) _ls_oldhead; \ LDECLTYPE(list) _tmp; \ int _ls_insize, _ls_nmerges, _ls_psize, _ls_qsize, _ls_i, _ls_looping; \ if (list) { \ _ls_insize = 1; \ _ls_looping = 1; \ while (_ls_looping) { \ _CASTASGN(_ls_p,list); \ _CASTASGN(_ls_oldhead,list); \ (list) = NULL; \ _ls_tail = NULL; \ _ls_nmerges = 0; \ while (_ls_p) { \ _ls_nmerges++; \ _ls_q = _ls_p; \ _ls_psize = 0; \ for (_ls_i = 0; _ls_i < _ls_insize; _ls_i++) { \ _ls_psize++; \ _SV(_ls_q,list); \ if (_NEXT(_ls_q,list,next) == _ls_oldhead) { \ _ls_q = NULL; \ } else { \ _ls_q = _NEXT(_ls_q,list,next); \ } \ _RS(list); \ if (!_ls_q) break; \ } \ _ls_qsize = _ls_insize; \ while (_ls_psize > 0 || (_ls_qsize > 0 && _ls_q)) { \ if (_ls_psize == 0) { \ _ls_e = _ls_q; _SV(_ls_q,list); _ls_q = \ _NEXT(_ls_q,list,next); _RS(list); _ls_qsize--; \ if (_ls_q == _ls_oldhead) { _ls_q = NULL; } \ } else if (_ls_qsize == 0 || !_ls_q) { \ _ls_e = _ls_p; _SV(_ls_p,list); _ls_p = \ _NEXT(_ls_p,list,next); _RS(list); _ls_psize--; \ if (_ls_p == _ls_oldhead) { _ls_p = NULL; } \ } else if (cmp(_ls_p,_ls_q) <= 0) { \ _ls_e = _ls_p; _SV(_ls_p,list); _ls_p = \ _NEXT(_ls_p,list,next); _RS(list); _ls_psize--; \ if (_ls_p == _ls_oldhead) { _ls_p = NULL; } \ } else { \ _ls_e = _ls_q; _SV(_ls_q,list); _ls_q = \ _NEXT(_ls_q,list,next); _RS(list); _ls_qsize--; \ if (_ls_q == _ls_oldhead) { _ls_q = NULL; } \ } \ if (_ls_tail) { \ _SV(_ls_tail,list); _NEXTASGN(_ls_tail,list,_ls_e,next); _RS(list); \ } else { \ _CASTASGN(list,_ls_e); \ } \ _SV(_ls_e,list); _PREVASGN(_ls_e,list,_ls_tail,prev); _RS(list); \ _ls_tail = _ls_e; \ } \ _ls_p = _ls_q; \ } \ _CASTASGN((list)->prev,_ls_tail); \ _CASTASGN(_tmp,list); \ _SV(_ls_tail,list); _NEXTASGN(_ls_tail,list,_tmp,next); _RS(list); \ if (_ls_nmerges <= 1) { \ _ls_looping=0; \ } \ _ls_insize *= 2; \ } \ } \ } while (0) /****************************************************************************** * singly linked list macros (non-circular) * *****************************************************************************/ #define LL_PREPEND(head,add) \ LL_PREPEND2(head,add,next) #define LL_PREPEND2(head,add,next) \ do { \ (add)->next = (head); \ (head) = (add); \ } while (0) #define LL_CONCAT(head1,head2) \ LL_CONCAT2(head1,head2,next) #define LL_CONCAT2(head1,head2,next) \ do { \ LDECLTYPE(head1) _tmp; \ if (head1) { \ _tmp = (head1); \ while (_tmp->next) { _tmp = _tmp->next; } \ _tmp->next=(head2); \ } else { \ (head1)=(head2); \ } \ } while (0) #define LL_APPEND(head,add) \ LL_APPEND2(head,add,next) #define LL_APPEND2(head,add,next) \ do { \ LDECLTYPE(head) _tmp; \ (add)->next=NULL; \ if (head) { \ _tmp = (head); \ while (_tmp->next) { _tmp = _tmp->next; } \ _tmp->next=(add); \ } else { \ (head)=(add); \ } \ } while (0) #define LL_DELETE(head,del) \ LL_DELETE2(head,del,next) #define LL_DELETE2(head,del,next) \ do { \ LDECLTYPE(head) _tmp; \ if ((head) == (del)) { \ (head)=(head)->next; \ } else { \ _tmp = (head); \ while (_tmp->next && (_tmp->next != (del))) { \ _tmp = _tmp->next; \ } \ if (_tmp->next) { \ _tmp->next = (del)->next; \ } \ } \ } while (0) #define LL_COUNT(head,el,counter) \ LL_COUNT2(head,el,counter,next) \ #define LL_COUNT2(head,el,counter,next) \ do { \ (counter) = 0; \ LL_FOREACH2(head,el,next) { ++(counter); } \ } while (0) #define LL_FOREACH(head,el) \ LL_FOREACH2(head,el,next) #define LL_FOREACH2(head,el,next) \ for ((el) = (head); el; (el) = (el)->next) #define LL_FOREACH_SAFE(head,el,tmp) \ LL_FOREACH_SAFE2(head,el,tmp,next) #define LL_FOREACH_SAFE2(head,el,tmp,next) \ for ((el) = (head); (el) && ((tmp) = (el)->next, 1); (el) = (tmp)) #define LL_SEARCH_SCALAR(head,out,field,val) \ LL_SEARCH_SCALAR2(head,out,field,val,next) #define LL_SEARCH_SCALAR2(head,out,field,val,next) \ do { \ LL_FOREACH2(head,out,next) { \ if ((out)->field == (val)) break; \ } \ } while (0) #define LL_SEARCH(head,out,elt,cmp) \ LL_SEARCH2(head,out,elt,cmp,next) #define LL_SEARCH2(head,out,elt,cmp,next) \ do { \ LL_FOREACH2(head,out,next) { \ if ((cmp(out,elt))==0) break; \ } \ } while (0) #define LL_REPLACE_ELEM2(head, el, add, next) \ do { \ LDECLTYPE(head) _tmp; \ assert((head) != NULL); \ assert((el) != NULL); \ assert((add) != NULL); \ (add)->next = (el)->next; \ if ((head) == (el)) { \ (head) = (add); \ } else { \ _tmp = (head); \ while (_tmp->next && (_tmp->next != (el))) { \ _tmp = _tmp->next; \ } \ if (_tmp->next) { \ _tmp->next = (add); \ } \ } \ } while (0) #define LL_REPLACE_ELEM(head, el, add) \ LL_REPLACE_ELEM2(head, el, add, next) #define LL_PREPEND_ELEM2(head, el, add, next) \ do { \ if (el) { \ LDECLTYPE(head) _tmp; \ assert((head) != NULL); \ assert((add) != NULL); \ (add)->next = (el); \ if ((head) == (el)) { \ (head) = (add); \ } else { \ _tmp = (head); \ while (_tmp->next && (_tmp->next != (el))) { \ _tmp = _tmp->next; \ } \ if (_tmp->next) { \ _tmp->next = (add); \ } \ } \ } else { \ LL_APPEND2(head, add, next); \ } \ } while (0) \ #define LL_PREPEND_ELEM(head, el, add) \ LL_PREPEND_ELEM2(head, el, add, next) #define LL_APPEND_ELEM2(head, el, add, next) \ do { \ if (el) { \ assert((head) != NULL); \ assert((add) != NULL); \ (add)->next = (el)->next; \ (el)->next = (add); \ } else { \ LL_PREPEND2(head, add, next); \ } \ } while (0) \ #define LL_APPEND_ELEM(head, el, add) \ LL_APPEND_ELEM2(head, el, add, next) #ifdef NO_DECLTYPE /* Here are VS2008 / NO_DECLTYPE replacements for a few functions */ #undef LL_CONCAT2 #define LL_CONCAT2(head1,head2,next) \ do { \ char *_tmp; \ if (head1) { \ _tmp = (char*)(head1); \ while ((head1)->next) { (head1) = (head1)->next; } \ (head1)->next = (head2); \ _RS(head1); \ } else { \ (head1)=(head2); \ } \ } while (0) #undef LL_APPEND2 #define LL_APPEND2(head,add,next) \ do { \ if (head) { \ (add)->next = head; /* use add->next as a temp variable */ \ while ((add)->next->next) { (add)->next = (add)->next->next; } \ (add)->next->next=(add); \ } else { \ (head)=(add); \ } \ (add)->next=NULL; \ } while (0) #undef LL_DELETE2 #define LL_DELETE2(head,del,next) \ do { \ if ((head) == (del)) { \ (head)=(head)->next; \ } else { \ char *_tmp = (char*)(head); \ while ((head)->next && ((head)->next != (del))) { \ (head) = (head)->next; \ } \ if ((head)->next) { \ (head)->next = ((del)->next); \ } \ _RS(head); \ } \ } while (0) #undef LL_REPLACE_ELEM2 #define LL_REPLACE_ELEM2(head, el, add, next) \ do { \ assert((head) != NULL); \ assert((el) != NULL); \ assert((add) != NULL); \ if ((head) == (el)) { \ (head) = (add); \ } else { \ (add)->next = head; \ while ((add)->next->next && ((add)->next->next != (el))) { \ (add)->next = (add)->next->next; \ } \ if ((add)->next->next) { \ (add)->next->next = (add); \ } \ } \ (add)->next = (el)->next; \ } while (0) #undef LL_PREPEND_ELEM2 #define LL_PREPEND_ELEM2(head, el, add, next) \ do { \ if (el) { \ assert((head) != NULL); \ assert((add) != NULL); \ if ((head) == (el)) { \ (head) = (add); \ } else { \ (add)->next = (head); \ while ((add)->next->next && ((add)->next->next != (el))) { \ (add)->next = (add)->next->next; \ } \ if ((add)->next->next) { \ (add)->next->next = (add); \ } \ } \ (add)->next = (el); \ } else { \ LL_APPEND2(head, add, next); \ } \ } while (0) \ #endif /* NO_DECLTYPE */ /****************************************************************************** * doubly linked list macros (non-circular) * *****************************************************************************/ #define DL_PREPEND(head,add) \ DL_PREPEND2(head,add,prev,next) #define DL_PREPEND2(head,add,prev,next) \ do { \ (add)->next = (head); \ if (head) { \ (add)->prev = (head)->prev; \ (head)->prev = (add); \ } else { \ (add)->prev = (add); \ } \ (head) = (add); \ } while (0) #define DL_APPEND(head,add) \ DL_APPEND2(head,add,prev,next) #define DL_APPEND2(head,add,prev,next) \ do { \ if (head) { \ (add)->prev = (head)->prev; \ (head)->prev->next = (add); \ (head)->prev = (add); \ (add)->next = NULL; \ } else { \ (head)=(add); \ (head)->prev = (head); \ (head)->next = NULL; \ } \ } while (0) #define DL_CONCAT(head1,head2) \ DL_CONCAT2(head1,head2,prev,next) #define DL_CONCAT2(head1,head2,prev,next) \ do { \ LDECLTYPE(head1) _tmp; \ if (head2) { \ if (head1) { \ _CASTASGN(_tmp, (head2)->prev); \ (head2)->prev = (head1)->prev; \ (head1)->prev->next = (head2); \ _CASTASGN((head1)->prev, _tmp); \ } else { \ (head1)=(head2); \ } \ } \ } while (0) #define DL_DELETE(head,del) \ DL_DELETE2(head,del,prev,next) #define DL_DELETE2(head,del,prev,next) \ do { \ assert((del)->prev != NULL); \ if ((del)->prev == (del)) { \ (head)=NULL; \ } else if ((del)==(head)) { \ (del)->next->prev = (del)->prev; \ (head) = (del)->next; \ } else { \ (del)->prev->next = (del)->next; \ if ((del)->next) { \ (del)->next->prev = (del)->prev; \ } else { \ (head)->prev = (del)->prev; \ } \ } \ } while (0) #define DL_COUNT(head,el,counter) \ DL_COUNT2(head,el,counter,next) \ #define DL_COUNT2(head,el,counter,next) \ do { \ (counter) = 0; \ DL_FOREACH2(head,el,next) { ++(counter); } \ } while (0) #define DL_FOREACH(head,el) \ DL_FOREACH2(head,el,next) #define DL_FOREACH2(head,el,next) \ for ((el) = (head); el; (el) = (el)->next) /* this version is safe for deleting the elements during iteration */ #define DL_FOREACH_SAFE(head,el,tmp) \ DL_FOREACH_SAFE2(head,el,tmp,next) #define DL_FOREACH_SAFE2(head,el,tmp,next) \ for ((el) = (head); (el) && ((tmp) = (el)->next, 1); (el) = (tmp)) /* these are identical to their singly-linked list counterparts */ #define DL_SEARCH_SCALAR LL_SEARCH_SCALAR #define DL_SEARCH LL_SEARCH #define DL_SEARCH_SCALAR2 LL_SEARCH_SCALAR2 #define DL_SEARCH2 LL_SEARCH2 #define DL_REPLACE_ELEM2(head, el, add, prev, next) \ do { \ assert((head) != NULL); \ assert((el) != NULL); \ assert((add) != NULL); \ if ((head) == (el)) { \ (head) = (add); \ (add)->next = (el)->next; \ if ((el)->next == NULL) { \ (add)->prev = (add); \ } else { \ (add)->prev = (el)->prev; \ (add)->next->prev = (add); \ } \ } else { \ (add)->next = (el)->next; \ (add)->prev = (el)->prev; \ (add)->prev->next = (add); \ if ((el)->next == NULL) { \ (head)->prev = (add); \ } else { \ (add)->next->prev = (add); \ } \ } \ } while (0) #define DL_REPLACE_ELEM(head, el, add) \ DL_REPLACE_ELEM2(head, el, add, prev, next) #define DL_PREPEND_ELEM2(head, el, add, prev, next) \ do { \ if (el) { \ assert((head) != NULL); \ assert((add) != NULL); \ (add)->next = (el); \ (add)->prev = (el)->prev; \ (el)->prev = (add); \ if ((head) == (el)) { \ (head) = (add); \ } else { \ (add)->prev->next = (add); \ } \ } else { \ DL_APPEND2(head, add, prev, next); \ } \ } while (0) \ #define DL_PREPEND_ELEM(head, el, add) \ DL_PREPEND_ELEM2(head, el, add, prev, next) #define DL_APPEND_ELEM2(head, el, add, prev, next) \ do { \ if (el) { \ assert((head) != NULL); \ assert((add) != NULL); \ (add)->next = (el)->next; \ (add)->prev = (el); \ (el)->next = (add); \ if ((add)->next) { \ (add)->next->prev = (add); \ } else { \ (head)->prev = (add); \ } \ } else { \ DL_PREPEND2(head, add, prev, next); \ } \ } while (0) \ #define DL_APPEND_ELEM(head, el, add) \ DL_APPEND_ELEM2(head, el, add, prev, next) /****************************************************************************** * circular doubly linked list macros * *****************************************************************************/ #define CDL_APPEND(head,add) \ CDL_APPEND2(head,add,prev,next) #define CDL_APPEND2(head,add,prev,next) \ do { \ if (head) { \ (add)->prev = (head)->prev; \ (add)->next = (head); \ (head)->prev = (add); \ (add)->prev->next = (add); \ } else { \ (add)->prev = (add); \ (add)->next = (add); \ (head) = (add); \ } \ } while (0) #define CDL_PREPEND(head,add) \ CDL_PREPEND2(head,add,prev,next) #define CDL_PREPEND2(head,add,prev,next) \ do { \ if (head) { \ (add)->prev = (head)->prev; \ (add)->next = (head); \ (head)->prev = (add); \ (add)->prev->next = (add); \ } else { \ (add)->prev = (add); \ (add)->next = (add); \ } \ (head) = (add); \ } while (0) #define CDL_DELETE(head,del) \ CDL_DELETE2(head,del,prev,next) #define CDL_DELETE2(head,del,prev,next) \ do { \ if (((head)==(del)) && ((head)->next == (head))) { \ (head) = NULL; \ } else { \ (del)->next->prev = (del)->prev; \ (del)->prev->next = (del)->next; \ if ((del) == (head)) (head)=(del)->next; \ } \ } while (0) #define CDL_COUNT(head,el,counter) \ CDL_COUNT2(head,el,counter,next) \ #define CDL_COUNT2(head, el, counter,next) \ do { \ (counter) = 0; \ CDL_FOREACH2(head,el,next) { ++(counter); } \ } while (0) #define CDL_FOREACH(head,el) \ CDL_FOREACH2(head,el,next) #define CDL_FOREACH2(head,el,next) \ for ((el)=(head);el;(el)=(((el)->next==(head)) ? NULL : (el)->next)) #define CDL_FOREACH_SAFE(head,el,tmp1,tmp2) \ CDL_FOREACH_SAFE2(head,el,tmp1,tmp2,prev,next) #define CDL_FOREACH_SAFE2(head,el,tmp1,tmp2,prev,next) \ for ((el) = (head), (tmp1) = (head) ? (head)->prev : NULL; \ (el) && ((tmp2) = (el)->next, 1); \ (el) = ((el) == (tmp1) ? NULL : (tmp2))) #define CDL_SEARCH_SCALAR(head,out,field,val) \ CDL_SEARCH_SCALAR2(head,out,field,val,next) #define CDL_SEARCH_SCALAR2(head,out,field,val,next) \ do { \ CDL_FOREACH2(head,out,next) { \ if ((out)->field == (val)) break; \ } \ } while (0) #define CDL_SEARCH(head,out,elt,cmp) \ CDL_SEARCH2(head,out,elt,cmp,next) #define CDL_SEARCH2(head,out,elt,cmp,next) \ do { \ CDL_FOREACH2(head,out,next) { \ if ((cmp(out,elt))==0) break; \ } \ } while (0) #define CDL_REPLACE_ELEM2(head, el, add, prev, next) \ do { \ assert((head) != NULL); \ assert((el) != NULL); \ assert((add) != NULL); \ if ((el)->next == (el)) { \ (add)->next = (add); \ (add)->prev = (add); \ (head) = (add); \ } else { \ (add)->next = (el)->next; \ (add)->prev = (el)->prev; \ (add)->next->prev = (add); \ (add)->prev->next = (add); \ if ((head) == (el)) { \ (head) = (add); \ } \ } \ } while (0) #define CDL_REPLACE_ELEM(head, el, add) \ CDL_REPLACE_ELEM2(head, el, add, prev, next) #define CDL_PREPEND_ELEM2(head, el, add, prev, next) \ do { \ if (el) { \ assert((head) != NULL); \ assert((add) != NULL); \ (add)->next = (el); \ (add)->prev = (el)->prev; \ (el)->prev = (add); \ (add)->prev->next = (add); \ if ((head) == (el)) { \ (head) = (add); \ } \ } else { \ CDL_APPEND2(head, add, prev, next); \ } \ } while (0) #define CDL_PREPEND_ELEM(head, el, add) \ CDL_PREPEND_ELEM2(head, el, add, prev, next) #define CDL_APPEND_ELEM2(head, el, add, prev, next) \ do { \ if (el) { \ assert((head) != NULL); \ assert((add) != NULL); \ (add)->next = (el)->next; \ (add)->prev = (el); \ (el)->next = (add); \ (add)->next->prev = (add); \ } else { \ CDL_PREPEND2(head, add, prev, next); \ } \ } while (0) #define CDL_APPEND_ELEM(head, el, add) \ CDL_APPEND_ELEM2(head, el, add, prev, next) #endif /* UTLIST_H */ libsignal-protocol-c-2.3.3/src/vpool.c000066400000000000000000000121011363751346500176440ustar00rootroot00000000000000/* * Copyright (c) 2006, 2008 Alexey Vatchenko * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #include #include #include #include #include #include #include "vpool.h" static void vpool_shift(struct vpool *pool); static int vpool_new_size(struct vpool *pool, size_t datsize, size_t *size); static int vpool_resize(struct vpool *pool, size_t datsize); static void vpool_shift(struct vpool *pool) { if (pool->v_buf != pool->v_basebuf) { memmove(pool->v_basebuf, pool->v_buf, pool->v_off); pool->v_buf = pool->v_basebuf; } } static int vpool_new_size(struct vpool *pool, size_t datsize, size_t *size) { size_t need; size_t rem; if (datsize <= pool->v_size - pool->v_off) { *size = pool->v_size; return (0); } /* Check limit of new requested size */ if (pool->v_limit - pool->v_off < datsize) return (EFBIG); need = pool->v_off + datsize; /* Check limit of new size aligned to block size */ rem = need % pool->v_blksize; if (rem != 0) { if (pool->v_limit - pool->v_off >= datsize + (pool->v_blksize - rem)) need += pool->v_blksize - rem; else need = pool->v_limit; } *size = need; return (0); } static int vpool_resize(struct vpool *pool, size_t datsize) { char *ret; size_t size; int error; error = vpool_new_size(pool, datsize, &size); if (error != 0) return (error); if (size > pool->v_size) { ret = (char *) malloc(size); if (ret == NULL) return (ENOMEM); memcpy(ret, pool->v_buf, pool->v_off); free(pool->v_basebuf); pool->v_basebuf = pool->v_buf = ret; pool->v_size = size; } else if ((pool->v_size - pool->v_off) - (size_t)((char*)pool->v_buf - (char*)pool->v_basebuf) < datsize) vpool_shift(pool); return (0); } void vpool_init(struct vpool *pool, size_t blksize, size_t limit) { pool->v_basebuf = pool->v_buf = NULL; pool->v_off = pool->v_size = 0; pool->v_blksize = (blksize == 0) ? 4096 : blksize; /* XXX */ pool->v_limit = (limit == 0) ? SIZE_MAX : limit; pool->v_lasterr = 0; } void vpool_final(struct vpool *pool) { free(pool->v_basebuf); } void vpool_reset(struct vpool *pool) { free(pool->v_basebuf); pool->v_basebuf = pool->v_buf = NULL; pool->v_off = pool->v_size = 0; pool->v_lasterr = 0; } void vpool_wipe(struct vpool *pool) { pool->v_off = 0; pool->v_lasterr = 0; } void * vpool_insert(struct vpool *pool, size_t where, void *data, size_t datsize) { char *ret; int error; error = vpool_resize(pool, datsize); if (error != 0) { pool->v_lasterr = error; return (NULL); } /* * If ``where'' is greater than or equal to offset then * we are appending data to the end of the buffer. */ if (where > pool->v_off) where = pool->v_off; ret = (char *)pool->v_buf + where; if (pool->v_off - where > 0) memmove(ret + datsize, ret, pool->v_off - where); memcpy(ret, data, datsize); pool->v_off += datsize; pool->v_lasterr = 0; return (ret); } void * vpool_expand(struct vpool *pool, size_t where, size_t size) { char *ret; int error; error = vpool_resize(pool, size); if (error != 0) { pool->v_lasterr = error; return (NULL); } /* * If ``where'' is greater than or equal to offset then * we are appending data to the end of the buffer. */ if (where > pool->v_off) where = pool->v_off; ret = (char *)pool->v_buf + where; if (pool->v_off - where > 0) memmove(ret + size, ret, pool->v_off - where); pool->v_off += size; pool->v_lasterr = 0; return (ret); } int vpool_truncate(struct vpool *pool, size_t where, size_t size, enum vpool_trunc how) { /* Check if caller wants to remove more data than we have */ if (where >= pool->v_off || size > pool->v_off || pool->v_off - size < where) { pool->v_lasterr = ERANGE; return (pool->v_lasterr); } if (how == VPOOL_EXCLUDE) { if (where == 0) { /* * Optimization. * Don't move data, just adjust pointer. */ pool->v_buf = (char *)pool->v_buf + size; } else { memmove((char *)pool->v_buf + where, (char *)pool->v_buf + where + size, pool->v_off - size - where); } pool->v_off -= size; } else { pool->v_buf = (char*)(pool->v_buf) + where; pool->v_off = size; } pool->v_lasterr = 0; return (0); } void vpool_export(struct vpool *pool, void **buf, size_t *size) { vpool_shift(pool); *buf = pool->v_buf; *size = pool->v_off; pool->v_basebuf = pool->v_buf = NULL; pool->v_off = pool->v_size = 0; pool->v_lasterr = 0; } libsignal-protocol-c-2.3.3/src/vpool.h000066400000000000000000000036331363751346500176630ustar00rootroot00000000000000/* * Copyright (c) 2006, 2008 Alexey Vatchenko * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ /* * VPool: implementation of pool of data with a variable size. */ #ifndef _VPOOL_H_ #define _VPOOL_H_ #include #include struct vpool { void *v_basebuf; /* pointer returned by (re|m)alloc() */ void *v_buf; /* actual data starts here */ size_t v_off; size_t v_size; size_t v_blksize; size_t v_limit; int v_lasterr; }; enum vpool_trunc {VPOOL_EXCLUDE, VPOOL_INCLUDE}; #define VPOOL_TAIL UINT_MAX void vpool_init(struct vpool *pool, size_t blksize, size_t limit); void vpool_final(struct vpool *pool); void vpool_reset(struct vpool *pool); void vpool_wipe(struct vpool *pool); void * vpool_insert(struct vpool *pool, size_t where, void *data, size_t datsize); void * vpool_expand(struct vpool *pool, size_t where, size_t size); int vpool_truncate(struct vpool *pool, size_t where, size_t size, enum vpool_trunc how); #define vpool_is_empty(pool) ((pool)->v_off == 0) #define vpool_get_buf(pool) ((pool)->v_buf) #define vpool_get_length(pool) ((pool)->v_off) #define vpool_get_error(pool) ((pool)->v_lasterr) void vpool_export(struct vpool *pool, void **buf, size_t *size); #endif /* !_VPOOL_H_ */ libsignal-protocol-c-2.3.3/tests/000077500000000000000000000000001363751346500167215ustar00rootroot00000000000000libsignal-protocol-c-2.3.3/tests/CMakeLists.txt000066400000000000000000000075031363751346500214660ustar00rootroot00000000000000enable_testing() find_library(M_LIB m) find_package(Check 0.9.10 REQUIRED) IF(NOT(APPLE AND ${CMAKE_SYSTEM_NAME} MATCHES "Darwin")) find_package(OpenSSL 1.0 REQUIRED) ENDIF() find_package(Threads) include_directories(${CHECK_INCLUDE_DIRS}) IF(CMAKE_COMPILER_IS_GNUCC OR CMAKE_C_COMPILER_ID MATCHES "Clang") SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wno-unused-function") ENDIF(CMAKE_COMPILER_IS_GNUCC OR CMAKE_C_COMPILER_ID MATCHES "Clang") IF(CMAKE_COMPILER_IS_GNUCC) SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wno-sign-compare") IF(GCC_WARN_SIGN_CONVERSION) SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wno-sign-conversion") ENDIF(GCC_WARN_SIGN_CONVERSION) ENDIF(CMAKE_COMPILER_IS_GNUCC) IF(CMAKE_C_COMPILER_ID MATCHES "Clang") SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wno-invalid-source-encoding -Wno-shorten-64-to-32") ENDIF(CMAKE_C_COMPILER_ID MATCHES "Clang") # On Windows .exe and .dll files must be placed at the same directory if(WIN32 AND BUILD_SHARED_LIBS) set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/src) set(TEST_PATH ${CMAKE_BINARY_DIR}/src) else() set(TEST_PATH ${CMAKE_CURRENT_BINARY_DIR}) endif() set(LIBS ${LIBS} ${M_LIB} ${CHECK_LDFLAGS} ${OPENSSL_LIBRARIES} ${CMAKE_THREAD_LIBS_INIT} ${CMAKE_DL_LIBS} signal-protocol-c ) set(common_SRCS test_common.c test_common.h ) include_directories(. ../src) IF(APPLE AND ${CMAKE_SYSTEM_NAME} MATCHES "Darwin") set(common_SRCS ${common_SRCS} test_common_ccrypto.c ) ELSE() set(common_SRCS ${common_SRCS} test_common_openssl.c ) include_directories(${OPENSSL_INCLUDE_DIR}) ENDIF() add_executable(test_curve25519 test_curve25519.c ${common_SRCS}) target_link_libraries(test_curve25519 ${LIBS}) add_test(test_curve25519 ${TEST_PATH}/test_curve25519) add_executable(test_hkdf test_hkdf.c ${common_SRCS}) target_link_libraries(test_hkdf ${LIBS}) add_test(test_hkdf ${TEST_PATH}/test_hkdf) add_executable(test_ratchet test_ratchet.c ${common_SRCS}) target_link_libraries(test_ratchet ${LIBS}) add_test(test_ratchet ${TEST_PATH}/test_ratchet) add_executable(test_protocol test_protocol.c ${common_SRCS}) target_link_libraries(test_protocol ${LIBS}) add_test(test_protocol ${TEST_PATH}/test_protocol) add_executable(test_session_record test_session_record.c ${common_SRCS}) target_link_libraries(test_session_record ${LIBS}) add_test(test_session_record ${TEST_PATH}/test_session_record) add_executable(test_session_cipher test_session_cipher.c ${common_SRCS}) target_link_libraries(test_session_cipher ${LIBS}) add_test(test_session_cipher ${TEST_PATH}/test_session_cipher) add_executable(test_session_builder test_session_builder.c ${common_SRCS}) target_link_libraries(test_session_builder ${LIBS}) add_test(test_session_builder ${TEST_PATH}/test_session_builder) add_executable(test_key_helper test_key_helper.c ${common_SRCS}) target_link_libraries(test_key_helper ${LIBS}) add_test(test_key_helper ${TEST_PATH}/test_key_helper) add_executable(test_simultaneous_initiate test_simultaneous_initiate.c ${common_SRCS}) target_link_libraries(test_simultaneous_initiate ${LIBS}) add_test(test_simultaneous_initiate ${TEST_PATH}/test_simultaneous_initiate) add_executable(test_sender_key_record test_sender_key_record.c ${common_SRCS}) target_link_libraries(test_sender_key_record ${LIBS}) add_test(test_sender_key_record ${TEST_PATH}/test_sender_key_record) add_executable(test_group_cipher test_group_cipher.c ${common_SRCS}) target_link_libraries(test_group_cipher ${LIBS}) add_test(test_group_cipher ${TEST_PATH}/test_group_cipher) add_executable(test_fingerprint test_fingerprint.c ${common_SRCS}) target_link_libraries(test_fingerprint ${LIBS}) add_test(test_fingerprint ${TEST_PATH}/test_fingerprint) add_executable(test_device_consistency test_device_consistency.c ${common_SRCS}) target_link_libraries(test_device_consistency ${LIBS}) add_test(test_device_consistency ${TEST_PATH}/test_device_consistency) libsignal-protocol-c-2.3.3/tests/test_common.c000066400000000000000000000633471363751346500214310ustar00rootroot00000000000000#include "test_common.h" #include #include #include #include "../src/signal_protocol.h" #include "curve.h" #include "uthash.h" /* * This is an implementation of Jenkin's "One-at-a-Time" hash. * * http://www.burtleburtle.net/bob/hash/doobs.html * * It is used to simplify using our new string recipient IDs * as part of our keys without having to significantly modify the * testing-only implementations of our data stores. */ int64_t jenkins_hash(const char *key, size_t len) { uint64_t hash, i; for(hash = i = 0; i < len; ++i) { hash += key[i]; hash += (hash << 10); hash ^= (hash >> 6); } hash += (hash << 3); hash ^= (hash >> 11); hash += (hash << 15); return hash; } void print_public_key(const char *prefix, ec_public_key *key) { signal_buffer *buffer; ec_public_key_serialize(&buffer, key); fprintf(stderr, "%s ", prefix); uint8_t *data = signal_buffer_data(buffer); int len = signal_buffer_len(buffer); int i; for(i = 0; i < len; i++) { if(i > 0 && (i % 40) == 0) { fprintf(stderr, "\n"); } fprintf(stderr, "%02X", data[i]); } fprintf(stderr, "\n"); signal_buffer_free(buffer); } void print_buffer(const char *prefix, signal_buffer *buffer) { fprintf(stderr, "%s ", prefix); uint8_t *data = signal_buffer_data(buffer); int len = signal_buffer_len(buffer); int i; for(i = 0; i < len; i++) { if(i > 0 && (i % 40) == 0) { fprintf(stderr, "\n"); } fprintf(stderr, "%02X", data[i]); } fprintf(stderr, "\n"); } void shuffle_buffers(signal_buffer **array, size_t n) { if (n > 1) { size_t i; for (i = 0; i < n - 1; i++) { size_t j = i + rand() / (RAND_MAX / (n - i) + 1); signal_buffer *t = array[j]; array[j] = array[i]; array[i] = t; } } } void shuffle_ec_public_keys(ec_public_key **array, size_t n) { if (n > 1) { size_t i; for (i = 0; i < n - 1; i++) { size_t j = i + rand() / (RAND_MAX / (n - i) + 1); ec_public_key *t = array[j]; array[j] = array[i]; array[i] = t; } } } ec_public_key *create_test_ec_public_key(signal_context *context) { int result = 0; ec_key_pair *key_pair; result = curve_generate_key_pair(context, &key_pair); ck_assert_int_eq(result, 0); ec_public_key *public_key = ec_key_pair_get_public(key_pair); SIGNAL_REF(public_key); SIGNAL_UNREF(key_pair); return public_key; } ec_private_key *create_test_ec_private_key(signal_context *context) { int result = 0; ec_key_pair *key_pair; result = curve_generate_key_pair(context, &key_pair); ck_assert_int_eq(result, 0); ec_private_key *private_key = ec_key_pair_get_private(key_pair); SIGNAL_REF(private_key); SIGNAL_UNREF(key_pair); return private_key; } void test_log(int level, const char *message, size_t len, void *user_data) { switch(level) { case SG_LOG_ERROR: fprintf(stderr, "[ERROR] %s\n", message); break; case SG_LOG_WARNING: fprintf(stderr, "[WARNING] %s\n", message); break; case SG_LOG_NOTICE: fprintf(stderr, "[NOTICE] %s\n", message); break; case SG_LOG_INFO: fprintf(stderr, "[INFO] %s\n", message); break; case SG_LOG_DEBUG: fprintf(stderr, "[DEBUG] %s\n", message); break; default: fprintf(stderr, "[%d] %s\n", level, message); break; } } void setup_test_crypto_provider(signal_context *context) { signal_crypto_provider provider = { .random_func = test_random_generator, .hmac_sha256_init_func = test_hmac_sha256_init, .hmac_sha256_update_func = test_hmac_sha256_update, .hmac_sha256_final_func = test_hmac_sha256_final, .hmac_sha256_cleanup_func = test_hmac_sha256_cleanup, .sha512_digest_init_func = test_sha512_digest_init, .sha512_digest_update_func = test_sha512_digest_update, .sha512_digest_final_func = test_sha512_digest_final, .sha512_digest_cleanup_func = test_sha512_digest_cleanup, .encrypt_func = test_encrypt, .decrypt_func = test_decrypt, .user_data = 0 }; signal_context_set_crypto_provider(context, &provider); } /*------------------------------------------------------------------------*/ void setup_test_store_context(signal_protocol_store_context **context, signal_context *global_context) { int result = 0; signal_protocol_store_context *store_context = 0; result = signal_protocol_store_context_create(&store_context, global_context); ck_assert_int_eq(result, 0); setup_test_session_store(store_context); setup_test_pre_key_store(store_context); setup_test_signed_pre_key_store(store_context); setup_test_identity_key_store(store_context, global_context); setup_test_sender_key_store(store_context, global_context); *context = store_context; } /*------------------------------------------------------------------------*/ typedef struct { int64_t recipient_id; int32_t device_id; } test_session_store_session_key; typedef struct { test_session_store_session_key key; signal_buffer *record; UT_hash_handle hh; } test_session_store_session; typedef struct { test_session_store_session *sessions; } test_session_store_data; int test_session_store_load_session(signal_buffer **record, signal_buffer **user_record, const signal_protocol_address *address, void *user_data) { test_session_store_data *data = user_data; test_session_store_session *s; test_session_store_session l; memset(&l, 0, sizeof(test_session_store_session)); l.key.recipient_id = jenkins_hash(address->name, address->name_len); l.key.device_id = address->device_id; HASH_FIND(hh, data->sessions, &l.key, sizeof(test_session_store_session_key), s); if(!s) { return 0; } signal_buffer *result = signal_buffer_copy(s->record); if(!result) { return SG_ERR_NOMEM; } *record = result; return 1; } int test_session_store_get_sub_device_sessions(signal_int_list **sessions, const char *name, size_t name_len, void *user_data) { test_session_store_data *data = user_data; signal_int_list *result = signal_int_list_alloc(); if(!result) { return SG_ERR_NOMEM; } int64_t recipient_hash = jenkins_hash(name, name_len); test_session_store_session *cur_node; test_session_store_session *tmp_node; HASH_ITER(hh, data->sessions, cur_node, tmp_node) { if(cur_node->key.recipient_id == recipient_hash) { signal_int_list_push_back(result, cur_node->key.device_id); } } *sessions = result; return 0; } int test_session_store_store_session(const signal_protocol_address *address, uint8_t *record, size_t record_len, uint8_t *user_record_data, size_t user_record_len, void *user_data) { test_session_store_data *data = user_data; test_session_store_session *s; test_session_store_session l; memset(&l, 0, sizeof(test_session_store_session)); l.key.recipient_id = jenkins_hash(address->name, address->name_len); l.key.device_id = address->device_id; signal_buffer *record_buf = signal_buffer_create(record, record_len); if(!record_buf) { return SG_ERR_NOMEM; } HASH_FIND(hh, data->sessions, &l.key, sizeof(test_session_store_session_key), s); if(s) { signal_buffer_free(s->record); s->record = record_buf; } else { s = malloc(sizeof(test_session_store_session)); if(!s) { signal_buffer_free(record_buf); return SG_ERR_NOMEM; } memset(s, 0, sizeof(test_session_store_session)); s->key.recipient_id = jenkins_hash(address->name, address->name_len); s->key.device_id = address->device_id; s->record = record_buf; HASH_ADD(hh, data->sessions, key, sizeof(test_session_store_session_key), s); } return 0; } int test_session_store_contains_session(const signal_protocol_address *address, void *user_data) { test_session_store_data *data = user_data; test_session_store_session *s; test_session_store_session l; memset(&l, 0, sizeof(test_session_store_session)); l.key.recipient_id = jenkins_hash(address->name, address->name_len); l.key.device_id = address->device_id; HASH_FIND(hh, data->sessions, &l.key, sizeof(test_session_store_session_key), s); return (s == 0) ? 0 : 1; } int test_session_store_delete_session(const signal_protocol_address *address, void *user_data) { int result = 0; test_session_store_data *data = user_data; test_session_store_session *s; test_session_store_session l; memset(&l, 0, sizeof(test_session_store_session)); l.key.recipient_id = jenkins_hash(address->name, address->name_len); l.key.device_id = address->device_id; HASH_FIND(hh, data->sessions, &l.key, sizeof(test_session_store_session_key), s); if(s) { HASH_DEL(data->sessions, s); signal_buffer_free(s->record); free(s); result = 1; } return result; } int test_session_store_delete_all_sessions(const char *name, size_t name_len, void *user_data) { int result = 0; test_session_store_data *data = user_data; int64_t recipient_hash = jenkins_hash(name, name_len); test_session_store_session *cur_node; test_session_store_session *tmp_node; HASH_ITER(hh, data->sessions, cur_node, tmp_node) { if(cur_node->key.recipient_id == recipient_hash) { HASH_DEL(data->sessions, cur_node); signal_buffer_free(cur_node->record); free(cur_node); result++; } } return result; } void test_session_store_destroy(void *user_data) { test_session_store_data *data = user_data; test_session_store_session *cur_node; test_session_store_session *tmp_node; HASH_ITER(hh, data->sessions, cur_node, tmp_node) { HASH_DEL(data->sessions, cur_node); signal_buffer_free(cur_node->record); free(cur_node); } free(data); } void setup_test_session_store(signal_protocol_store_context *context) { test_session_store_data *data = malloc(sizeof(test_session_store_data)); memset(data, 0, sizeof(test_session_store_data)); signal_protocol_session_store store = { .load_session_func = test_session_store_load_session, .get_sub_device_sessions_func = test_session_store_get_sub_device_sessions, .store_session_func = test_session_store_store_session, .contains_session_func = test_session_store_contains_session, .delete_session_func = test_session_store_delete_session, .delete_all_sessions_func = test_session_store_delete_all_sessions, .destroy_func = test_session_store_destroy, .user_data = data }; signal_protocol_store_context_set_session_store(context, &store); } /*------------------------------------------------------------------------*/ typedef struct { uint32_t key_id; signal_buffer *key_record; UT_hash_handle hh; } test_pre_key_store_key; typedef struct { test_pre_key_store_key *keys; } test_pre_key_store_data; int test_pre_key_store_load_pre_key(signal_buffer **record, uint32_t pre_key_id, void *user_data) { test_pre_key_store_data *data = user_data; test_pre_key_store_key *s; HASH_FIND(hh, data->keys, &pre_key_id, sizeof(uint32_t), s); if(s) { *record = signal_buffer_copy(s->key_record); return SG_SUCCESS; } else { return SG_ERR_INVALID_KEY_ID; } } int test_pre_key_store_store_pre_key(uint32_t pre_key_id, uint8_t *record, size_t record_len, void *user_data) { test_pre_key_store_data *data = user_data; test_pre_key_store_key *s; signal_buffer *key_buf = signal_buffer_create(record, record_len); if(!key_buf) { return SG_ERR_NOMEM; } HASH_FIND(hh, data->keys, &pre_key_id, sizeof(uint32_t), s); if(s) { signal_buffer_free(s->key_record); s->key_record = key_buf; } else { s = malloc(sizeof(test_pre_key_store_key)); if(!s) { signal_buffer_free(key_buf); return SG_ERR_NOMEM; } memset(s, 0, sizeof(test_pre_key_store_key)); s->key_id = pre_key_id; s->key_record = key_buf; HASH_ADD(hh, data->keys, key_id, sizeof(uint32_t), s); } return 0; } int test_pre_key_store_contains_pre_key(uint32_t pre_key_id, void *user_data) { test_pre_key_store_data *data = user_data; test_pre_key_store_key *s; HASH_FIND(hh, data->keys, &pre_key_id, sizeof(uint32_t), s); return (s == 0) ? 0 : 1; } int test_pre_key_store_remove_pre_key(uint32_t pre_key_id, void *user_data) { test_pre_key_store_data *data = user_data; test_pre_key_store_key *s; HASH_FIND(hh, data->keys, &pre_key_id, sizeof(uint32_t), s); if(s) { HASH_DEL(data->keys, s); signal_buffer_free(s->key_record); free(s); } return 0; } void test_pre_key_store_destroy(void *user_data) { test_pre_key_store_data *data = user_data; test_pre_key_store_key *cur_node; test_pre_key_store_key *tmp_node; HASH_ITER(hh, data->keys, cur_node, tmp_node) { HASH_DEL(data->keys, cur_node); signal_buffer_free(cur_node->key_record); free(cur_node); } free(data); } void setup_test_pre_key_store(signal_protocol_store_context *context) { test_pre_key_store_data *data = malloc(sizeof(test_pre_key_store_data)); memset(data, 0, sizeof(test_pre_key_store_data)); signal_protocol_pre_key_store store = { .load_pre_key = test_pre_key_store_load_pre_key, .store_pre_key = test_pre_key_store_store_pre_key, .contains_pre_key = test_pre_key_store_contains_pre_key, .remove_pre_key = test_pre_key_store_remove_pre_key, .destroy_func = test_pre_key_store_destroy, .user_data = data }; signal_protocol_store_context_set_pre_key_store(context, &store); } /*------------------------------------------------------------------------*/ typedef struct { uint32_t key_id; signal_buffer *key_record; UT_hash_handle hh; } test_signed_pre_key_store_key; typedef struct { test_signed_pre_key_store_key *keys; } test_signed_pre_key_store_data; int test_signed_pre_key_store_load_signed_pre_key(signal_buffer **record, uint32_t signed_pre_key_id, void *user_data) { test_signed_pre_key_store_data *data = user_data; test_signed_pre_key_store_key *s; HASH_FIND(hh, data->keys, &signed_pre_key_id, sizeof(uint32_t), s); if(s) { *record = signal_buffer_copy(s->key_record); return SG_SUCCESS; } else { return SG_ERR_INVALID_KEY_ID; } } int test_signed_pre_key_store_store_signed_pre_key(uint32_t signed_pre_key_id, uint8_t *record, size_t record_len, void *user_data) { test_signed_pre_key_store_data *data = user_data; test_signed_pre_key_store_key *s; signal_buffer *key_buf = signal_buffer_create(record, record_len); if(!key_buf) { return SG_ERR_NOMEM; } HASH_FIND(hh, data->keys, &signed_pre_key_id, sizeof(uint32_t), s); if(s) { signal_buffer_free(s->key_record); s->key_record = key_buf; } else { s = malloc(sizeof(test_signed_pre_key_store_key)); if(!s) { signal_buffer_free(key_buf); return SG_ERR_NOMEM; } memset(s, 0, sizeof(test_signed_pre_key_store_key)); s->key_id = signed_pre_key_id; s->key_record = key_buf; HASH_ADD(hh, data->keys, key_id, sizeof(uint32_t), s); } return 0; } int test_signed_pre_key_store_contains_signed_pre_key(uint32_t signed_pre_key_id, void *user_data) { test_signed_pre_key_store_data *data = user_data; test_signed_pre_key_store_key *s; HASH_FIND(hh, data->keys, &signed_pre_key_id, sizeof(uint32_t), s); return (s == 0) ? 0 : 1; } int test_signed_pre_key_store_remove_signed_pre_key(uint32_t signed_pre_key_id, void *user_data) { test_signed_pre_key_store_data *data = user_data; test_signed_pre_key_store_key *s; HASH_FIND(hh, data->keys, &signed_pre_key_id, sizeof(uint32_t), s); if(s) { HASH_DEL(data->keys, s); signal_buffer_free(s->key_record); free(s); } return 0; } void test_signed_pre_key_store_destroy(void *user_data) { test_signed_pre_key_store_data *data = user_data; test_signed_pre_key_store_key *cur_node; test_signed_pre_key_store_key *tmp_node; HASH_ITER(hh, data->keys, cur_node, tmp_node) { HASH_DEL(data->keys, cur_node); signal_buffer_free(cur_node->key_record); free(cur_node); } free(data); } void setup_test_signed_pre_key_store(signal_protocol_store_context *context) { test_signed_pre_key_store_data *data = malloc(sizeof(test_signed_pre_key_store_data)); memset(data, 0, sizeof(test_signed_pre_key_store_data)); signal_protocol_signed_pre_key_store store = { .load_signed_pre_key = test_signed_pre_key_store_load_signed_pre_key, .store_signed_pre_key = test_signed_pre_key_store_store_signed_pre_key, .contains_signed_pre_key = test_signed_pre_key_store_contains_signed_pre_key, .remove_signed_pre_key = test_signed_pre_key_store_remove_signed_pre_key, .destroy_func = test_signed_pre_key_store_destroy, .user_data = data }; signal_protocol_store_context_set_signed_pre_key_store(context, &store); } /*------------------------------------------------------------------------*/ typedef struct { int64_t recipient_id; signal_buffer *identity_key; UT_hash_handle hh; } test_identity_store_key; typedef struct { test_identity_store_key *keys; signal_buffer *identity_key_public; signal_buffer *identity_key_private; uint32_t local_registration_id; } test_identity_store_data; int test_identity_key_store_get_identity_key_pair(signal_buffer **public_data, signal_buffer **private_data, void *user_data) { test_identity_store_data *data = user_data; *public_data = signal_buffer_copy(data->identity_key_public); *private_data = signal_buffer_copy(data->identity_key_private); return 0; } int test_identity_key_store_get_local_registration_id(void *user_data, uint32_t *registration_id) { test_identity_store_data *data = user_data; *registration_id = data->local_registration_id; return 0; } int test_identity_key_store_save_identity(const signal_protocol_address *address, uint8_t *key_data, size_t key_len, void *user_data) { test_identity_store_data *data = user_data; test_identity_store_key *s; signal_buffer *key_buf = signal_buffer_create(key_data, key_len); if(!key_buf) { return SG_ERR_NOMEM; } int64_t recipient_hash = jenkins_hash(address->name, address->name_len); HASH_FIND(hh, data->keys, &recipient_hash, sizeof(int64_t), s); if(s) { signal_buffer_free(s->identity_key); s->identity_key = key_buf; } else { s = malloc(sizeof(test_identity_store_key)); if(!s) { signal_buffer_free(key_buf); return SG_ERR_NOMEM; } memset(s, 0, sizeof(test_identity_store_key)); s->recipient_id = recipient_hash; s->identity_key = key_buf; HASH_ADD(hh, data->keys, recipient_id, sizeof(int64_t), s); } return 0; } int test_identity_key_store_is_trusted_identity(const signal_protocol_address *address, uint8_t *key_data, size_t key_len, void *user_data) { test_identity_store_data *data = user_data; int64_t recipient_hash = jenkins_hash(address->name, address->name_len); test_identity_store_key *s; HASH_FIND(hh, data->keys, &recipient_hash, sizeof(int64_t), s); if(s) { uint8_t *store_data = signal_buffer_data(s->identity_key); size_t store_len = signal_buffer_len(s->identity_key); if(store_len != key_len) { return 0; } if(memcmp(key_data, store_data, key_len) == 0) { return 1; } else { return 0; } } else { return 1; } } void test_identity_key_store_destroy(void *user_data) { test_identity_store_data *data = user_data; test_identity_store_key *cur_node; test_identity_store_key *tmp_node; HASH_ITER(hh, data->keys, cur_node, tmp_node) { HASH_DEL(data->keys, cur_node); signal_buffer_free(cur_node->identity_key); free(cur_node); } signal_buffer_free(data->identity_key_public); signal_buffer_free(data->identity_key_private); free(data); } void setup_test_identity_key_store(signal_protocol_store_context *context, signal_context *global_context) { test_identity_store_data *data = malloc(sizeof(test_identity_store_data)); memset(data, 0, sizeof(test_identity_store_data)); ec_key_pair *identity_key_pair_keys = 0; curve_generate_key_pair(global_context, &identity_key_pair_keys); ec_public_key *identity_key_public = ec_key_pair_get_public(identity_key_pair_keys); ec_private_key *identity_key_private = ec_key_pair_get_private(identity_key_pair_keys); ec_public_key_serialize(&data->identity_key_public, identity_key_public); ec_private_key_serialize(&data->identity_key_private, identity_key_private); SIGNAL_UNREF(identity_key_pair_keys); data->local_registration_id = (rand() % 16380) + 1; signal_protocol_identity_key_store store = { .get_identity_key_pair = test_identity_key_store_get_identity_key_pair, .get_local_registration_id = test_identity_key_store_get_local_registration_id, .save_identity = test_identity_key_store_save_identity, .is_trusted_identity = test_identity_key_store_is_trusted_identity, .destroy_func = test_identity_key_store_destroy, .user_data = data }; signal_protocol_store_context_set_identity_key_store(context, &store); } /*------------------------------------------------------------------------*/ typedef struct { int64_t group_id; int64_t recipient_id; int32_t device_id; } test_sender_key_store_key; typedef struct { test_sender_key_store_key key; signal_buffer *record; UT_hash_handle hh; } test_sender_key_store_record; typedef struct { test_sender_key_store_record *records; } test_sender_key_store_data; int test_sender_key_store_store_sender_key(const signal_protocol_sender_key_name *sender_key_name, uint8_t *record, size_t record_len, uint8_t *user_record_data, size_t user_record_len, void *user_data) { test_sender_key_store_data *data = user_data; test_sender_key_store_record *s; test_sender_key_store_record l; memset(&l, 0, sizeof(test_sender_key_store_record)); l.key.group_id = jenkins_hash(sender_key_name->group_id, sender_key_name->group_id_len); l.key.recipient_id = jenkins_hash(sender_key_name->sender.name, sender_key_name->sender.name_len); l.key.device_id = sender_key_name->sender.device_id; signal_buffer *record_buf = signal_buffer_create(record, record_len); if(!record_buf) { return SG_ERR_NOMEM; } HASH_FIND(hh, data->records, &l.key, sizeof(test_sender_key_store_key), s); if(s) { signal_buffer_free(s->record); s->record = record_buf; } else { s = malloc(sizeof(test_sender_key_store_record)); if(!s) { signal_buffer_free(record_buf); return SG_ERR_NOMEM; } memset(s, 0, sizeof(test_sender_key_store_record)); s->key.group_id = jenkins_hash(sender_key_name->group_id, sender_key_name->group_id_len); s->key.recipient_id = jenkins_hash(sender_key_name->sender.name, sender_key_name->sender.name_len); s->key.device_id = sender_key_name->sender.device_id; s->record = record_buf; HASH_ADD(hh, data->records, key, sizeof(test_sender_key_store_key), s); } return 0; } int test_sender_key_store_load_sender_key(signal_buffer **record, signal_buffer **user_record, const signal_protocol_sender_key_name *sender_key_name, void *user_data) { test_sender_key_store_data *data = user_data; test_sender_key_store_record *s; test_sender_key_store_record l; memset(&l, 0, sizeof(test_sender_key_store_record)); l.key.group_id = jenkins_hash(sender_key_name->group_id, sender_key_name->group_id_len); l.key.recipient_id = jenkins_hash(sender_key_name->sender.name, sender_key_name->sender.name_len); l.key.device_id = sender_key_name->sender.device_id; HASH_FIND(hh, data->records, &l.key, sizeof(test_sender_key_store_key), s); if(!s) { return 0; } signal_buffer *result = signal_buffer_copy(s->record); if(!result) { return SG_ERR_NOMEM; } *record = result; return 1; } void test_sender_key_store_destroy(void *user_data) { test_sender_key_store_data *data = user_data; test_sender_key_store_record *cur_node; test_sender_key_store_record *tmp_node; HASH_ITER(hh, data->records, cur_node, tmp_node) { HASH_DEL(data->records, cur_node); signal_buffer_free(cur_node->record); free(cur_node); } free(data); } void setup_test_sender_key_store(signal_protocol_store_context *context, signal_context *global_context) { test_sender_key_store_data *data = malloc(sizeof(test_sender_key_store_data)); memset(data, 0, sizeof(test_sender_key_store_data)); signal_protocol_sender_key_store store = { .store_sender_key = test_sender_key_store_store_sender_key, .load_sender_key = test_sender_key_store_load_sender_key, .destroy_func = test_sender_key_store_destroy, .user_data = data }; signal_protocol_store_context_set_sender_key_store(context, &store); } #ifndef __OpenBSD__ void srand_deterministic(unsigned int seed) { srand(seed); } #endif libsignal-protocol-c-2.3.3/tests/test_common.h000066400000000000000000000126051363751346500214250ustar00rootroot00000000000000#ifndef TEST_COMMON_H #define TEST_COMMON_H #include #include #include "../src/signal_protocol.h" /* Test utility functions */ void print_public_key(const char *prefix, ec_public_key *key); void print_buffer(const char *prefix, signal_buffer *buffer); void shuffle_buffers(signal_buffer **array, size_t n); void shuffle_ec_public_keys(ec_public_key **array, size_t n); ec_public_key *create_test_ec_public_key(signal_context *context); ec_private_key *create_test_ec_private_key(signal_context *context); /* Test logging */ void test_log(int level, const char *message, size_t len, void *user_data); /* Test crypto provider */ int test_random_generator(uint8_t *data, size_t len, void *user_data); int test_hmac_sha256_init(void **hmac_context, const uint8_t *key, size_t key_len, void *user_data); int test_hmac_sha256_update(void *hmac_context, const uint8_t *data, size_t data_len, void *user_data); int test_hmac_sha256_final(void *hmac_context, signal_buffer **output, void *user_data); void test_hmac_sha256_cleanup(void *hmac_context, void *user_data); int test_sha512_digest_init(void **digest_context, void *user_data); int test_sha512_digest_update(void *digest_context, const uint8_t *data, size_t data_len, void *user_data); int test_sha512_digest_final(void *digest_context, signal_buffer **output, void *user_data); void test_sha512_digest_cleanup(void *digest_context, void *user_data); int test_encrypt(signal_buffer **output, int cipher, const uint8_t *key, size_t key_len, const uint8_t *iv, size_t iv_len, const uint8_t *plaintext, size_t plaintext_len, void *user_data); int test_decrypt(signal_buffer **output, int cipher, const uint8_t *key, size_t key_len, const uint8_t *iv, size_t iv_len, const uint8_t *ciphertext, size_t ciphertext_len, void *user_data); void setup_test_crypto_provider(signal_context *context); /* Test data store context */ void setup_test_store_context(signal_protocol_store_context **context, signal_context *global_context); /* Test session store */ int test_session_store_load_session(signal_buffer **record, signal_buffer **user_record, const signal_protocol_address *address, void *user_data); int test_session_store_get_sub_device_sessions(signal_int_list **sessions, const char *name, size_t name_len, void *user_data); int test_session_store_store_session(const signal_protocol_address *address, uint8_t *record, size_t record_len, uint8_t *user_record_data, size_t user_record_len, void *user_data); int test_session_store_contains_session(const signal_protocol_address *address, void *user_data); int test_session_store_delete_session(const signal_protocol_address *address, void *user_data); int test_session_store_delete_all_sessions(const char *name, size_t name_len, void *user_data); void test_session_store_destroy(void *user_data); void setup_test_session_store(signal_protocol_store_context *context); /* Test pre-key store */ int test_pre_key_store_load_pre_key(signal_buffer **record, uint32_t pre_key_id, void *user_data); int test_pre_key_store_store_pre_key(uint32_t pre_key_id, uint8_t *record, size_t record_len, void *user_data); int test_pre_key_store_contains_pre_key(uint32_t pre_key_id, void *user_data); int test_pre_key_store_remove_pre_key(uint32_t pre_key_id, void *user_data); void test_pre_key_store_destroy(void *user_data); void setup_test_pre_key_store(signal_protocol_store_context *context); /* Test signed pre-key store */ int test_signed_pre_key_store_load_signed_pre_key(signal_buffer **record, uint32_t signed_pre_key_id, void *user_data); int test_signed_pre_key_store_store_signed_pre_key(uint32_t signed_pre_key_id, uint8_t *record, size_t record_len, void *user_data); int test_signed_pre_key_store_contains_signed_pre_key(uint32_t signed_pre_key_id, void *user_data); int test_signed_pre_key_store_remove_signed_pre_key(uint32_t signed_pre_key_id, void *user_data); void test_signed_pre_key_store_destroy(void *user_data); void setup_test_signed_pre_key_store(signal_protocol_store_context *context); /* Test identity key store */ int test_identity_key_store_get_identity_key_pair(signal_buffer **public_data, signal_buffer **private_data, void *user_data); int test_identity_key_store_get_local_registration_id(void *user_data, uint32_t *registration_id); int test_identity_key_store_save_identity(const signal_protocol_address *address, uint8_t *key_data, size_t key_len, void *user_data); int test_identity_key_store_is_trusted_identity(const signal_protocol_address *address, uint8_t *key_data, size_t key_len, void *user_data); void test_identity_key_store_destroy(void *user_data); void setup_test_identity_key_store(signal_protocol_store_context *context, signal_context *global_context); /* Test sender key store */ int test_sender_key_store_store_sender_key(const signal_protocol_sender_key_name *sender_key_name, uint8_t *record, size_t record_len, uint8_t *user_record_data, size_t user_record_len, void *user_data); int test_sender_key_store_load_sender_key(signal_buffer **record, signal_buffer **user_record, const signal_protocol_sender_key_name *sender_key_name, void *user_data); void test_sender_key_store_destroy(void *user_data); void setup_test_sender_key_store(signal_protocol_store_context *context, signal_context *global_context); /* Portability */ #ifndef __OpenBSD__ /* OpenBSD extension */ void srand_deterministic(unsigned int seed); #endif #endif /* TEST_COMMON_H */ libsignal-protocol-c-2.3.3/tests/test_common_ccrypto.c000066400000000000000000000174311363751346500231650ustar00rootroot00000000000000#include "test_common.h" #include #include #include #include int test_random_generator(uint8_t *data, size_t len, void *user_data) { arc4random_buf(data, len); return 0; #if 0 /* * Apple's documentation recommends this method for generating secure * random numbers. However, it is too slow for the purpose of unit tests. */ int result = 0; FILE *fp = fopen("/dev/random", "r"); if(!fp) { result = SG_ERR_UNKNOWN; goto complete; } size_t n = fread(data, 1, len, fp); if(n != len) { result = SG_ERR_UNKNOWN; goto complete; } complete: if(fp) { fclose(fp); } return result; #endif } int test_hmac_sha256_init(void **hmac_context, const uint8_t *key, size_t key_len, void *user_data) { CCHmacContext *ctx = malloc(sizeof(CCHmacContext)); if(!ctx) { return SG_ERR_NOMEM; } CCHmacInit(ctx, kCCHmacAlgSHA256, key, key_len); *hmac_context = ctx; return 0; } int test_hmac_sha256_update(void *hmac_context, const uint8_t *data, size_t data_len, void *user_data) { CCHmacContext *ctx = hmac_context; CCHmacUpdate(ctx, data, data_len); return 0; } int test_hmac_sha256_final(void *hmac_context, signal_buffer **output, void *user_data) { CCHmacContext *ctx = hmac_context; signal_buffer *output_buffer = signal_buffer_alloc(CC_SHA256_DIGEST_LENGTH); if(!output_buffer) { return SG_ERR_NOMEM; } CCHmacFinal(ctx, signal_buffer_data(output_buffer)); *output = output_buffer; return 0; } void test_hmac_sha256_cleanup(void *hmac_context, void *user_data) { if(hmac_context) { CCHmacContext *ctx = hmac_context; free(ctx); } } int test_sha512_digest_init(void **digest_context, void *user_data) { int result = 0; CC_SHA512_CTX *ctx = malloc(sizeof(CC_SHA512_CTX)); if(!ctx) { result = SG_ERR_NOMEM; goto complete; } result = CC_SHA512_Init(ctx); if(result != 1) { result = SG_ERR_UNKNOWN; goto complete; } complete: if(result < 0) { if(ctx) { free(ctx); } } else { *digest_context = ctx; } return result; } int test_sha512_digest_update(void *digest_context, const uint8_t *data, size_t data_len, void *user_data) { CC_SHA512_CTX *ctx = digest_context; int result = CC_SHA512_Update(ctx, data, data_len); return (result == 1) ? SG_SUCCESS : SG_ERR_UNKNOWN; } int test_sha512_digest_final(void *digest_context, signal_buffer **output, void *user_data) { int result = 0; unsigned char md[CC_SHA512_DIGEST_LENGTH]; CC_SHA512_CTX *ctx = digest_context; result = CC_SHA512_Final(md, ctx); if(result == 1) { result = SG_SUCCESS; } else { result = SG_ERR_UNKNOWN; goto complete; } result = CC_SHA512_Init(ctx); if(result == 1) { result = SG_SUCCESS; } else { result = SG_ERR_UNKNOWN; goto complete; } signal_buffer *output_buffer = signal_buffer_create(md, CC_SHA512_DIGEST_LENGTH); if(!output_buffer) { result = SG_ERR_NOMEM; goto complete; } *output = output_buffer; complete: return result; } void test_sha512_digest_cleanup(void *digest_context, void *user_data) { if(digest_context) { CC_SHA512_CTX *ctx = digest_context; free(ctx); } } int cc_status_to_result(CCCryptorStatus status) { switch(status) { case kCCSuccess: return SG_SUCCESS; case kCCParamError: case kCCBufferTooSmall: return SG_ERR_INVAL; case kCCMemoryFailure: return SG_ERR_NOMEM; case kCCAlignmentError: case kCCDecodeError: case kCCUnimplemented: case kCCOverflow: case kCCRNGFailure: case kCCUnspecifiedError: case kCCCallSequenceError: default: return SG_ERR_UNKNOWN; } } int test_encrypt(signal_buffer **output, int cipher, const uint8_t *key, size_t key_len, const uint8_t *iv, size_t iv_len, const uint8_t *plaintext, size_t plaintext_len, void *user_data) { int result = 0; uint8_t *out_buf = 0; CCCryptorStatus status = kCCSuccess; CCCryptorRef ref = 0; if(cipher == SG_CIPHER_AES_CBC_PKCS5) { status = CCCryptorCreate(kCCEncrypt, kCCAlgorithmAES, kCCOptionPKCS7Padding, key, key_len, iv, &ref); } else if(cipher == SG_CIPHER_AES_CTR_NOPADDING) { status = CCCryptorCreateWithMode(kCCEncrypt, kCCModeCTR, kCCAlgorithmAES, ccNoPadding, iv, key, key_len, 0, 0, 0, kCCModeOptionCTR_BE, &ref); } else { status = kCCParamError; } if(status != kCCSuccess) { result = cc_status_to_result(status); goto complete; } size_t available_len = CCCryptorGetOutputLength(ref, plaintext_len, 1); out_buf = malloc(available_len); if(!out_buf) { fprintf(stderr, "cannot allocate output buffer\n"); result = SG_ERR_NOMEM; goto complete; } size_t update_moved_len = 0; status = CCCryptorUpdate(ref, plaintext, plaintext_len, out_buf, available_len, &update_moved_len); if(status != kCCSuccess) { result = cc_status_to_result(status); goto complete; } size_t final_moved_len = 0; status = CCCryptorFinal(ref, out_buf + update_moved_len, available_len - update_moved_len, &final_moved_len); if(status != kCCSuccess) { result = cc_status_to_result(status); goto complete; } signal_buffer *output_buffer = signal_buffer_create(out_buf, update_moved_len + final_moved_len); if(!output_buffer) { result = SG_ERR_NOMEM; goto complete; } *output = output_buffer; complete: if(ref) { CCCryptorRelease(ref); } if(out_buf) { free(out_buf); } return result; } int test_decrypt(signal_buffer **output, int cipher, const uint8_t *key, size_t key_len, const uint8_t *iv, size_t iv_len, const uint8_t *ciphertext, size_t ciphertext_len, void *user_data) { int result = 0; uint8_t *out_buf = 0; CCCryptorStatus status = kCCSuccess; CCCryptorRef ref = 0; if(cipher == SG_CIPHER_AES_CBC_PKCS5) { status = CCCryptorCreate(kCCDecrypt, kCCAlgorithmAES, kCCOptionPKCS7Padding, key, key_len, iv, &ref); } else if(cipher == SG_CIPHER_AES_CTR_NOPADDING) { status = CCCryptorCreateWithMode(kCCDecrypt, kCCModeCTR, kCCAlgorithmAES, ccNoPadding, iv, key, key_len, 0, 0, 0, kCCModeOptionCTR_BE, &ref); } else { status = kCCParamError; } if(status != kCCSuccess) { result = cc_status_to_result(status); goto complete; } out_buf = malloc(sizeof(uint8_t) * ciphertext_len); if(!out_buf) { fprintf(stderr, "cannot allocate output buffer\n"); result = SG_ERR_UNKNOWN; goto complete; } size_t update_moved_len = 0; status = CCCryptorUpdate(ref, ciphertext, ciphertext_len, out_buf, ciphertext_len, &update_moved_len); if(status != kCCSuccess) { result = cc_status_to_result(status); goto complete; } size_t final_moved_len = 0; status = CCCryptorFinal(ref, out_buf + update_moved_len, ciphertext_len - update_moved_len, &final_moved_len); if(status != kCCSuccess) { result = cc_status_to_result(status); goto complete; } signal_buffer *output_buffer = signal_buffer_create(out_buf, update_moved_len + final_moved_len); if(!output_buffer) { result = SG_ERR_NOMEM; goto complete; } *output = output_buffer; complete: if(ref) { CCCryptorRelease(ref); } if(out_buf) { free(out_buf); } return result; } libsignal-protocol-c-2.3.3/tests/test_common_openssl.c000066400000000000000000000224401363751346500231610ustar00rootroot00000000000000#include "test_common.h" #include #include #include #include #include #include int test_random_generator(uint8_t *data, size_t len, void *user_data) { if(RAND_bytes(data, len)) { return 0; } else { return SG_ERR_UNKNOWN; } } int test_hmac_sha256_init(void **hmac_context, const uint8_t *key, size_t key_len, void *user_data) { #if OPENSSL_VERSION_NUMBER >= 0x1010000fL HMAC_CTX *ctx = HMAC_CTX_new(); if(!ctx) { return SG_ERR_NOMEM; } #else HMAC_CTX *ctx = malloc(sizeof(HMAC_CTX)); if(!ctx) { return SG_ERR_NOMEM; } HMAC_CTX_init(ctx); #endif *hmac_context = ctx; if(HMAC_Init_ex(ctx, key, key_len, EVP_sha256(), 0) != 1) { return SG_ERR_UNKNOWN; } return 0; } int test_hmac_sha256_update(void *hmac_context, const uint8_t *data, size_t data_len, void *user_data) { HMAC_CTX *ctx = hmac_context; int result = HMAC_Update(ctx, data, data_len); return (result == 1) ? 0 : -1; } int test_hmac_sha256_final(void *hmac_context, signal_buffer **output, void *user_data) { int result = 0; unsigned char md[EVP_MAX_MD_SIZE]; unsigned int len = 0; HMAC_CTX *ctx = hmac_context; if(HMAC_Final(ctx, md, &len) != 1) { return SG_ERR_UNKNOWN; } signal_buffer *output_buffer = signal_buffer_create(md, len); if(!output_buffer) { result = SG_ERR_NOMEM; goto complete; } *output = output_buffer; complete: return result; } void test_hmac_sha256_cleanup(void *hmac_context, void *user_data) { if(hmac_context) { HMAC_CTX *ctx = hmac_context; #if OPENSSL_VERSION_NUMBER >= 0x1010000fL HMAC_CTX_free(ctx); #else HMAC_CTX_cleanup(ctx); free(ctx); #endif } } const EVP_CIPHER *aes_cipher(int cipher, size_t key_len) { if(cipher == SG_CIPHER_AES_CBC_PKCS5) { if(key_len == 16) { return EVP_aes_128_cbc(); } else if(key_len == 24) { return EVP_aes_192_cbc(); } else if(key_len == 32) { return EVP_aes_256_cbc(); } } else if(cipher == SG_CIPHER_AES_CTR_NOPADDING) { if(key_len == 16) { return EVP_aes_128_ctr(); } else if(key_len == 24) { return EVP_aes_192_ctr(); } else if(key_len == 32) { return EVP_aes_256_ctr(); } } return 0; } int test_sha512_digest_init(void **digest_context, void *user_data) { int result = 0; EVP_MD_CTX *ctx; ctx = EVP_MD_CTX_create(); if(!ctx) { result = SG_ERR_NOMEM; goto complete; } result = EVP_DigestInit_ex(ctx, EVP_sha512(), 0); if(result == 1) { result = SG_SUCCESS; } else { result = SG_ERR_UNKNOWN; } complete: if(result < 0) { if(ctx) { EVP_MD_CTX_destroy(ctx); } } else { *digest_context = ctx; } return result; } int test_sha512_digest_update(void *digest_context, const uint8_t *data, size_t data_len, void *user_data) { EVP_MD_CTX *ctx = digest_context; int result = EVP_DigestUpdate(ctx, data, data_len); return (result == 1) ? SG_SUCCESS : SG_ERR_UNKNOWN; } int test_sha512_digest_final(void *digest_context, signal_buffer **output, void *user_data) { int result = 0; unsigned char md[EVP_MAX_MD_SIZE]; unsigned int len = 0; EVP_MD_CTX *ctx = digest_context; result = EVP_DigestFinal_ex(ctx, md, &len); if(result == 1) { result = SG_SUCCESS; } else { result = SG_ERR_UNKNOWN; goto complete; } result = EVP_DigestInit_ex(ctx, EVP_sha512(), 0); if(result == 1) { result = SG_SUCCESS; } else { result = SG_ERR_UNKNOWN; goto complete; } signal_buffer *output_buffer = signal_buffer_create(md, len); if(!output_buffer) { result = SG_ERR_NOMEM; goto complete; } *output = output_buffer; complete: return result; } void test_sha512_digest_cleanup(void *digest_context, void *user_data) { EVP_MD_CTX *ctx = digest_context; EVP_MD_CTX_destroy(ctx); } int test_encrypt(signal_buffer **output, int cipher, const uint8_t *key, size_t key_len, const uint8_t *iv, size_t iv_len, const uint8_t *plaintext, size_t plaintext_len, void *user_data) { int result = 0; EVP_CIPHER_CTX *ctx = 0; uint8_t *out_buf = 0; const EVP_CIPHER *evp_cipher = aes_cipher(cipher, key_len); if(!evp_cipher) { fprintf(stderr, "invalid AES mode or key size: %zu\n", key_len); return SG_ERR_UNKNOWN; } if(iv_len != 16) { fprintf(stderr, "invalid AES IV size: %zu\n", iv_len); return SG_ERR_UNKNOWN; } if(plaintext_len > INT_MAX - EVP_CIPHER_block_size(evp_cipher)) { fprintf(stderr, "invalid plaintext length: %zu\n", plaintext_len); return SG_ERR_UNKNOWN; } #if OPENSSL_VERSION_NUMBER >= 0x1010000fL ctx = EVP_CIPHER_CTX_new(); if(!ctx) { result = SG_ERR_NOMEM; goto complete; } #else ctx = malloc(sizeof(EVP_CIPHER_CTX)); if(!ctx) { result = SG_ERR_NOMEM; goto complete; } EVP_CIPHER_CTX_init(ctx); #endif result = EVP_EncryptInit_ex(ctx, evp_cipher, 0, key, iv); if(!result) { fprintf(stderr, "cannot initialize cipher\n"); result = SG_ERR_UNKNOWN; goto complete; } if(cipher == SG_CIPHER_AES_CTR_NOPADDING) { result = EVP_CIPHER_CTX_set_padding(ctx, 0); if(!result) { fprintf(stderr, "cannot set padding\n"); result = SG_ERR_UNKNOWN; goto complete; } } out_buf = malloc(sizeof(uint8_t) * (plaintext_len + EVP_CIPHER_block_size(evp_cipher))); if(!out_buf) { fprintf(stderr, "cannot allocate output buffer\n"); result = SG_ERR_NOMEM; goto complete; } int out_len = 0; result = EVP_EncryptUpdate(ctx, out_buf, &out_len, plaintext, plaintext_len); if(!result) { fprintf(stderr, "cannot encrypt plaintext\n"); result = SG_ERR_UNKNOWN; goto complete; } int final_len = 0; result = EVP_EncryptFinal_ex(ctx, out_buf + out_len, &final_len); if(!result) { fprintf(stderr, "cannot finish encrypting plaintext\n"); result = SG_ERR_UNKNOWN; goto complete; } *output = signal_buffer_create(out_buf, out_len + final_len); complete: if(ctx) { #if OPENSSL_VERSION_NUMBER >= 0x1010000fL EVP_CIPHER_CTX_free(ctx); #else EVP_CIPHER_CTX_cleanup(ctx); free(ctx); #endif } if(out_buf) { free(out_buf); } return result; } int test_decrypt(signal_buffer **output, int cipher, const uint8_t *key, size_t key_len, const uint8_t *iv, size_t iv_len, const uint8_t *ciphertext, size_t ciphertext_len, void *user_data) { int result = 0; EVP_CIPHER_CTX *ctx = 0; uint8_t *out_buf = 0; const EVP_CIPHER *evp_cipher = aes_cipher(cipher, key_len); if(!evp_cipher) { fprintf(stderr, "invalid AES mode or key size: %zu\n", key_len); return SG_ERR_INVAL; } if(iv_len != 16) { fprintf(stderr, "invalid AES IV size: %zu\n", iv_len); return SG_ERR_INVAL; } if(ciphertext_len > INT_MAX - EVP_CIPHER_block_size(evp_cipher)) { fprintf(stderr, "invalid ciphertext length: %zu\n", ciphertext_len); return SG_ERR_UNKNOWN; } #if OPENSSL_VERSION_NUMBER >= 0x1010000fL ctx = EVP_CIPHER_CTX_new(); if(!ctx) { result = SG_ERR_NOMEM; goto complete; } #else ctx = malloc(sizeof(EVP_CIPHER_CTX)); if(!ctx) { result = SG_ERR_NOMEM; goto complete; } EVP_CIPHER_CTX_init(ctx); #endif result = EVP_DecryptInit_ex(ctx, evp_cipher, 0, key, iv); if(!result) { fprintf(stderr, "cannot initialize cipher\n"); result = SG_ERR_UNKNOWN; goto complete; } if(cipher == SG_CIPHER_AES_CTR_NOPADDING) { result = EVP_CIPHER_CTX_set_padding(ctx, 0); if(!result) { fprintf(stderr, "cannot set padding\n"); result = SG_ERR_UNKNOWN; goto complete; } } out_buf = malloc(sizeof(uint8_t) * (ciphertext_len + EVP_CIPHER_block_size(evp_cipher))); if(!out_buf) { fprintf(stderr, "cannot allocate output buffer\n"); result = SG_ERR_UNKNOWN; goto complete; } int out_len = 0; result = EVP_DecryptUpdate(ctx, out_buf, &out_len, ciphertext, ciphertext_len); if(!result) { fprintf(stderr, "cannot decrypt ciphertext\n"); result = SG_ERR_UNKNOWN; goto complete; } int final_len = 0; result = EVP_DecryptFinal_ex(ctx, out_buf + out_len, &final_len); if(!result) { fprintf(stderr, "cannot finish decrypting ciphertext\n"); result = SG_ERR_UNKNOWN; goto complete; } *output = signal_buffer_create(out_buf, out_len + final_len); complete: if(ctx) { #if OPENSSL_VERSION_NUMBER >= 0x1010000fL EVP_CIPHER_CTX_free(ctx); #else EVP_CIPHER_CTX_cleanup(ctx); free(ctx); #endif } if(out_buf) { free(out_buf); } return result; } libsignal-protocol-c-2.3.3/tests/test_curve25519.c000066400000000000000000000416771363751346500216750ustar00rootroot00000000000000#include #include #include #include #include "../src/signal_protocol.h" #include "../src/signal_protocol_internal.h" #include "curve.h" #include "test_common.h" signal_context *global_context; void test_setup() { int result; result = signal_context_create(&global_context, 0); ck_assert_int_eq(result, 0); signal_context_set_log_function(global_context, test_log); setup_test_crypto_provider(global_context); } void test_teardown() { signal_context_destroy(global_context); } START_TEST(test_internal) { ck_assert_int_eq(curve_internal_fast_tests(1), 0); } END_TEST START_TEST(test_curve25519_agreement) { int result; uint8_t alicePublic[] = { 0x05, 0x1b, 0xb7, 0x59, 0x66, 0xf2, 0xe9, 0x3a, 0x36, 0x91, 0xdf, 0xff, 0x94, 0x2b, 0xb2, 0xa4, 0x66, 0xa1, 0xc0, 0x8b, 0x8d, 0x78, 0xca, 0x3f, 0x4d, 0x6d, 0xf8, 0xb8, 0xbf, 0xa2, 0xe4, 0xee, 0x28}; uint8_t alicePrivate[] = { 0xc8, 0x06, 0x43, 0x9d, 0xc9, 0xd2, 0xc4, 0x76, 0xff, 0xed, 0x8f, 0x25, 0x80, 0xc0, 0x88, 0x8d, 0x58, 0xab, 0x40, 0x6b, 0xf7, 0xae, 0x36, 0x98, 0x87, 0x90, 0x21, 0xb9, 0x6b, 0xb4, 0xbf, 0x59}; uint8_t bobPublic[] = { 0x05, 0x65, 0x36, 0x14, 0x99, 0x3d, 0x2b, 0x15, 0xee, 0x9e, 0x5f, 0xd3, 0xd8, 0x6c, 0xe7, 0x19, 0xef, 0x4e, 0xc1, 0xda, 0xae, 0x18, 0x86, 0xa8, 0x7b, 0x3f, 0x5f, 0xa9, 0x56, 0x5a, 0x27, 0xa2, 0x2f}; uint8_t bobPrivate[] = { 0xb0, 0x3b, 0x34, 0xc3, 0x3a, 0x1c, 0x44, 0xf2, 0x25, 0xb6, 0x62, 0xd2, 0xbf, 0x48, 0x59, 0xb8, 0x13, 0x54, 0x11, 0xfa, 0x7b, 0x03, 0x86, 0xd4, 0x5f, 0xb7, 0x5d, 0xc5, 0xb9, 0x1b, 0x44, 0x66}; uint8_t shared[] = { 0x32, 0x5f, 0x23, 0x93, 0x28, 0x94, 0x1c, 0xed, 0x6e, 0x67, 0x3b, 0x86, 0xba, 0x41, 0x01, 0x74, 0x48, 0xe9, 0x9b, 0x64, 0x9a, 0x9c, 0x38, 0x06, 0xc1, 0xdd, 0x7c, 0xa4, 0xc4, 0x77, 0xe6, 0x29}; ec_public_key *alice_public_key = 0; ec_private_key *alice_private_key = 0; ec_public_key *bob_public_key = 0; ec_private_key *bob_private_key = 0; uint8_t *shared_one = 0; uint8_t *shared_two = 0; /* Initialize Alice's public key */ result = curve_decode_point(&alice_public_key, alicePublic, sizeof(alicePublic), global_context); ck_assert_int_eq(result, 0); ck_assert_ptr_ne(alice_public_key, 0); /* Initialize Alice's private key */ result = curve_decode_private_point(&alice_private_key, alicePrivate, sizeof(alicePrivate), global_context); ck_assert_int_eq(result, 0); ck_assert_ptr_ne(alice_private_key, 0); /* Initialize Bob's public key */ result = curve_decode_point(&bob_public_key, bobPublic, sizeof(bobPublic), global_context); ck_assert_int_eq(result, 0); ck_assert_ptr_ne(bob_public_key, 0); /* Initialize Bob's private key */ result = curve_decode_private_point(&bob_private_key, bobPrivate, sizeof(bobPrivate), global_context); ck_assert_int_eq(result, 0); ck_assert_ptr_ne(bob_private_key, 0); /* Calculate key agreement one */ result = curve_calculate_agreement(&shared_one, alice_public_key, bob_private_key); ck_assert_int_eq(result, 32); ck_assert_ptr_ne(shared_one, 0); /* Calculate key agreement two */ result = curve_calculate_agreement(&shared_two, bob_public_key, alice_private_key); ck_assert_int_eq(result, 32); ck_assert_ptr_ne(shared_two, 0); /* Assert that key agreements are correct */ ck_assert_int_eq(memcmp(shared_one, shared, 32), 0); ck_assert_int_eq(memcmp(shared_two, shared, 32), 0); /* Cleanup */ if(shared_one) { free(shared_one); } if(shared_two) { free(shared_two); } SIGNAL_UNREF(alice_public_key); SIGNAL_UNREF(alice_private_key); SIGNAL_UNREF(bob_public_key); SIGNAL_UNREF(bob_private_key); } END_TEST START_TEST(test_curve25519_generate_public) { int result; uint8_t alicePublic[] = { 0x05, 0x1b, 0xb7, 0x59, 0x66, 0xf2, 0xe9, 0x3a, 0x36, 0x91, 0xdf, 0xff, 0x94, 0x2b, 0xb2, 0xa4, 0x66, 0xa1, 0xc0, 0x8b, 0x8d, 0x78, 0xca, 0x3f, 0x4d, 0x6d, 0xf8, 0xb8, 0xbf, 0xa2, 0xe4, 0xee, 0x28}; uint8_t alicePrivate[] = { 0xc8, 0x06, 0x43, 0x9d, 0xc9, 0xd2, 0xc4, 0x76, 0xff, 0xed, 0x8f, 0x25, 0x80, 0xc0, 0x88, 0x8d, 0x58, 0xab, 0x40, 0x6b, 0xf7, 0xae, 0x36, 0x98, 0x87, 0x90, 0x21, 0xb9, 0x6b, 0xb4, 0xbf, 0x59}; ec_private_key *alice_private_key = 0; ec_public_key *alice_expected_public_key = 0; ec_public_key *alice_public_key = 0; /* Initialize Alice's private key */ result = curve_decode_private_point(&alice_private_key, alicePrivate, sizeof(alicePrivate), global_context); ck_assert_int_eq(result, 0); ck_assert_ptr_ne(alice_private_key, 0); /* Initialize Alice's expected public key */ result = curve_decode_point(&alice_expected_public_key, alicePublic, sizeof(alicePublic), global_context); ck_assert_int_eq(result, 0); ck_assert_ptr_ne(alice_expected_public_key, 0); /* Generate Alice's actual public key */ result = curve_generate_public_key(&alice_public_key, alice_private_key); ck_assert_int_eq(result, 0); ck_assert_ptr_ne(alice_public_key, 0); /* Assert that expected and actual public keys match */ ck_assert_int_eq(ec_public_key_compare(alice_expected_public_key, alice_public_key), 0); /* Cleanup */ SIGNAL_UNREF(alice_public_key); SIGNAL_UNREF(alice_expected_public_key); SIGNAL_UNREF(alice_private_key); } END_TEST START_TEST(test_curve25519_random_agreements) { int result; int i; ec_key_pair *alice_key_pair = 0; ec_public_key *alice_public_key = 0; ec_private_key *alice_private_key = 0; ec_key_pair *bob_key_pair = 0; ec_public_key *bob_public_key = 0; ec_private_key *bob_private_key = 0; uint8_t *shared_alice = 0; uint8_t *shared_bob = 0; signal_context *context; signal_context_create(&context, 0); setup_test_crypto_provider(context); for(i = 0; i < 50; i++) { /* Generate Alice's key pair */ result = curve_generate_key_pair(context, &alice_key_pair); ck_assert_int_eq(result, 0); alice_public_key = ec_key_pair_get_public(alice_key_pair); alice_private_key = ec_key_pair_get_private(alice_key_pair); ck_assert_ptr_ne(alice_public_key, 0); ck_assert_ptr_ne(alice_private_key, 0); /* Generate Bob's key pair */ result = curve_generate_key_pair(context, &bob_key_pair); ck_assert_int_eq(result, 0); bob_public_key = ec_key_pair_get_public(bob_key_pair); bob_private_key = ec_key_pair_get_private(bob_key_pair); ck_assert_ptr_ne(bob_public_key, 0); ck_assert_ptr_ne(bob_private_key, 0); /* Calculate Alice's key agreement */ result = curve_calculate_agreement(&shared_alice, bob_public_key, alice_private_key); ck_assert_int_eq(result, 32); ck_assert_ptr_ne(shared_alice, 0); /* Calculate Bob's key agreement */ result = curve_calculate_agreement(&shared_bob, alice_public_key, bob_private_key); ck_assert_int_eq(result, 32); ck_assert_ptr_ne(shared_bob, 0); /* Assert that key agreements match */ ck_assert_int_eq(memcmp(shared_alice, shared_bob, 32), 0); /* Cleanup */ if(shared_alice) { free(shared_alice); } if(shared_bob) { free(shared_bob); } SIGNAL_UNREF(alice_key_pair); SIGNAL_UNREF(bob_key_pair); alice_key_pair = 0; bob_key_pair = 0; alice_public_key = 0; alice_private_key = 0; bob_public_key = 0; bob_private_key = 0; shared_alice = 0; shared_bob = 0; } signal_context_destroy(context); } END_TEST START_TEST(test_curve25519_signature) { int result; uint8_t aliceIdentityPrivate[] = { 0xc0, 0x97, 0x24, 0x84, 0x12, 0xe5, 0x8b, 0xf0, 0x5d, 0xf4, 0x87, 0x96, 0x82, 0x05, 0x13, 0x27, 0x94, 0x17, 0x8e, 0x36, 0x76, 0x37, 0xf5, 0x81, 0x8f, 0x81, 0xe0, 0xe6, 0xce, 0x73, 0xe8, 0x65}; uint8_t aliceIdentityPublic[] = { 0x05, 0xab, 0x7e, 0x71, 0x7d, 0x4a, 0x16, 0x3b, 0x7d, 0x9a, 0x1d, 0x80, 0x71, 0xdf, 0xe9, 0xdc, 0xf8, 0xcd, 0xcd, 0x1c, 0xea, 0x33, 0x39, 0xb6, 0x35, 0x6b, 0xe8, 0x4d, 0x88, 0x7e, 0x32, 0x2c, 0x64}; uint8_t aliceEphemeralPublic[] = { 0x05, 0xed, 0xce, 0x9d, 0x9c, 0x41, 0x5c, 0xa7, 0x8c, 0xb7, 0x25, 0x2e, 0x72, 0xc2, 0xc4, 0xa5, 0x54, 0xd3, 0xeb, 0x29, 0x48, 0x5a, 0x0e, 0x1d, 0x50, 0x31, 0x18, 0xd1, 0xa8, 0x2d, 0x99, 0xfb, 0x4a}; uint8_t aliceSignature[] = { 0x5d, 0xe8, 0x8c, 0xa9, 0xa8, 0x9b, 0x4a, 0x11, 0x5d, 0xa7, 0x91, 0x09, 0xc6, 0x7c, 0x9c, 0x74, 0x64, 0xa3, 0xe4, 0x18, 0x02, 0x74, 0xf1, 0xcb, 0x8c, 0x63, 0xc2, 0x98, 0x4e, 0x28, 0x6d, 0xfb, 0xed, 0xe8, 0x2d, 0xeb, 0x9d, 0xcd, 0x9f, 0xae, 0x0b, 0xfb, 0xb8, 0x21, 0x56, 0x9b, 0x3d, 0x90, 0x01, 0xbd, 0x81, 0x30, 0xcd, 0x11, 0xd4, 0x86, 0xce, 0xf0, 0x47, 0xbd, 0x60, 0xb8, 0x6e, 0x88}; ec_private_key *alice_private_key = 0; ec_public_key *alice_public_key = 0; ec_public_key *alice_ephemeral = 0; /* Initialize Alice's private key */ result = curve_decode_private_point(&alice_private_key, aliceIdentityPrivate, sizeof(aliceIdentityPrivate), global_context); ck_assert_int_eq(result, 0); ck_assert_ptr_ne(alice_private_key, 0); /* Initialize Alice's public key */ result = curve_decode_point(&alice_public_key, aliceIdentityPublic, sizeof(aliceIdentityPublic), global_context); ck_assert_int_eq(result, 0); ck_assert_ptr_ne(alice_public_key, 0); /* Initialize Alice's ephemeral key */ result = curve_decode_point(&alice_ephemeral, aliceEphemeralPublic, sizeof(aliceEphemeralPublic), global_context); ck_assert_int_eq(result, 0); ck_assert_ptr_ne(alice_ephemeral, 0); result = curve_verify_signature(alice_public_key, aliceEphemeralPublic, sizeof(aliceEphemeralPublic), aliceSignature, sizeof(aliceSignature)); ck_assert_msg(result == 1, "signature verification failed"); uint8_t modifiedSignature[sizeof(aliceSignature)]; int i; for(i = 0; i < sizeof(aliceSignature); i++) { memcpy(modifiedSignature, aliceSignature, sizeof(aliceSignature)); modifiedSignature[i] ^= 0x01; result = curve_verify_signature(alice_public_key, aliceEphemeralPublic, sizeof(aliceEphemeralPublic), modifiedSignature, sizeof(modifiedSignature)); ck_assert_msg(result != 1, "signature verification succeeded"); } /* Cleanup */ SIGNAL_UNREF(alice_private_key); SIGNAL_UNREF(alice_public_key); SIGNAL_UNREF(alice_ephemeral); } END_TEST START_TEST(test_curve25519_large_signatures) { int result; ec_key_pair *keys = 0; result = curve_generate_key_pair(global_context, &keys); ck_assert_int_eq(result, 0); uint8_t message[1048576]; memset(message, 0, sizeof(message)); signal_buffer *signature = 0; result = curve_calculate_signature(global_context, &signature, ec_key_pair_get_private(keys), message, sizeof(message)); ck_assert_int_eq(result, 0); uint8_t *data = signal_buffer_data(signature); size_t len = signal_buffer_len(signature); result = curve_verify_signature(ec_key_pair_get_public(keys), message, sizeof(message), data, len); ck_assert_int_eq(result, 1); data[0] ^= 0x01; result = curve_verify_signature(ec_key_pair_get_public(keys), message, sizeof(message), data, len); ck_assert_int_eq(result, 0); /* Cleanup */ SIGNAL_UNREF(keys); if(signature) { signal_buffer_free(signature); } } END_TEST START_TEST(test_unique_signatures) { int result; size_t i; size_t r; ec_key_pair *key_pair = 0; uint8_t *message = 0; signal_buffer *signature = 0; signal_buffer *vrf_output = 0; result = curve_generate_key_pair(global_context, &key_pair); ck_assert_int_eq(result, 0); message = malloc(256); ck_assert_ptr_ne(message, 0); for(i = 1; i <= 256; i++) { result = signal_crypto_random(global_context, message, i); ck_assert_int_eq(result, 0); result = curve_calculate_vrf_signature(global_context, &signature, ec_key_pair_get_private(key_pair), message, i); ck_assert_int_eq(result, 0); result = curve_verify_vrf_signature(global_context, &vrf_output, ec_key_pair_get_public(key_pair), message, i, signal_buffer_data(signature), signal_buffer_len(signature)); ck_assert_int_eq(result, 0); result = curve_verify_signature( ec_key_pair_get_public(key_pair), message, i, signal_buffer_data(signature), signal_buffer_len(signature)); ck_assert_int_ne(result, 0); signal_buffer_free(vrf_output); result = signal_crypto_random(global_context, (uint8_t *)&r, sizeof(size_t)); ck_assert_int_eq(result, 0); message[r % i] ^= 0x01; result = curve_verify_vrf_signature(global_context, &vrf_output, ec_key_pair_get_public(key_pair), message, i, signal_buffer_data(signature), signal_buffer_len(signature)); ck_assert_int_eq(result, SG_ERR_VRF_SIG_VERIF_FAILED); signal_buffer_free(signature); } /* Cleanup */ SIGNAL_UNREF(key_pair); if(message) { free(message); } } END_TEST START_TEST(test_unique_signature_vector) { uint8_t publicKey[] = { 0x05, 0x21, 0xf7, 0x34, 0x5f, 0x56, 0xd9, 0x60, 0x2f, 0x15, 0x23, 0x29, 0x8f, 0x4f, 0x6f, 0xce, 0xcb, 0x14, 0xdd, 0xe2, 0xd5, 0xb9, 0xa9, 0xb4, 0x8b, 0xca, 0x82, 0x42, 0x68, 0x14, 0x92, 0xb9, 0x20}; uint8_t privateKey[] = { 0x38, 0x61, 0x1d, 0x25, 0x3b, 0xea, 0x85, 0xa2, 0x03, 0x80, 0x53, 0x43, 0xb7, 0x4a, 0x93, 0x6d, 0x3b, 0x13, 0xb9, 0xe3, 0x12, 0x14, 0x53, 0xe9, 0x74, 0x0b, 0x6b, 0x82, 0x7e, 0x33, 0x7e, 0x5d}; uint8_t message[] = { 0x54, 0x68, 0x69, 0x73, 0x20, 0x69, 0x73, 0x20, 0x75, 0x6e, 0x69, 0x71, 0x75, 0x65, 0x2e}; uint8_t vrf[] = { 0x45, 0xDC, 0x7B, 0x81, 0x6B, 0x01, 0xB3, 0x6C, 0xFA, 0x16, 0x45, 0xDC, 0xAE, 0x8A, 0xC9, 0xBC, 0x8E, 0x52, 0x3C, 0xD8, 0x6D, 0x00, 0x7D, 0x19, 0x95, 0x3F, 0x03, 0xE7, 0xD5, 0x45, 0x54, 0xA0 }; int result; ec_public_key *public_key = 0; ec_private_key *private_key = 0; signal_buffer *signature = 0; signal_buffer *vrf_output = 0; result = curve_decode_point(&public_key, publicKey, sizeof(publicKey), global_context); ck_assert_int_eq(result, 0); result = curve_decode_private_point(&private_key, privateKey, sizeof(privateKey), global_context); ck_assert_int_eq(result, 0); result = curve_calculate_vrf_signature(global_context, &signature, private_key, message, sizeof(message)); ck_assert_int_eq(result, 0); result = curve_verify_vrf_signature(global_context, &vrf_output, public_key, message, sizeof(message), signal_buffer_data(signature), signal_buffer_len(signature)); ck_assert_int_eq(result, 0); ck_assert_int_eq(signal_buffer_len(vrf_output), sizeof(vrf)); ck_assert_int_eq(memcmp(signal_buffer_data(vrf_output), vrf, sizeof(vrf)), 0); /* Cleanup */ signal_buffer_free(signature); signal_buffer_free(vrf_output); SIGNAL_UNREF(public_key); SIGNAL_UNREF(private_key); } END_TEST Suite *curve25519_suite(void) { Suite *suite = suite_create("curve25519"); TCase *tcase = tcase_create("case"); tcase_add_checked_fixture(tcase, test_setup, test_teardown); tcase_add_test(tcase, test_internal); tcase_add_test(tcase, test_curve25519_agreement); tcase_add_test(tcase, test_curve25519_generate_public); tcase_add_test(tcase, test_curve25519_random_agreements); tcase_add_test(tcase, test_curve25519_signature); tcase_add_test(tcase, test_curve25519_large_signatures); tcase_add_test(tcase, test_unique_signatures); tcase_add_test(tcase, test_unique_signature_vector); suite_add_tcase(suite, tcase); return suite; } int main(void) { int number_failed; Suite *suite; SRunner *runner; suite = curve25519_suite(); runner = srunner_create(suite); srunner_run_all(runner, CK_VERBOSE); number_failed = srunner_ntests_failed(runner); srunner_free(runner); return (number_failed == 0) ? EXIT_SUCCESS : EXIT_FAILURE; } libsignal-protocol-c-2.3.3/tests/test_device_consistency.c000066400000000000000000000231501363751346500240050ustar00rootroot00000000000000#include #include "../src/signal_protocol.h" #include "device_consistency.h" #include "curve.h" #include "test_common.h" signal_context *global_context; static char *generate_code(device_consistency_commitment *commitment, device_consistency_message *msg1, device_consistency_message *msg2, device_consistency_message *msg3); void test_setup() { int result; result = signal_context_create(&global_context, 0); ck_assert_int_eq(result, 0); signal_context_set_log_function(global_context, test_log); setup_test_crypto_provider(global_context); } void test_teardown() { signal_context_destroy(global_context); } START_TEST(test_device_consistency) { int result = 0; int i; /* Create three device key pairs */ ec_key_pair *device_one = 0; result = curve_generate_key_pair(global_context, &device_one); ck_assert_int_eq(result, 0); ec_key_pair *device_two = 0; result = curve_generate_key_pair(global_context, &device_two); ck_assert_int_eq(result, 0); ec_key_pair *device_three = 0; result = curve_generate_key_pair(global_context, &device_three); ck_assert_int_eq(result, 0); ec_public_key *key_array[] = { ec_key_pair_get_public(device_one), ec_key_pair_get_public(device_two), ec_key_pair_get_public(device_three) }; /* Create device one commitment */ ec_public_key_list *key_list = ec_public_key_list_alloc(); ck_assert_ptr_ne(key_list, 0); shuffle_ec_public_keys(key_array, 3); for(i = 0; i < 3; i++) { ec_public_key_list_push_back(key_list, key_array[i]); } device_consistency_commitment *device_one_commitment = 0; result = device_consistency_commitment_create(&device_one_commitment, 1, key_list, global_context); ck_assert_int_eq(result, 0); ec_public_key_list_free(key_list); /* Create device two commitment */ key_list = ec_public_key_list_alloc(); ck_assert_ptr_ne(key_list, 0); shuffle_ec_public_keys(key_array, 3); for(i = 0; i < 3; i++) { ec_public_key_list_push_back(key_list, key_array[i]); } device_consistency_commitment *device_two_commitment = 0; result = device_consistency_commitment_create(&device_two_commitment, 1, key_list, global_context); ck_assert_int_eq(result, 0); ec_public_key_list_free(key_list); /* Create device three commitment */ key_list = ec_public_key_list_alloc(); ck_assert_ptr_ne(key_list, 0); shuffle_ec_public_keys(key_array, 3); for(i = 0; i < 3; i++) { ec_public_key_list_push_back(key_list, key_array[i]); } device_consistency_commitment *device_three_commitment = 0; result = device_consistency_commitment_create(&device_three_commitment, 1, key_list, global_context); ck_assert_int_eq(result, 0); ec_public_key_list_free(key_list); /* Check that all three commitments are equal */ ck_assert_int_eq(signal_buffer_compare( device_consistency_commitment_get_serialized(device_one_commitment), device_consistency_commitment_get_serialized(device_two_commitment)), 0); ck_assert_int_eq(signal_buffer_compare( device_consistency_commitment_get_serialized(device_two_commitment), device_consistency_commitment_get_serialized(device_three_commitment)), 0); /* Create device consistency messages */ device_consistency_message *device_one_message = 0; result = device_consistency_message_create_from_pair(&device_one_message, device_one_commitment, device_one, global_context); ck_assert_int_eq(result, 0); device_consistency_message *device_two_message = 0; result = device_consistency_message_create_from_pair(&device_two_message, device_one_commitment, device_two, global_context); ck_assert_int_eq(result, 0); device_consistency_message *device_three_message = 0; result = device_consistency_message_create_from_pair(&device_three_message, device_one_commitment, device_three, global_context); ck_assert_int_eq(result, 0); /* Create received device consistency messages */ signal_buffer *device_one_message_serialized = device_consistency_message_get_serialized(device_one_message); device_consistency_message *received_device_one_message = 0; result = device_consistency_message_create_from_serialized(&received_device_one_message, device_one_commitment, signal_buffer_data(device_one_message_serialized), signal_buffer_len(device_one_message_serialized), ec_key_pair_get_public(device_one), global_context); ck_assert_int_eq(result, 0); signal_buffer *device_two_message_serialized = device_consistency_message_get_serialized(device_two_message); device_consistency_message *received_device_two_message = 0; result = device_consistency_message_create_from_serialized(&received_device_two_message, device_one_commitment, signal_buffer_data(device_two_message_serialized), signal_buffer_len(device_two_message_serialized), ec_key_pair_get_public(device_two), global_context); ck_assert_int_eq(result, 0); signal_buffer *device_three_message_serialized = device_consistency_message_get_serialized(device_three_message); device_consistency_message *received_device_three_message = 0; result = device_consistency_message_create_from_serialized(&received_device_three_message, device_one_commitment, signal_buffer_data(device_three_message_serialized), signal_buffer_len(device_three_message_serialized), ec_key_pair_get_public(device_three), global_context); ck_assert_int_eq(result, 0); /* Check that all sent-and-received pairs have the same VRF output */ ck_assert_int_eq(signal_buffer_compare( device_consistency_signature_get_vrf_output( device_consistency_message_get_signature(device_one_message)), device_consistency_signature_get_vrf_output( device_consistency_message_get_signature(received_device_one_message))), 0); ck_assert_int_eq(signal_buffer_compare( device_consistency_signature_get_vrf_output( device_consistency_message_get_signature(device_two_message)), device_consistency_signature_get_vrf_output( device_consistency_message_get_signature(received_device_two_message))), 0); ck_assert_int_eq(signal_buffer_compare( device_consistency_signature_get_vrf_output( device_consistency_message_get_signature(device_three_message)), device_consistency_signature_get_vrf_output( device_consistency_message_get_signature(received_device_three_message))), 0); /* Generate consistency codes */ char *code_one = generate_code(device_one_commitment, device_one_message, received_device_two_message, received_device_three_message); char *code_two = generate_code(device_two_commitment, device_two_message, received_device_three_message, received_device_one_message); char *code_three = generate_code(device_three_commitment, device_three_message, received_device_two_message, received_device_one_message); /* Check that all the consistency codes match */ ck_assert_str_eq(code_one, code_two); ck_assert_str_eq(code_two, code_three); /* Cleanup */ SIGNAL_UNREF(device_one); SIGNAL_UNREF(device_two); SIGNAL_UNREF(device_three); SIGNAL_UNREF(device_one_commitment); SIGNAL_UNREF(device_two_commitment); SIGNAL_UNREF(device_three_commitment); SIGNAL_UNREF(device_one_message); SIGNAL_UNREF(device_two_message); SIGNAL_UNREF(device_three_message); SIGNAL_UNREF(received_device_one_message); SIGNAL_UNREF(received_device_two_message); SIGNAL_UNREF(received_device_three_message); free(code_one); free(code_two); free(code_three); } END_TEST char *generate_code(device_consistency_commitment *commitment, device_consistency_message *msg1, device_consistency_message *msg2, device_consistency_message *msg3) { int result = 0; char *code_string = 0; /* Build the list of signatures */ device_consistency_signature_list *signatures = device_consistency_signature_list_alloc(); ck_assert_ptr_ne(signatures, 0); device_consistency_signature_list_push_back(signatures, device_consistency_message_get_signature(msg1)); device_consistency_signature_list_push_back(signatures, device_consistency_message_get_signature(msg2)); device_consistency_signature_list_push_back(signatures, device_consistency_message_get_signature(msg3)); result = device_consistency_code_generate_for(commitment, signatures, &code_string, global_context); ck_assert_int_eq(result, 0); ck_assert_ptr_ne(code_string, 0); device_consistency_signature_list_free(signatures); return code_string; } Suite *device_consistency_suite(void) { Suite *suite = suite_create("device_consistency"); TCase *tcase = tcase_create("case"); tcase_add_checked_fixture(tcase, test_setup, test_teardown); tcase_add_test(tcase, test_device_consistency); suite_add_tcase(suite, tcase); return suite; } int main(void) { int number_failed; Suite *suite; SRunner *runner; suite = device_consistency_suite(); runner = srunner_create(suite); srunner_run_all(runner, CK_VERBOSE); number_failed = srunner_ntests_failed(runner); srunner_free(runner); return (number_failed == 0) ? EXIT_SUCCESS : EXIT_FAILURE; } libsignal-protocol-c-2.3.3/tests/test_fingerprint.c000066400000000000000000000545121363751346500224620ustar00rootroot00000000000000#include #include "../src/signal_protocol.h" #include "curve.h" #include "fingerprint.h" #include "test_common.h" signal_context *global_context; static uint8_t ALICE_IDENTITY[] = { 0x05, 0x06, 0x86, 0x3b, 0xc6, 0x6d, 0x02, 0xb4, 0x0d, 0x27, 0xb8, 0xd4, 0x9c, 0xa7, 0xc0, 0x9e, 0x92, 0x39, 0x23, 0x6f, 0x9d, 0x7d, 0x25, 0xd6, 0xfc, 0xca, 0x5c, 0xe1, 0x3c, 0x70, 0x64, 0xd8, 0x68}; static uint8_t BOB_IDENTITY[] = { 0x05, 0xf7, 0x81, 0xb6, 0xfb, 0x32, 0xfe, 0xd9, 0xba, 0x1c, 0xf2, 0xde, 0x97, 0x8d, 0x4d, 0x5d, 0xa2, 0x8d, 0xc3, 0x40, 0x46, 0xae, 0x81, 0x44, 0x02, 0xb5, 0xc0, 0xdb, 0xd9, 0x6f, 0xda, 0x90, 0x7b}; static const char *DISPLAYABLE_FINGERPRINT = "300354477692869396892869876765458257569162576843440918079131"; static uint8_t ALICE_SCANNABLE_FINGERPRINT_V0[] = { 0x08, 0x00, 0x12, 0x31, 0x0a, 0x21, 0x05, 0x06, 0x86, 0x3b, 0xc6, 0x6d, 0x02, 0xb4, 0x0d, 0x27, 0xb8, 0xd4, 0x9c, 0xa7, 0xc0, 0x9e, 0x92, 0x39, 0x23, 0x6f, 0x9d, 0x7d, 0x25, 0xd6, 0xfc, 0xca, 0x5c, 0xe1, 0x3c, 0x70, 0x64, 0xd8, 0x68, 0x12, 0x0c, 0x2b, 0x31, 0x34, 0x31, 0x35, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x1a, 0x31, 0x0a, 0x21, 0x05, 0xf7, 0x81, 0xb6, 0xfb, 0x32, 0xfe, 0xd9, 0xba, 0x1c, 0xf2, 0xde, 0x97, 0x8d, 0x4d, 0x5d, 0xa2, 0x8d, 0xc3, 0x40, 0x46, 0xae, 0x81, 0x44, 0x02, 0xb5, 0xc0, 0xdb, 0xd9, 0x6f, 0xda, 0x90, 0x7b, 0x12, 0x0c, 0x2b, 0x31, 0x34, 0x31, 0x35, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33}; static uint8_t BOB_SCANNABLE_FINGERPRINT_V0[] = { 0x08, 0x00, 0x12, 0x31, 0x0a, 0x21, 0x05, 0xf7, 0x81, 0xb6, 0xfb, 0x32, 0xfe, 0xd9, 0xba, 0x1c, 0xf2, 0xde, 0x97, 0x8d, 0x4d, 0x5d, 0xa2, 0x8d, 0xc3, 0x40, 0x46, 0xae, 0x81, 0x44, 0x02, 0xb5, 0xc0, 0xdb, 0xd9, 0x6f, 0xda, 0x90, 0x7b, 0x12, 0x0c, 0x2b, 0x31, 0x34, 0x31, 0x35, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x1a, 0x31, 0x0a, 0x21, 0x05, 0x06, 0x86, 0x3b, 0xc6, 0x6d, 0x02, 0xb4, 0x0d, 0x27, 0xb8, 0xd4, 0x9c, 0xa7, 0xc0, 0x9e, 0x92, 0x39, 0x23, 0x6f, 0x9d, 0x7d, 0x25, 0xd6, 0xfc, 0xca, 0x5c, 0xe1, 0x3c, 0x70, 0x64, 0xd8, 0x68, 0x12, 0x0c, 0x2b, 0x31, 0x34, 0x31, 0x35, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32}; static uint8_t ALICE_SCANNABLE_FINGERPRINT_V1[] = { 0x08, 0x01, 0x12, 0x22, 0x0a, 0x20, 0x1e, 0x30, 0x1a, 0x03, 0x53, 0xdc, 0xe3, 0xdb, 0xe7, 0x68, 0x4c, 0xb8, 0x33, 0x6e, 0x85, 0x13, 0x6c, 0xdc, 0x0e, 0xe9, 0x62, 0x19, 0x49, 0x4a, 0xda, 0x30, 0x5d, 0x62, 0xa7, 0xbd, 0x61, 0xdf, 0x1a, 0x22, 0x0a, 0x20, 0xd6, 0x2c, 0xbf, 0x73, 0xa1, 0x15, 0x92, 0x01, 0x5b, 0x6b, 0x9f, 0x16, 0x82, 0xac, 0x30, 0x6f, 0xea, 0x3a, 0xaf, 0x38, 0x85, 0xb8, 0x4d, 0x12, 0xbc, 0xa6, 0x31, 0xe9, 0xd4, 0xfb, 0x3a, 0x4d}; static uint8_t BOB_SCANNABLE_FINGERPRINT_V1[] = { 0x08, 0x01, 0x12, 0x22, 0x0a, 0x20, 0xd6, 0x2c, 0xbf, 0x73, 0xa1, 0x15, 0x92, 0x01, 0x5b, 0x6b, 0x9f, 0x16, 0x82, 0xac, 0x30, 0x6f, 0xea, 0x3a, 0xaf, 0x38, 0x85, 0xb8, 0x4d, 0x12, 0xbc, 0xa6, 0x31, 0xe9, 0xd4, 0xfb, 0x3a, 0x4d, 0x1a, 0x22, 0x0a, 0x20, 0x1e, 0x30, 0x1a, 0x03, 0x53, 0xdc, 0xe3, 0xdb, 0xe7, 0x68, 0x4c, 0xb8, 0x33, 0x6e, 0x85, 0x13, 0x6c, 0xdc, 0x0e, 0xe9, 0x62, 0x19, 0x49, 0x4a, 0xda, 0x30, 0x5d, 0x62, 0xa7, 0xbd, 0x61, 0xdf}; void test_setup() { int result; result = signal_context_create(&global_context, 0); ck_assert_int_eq(result, 0); signal_context_set_log_function(global_context, test_log); setup_test_crypto_provider(global_context); } void test_teardown() { signal_context_destroy(global_context); } static void test_scannable_fingerprint_serialize_impl(int version) { int result = 0; ec_public_key *alice_identity_key = create_test_ec_public_key(global_context); ec_public_key *bob_identity_key = create_test_ec_public_key(global_context); signal_buffer *alice_identity_buffer = 0; signal_buffer *bob_identity_buffer = 0; scannable_fingerprint *alice_scannable = 0; scannable_fingerprint *bob_scannable = 0; signal_buffer *buffer = 0; scannable_fingerprint *bob_deserialized = 0; result = ec_public_key_serialize(&alice_identity_buffer, alice_identity_key); ck_assert_int_eq(result, 0); result = ec_public_key_serialize(&bob_identity_buffer, bob_identity_key); ck_assert_int_eq(result, 0); result = scannable_fingerprint_create(&alice_scannable, version, "+14152222222", alice_identity_buffer, "+14153333333", bob_identity_buffer); ck_assert_int_eq(result, 0); result = scannable_fingerprint_create(&bob_scannable, version, "+14153333333", bob_identity_buffer, "+14152222222", alice_identity_buffer); ck_assert_int_eq(result, 0); ck_assert_int_eq(scannable_fingerprint_compare(alice_scannable, bob_scannable), 1); result = scannable_fingerprint_serialize(&buffer, bob_scannable); ck_assert_int_eq(result, 0); result = scannable_fingerprint_deserialize(&bob_deserialized, signal_buffer_data(buffer), signal_buffer_len(buffer), global_context); ck_assert_int_eq(result, 0); ck_assert_int_eq(scannable_fingerprint_compare(alice_scannable, bob_deserialized), 1); /* Cleanup */ SIGNAL_UNREF(alice_identity_key); SIGNAL_UNREF(bob_identity_key); SIGNAL_UNREF(alice_scannable); SIGNAL_UNREF(bob_scannable); SIGNAL_UNREF(bob_deserialized); signal_buffer_free(alice_identity_buffer); signal_buffer_free(bob_identity_buffer); signal_buffer_free(buffer); } START_TEST(test_scannable_fingerprint_serialize_v0) { test_scannable_fingerprint_serialize_impl(0); } END_TEST START_TEST(test_scannable_fingerprint_serialize_v1) { test_scannable_fingerprint_serialize_impl(1); } END_TEST static void test_vectors_impl(int version) { int result = 0; ec_public_key *alice_identity_key = 0; ec_public_key *bob_identity_key = 0; fingerprint_generator *generator = 0; fingerprint *alice_fingerprint = 0; fingerprint *bob_fingerprint = 0; signal_buffer *alice_buffer = 0; signal_buffer *bob_buffer = 0; result = curve_decode_point(&alice_identity_key, ALICE_IDENTITY, sizeof(ALICE_IDENTITY), global_context); ck_assert_int_eq(result, 0); result = curve_decode_point(&bob_identity_key, BOB_IDENTITY, sizeof(BOB_IDENTITY), global_context); ck_assert_int_eq(result, 0); result = fingerprint_generator_create(&generator, 5200, version, global_context); ck_assert_int_eq(result, 0); result = fingerprint_generator_create_for(generator, "+14152222222", alice_identity_key, "+14153333333", bob_identity_key, &alice_fingerprint); ck_assert_int_eq(result, 0); result = fingerprint_generator_create_for(generator, "+14153333333", bob_identity_key, "+14152222222", alice_identity_key, &bob_fingerprint); ck_assert_int_eq(result, 0); displayable_fingerprint *alice_displayable = fingerprint_get_displayable(alice_fingerprint); ck_assert_str_eq( displayable_fingerprint_text(alice_displayable), DISPLAYABLE_FINGERPRINT); displayable_fingerprint *bob_displayable = fingerprint_get_displayable(bob_fingerprint); ck_assert_str_eq( displayable_fingerprint_text(bob_displayable), DISPLAYABLE_FINGERPRINT); scannable_fingerprint *alice_scannable = fingerprint_get_scannable(alice_fingerprint); scannable_fingerprint_serialize(&alice_buffer, alice_scannable); ck_assert_int_eq(result, 0); scannable_fingerprint *bob_scannable = fingerprint_get_scannable(bob_fingerprint); scannable_fingerprint_serialize(&bob_buffer, bob_scannable); ck_assert_int_eq(result, 0); if(version == 0) { ck_assert_int_eq(signal_buffer_len(alice_buffer), sizeof(ALICE_SCANNABLE_FINGERPRINT_V0)); ck_assert_int_eq(memcmp(signal_buffer_data(alice_buffer), ALICE_SCANNABLE_FINGERPRINT_V0, sizeof(ALICE_SCANNABLE_FINGERPRINT_V0)), 0); ck_assert_int_eq(signal_buffer_len(bob_buffer), sizeof(BOB_SCANNABLE_FINGERPRINT_V0)); ck_assert_int_eq(memcmp(signal_buffer_data(bob_buffer), BOB_SCANNABLE_FINGERPRINT_V0, sizeof(BOB_SCANNABLE_FINGERPRINT_V0)), 0); } else if(version == 1) { ck_assert_int_eq(signal_buffer_len(alice_buffer), sizeof(ALICE_SCANNABLE_FINGERPRINT_V1)); ck_assert_int_eq(memcmp(signal_buffer_data(alice_buffer), ALICE_SCANNABLE_FINGERPRINT_V1, sizeof(ALICE_SCANNABLE_FINGERPRINT_V1)), 0); ck_assert_int_eq(signal_buffer_len(bob_buffer), sizeof(BOB_SCANNABLE_FINGERPRINT_V1)); ck_assert_int_eq(memcmp(signal_buffer_data(bob_buffer), BOB_SCANNABLE_FINGERPRINT_V1, sizeof(BOB_SCANNABLE_FINGERPRINT_V1)), 0); } /* Cleanup */ signal_buffer_free(alice_buffer); signal_buffer_free(bob_buffer); fingerprint_generator_free(generator); SIGNAL_UNREF(alice_identity_key); SIGNAL_UNREF(bob_identity_key); SIGNAL_UNREF(alice_fingerprint); SIGNAL_UNREF(bob_fingerprint); } START_TEST(test_vectors_v0) { test_vectors_impl(0); } END_TEST START_TEST(test_vectors_v1) { test_vectors_impl(1); } END_TEST static void test_matching_fingerprints_impl(int version) { int result = 0; ec_public_key *alice_identity_key = create_test_ec_public_key(global_context); ec_public_key *bob_identity_key = create_test_ec_public_key(global_context); fingerprint_generator *generator = 0; fingerprint *alice_fingerprint = 0; fingerprint *bob_fingerprint = 0; result = fingerprint_generator_create(&generator, 1024, version, global_context); ck_assert_int_eq(result, 0); result = fingerprint_generator_create_for(generator, "+14152222222", alice_identity_key, "+14153333333", bob_identity_key, &alice_fingerprint); ck_assert_int_eq(result, 0); result = fingerprint_generator_create_for(generator, "+14153333333", bob_identity_key, "+14152222222", alice_identity_key, &bob_fingerprint); ck_assert_int_eq(result, 0); displayable_fingerprint *alice_displayable = fingerprint_get_displayable(alice_fingerprint); displayable_fingerprint *bob_displayable = fingerprint_get_displayable(bob_fingerprint); ck_assert_str_eq( displayable_fingerprint_text(alice_displayable), displayable_fingerprint_text(bob_displayable)); scannable_fingerprint *alice_scannable = fingerprint_get_scannable(alice_fingerprint); scannable_fingerprint *bob_scannable = fingerprint_get_scannable(bob_fingerprint); ck_assert_int_eq(scannable_fingerprint_compare(alice_scannable, bob_scannable), 1); ck_assert_int_eq(scannable_fingerprint_compare(bob_scannable, alice_scannable), 1); ck_assert_int_eq(strlen(displayable_fingerprint_text(alice_displayable)), 60); /* Cleanup */ fingerprint_generator_free(generator); SIGNAL_UNREF(alice_identity_key); SIGNAL_UNREF(bob_identity_key); SIGNAL_UNREF(alice_fingerprint); SIGNAL_UNREF(bob_fingerprint); } START_TEST(test_matching_fingerprints_v0) { test_matching_fingerprints_impl(0); } END_TEST START_TEST(test_matching_fingerprints_v1) { test_matching_fingerprints_impl(1); } END_TEST START_TEST(test_matching_list_fingerprints) { int result = 0; ec_public_key *alice_identity_key1 = create_test_ec_public_key(global_context); ec_public_key *alice_identity_key2 = create_test_ec_public_key(global_context); ec_public_key *alice_identity_key3 = create_test_ec_public_key(global_context); ec_public_key *alice_identity_key4 = create_test_ec_public_key(global_context); ec_public_key *bob_identity_key1 = create_test_ec_public_key(global_context); ec_public_key *bob_identity_key2 = create_test_ec_public_key(global_context); ec_public_key *bob_identity_key3 = create_test_ec_public_key(global_context); ec_public_key *bob_identity_key4 = create_test_ec_public_key(global_context); fingerprint_generator *generator = 0; fingerprint *alice_fingerprint = 0; fingerprint *bob_fingerprint = 0; ec_public_key_list *alice_key_list = ec_public_key_list_alloc(); ck_assert_ptr_ne(alice_key_list, 0); result = ec_public_key_list_push_back(alice_key_list, alice_identity_key1); ck_assert_int_eq(result, 0); result = ec_public_key_list_push_back(alice_key_list, alice_identity_key2); ck_assert_int_eq(result, 0); result = ec_public_key_list_push_back(alice_key_list, alice_identity_key3); ck_assert_int_eq(result, 0); result = ec_public_key_list_push_back(alice_key_list, alice_identity_key4); ck_assert_int_eq(result, 0); ec_public_key_list *bob_key_list = ec_public_key_list_alloc(); ck_assert_ptr_ne(bob_key_list, 0); result = ec_public_key_list_push_back(bob_key_list, bob_identity_key1); ck_assert_int_eq(result, 0); result = ec_public_key_list_push_back(bob_key_list, bob_identity_key2); ck_assert_int_eq(result, 0); result = ec_public_key_list_push_back(bob_key_list, bob_identity_key3); ck_assert_int_eq(result, 0); result = ec_public_key_list_push_back(bob_key_list, bob_identity_key4); ck_assert_int_eq(result, 0); result = fingerprint_generator_create(&generator, 1024, 1, global_context); ck_assert_int_eq(result, 0); result = fingerprint_generator_create_for_list(generator, "+14152222222", alice_key_list, "+14153333333", bob_key_list, &alice_fingerprint); ck_assert_int_eq(result, 0); result = fingerprint_generator_create_for_list(generator, "+14153333333", bob_key_list, "+14152222222", alice_key_list, &bob_fingerprint); ck_assert_int_eq(result, 0); displayable_fingerprint *alice_displayable = fingerprint_get_displayable(alice_fingerprint); displayable_fingerprint *bob_displayable = fingerprint_get_displayable(bob_fingerprint); ck_assert_str_eq( displayable_fingerprint_text(alice_displayable), displayable_fingerprint_text(bob_displayable)); scannable_fingerprint *alice_scannable = fingerprint_get_scannable(alice_fingerprint); scannable_fingerprint *bob_scannable = fingerprint_get_scannable(bob_fingerprint); ck_assert_int_eq(scannable_fingerprint_compare(alice_scannable, bob_scannable), 1); ck_assert_int_eq(scannable_fingerprint_compare(bob_scannable, alice_scannable), 1); ck_assert_int_eq(strlen(displayable_fingerprint_text(alice_displayable)), 60); /* Cleanup */ fingerprint_generator_free(generator); SIGNAL_UNREF(alice_identity_key1); SIGNAL_UNREF(alice_identity_key2); SIGNAL_UNREF(alice_identity_key3); SIGNAL_UNREF(alice_identity_key4); SIGNAL_UNREF(bob_identity_key1); SIGNAL_UNREF(bob_identity_key2); SIGNAL_UNREF(bob_identity_key3); SIGNAL_UNREF(bob_identity_key4); ec_public_key_list_free(alice_key_list); ec_public_key_list_free(bob_key_list); SIGNAL_UNREF(alice_fingerprint); SIGNAL_UNREF(bob_fingerprint); } END_TEST static void test_mismatching_fingerprints_impl(int version) { int result = 0; ec_public_key *alice_identity_key = create_test_ec_public_key(global_context); ec_public_key *bob_identity_key = create_test_ec_public_key(global_context); ec_public_key *mitm_identity_key = create_test_ec_public_key(global_context); fingerprint_generator *generator = 0; fingerprint *alice_fingerprint = 0; fingerprint *bob_fingerprint = 0; result = fingerprint_generator_create(&generator, 1024, version, global_context); ck_assert_int_eq(result, 0); result = fingerprint_generator_create_for(generator, "+14152222222", alice_identity_key, "+14153333333", mitm_identity_key, &alice_fingerprint); ck_assert_int_eq(result, 0); result = fingerprint_generator_create_for(generator, "+14153333333", bob_identity_key, "+14152222222", alice_identity_key, &bob_fingerprint); ck_assert_int_eq(result, 0); displayable_fingerprint *alice_displayable = fingerprint_get_displayable(alice_fingerprint); displayable_fingerprint *bob_displayable = fingerprint_get_displayable(bob_fingerprint); ck_assert_str_ne( displayable_fingerprint_text(alice_displayable), displayable_fingerprint_text(bob_displayable)); scannable_fingerprint *alice_scannable = fingerprint_get_scannable(alice_fingerprint); scannable_fingerprint *bob_scannable = fingerprint_get_scannable(bob_fingerprint); ck_assert_int_ne(scannable_fingerprint_compare(alice_scannable, bob_scannable), 1); ck_assert_int_ne(scannable_fingerprint_compare(bob_scannable, alice_scannable), 1); /* Cleanup */ fingerprint_generator_free(generator); SIGNAL_UNREF(alice_identity_key); SIGNAL_UNREF(bob_identity_key); SIGNAL_UNREF(mitm_identity_key); SIGNAL_UNREF(alice_fingerprint); SIGNAL_UNREF(bob_fingerprint); } START_TEST(test_mismatching_fingerprints_v0) { test_mismatching_fingerprints_impl(0); } END_TEST START_TEST(test_mismatching_fingerprints_v1) { test_mismatching_fingerprints_impl(1); } END_TEST START_TEST(test_mismatching_identifiers) { int result = 0; ec_public_key *alice_identity_key = create_test_ec_public_key(global_context); ec_public_key *bob_identity_key = create_test_ec_public_key(global_context); fingerprint_generator *generator = 0; fingerprint *alice_fingerprint = 0; fingerprint *bob_fingerprint = 0; result = fingerprint_generator_create(&generator, 1024, 0, global_context); ck_assert_int_eq(result, 0); result = fingerprint_generator_create_for(generator, "+14152222222", alice_identity_key, "+1415333333", bob_identity_key, &alice_fingerprint); ck_assert_int_eq(result, 0); result = fingerprint_generator_create_for(generator, "+14153333333", bob_identity_key, "+14152222222", alice_identity_key, &bob_fingerprint); ck_assert_int_eq(result, 0); displayable_fingerprint *alice_displayable = fingerprint_get_displayable(alice_fingerprint); displayable_fingerprint *bob_displayable = fingerprint_get_displayable(bob_fingerprint); ck_assert_str_ne( displayable_fingerprint_text(alice_displayable), displayable_fingerprint_text(bob_displayable)); scannable_fingerprint *alice_scannable = fingerprint_get_scannable(alice_fingerprint); scannable_fingerprint *bob_scannable = fingerprint_get_scannable(bob_fingerprint); ck_assert_int_eq(scannable_fingerprint_compare(alice_scannable, bob_scannable), SG_ERR_FP_IDENT_MISMATCH); ck_assert_int_eq(scannable_fingerprint_compare(bob_scannable, alice_scannable), SG_ERR_FP_IDENT_MISMATCH); /* Cleanup */ fingerprint_generator_free(generator); SIGNAL_UNREF(alice_identity_key); SIGNAL_UNREF(bob_identity_key); SIGNAL_UNREF(alice_fingerprint); SIGNAL_UNREF(bob_fingerprint); } END_TEST START_TEST(test_mismatching_versions) { int result = 0; ec_public_key *alice_identity_key = create_test_ec_public_key(global_context); ec_public_key *bob_identity_key = create_test_ec_public_key(global_context); ec_public_key *mitm_identity_key = create_test_ec_public_key(global_context); fingerprint_generator *generator_v0 = 0; fingerprint_generator *generator_v1 = 0; fingerprint *alice_fingerprint = 0; fingerprint *bob_fingerprint = 0; result = fingerprint_generator_create(&generator_v0, 1024, 0, global_context); ck_assert_int_eq(result, 0); result = fingerprint_generator_create_for(generator_v0, "+14152222222", alice_identity_key, "+14153333333", mitm_identity_key, &alice_fingerprint); ck_assert_int_eq(result, 0); result = fingerprint_generator_create(&generator_v1, 1024, 1, global_context); ck_assert_int_eq(result, 0); result = fingerprint_generator_create_for(generator_v1, "+14153333333", bob_identity_key, "+14152222222", alice_identity_key, &bob_fingerprint); ck_assert_int_eq(result, 0); displayable_fingerprint *alice_displayable = fingerprint_get_displayable(alice_fingerprint); displayable_fingerprint *bob_displayable = fingerprint_get_displayable(bob_fingerprint); ck_assert_str_ne( displayable_fingerprint_text(alice_displayable), displayable_fingerprint_text(bob_displayable)); scannable_fingerprint *alice_scannable = fingerprint_get_scannable(alice_fingerprint); scannable_fingerprint *bob_scannable = fingerprint_get_scannable(bob_fingerprint); ck_assert_int_eq(scannable_fingerprint_compare(alice_scannable, bob_scannable), SG_ERR_FP_VERSION_MISMATCH); ck_assert_int_eq(scannable_fingerprint_compare(bob_scannable, alice_scannable), SG_ERR_FP_VERSION_MISMATCH); /* Cleanup */ fingerprint_generator_free(generator_v0); fingerprint_generator_free(generator_v1); SIGNAL_UNREF(alice_identity_key); SIGNAL_UNREF(bob_identity_key); SIGNAL_UNREF(mitm_identity_key); SIGNAL_UNREF(alice_fingerprint); SIGNAL_UNREF(bob_fingerprint); } END_TEST Suite *fingerprint_suite(void) { Suite *suite = suite_create("fingerprint"); TCase *tcase = tcase_create("case"); tcase_add_checked_fixture(tcase, test_setup, test_teardown); tcase_add_test(tcase, test_scannable_fingerprint_serialize_v0); tcase_add_test(tcase, test_scannable_fingerprint_serialize_v1); tcase_add_test(tcase, test_vectors_v0); tcase_add_test(tcase, test_vectors_v1); tcase_add_test(tcase, test_matching_fingerprints_v0); tcase_add_test(tcase, test_matching_fingerprints_v1); tcase_add_test(tcase, test_matching_list_fingerprints); tcase_add_test(tcase, test_mismatching_fingerprints_v0); tcase_add_test(tcase, test_mismatching_fingerprints_v1); tcase_add_test(tcase, test_mismatching_identifiers); tcase_add_test(tcase, test_mismatching_versions); suite_add_tcase(suite, tcase); return suite; } int main(void) { int number_failed; Suite *suite; SRunner *runner; suite = fingerprint_suite(); runner = srunner_create(suite); srunner_run_all(runner, CK_VERBOSE); number_failed = srunner_ntests_failed(runner); srunner_free(runner); return (number_failed == 0) ? EXIT_SUCCESS : EXIT_FAILURE; } libsignal-protocol-c-2.3.3/tests/test_group_cipher.c000066400000000000000000001016701363751346500226170ustar00rootroot00000000000000#include #include #include #include #include "../src/signal_protocol.h" #include "protocol.h" #include "group_cipher.h" #include "group_session_builder.h" #include "test_common.h" #include "test_utarray.h" signal_context *global_context; pthread_mutex_t global_mutex; pthread_mutexattr_t global_mutex_attr; static signal_protocol_sender_key_name GROUP_SENDER = { "nihilist history reading group", 30, {"+14150001111", 12, 1} }; void test_lock(void *user_data) { pthread_mutex_lock(&global_mutex); } void test_unlock(void *user_data) { pthread_mutex_unlock(&global_mutex); } void test_setup() { int result; pthread_mutexattr_init(&global_mutex_attr); pthread_mutexattr_settype(&global_mutex_attr, PTHREAD_MUTEX_RECURSIVE); pthread_mutex_init(&global_mutex, &global_mutex_attr); result = signal_context_create(&global_context, 0); ck_assert_int_eq(result, 0); signal_context_set_log_function(global_context, test_log); setup_test_crypto_provider(global_context); result = signal_context_set_locking_functions(global_context, test_lock, test_unlock); ck_assert_int_eq(result, 0); } void test_teardown() { signal_context_destroy(global_context); } START_TEST(test_no_session) { int result = 0; /* Create the test data stores */ signal_protocol_store_context *alice_store = 0; setup_test_store_context(&alice_store, global_context); signal_protocol_store_context *bob_store = 0; setup_test_store_context(&bob_store, global_context); /* Create the session builder */ group_session_builder *alice_session_builder = 0; result = group_session_builder_create(&alice_session_builder, alice_store, global_context); ck_assert_int_eq(result, 0); /* Create the group ciphers */ group_cipher *alice_group_cipher = 0; result = group_cipher_create(&alice_group_cipher, alice_store, &GROUP_SENDER, global_context); group_cipher *bob_group_cipher = 0; result = group_cipher_create(&bob_group_cipher, bob_store, &GROUP_SENDER, global_context); /* Create the sender key distribution messages */ sender_key_distribution_message *sent_alice_distribution_message = 0; result = group_session_builder_create_session(alice_session_builder, &sent_alice_distribution_message, &GROUP_SENDER); ck_assert_int_eq(result, 0); sender_key_distribution_message *received_alice_distribution_message = 0; signal_buffer *serialized_distribution_message = ciphertext_message_get_serialized((ciphertext_message *)sent_alice_distribution_message); result = sender_key_distribution_message_deserialize(&received_alice_distribution_message, signal_buffer_data(serialized_distribution_message), signal_buffer_len(serialized_distribution_message), global_context); ck_assert_int_eq(result, 0); /* Intentionally omitting Bob's processing of received_alice_distribution_message */ /* Encrypt a test message from Alice */ static const char alice_plaintext[] = "smert ze smert"; size_t alice_plaintext_len = sizeof(alice_plaintext) - 1; ciphertext_message *ciphertext_from_alice = 0; result = group_cipher_encrypt(alice_group_cipher, (const uint8_t *)alice_plaintext, alice_plaintext_len, &ciphertext_from_alice); ck_assert_int_eq(result, 0); /* Attempt to have Bob decrypt the message */ signal_buffer *plaintext_from_alice = 0; result = group_cipher_decrypt(bob_group_cipher, (sender_key_message *)ciphertext_from_alice, 0, &plaintext_from_alice); ck_assert_int_eq(result, SG_ERR_NO_SESSION);; /* Cleanup */ signal_buffer_free(plaintext_from_alice); SIGNAL_UNREF(ciphertext_from_alice); SIGNAL_UNREF(received_alice_distribution_message); SIGNAL_UNREF(sent_alice_distribution_message); group_cipher_free(bob_group_cipher); group_cipher_free(alice_group_cipher); group_session_builder_free(alice_session_builder); signal_protocol_store_context_destroy(bob_store); signal_protocol_store_context_destroy(alice_store); } END_TEST START_TEST(test_basic_encrypt_decrypt) { int result = 0; /* Create the test data stores */ signal_protocol_store_context *alice_store = 0; setup_test_store_context(&alice_store, global_context); signal_protocol_store_context *bob_store = 0; setup_test_store_context(&bob_store, global_context); /* Create the session builders */ group_session_builder *alice_session_builder = 0; result = group_session_builder_create(&alice_session_builder, alice_store, global_context); ck_assert_int_eq(result, 0); group_session_builder *bob_session_builder = 0; result = group_session_builder_create(&bob_session_builder, bob_store, global_context); ck_assert_int_eq(result, 0); /* Create the group ciphers */ group_cipher *alice_group_cipher = 0; result = group_cipher_create(&alice_group_cipher, alice_store, &GROUP_SENDER, global_context); group_cipher *bob_group_cipher = 0; result = group_cipher_create(&bob_group_cipher, bob_store, &GROUP_SENDER, global_context); /* Create the sender key distribution messages */ sender_key_distribution_message *sent_alice_distribution_message = 0; result = group_session_builder_create_session(alice_session_builder, &sent_alice_distribution_message, &GROUP_SENDER); ck_assert_int_eq(result, 0); sender_key_distribution_message *received_alice_distribution_message = 0; signal_buffer *serialized_distribution_message = ciphertext_message_get_serialized((ciphertext_message *)sent_alice_distribution_message); result = sender_key_distribution_message_deserialize(&received_alice_distribution_message, signal_buffer_data(serialized_distribution_message), signal_buffer_len(serialized_distribution_message), global_context); ck_assert_int_eq(result, 0); /* Processing Alice's distribution message */ result = group_session_builder_process_session(bob_session_builder, &GROUP_SENDER, received_alice_distribution_message); ck_assert_int_eq(result, 0); /* Encrypt a test message from Alice */ static const char alice_plaintext[] = "smert ze smert"; size_t alice_plaintext_len = sizeof(alice_plaintext) - 1; ciphertext_message *ciphertext_from_alice = 0; result = group_cipher_encrypt(alice_group_cipher, (const uint8_t *)alice_plaintext, alice_plaintext_len, &ciphertext_from_alice); ck_assert_int_eq(result, 0); /* Have Bob decrypt the message */ signal_buffer *plaintext_from_alice = 0; result = group_cipher_decrypt(bob_group_cipher, (sender_key_message *)ciphertext_from_alice, 0, &plaintext_from_alice); ck_assert_int_eq(result, 0); uint8_t *plaintext_data = signal_buffer_data(plaintext_from_alice); size_t plaintext_len = signal_buffer_len(plaintext_from_alice); ck_assert_int_eq(alice_plaintext_len, plaintext_len); ck_assert_int_eq(memcmp(alice_plaintext, plaintext_data, plaintext_len), 0); /* Cleanup */ signal_buffer_free(plaintext_from_alice); SIGNAL_UNREF(ciphertext_from_alice); SIGNAL_UNREF(received_alice_distribution_message); SIGNAL_UNREF(sent_alice_distribution_message); group_cipher_free(bob_group_cipher); group_cipher_free(alice_group_cipher); group_session_builder_free(bob_session_builder); group_session_builder_free(alice_session_builder); signal_protocol_store_context_destroy(bob_store); signal_protocol_store_context_destroy(alice_store); } END_TEST START_TEST(test_basic_ratchet) { int result = 0; /* Create the test data stores */ signal_protocol_store_context *alice_store = 0; setup_test_store_context(&alice_store, global_context); signal_protocol_store_context *bob_store = 0; setup_test_store_context(&bob_store, global_context); /* Create the session builders */ group_session_builder *alice_session_builder = 0; result = group_session_builder_create(&alice_session_builder, alice_store, global_context); ck_assert_int_eq(result, 0); group_session_builder *bob_session_builder = 0; result = group_session_builder_create(&bob_session_builder, bob_store, global_context); ck_assert_int_eq(result, 0); signal_protocol_sender_key_name *alice_name = &GROUP_SENDER; /* Create the group ciphers */ group_cipher *alice_group_cipher = 0; result = group_cipher_create(&alice_group_cipher, alice_store, alice_name, global_context); group_cipher *bob_group_cipher = 0; result = group_cipher_create(&bob_group_cipher, bob_store, alice_name, global_context); /* Create the sender key distribution messages */ sender_key_distribution_message *sent_alice_distribution_message = 0; result = group_session_builder_create_session(alice_session_builder, &sent_alice_distribution_message, alice_name); ck_assert_int_eq(result, 0); sender_key_distribution_message *received_alice_distribution_message = 0; signal_buffer *serialized_distribution_message = ciphertext_message_get_serialized((ciphertext_message *)sent_alice_distribution_message); result = sender_key_distribution_message_deserialize(&received_alice_distribution_message, signal_buffer_data(serialized_distribution_message), signal_buffer_len(serialized_distribution_message), global_context); ck_assert_int_eq(result, 0); /* Processing Alice's distribution message */ result = group_session_builder_process_session(bob_session_builder, alice_name, received_alice_distribution_message); ck_assert_int_eq(result, 0); /* Prepare some text to encrypt */ static const char alice_plaintext[] = "smert ze smert"; size_t alice_plaintext_len = sizeof(alice_plaintext) - 1; static const char alice_plaintext_2[] = "smert ze smert2"; size_t alice_plaintext_2_len = sizeof(alice_plaintext_2) - 1; static const char alice_plaintext_3[] = "smert ze smert3"; size_t alice_plaintext_3_len = sizeof(alice_plaintext_3) - 1; /* Encrypt a series of messages from Alice */ ciphertext_message *ciphertext_from_alice = 0; result = group_cipher_encrypt(alice_group_cipher, (const uint8_t *)alice_plaintext, alice_plaintext_len, &ciphertext_from_alice); ck_assert_int_eq(result, 0); ciphertext_message *ciphertext_from_alice_2 = 0; result = group_cipher_encrypt(alice_group_cipher, (const uint8_t *)alice_plaintext_2, alice_plaintext_2_len, &ciphertext_from_alice_2); ck_assert_int_eq(result, 0); ciphertext_message *ciphertext_from_alice_3 = 0; result = group_cipher_encrypt(alice_group_cipher, (const uint8_t *)alice_plaintext_3, alice_plaintext_3_len, &ciphertext_from_alice_3); ck_assert_int_eq(result, 0); /* Have Bob decrypt the message */ signal_buffer *plaintext_from_alice = 0; result = group_cipher_decrypt(bob_group_cipher, (sender_key_message *)ciphertext_from_alice, 0, &plaintext_from_alice); ck_assert_int_eq(result, 0); /* Have Bob attempt to decrypt the same message again */ signal_buffer *plaintext_from_alice_repeat = 0; result = group_cipher_decrypt(bob_group_cipher, (sender_key_message *)ciphertext_from_alice, 0, &plaintext_from_alice_repeat); ck_assert_int_eq(result, SG_ERR_DUPLICATE_MESSAGE); /* Should have ratcheted forward */ ck_assert_ptr_eq(plaintext_from_alice_repeat, 0); /* Have Bob decrypt the remaining messages */ signal_buffer *plaintext_from_alice_2 = 0; result = group_cipher_decrypt(bob_group_cipher, (sender_key_message *)ciphertext_from_alice_2, 0, &plaintext_from_alice_2); ck_assert_int_eq(result, 0); signal_buffer *plaintext_from_alice_3 = 0; result = group_cipher_decrypt(bob_group_cipher, (sender_key_message *)ciphertext_from_alice_3, 0, &plaintext_from_alice_3); ck_assert_int_eq(result, 0); /* Verify that the plaintext matches */ uint8_t *plaintext_data = signal_buffer_data(plaintext_from_alice); size_t plaintext_len = signal_buffer_len(plaintext_from_alice); ck_assert_int_eq(alice_plaintext_len, plaintext_len); ck_assert_int_eq(memcmp(alice_plaintext, plaintext_data, plaintext_len), 0); plaintext_data = signal_buffer_data(plaintext_from_alice_2); plaintext_len = signal_buffer_len(plaintext_from_alice_2); ck_assert_int_eq(alice_plaintext_2_len, plaintext_len); ck_assert_int_eq(memcmp(alice_plaintext_2, plaintext_data, plaintext_len), 0); plaintext_data = signal_buffer_data(plaintext_from_alice_3); plaintext_len = signal_buffer_len(plaintext_from_alice_3); ck_assert_int_eq(alice_plaintext_3_len, plaintext_len); ck_assert_int_eq(memcmp(alice_plaintext_3, plaintext_data, plaintext_len), 0); /* Cleanup */ signal_buffer_free(plaintext_from_alice_3); signal_buffer_free(plaintext_from_alice_2); signal_buffer_free(plaintext_from_alice); SIGNAL_UNREF(ciphertext_from_alice_3); SIGNAL_UNREF(ciphertext_from_alice_2); SIGNAL_UNREF(ciphertext_from_alice); SIGNAL_UNREF(received_alice_distribution_message); SIGNAL_UNREF(sent_alice_distribution_message); group_cipher_free(bob_group_cipher); group_cipher_free(alice_group_cipher); group_session_builder_free(bob_session_builder); group_session_builder_free(alice_session_builder); signal_protocol_store_context_destroy(bob_store); signal_protocol_store_context_destroy(alice_store); } END_TEST START_TEST(test_late_join) { int result = 0; /* Create the test data stores */ signal_protocol_store_context *alice_store = 0; setup_test_store_context(&alice_store, global_context); signal_protocol_store_context *bob_store = 0; setup_test_store_context(&bob_store, global_context); /* Create Alice's session builder */ group_session_builder *alice_session_builder = 0; result = group_session_builder_create(&alice_session_builder, alice_store, global_context); ck_assert_int_eq(result, 0); signal_protocol_sender_key_name *alice_name = &GROUP_SENDER; /* Create Alice's group cipher */ group_cipher *alice_group_cipher = 0; result = group_cipher_create(&alice_group_cipher, alice_store, alice_name, global_context); /* Create Alice's sender key distribution message */ sender_key_distribution_message *alice_distribution_message = 0; result = group_session_builder_create_session(alice_session_builder, &alice_distribution_message, alice_name); ck_assert_int_eq(result, 0); /* Pretend this was sent to some people other than Bob */ /* Encrypt a batch of messages that Bob never receives */ int i = 0; for(i = 0; i < 100; i++) { static const char alice_plaintext[] = "up the punks up the punks up the punks"; size_t alice_plaintext_len = sizeof(alice_plaintext) - 1; ciphertext_message *ciphertext_from_alice = 0; result = group_cipher_encrypt(alice_group_cipher, (const uint8_t *)alice_plaintext, alice_plaintext_len, &ciphertext_from_alice); ck_assert_int_eq(result, 0); SIGNAL_UNREF(ciphertext_from_alice); } /* Now Bob Joins */ group_session_builder *bob_session_builder = 0; result = group_session_builder_create(&bob_session_builder, bob_store, global_context); ck_assert_int_eq(result, 0); group_cipher *bob_group_cipher = 0; result = group_cipher_create(&bob_group_cipher, bob_store, alice_name, global_context); /* Create Alice's sender key distribution message for Bob */ sender_key_distribution_message *distribution_message_to_bob = 0; result = group_session_builder_create_session(alice_session_builder, &distribution_message_to_bob, alice_name); ck_assert_int_eq(result, 0); sender_key_distribution_message *received_distribution_message_to_bob = 0; signal_buffer *serialized_distribution_message = ciphertext_message_get_serialized((ciphertext_message *)distribution_message_to_bob); result = sender_key_distribution_message_deserialize(&received_distribution_message_to_bob, signal_buffer_data(serialized_distribution_message), signal_buffer_len(serialized_distribution_message), global_context); ck_assert_int_eq(result, 0); /* Have Bob process Alice's distribution message */ result = group_session_builder_process_session(bob_session_builder, alice_name, received_distribution_message_to_bob); ck_assert_int_eq(result, 0); /* Alice sends a message welcoming Bob */ static const char welcome_plaintext[] = "welcome to the group"; size_t welcome_plaintext_len = sizeof(welcome_plaintext) - 1; ciphertext_message *ciphertext = 0; result = group_cipher_encrypt(alice_group_cipher, (const uint8_t *)welcome_plaintext, welcome_plaintext_len, &ciphertext); ck_assert_int_eq(result, 0); /* Bob decrypts the message */ signal_buffer *plaintext_from_alice = 0; result = group_cipher_decrypt(bob_group_cipher, (sender_key_message*)ciphertext, 0, &plaintext_from_alice); ck_assert_int_eq(result, 0); /* Verify that the plaintext matches */ uint8_t *plaintext_data = signal_buffer_data(plaintext_from_alice); size_t plaintext_len = signal_buffer_len(plaintext_from_alice); ck_assert_int_eq(welcome_plaintext_len, plaintext_len); ck_assert_int_eq(memcmp(welcome_plaintext, plaintext_data, plaintext_len), 0); /* Cleanup */ signal_buffer_free(plaintext_from_alice); SIGNAL_UNREF(ciphertext); SIGNAL_UNREF(received_distribution_message_to_bob); SIGNAL_UNREF(distribution_message_to_bob); group_cipher_free(bob_group_cipher); group_session_builder_free(bob_session_builder); SIGNAL_UNREF(alice_distribution_message); group_cipher_free(alice_group_cipher); group_session_builder_free(alice_session_builder); signal_protocol_store_context_destroy(bob_store); signal_protocol_store_context_destroy(alice_store); } END_TEST START_TEST(test_out_of_order) { int result = 0; /* Create the test data stores */ signal_protocol_store_context *alice_store = 0; setup_test_store_context(&alice_store, global_context); signal_protocol_store_context *bob_store = 0; setup_test_store_context(&bob_store, global_context); /* Create the session builders */ group_session_builder *alice_session_builder = 0; result = group_session_builder_create(&alice_session_builder, alice_store, global_context); ck_assert_int_eq(result, 0); group_session_builder *bob_session_builder = 0; result = group_session_builder_create(&bob_session_builder, bob_store, global_context); ck_assert_int_eq(result, 0); signal_protocol_sender_key_name *alice_name = &GROUP_SENDER; /* Create the group ciphers */ group_cipher *alice_group_cipher = 0; result = group_cipher_create(&alice_group_cipher, alice_store, alice_name, global_context); group_cipher *bob_group_cipher = 0; result = group_cipher_create(&bob_group_cipher, bob_store, alice_name, global_context); /* Create Alice's sender key distribution message */ sender_key_distribution_message *alice_distribution_message = 0; result = group_session_builder_create_session( alice_session_builder, &alice_distribution_message, alice_name); ck_assert_int_eq(result, 0); /* Have Bob process the distribution message */ result = group_session_builder_process_session(bob_session_builder, alice_name, alice_distribution_message); ck_assert_int_eq(result, 0); /* Populate a batch of 100 messages */ UT_array *ciphertexts; utarray_new(ciphertexts, &ut_ptr_icd); utarray_reserve(ciphertexts, 100); static const char plaintext[] = "up the punks"; size_t plaintext_len = sizeof(plaintext) - 1; int i = 0; for(i = 0; i < 100; i++) { ciphertext_message *ciphertext = 0; result = group_cipher_encrypt(alice_group_cipher, (const uint8_t *)plaintext, plaintext_len, &ciphertext); ck_assert_int_eq(result, 0); signal_buffer *serialized = ciphertext_message_get_serialized(ciphertext); signal_buffer *serialized_copy = signal_buffer_copy(serialized); utarray_push_back(ciphertexts, &serialized_copy); SIGNAL_UNREF(ciphertext); } /* Try decrypting those messages in random order */ while(utarray_len(ciphertexts) > 0) { /* Get the next element */ int index = rand() % utarray_len(ciphertexts); signal_buffer *element = *((signal_buffer **)utarray_eltptr(ciphertexts, index)); utarray_erase(ciphertexts, index, 1); /* Deserialize the message */ sender_key_message *ciphertext = 0; result = sender_key_message_deserialize(&ciphertext, signal_buffer_data(element), signal_buffer_len(element), global_context); ck_assert_int_eq(result, 0); /* Decrypt the message */ signal_buffer *plaintext_buffer = 0; result = group_cipher_decrypt(bob_group_cipher, ciphertext, 0, &plaintext_buffer); ck_assert_int_eq(result, 0); /* Verify that the plaintext matches */ uint8_t *decrypted_plaintext_data = signal_buffer_data(plaintext_buffer); size_t decrypted_plaintext_len = signal_buffer_len(plaintext_buffer); ck_assert_int_eq(plaintext_len, decrypted_plaintext_len); ck_assert_int_eq(memcmp(plaintext, decrypted_plaintext_data, decrypted_plaintext_len), 0); signal_buffer_free(element); signal_buffer_free(plaintext_buffer); SIGNAL_UNREF(ciphertext); } /* Cleanup */ utarray_free(ciphertexts); SIGNAL_UNREF(alice_distribution_message); group_cipher_free(bob_group_cipher); group_cipher_free(alice_group_cipher); group_session_builder_free(bob_session_builder); group_session_builder_free(alice_session_builder); signal_protocol_store_context_destroy(bob_store); signal_protocol_store_context_destroy(alice_store); } END_TEST START_TEST(test_encrypt_no_session) { int result = 0; static const signal_protocol_sender_key_name alice_sender_name = { "coolio groupio", 14, {"+10002223333", 12, 1} }; /* Create the test data store for Alice */ signal_protocol_store_context *alice_store = 0; setup_test_store_context(&alice_store, global_context); /* Create Alice's group cipher */ group_cipher *alice_group_cipher = 0; result = group_cipher_create(&alice_group_cipher, alice_store, &alice_sender_name, global_context); ck_assert_int_eq(result, 0); /* Try to encrypt without a session */ static const char plaintext[] = "up the punks"; size_t plaintext_len = sizeof(plaintext) - 1; ciphertext_message *ciphertext = 0; result = group_cipher_encrypt(alice_group_cipher, (const uint8_t *)plaintext, plaintext_len, &ciphertext); ck_assert_int_eq(result, SG_ERR_NO_SESSION); ck_assert_ptr_eq(ciphertext, 0); /* Cleanup */ group_cipher_free(alice_group_cipher); signal_protocol_store_context_destroy(alice_store); } END_TEST START_TEST(test_too_far_in_future) { int result = 0; /* Create the test data stores */ signal_protocol_store_context *alice_store = 0; setup_test_store_context(&alice_store, global_context); signal_protocol_store_context *bob_store = 0; setup_test_store_context(&bob_store, global_context); /* Create the session builders */ group_session_builder *alice_session_builder = 0; result = group_session_builder_create(&alice_session_builder, alice_store, global_context); ck_assert_int_eq(result, 0); group_session_builder *bob_session_builder = 0; result = group_session_builder_create(&bob_session_builder, bob_store, global_context); ck_assert_int_eq(result, 0); signal_protocol_sender_key_name *alice_name = &GROUP_SENDER; /* Create the group ciphers */ group_cipher *alice_group_cipher = 0; result = group_cipher_create(&alice_group_cipher, alice_store, alice_name, global_context); group_cipher *bob_group_cipher = 0; result = group_cipher_create(&bob_group_cipher, bob_store, alice_name, global_context); /* Create Alice's sender key distribution message */ sender_key_distribution_message *alice_distribution_message = 0; result = group_session_builder_create_session( alice_session_builder, &alice_distribution_message, alice_name); ck_assert_int_eq(result, 0); /* Have Bob process the distribution message */ result = group_session_builder_process_session(bob_session_builder, alice_name, alice_distribution_message); ck_assert_int_eq(result, 0); /* Have Alice encrypt a batch of 2001 messages */ static const char plaintext[] = "up the punks"; size_t plaintext_len = sizeof(plaintext) - 1; int i = 0; for(i = 0; i < 2001; i++) { ciphertext_message *ciphertext = 0; result = group_cipher_encrypt(alice_group_cipher, (const uint8_t *)plaintext, plaintext_len, &ciphertext); ck_assert_int_eq(result, 0); SIGNAL_UNREF(ciphertext); } /* Have Alice encrypt a message too far in the future */ static const char too_far_plaintext[] = "notta gonna worka"; size_t too_far_plaintext_len = sizeof(too_far_plaintext) - 1; ciphertext_message *too_far_ciphertext = 0; result = group_cipher_encrypt(alice_group_cipher, (const uint8_t *)too_far_plaintext, too_far_plaintext_len, &too_far_ciphertext); ck_assert_int_eq(result, 0); /* Have Bob try, and fail, to decrypt the message */ signal_buffer *plaintext_from_alice = 0; result = group_cipher_decrypt(bob_group_cipher, (sender_key_message*)too_far_ciphertext, 0, &plaintext_from_alice); ck_assert_int_eq(result, SG_ERR_INVALID_MESSAGE); /* Cleanup */ SIGNAL_UNREF(too_far_ciphertext); SIGNAL_UNREF(alice_distribution_message); group_cipher_free(bob_group_cipher); group_cipher_free(alice_group_cipher); group_session_builder_free(bob_session_builder); group_session_builder_free(alice_session_builder); signal_protocol_store_context_destroy(bob_store); signal_protocol_store_context_destroy(alice_store); } END_TEST START_TEST(test_message_key_limit) { int result = 0; int i; /* Create the test data stores */ signal_protocol_store_context *alice_store = 0; setup_test_store_context(&alice_store, global_context); signal_protocol_store_context *bob_store = 0; setup_test_store_context(&bob_store, global_context); /* Create the session builders */ group_session_builder *alice_session_builder = 0; result = group_session_builder_create(&alice_session_builder, alice_store, global_context); ck_assert_int_eq(result, 0); group_session_builder *bob_session_builder = 0; result = group_session_builder_create(&bob_session_builder, bob_store, global_context); ck_assert_int_eq(result, 0); signal_protocol_sender_key_name *alice_name = &GROUP_SENDER; /* Create the group ciphers */ group_cipher *alice_group_cipher = 0; result = group_cipher_create(&alice_group_cipher, alice_store, alice_name, global_context); group_cipher *bob_group_cipher = 0; result = group_cipher_create(&bob_group_cipher, bob_store, alice_name, global_context); /* Create the sender key distribution messages */ sender_key_distribution_message *alice_distribution_message = 0; result = group_session_builder_create_session(alice_session_builder, &alice_distribution_message, alice_name); ck_assert_int_eq(result, 0); /* Processing Alice's distribution message */ result = group_session_builder_process_session(bob_session_builder, alice_name, alice_distribution_message); ck_assert_int_eq(result, 0); ciphertext_message *inflight[2010]; memset(inflight, 0, sizeof(inflight)); for(i = 0; i <2010; i++) { static const char plaintext[] = "up the punks"; size_t plaintext_len = sizeof(plaintext) - 1; ciphertext_message *message = 0; result = group_cipher_encrypt(alice_group_cipher, (uint8_t *)plaintext, plaintext_len, &message); ck_assert_int_eq(result, 0); inflight[i] = message; } signal_buffer *buffer = 0; /* Try decrypting in-flight message 1000 */ result = group_cipher_decrypt(bob_group_cipher, (sender_key_message *)inflight[1000], 0, &buffer); ck_assert_int_eq(result, 0); ck_assert_ptr_ne(buffer, 0); signal_buffer_free(buffer); buffer = 0; /* Try decrypting in-flight message 2009 */ result = group_cipher_decrypt(bob_group_cipher, (sender_key_message *)inflight[2009], 0, &buffer); ck_assert_int_eq(result, 0); ck_assert_ptr_ne(buffer, 0); signal_buffer_free(buffer); buffer = 0; /* Try decrypting in-flight message 0, which should fail */ result = group_cipher_decrypt(bob_group_cipher, (sender_key_message *)inflight[0], 0, &buffer); ck_assert_int_eq(result, SG_ERR_DUPLICATE_MESSAGE); signal_buffer_free(buffer); buffer = 0; /* Cleanup */ for(i = 0; i < 2010; i++) { if(inflight[i]) { SIGNAL_UNREF(inflight[i]); } } SIGNAL_UNREF(alice_distribution_message); group_cipher_free(bob_group_cipher); group_cipher_free(alice_group_cipher); group_session_builder_free(bob_session_builder); group_session_builder_free(alice_session_builder); signal_protocol_store_context_destroy(bob_store); signal_protocol_store_context_destroy(alice_store); } END_TEST START_TEST(test_invalid_signature_key) { int result = 0; /* Create the test data stores */ signal_protocol_store_context *alice_store = 0; setup_test_store_context(&alice_store, global_context); signal_protocol_store_context *bob_store = 0; setup_test_store_context(&bob_store, global_context); /* Create the session builders */ group_session_builder *alice_session_builder = 0; result = group_session_builder_create(&alice_session_builder, alice_store, global_context); ck_assert_int_eq(result, 0); group_session_builder *bob_session_builder = 0; result = group_session_builder_create(&bob_session_builder, bob_store, global_context); ck_assert_int_eq(result, 0); /* Create the group cipher for Bob */ group_cipher *bob_group_cipher = 0; result = group_cipher_create(&bob_group_cipher, bob_store, &GROUP_SENDER, global_context); /* Create a sender key distribution message from Alice to Bob */ sender_key_distribution_message *sent_alice_distribution_message = 0; result = group_session_builder_create_session(alice_session_builder, &sent_alice_distribution_message, &GROUP_SENDER); ck_assert_int_eq(result, 0); sender_key_distribution_message *received_alice_distribution_message = 0; signal_buffer *serialized_distribution_message = ciphertext_message_get_serialized((ciphertext_message *)sent_alice_distribution_message); result = sender_key_distribution_message_deserialize(&received_alice_distribution_message, signal_buffer_data(serialized_distribution_message), signal_buffer_len(serialized_distribution_message), global_context); ck_assert_int_eq(result, 0); /* Processing Alice's distribution message */ result = group_session_builder_process_session(bob_session_builder, &GROUP_SENDER, received_alice_distribution_message); ck_assert_int_eq(result, 0); /* Encrypt a test message from Bob */ static const char bob_plaintext[] = "smert ze smert"; size_t bob_plaintext_len = sizeof(bob_plaintext) - 1; ciphertext_message *ciphertext_from_bob = 0; result = group_cipher_encrypt(bob_group_cipher, (const uint8_t *)bob_plaintext, bob_plaintext_len, &ciphertext_from_bob); ck_assert_int_eq(result, SG_ERR_INVALID_KEY); /* Cleanup */ SIGNAL_UNREF(ciphertext_from_bob); SIGNAL_UNREF(received_alice_distribution_message); SIGNAL_UNREF(sent_alice_distribution_message); group_cipher_free(bob_group_cipher); group_session_builder_free(bob_session_builder); group_session_builder_free(alice_session_builder); signal_protocol_store_context_destroy(bob_store); signal_protocol_store_context_destroy(alice_store); } END_TEST Suite *group_cipher_suite(void) { Suite *suite = suite_create("group_cipher"); TCase *tcase = tcase_create("case"); tcase_add_checked_fixture(tcase, test_setup, test_teardown); tcase_add_test(tcase, test_no_session); tcase_add_test(tcase, test_basic_encrypt_decrypt); tcase_add_test(tcase, test_basic_ratchet); tcase_add_test(tcase, test_late_join); tcase_add_test(tcase, test_out_of_order); tcase_add_test(tcase, test_encrypt_no_session); tcase_add_test(tcase, test_too_far_in_future); tcase_add_test(tcase, test_message_key_limit); tcase_add_test(tcase, test_invalid_signature_key); suite_add_tcase(suite, tcase); return suite; } int main(void) { int number_failed; Suite *suite; SRunner *runner; suite = group_cipher_suite(); runner = srunner_create(suite); srunner_run_all(runner, CK_VERBOSE); number_failed = srunner_ntests_failed(runner); srunner_free(runner); return (number_failed == 0) ? EXIT_SUCCESS : EXIT_FAILURE; } libsignal-protocol-c-2.3.3/tests/test_hkdf.c000066400000000000000000000153171363751346500210470ustar00rootroot00000000000000#include #include #include #include "../src/signal_protocol.h" #include "hkdf.h" #include "test_common.h" signal_context *global_context; void test_setup() { int result; result = signal_context_create(&global_context, 0); ck_assert_int_eq(result, 0); signal_context_set_log_function(global_context, test_log); setup_test_crypto_provider(global_context); } void test_teardown() { signal_context_destroy(global_context); } START_TEST(test_hkdf_vector_v3) { int result; uint8_t ikm[] = { 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b}; uint8_t salt[] = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c}; uint8_t info[] = { 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, 0xf9}; uint8_t okm[] = { 0x3c, 0xb2, 0x5f, 0x25, 0xfa, 0xac, 0xd5, 0x7a, 0x90, 0x43, 0x4f, 0x64, 0xd0, 0x36, 0x2f, 0x2a, 0x2d, 0x2d, 0x0a, 0x90, 0xcf, 0x1a, 0x5a, 0x4c, 0x5d, 0xb0, 0x2d, 0x56, 0xec, 0xc4, 0xc5, 0xbf, 0x34, 0x00, 0x72, 0x08, 0xd5, 0xb8, 0x87, 0x18, 0x58, 0x65}; hkdf_context *context; result = hkdf_create(&context, 3, global_context); ck_assert_int_eq(result, 0); uint8_t *output = 0; result = hkdf_derive_secrets(context, &output, ikm, sizeof(ikm), salt, sizeof(salt), info, sizeof(info), 42); ck_assert_int_eq(result, sizeof(okm)); ck_assert_int_eq(memcmp(okm, output, result), 0); if(output) { free(output); } SIGNAL_UNREF(context); } END_TEST START_TEST(test_hkdf_vector_long_v3) { int result = 0; uint8_t ikm[] = { 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}; uint8_t salt[] = { 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}; uint8_t info[] = { 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}; uint8_t okm[] = { 0xb1, 0x1e, 0x39, 0x8d, 0xc8, 0x03, 0x27, 0xa1, 0xc8, 0xe7, 0xf7, 0x8c, 0x59, 0x6a, 0x49, 0x34, 0x4f, 0x01, 0x2e, 0xda, 0x2d, 0x4e, 0xfa, 0xd8, 0xa0, 0x50, 0xcc, 0x4c, 0x19, 0xaf, 0xa9, 0x7c, 0x59, 0x04, 0x5a, 0x99, 0xca, 0xc7, 0x82, 0x72, 0x71, 0xcb, 0x41, 0xc6, 0x5e, 0x59, 0x0e, 0x09, 0xda, 0x32, 0x75, 0x60, 0x0c, 0x2f, 0x09, 0xb8, 0x36, 0x77, 0x93, 0xa9, 0xac, 0xa3, 0xdb, 0x71, 0xcc, 0x30, 0xc5, 0x81, 0x79, 0xec, 0x3e, 0x87, 0xc1, 0x4c, 0x01, 0xd5, 0xc1, 0xf3, 0x43, 0x4f, 0x1d, 0x87}; hkdf_context *context; result = hkdf_create(&context, 3, global_context); ck_assert_int_eq(result, 0); uint8_t *output = 0; result = hkdf_derive_secrets(context, &output, ikm, sizeof(ikm), salt, sizeof(salt), info, sizeof(info), 82); ck_assert_int_eq(result, sizeof(okm)); ck_assert_int_eq(memcmp(okm, output, result), 0); if(output) { free(output); } SIGNAL_UNREF(context); } END_TEST START_TEST(test_hkdf_vector_v2) { int result = 0; uint8_t ikm[] = { 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b}; uint8_t salt[] = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c}; uint8_t info[] = { 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, 0xf9}; uint8_t okm[] = { 0x6e, 0xc2, 0x55, 0x6d, 0x5d, 0x7b, 0x1d, 0x81, 0xde, 0xe4, 0x22, 0x2a, 0xd7, 0x48, 0x36, 0x95, 0xdd, 0xc9, 0x8f, 0x4f, 0x5f, 0xab, 0xc0, 0xe0, 0x20, 0x5d, 0xc2, 0xef, 0x87, 0x52, 0xd4, 0x1e, 0x04, 0xe2, 0xe2, 0x11, 0x01, 0xc6, 0x8f, 0xf0, 0x93, 0x94, 0xb8, 0xad, 0x0b, 0xdc, 0xb9, 0x60, 0x9c, 0xd4, 0xee, 0x82, 0xac, 0x13, 0x19, 0x9b, 0x4a, 0xa9, 0xfd, 0xa8, 0x99, 0xda, 0xeb, 0xec}; hkdf_context *context; result = hkdf_create(&context, 2, global_context); ck_assert_int_eq(result, 0); uint8_t *output = 0; result = hkdf_derive_secrets(context, &output, ikm, sizeof(ikm), salt, sizeof(salt), info, sizeof(info), 64); ck_assert_int_eq(result, sizeof(okm)); ck_assert_int_eq(memcmp(okm, output, result), 0); if(output) { free(output); } SIGNAL_UNREF(context); } END_TEST Suite *hkdf_suite(void) { Suite *suite = suite_create("hkdf"); TCase *tcase = tcase_create("case"); tcase_add_checked_fixture(tcase, test_setup, test_teardown); tcase_add_test(tcase, test_hkdf_vector_v3); tcase_add_test(tcase, test_hkdf_vector_long_v3); tcase_add_test(tcase, test_hkdf_vector_v2); suite_add_tcase(suite, tcase); return suite; } int main(void) { int number_failed; Suite *suite; SRunner *runner; suite = hkdf_suite(); runner = srunner_create(suite); srunner_run_all(runner, CK_VERBOSE); number_failed = srunner_ntests_failed(runner); srunner_free(runner); return (number_failed == 0) ? EXIT_SUCCESS : EXIT_FAILURE; } libsignal-protocol-c-2.3.3/tests/test_key_helper.c000066400000000000000000000246301363751346500222600ustar00rootroot00000000000000#include #include #include #include "../src/signal_protocol.h" #include "key_helper.h" #include "test_common.h" /* * Since the expected output from all these operations is random, these tests * use a special fake random number generator. * The expected output for these tests was generated by running the equivalent * functions in the Java version with a similarly fake random number generator. */ signal_context *global_context; uint8_t test_next_random; int fake_random_generator(uint8_t *data, size_t len, void *user_data) { unsigned int i = 0; for(i = 0; i < len; i++) { data[i] = test_next_random++; } return 0; } void test_setup() { int result; result = signal_context_create(&global_context, 0); ck_assert_int_eq(result, 0); signal_context_set_log_function(global_context, test_log); signal_crypto_provider provider = { .random_func = fake_random_generator, .hmac_sha256_init_func = test_hmac_sha256_init, .hmac_sha256_update_func = test_hmac_sha256_update, .hmac_sha256_final_func = test_hmac_sha256_final, .hmac_sha256_cleanup_func = test_hmac_sha256_cleanup, .user_data = 0 }; signal_context_set_crypto_provider(global_context, &provider); test_next_random = 0; } void test_teardown() { signal_context_destroy(global_context); } START_TEST(test_generate_identity_key_pair) { int result = 0; uint8_t identityKeyPair[] = { 0x0a, 0x21, 0x05, 0x8f, 0x40, 0xc5, 0xad, 0xb6, 0x8f, 0x25, 0x62, 0x4a, 0xe5, 0xb2, 0x14, 0xea, 0x76, 0x7a, 0x6e, 0xc9, 0x4d, 0x82, 0x9d, 0x3d, 0x7b, 0x5e, 0x1a, 0xd1, 0xba, 0x6f, 0x3e, 0x21, 0x38, 0x28, 0x5f, 0x12, 0x20, 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, 0x5f }; ratchet_identity_key_pair *key_pair = 0; signal_buffer *buffer = 0; result = signal_protocol_key_helper_generate_identity_key_pair(&key_pair, global_context); ck_assert_int_eq(result, 0); result = ratchet_identity_key_pair_serialize(&buffer, key_pair); ck_assert_int_ge(result, 0); uint8_t *data = signal_buffer_data(buffer); size_t len = signal_buffer_len(buffer); ck_assert_int_eq(len, sizeof(identityKeyPair)); ck_assert_int_eq(memcmp(identityKeyPair, data, len), 0); /* Cleanup */ SIGNAL_UNREF(key_pair); signal_buffer_free(buffer); } END_TEST START_TEST(test_generate_pre_keys) { uint8_t preKey1[] = { 0x08, 0x01, 0x12, 0x21, 0x05, 0x8f, 0x40, 0xc5, 0xad, 0xb6, 0x8f, 0x25, 0x62, 0x4a, 0xe5, 0xb2, 0x14, 0xea, 0x76, 0x7a, 0x6e, 0xc9, 0x4d, 0x82, 0x9d, 0x3d, 0x7b, 0x5e, 0x1a, 0xd1, 0xba, 0x6f, 0x3e, 0x21, 0x38, 0x28, 0x5f, 0x1a, 0x20, 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, 0x5f }; uint8_t preKey2[] = { 0x08, 0x02, 0x12, 0x21, 0x05, 0x35, 0x80, 0x72, 0xd6, 0x36, 0x58, 0x80, 0xd1, 0xae, 0xea, 0x32, 0x9a, 0xdf, 0x91, 0x21, 0x38, 0x38, 0x51, 0xed, 0x21, 0xa2, 0x8e, 0x3b, 0x75, 0xe9, 0x65, 0xd0, 0xd2, 0xcd, 0x16, 0x62, 0x54, 0x1a, 0x20, 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, 0x7f }; uint8_t preKey3[] = { 0x08, 0x03, 0x12, 0x21, 0x05, 0x79, 0xa6, 0x31, 0xee, 0xde, 0x1b, 0xf9, 0xc9, 0x8f, 0x12, 0x03, 0x2c, 0xde, 0xad, 0xd0, 0xe7, 0xa0, 0x79, 0x39, 0x8f, 0xc7, 0x86, 0xb8, 0x8c, 0xc8, 0x46, 0xec, 0x89, 0xaf, 0x85, 0xa5, 0x1a, 0x1a, 0x20, 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 }; uint8_t preKey4[] = { 0x08, 0x04, 0x12, 0x21, 0x05, 0x67, 0x5d, 0xd5, 0x74, 0xed, 0x77, 0x89, 0x31, 0x0b, 0x3d, 0x2e, 0x76, 0x81, 0xf3, 0x79, 0x0b, 0x46, 0x6c, 0x77, 0x3b, 0x15, 0x21, 0xfe, 0xcf, 0x36, 0x57, 0x79, 0x58, 0x37, 0x1e, 0xa5, 0x2f, 0x1a, 0x20, 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 }; int result = 0; signal_protocol_key_helper_pre_key_list_node *head = 0; signal_protocol_key_helper_pre_key_list_node *cur_node = 0; session_pre_key *pre_key1 = 0; session_pre_key *pre_key2 = 0; session_pre_key *pre_key3 = 0; session_pre_key *pre_key4 = 0; signal_buffer *pre_key_buf1 = 0; signal_buffer *pre_key_buf2 = 0; signal_buffer *pre_key_buf3 = 0; signal_buffer *pre_key_buf4 = 0; /* Generate a list of 4 pre-keys */ result = signal_protocol_key_helper_generate_pre_keys(&head, 1, 4, global_context); ck_assert_int_eq(result, 0); ck_assert_ptr_ne(head, 0); cur_node = head; /* Explicitly iterate the list to get the 4 generated keys */ pre_key1 = signal_protocol_key_helper_key_list_element(cur_node); cur_node = signal_protocol_key_helper_key_list_next(cur_node); ck_assert_ptr_ne(cur_node, 0); pre_key2 = signal_protocol_key_helper_key_list_element(cur_node); cur_node = signal_protocol_key_helper_key_list_next(cur_node); ck_assert_ptr_ne(cur_node, 0); pre_key3 = signal_protocol_key_helper_key_list_element(cur_node); cur_node = signal_protocol_key_helper_key_list_next(cur_node); ck_assert_ptr_ne(cur_node, 0); pre_key4 = signal_protocol_key_helper_key_list_element(cur_node); cur_node = signal_protocol_key_helper_key_list_next(cur_node); ck_assert_ptr_eq(cur_node, 0); /* Get the serialized data for the 4 generated keys */ result = session_pre_key_serialize(&pre_key_buf1, pre_key1); ck_assert_int_ge(result, 0); result = session_pre_key_serialize(&pre_key_buf2, pre_key2); ck_assert_int_ge(result, 0); result = session_pre_key_serialize(&pre_key_buf3, pre_key3); ck_assert_int_ge(result, 0); result = session_pre_key_serialize(&pre_key_buf4, pre_key4); ck_assert_int_ge(result, 0); /* Compare to the expected values */ ck_assert_int_eq(signal_buffer_len(pre_key_buf1), sizeof(preKey1)); ck_assert_int_eq(memcmp(preKey1, signal_buffer_data(pre_key_buf1), sizeof(preKey1)), 0); ck_assert_int_eq(signal_buffer_len(pre_key_buf2), sizeof(preKey2)); ck_assert_int_eq(memcmp(preKey2, signal_buffer_data(pre_key_buf2), sizeof(preKey2)), 0); ck_assert_int_eq(signal_buffer_len(pre_key_buf3), sizeof(preKey3)); ck_assert_int_eq(memcmp(preKey3, signal_buffer_data(pre_key_buf3), sizeof(preKey3)), 0); ck_assert_int_eq(signal_buffer_len(pre_key_buf4), sizeof(preKey4)); ck_assert_int_eq(memcmp(preKey4, signal_buffer_data(pre_key_buf4), sizeof(preKey4)), 0); /* Cleanup */ signal_protocol_key_helper_key_list_free(head); signal_buffer_free(pre_key_buf1); signal_buffer_free(pre_key_buf2); signal_buffer_free(pre_key_buf3); signal_buffer_free(pre_key_buf4); } END_TEST START_TEST(test_generate_signed_pre_key) { int64_t timestamp = 1411152577000LL; uint8_t signedPreKey[] = { 0x08, 0xd2, 0x09, 0x12, 0x21, 0x05, 0x35, 0x80, 0x72, 0xd6, 0x36, 0x58, 0x80, 0xd1, 0xae, 0xea, 0x32, 0x9a, 0xdf, 0x91, 0x21, 0x38, 0x38, 0x51, 0xed, 0x21, 0xa2, 0x8e, 0x3b, 0x75, 0xe9, 0x65, 0xd0, 0xd2, 0xcd, 0x16, 0x62, 0x54, 0x1a, 0x20, 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, 0x7f, 0x22, 0x40, 0xd8, 0x12, 0x88, 0xf2, 0x77, 0x38, 0x08, 0x86, 0xac, 0xa4, 0x06, 0x2f, 0x06, 0xd8, 0x30, 0xe6, 0xab, 0x73, 0x39, 0x4c, 0x85, 0xa0, 0xc0, 0x5a, 0x81, 0x16, 0x3d, 0x21, 0x9c, 0x77, 0xed, 0x41, 0xc1, 0x2d, 0x72, 0x61, 0x25, 0x4f, 0xf4, 0x11, 0x64, 0xba, 0x6d, 0x89, 0x5c, 0x09, 0x6c, 0x5e, 0x1f, 0xa6, 0xaa, 0x42, 0x53, 0x8d, 0xb9, 0xe2, 0x6b, 0xbb, 0xb0, 0xb3, 0x6c, 0x99, 0x74, 0x04, 0x29, 0xe8, 0x81, 0x3f, 0x8f, 0x48, 0x01, 0x00, 0x00 }; int result = 0; ratchet_identity_key_pair *identity_key_pair = 0; session_signed_pre_key *signed_pre_key = 0; signal_buffer *buffer = 0; result = signal_protocol_key_helper_generate_identity_key_pair(&identity_key_pair, global_context); ck_assert_int_eq(result, 0); result = signal_protocol_key_helper_generate_signed_pre_key(&signed_pre_key, identity_key_pair, 1234, timestamp, global_context); ck_assert_int_eq(result, 0); result = session_signed_pre_key_serialize(&buffer, signed_pre_key); ck_assert_int_ge(result, 0); uint8_t *data = signal_buffer_data(buffer); size_t len = signal_buffer_len(buffer); ck_assert_int_eq(len, sizeof(signedPreKey)); ck_assert_int_eq(memcmp(signedPreKey, data, len), 0); /* Cleanup */ SIGNAL_UNREF(identity_key_pair); SIGNAL_UNREF(signed_pre_key); signal_buffer_free(buffer); } END_TEST Suite *key_helper_suite(void) { Suite *suite = suite_create("key_helper"); TCase *tcase = tcase_create("case"); tcase_add_checked_fixture(tcase, test_setup, test_teardown); tcase_add_test(tcase, test_generate_identity_key_pair); tcase_add_test(tcase, test_generate_pre_keys); tcase_add_test(tcase, test_generate_signed_pre_key); suite_add_tcase(suite, tcase); return suite; } int main(void) { int number_failed; Suite *suite; SRunner *runner; suite = key_helper_suite(); runner = srunner_create(suite); srunner_run_all(runner, CK_VERBOSE); number_failed = srunner_ntests_failed(runner); srunner_free(runner); return (number_failed == 0) ? EXIT_SUCCESS : EXIT_FAILURE; } libsignal-protocol-c-2.3.3/tests/test_protocol.c000066400000000000000000000274451363751346500220010ustar00rootroot00000000000000#include #include #include #include "../src/signal_protocol.h" #include "curve.h" #include "protocol.h" #include "ratchet.h" #include "test_common.h" signal_context *global_context; void test_setup() { int result; result = signal_context_create(&global_context, 0); ck_assert_int_eq(result, 0); signal_context_set_log_function(global_context, test_log); setup_test_crypto_provider(global_context); } void test_teardown() { signal_context_destroy(global_context); } void compare_signal_messages(signal_message *message1, signal_message *message2) { ec_public_key *sender_ratchet_key1 = signal_message_get_sender_ratchet_key(message1); ec_public_key *sender_ratchet_key2 = signal_message_get_sender_ratchet_key(message2); ck_assert_int_eq(ec_public_key_compare(sender_ratchet_key1, sender_ratchet_key2), 0); int version1 = signal_message_get_message_version(message1); int version2 = signal_message_get_message_version(message2); ck_assert_int_eq(version1, version2); int counter1 = signal_message_get_counter(message1); int counter2 = signal_message_get_counter(message2); ck_assert_int_eq(counter1, counter2); signal_buffer *body1 = signal_message_get_body(message1); signal_buffer *body2 = signal_message_get_body(message2); ck_assert_int_eq(signal_buffer_compare(body1, body2), 0); } START_TEST(test_serialize_signal_message) { int result = 0; static const char ciphertext[] = "WhisperCipherText"; ec_public_key *sender_ratchet_key = create_test_ec_public_key(global_context); ec_public_key *sender_identity_key = create_test_ec_public_key(global_context); ec_public_key *receiver_identity_key = create_test_ec_public_key(global_context); uint8_t mac_key[RATCHET_MAC_KEY_LENGTH]; memset(mac_key, 1, sizeof(mac_key)); signal_message *message = 0; signal_message *result_message = 0; result = signal_message_create(&message, 3, mac_key, sizeof(mac_key), sender_ratchet_key, 2, /* counter */ 1, /* previous counter */ (uint8_t *)ciphertext, sizeof(ciphertext) - 1, sender_identity_key, receiver_identity_key, global_context); ck_assert_int_eq(result, 0); signal_buffer *serialized = ciphertext_message_get_serialized((ciphertext_message *)message); ck_assert_ptr_ne(serialized, 0); result = signal_message_deserialize(&result_message, signal_buffer_data(serialized), signal_buffer_len(serialized), global_context); ck_assert_int_eq(result, 0); compare_signal_messages(message, result_message); /* Exercise the MAC verification code */ result = signal_message_verify_mac(result_message, sender_identity_key, receiver_identity_key, mac_key, sizeof(mac_key), global_context); ck_assert_int_eq(result, 1); /* Cleanup */ SIGNAL_UNREF(message); SIGNAL_UNREF(result_message); SIGNAL_UNREF(sender_ratchet_key); SIGNAL_UNREF(sender_identity_key); SIGNAL_UNREF(receiver_identity_key); } END_TEST START_TEST(test_serialize_pre_key_signal_message) { int result = 0; static const char ciphertext[] = "WhisperCipherText"; ec_public_key *sender_ratchet_key = create_test_ec_public_key(global_context); ec_public_key *sender_identity_key = create_test_ec_public_key(global_context); ec_public_key *receiver_identity_key = create_test_ec_public_key(global_context); ec_public_key *base_key = create_test_ec_public_key(global_context); ec_public_key *identity_key = create_test_ec_public_key(global_context); uint8_t mac_key[RATCHET_MAC_KEY_LENGTH]; memset(mac_key, 1, sizeof(mac_key)); signal_message *message = 0; pre_key_signal_message *pre_key_message = 0; pre_key_signal_message *result_pre_key_message = 0; result = signal_message_create(&message, 3, mac_key, sizeof(mac_key), sender_ratchet_key, 2, /* counter */ 1, /* previous counter */ (uint8_t *)ciphertext, sizeof(ciphertext) - 1, sender_identity_key, receiver_identity_key, global_context); ck_assert_int_eq(result, 0); uint32_t pre_key_id = 56; result = pre_key_signal_message_create(&pre_key_message, 3, /* message version */ 42, /* registration ID */ &pre_key_id, /* pre key ID */ 72, /* signed pre key ID */ base_key, identity_key, message, global_context); ck_assert_int_eq(result, 0); signal_buffer *serialized = ciphertext_message_get_serialized((ciphertext_message *)pre_key_message); ck_assert_ptr_ne(serialized, 0); result = pre_key_signal_message_deserialize(&result_pre_key_message, signal_buffer_data(serialized), signal_buffer_len(serialized), global_context); ck_assert_int_eq(result, 0); int version1 = pre_key_signal_message_get_message_version(pre_key_message); int version2 = pre_key_signal_message_get_message_version(result_pre_key_message); ck_assert_int_eq(version1, version2); ec_public_key *identity_key1 = pre_key_signal_message_get_identity_key(pre_key_message); ec_public_key *identity_key2 = pre_key_signal_message_get_identity_key(result_pre_key_message); ck_assert_int_eq(ec_public_key_compare(identity_key1, identity_key2), 0); int registration_id1 = pre_key_signal_message_get_registration_id(pre_key_message); int registration_id2 = pre_key_signal_message_get_registration_id(result_pre_key_message); ck_assert_int_eq(registration_id1, registration_id2); int has_pre_key_id1 = pre_key_signal_message_has_pre_key_id(pre_key_message); int has_pre_key_id2 = pre_key_signal_message_has_pre_key_id(result_pre_key_message); ck_assert_int_eq(has_pre_key_id1, has_pre_key_id2); if(has_pre_key_id1) { int pre_key_id1 = pre_key_signal_message_get_pre_key_id(pre_key_message); int pre_key_id2 = pre_key_signal_message_get_pre_key_id(result_pre_key_message); ck_assert_int_eq(pre_key_id1, pre_key_id2); } int signed_pre_key_id1 = pre_key_signal_message_get_signed_pre_key_id(pre_key_message); int signed_pre_key_id2 = pre_key_signal_message_get_signed_pre_key_id(result_pre_key_message); ck_assert_int_eq(signed_pre_key_id1, signed_pre_key_id2); ec_public_key *base_key1 = pre_key_signal_message_get_base_key(pre_key_message); ec_public_key *base_key2 = pre_key_signal_message_get_base_key(result_pre_key_message); ck_assert_int_eq(ec_public_key_compare(base_key1, base_key2), 0); signal_message *message1 = pre_key_signal_message_get_signal_message(pre_key_message); signal_message *message2 = pre_key_signal_message_get_signal_message(result_pre_key_message); compare_signal_messages(message1, message2); /* Cleanup */ SIGNAL_UNREF(message); SIGNAL_UNREF(result_pre_key_message); SIGNAL_UNREF(pre_key_message); SIGNAL_UNREF(sender_ratchet_key); SIGNAL_UNREF(sender_identity_key); SIGNAL_UNREF(receiver_identity_key); SIGNAL_UNREF(base_key); SIGNAL_UNREF(identity_key); } END_TEST START_TEST(test_serialize_sender_key_message) { int result = 0; sender_key_message *message = 0; sender_key_message *result_message = 0; static const char ciphertext[] = "WhisperCipherText"; ec_key_pair *signature_key_pair = 0; result = curve_generate_key_pair(global_context, &signature_key_pair); ck_assert_int_eq(result, 0); result = sender_key_message_create(&message, 10, /* key_id */ 1, /* iteration */ (uint8_t *)ciphertext, sizeof(ciphertext) - 1, ec_key_pair_get_private(signature_key_pair), global_context); ck_assert_int_eq(result, 0); result = sender_key_message_verify_signature(message, ec_key_pair_get_public(signature_key_pair)); ck_assert_int_eq(result, 0); signal_buffer *serialized = ciphertext_message_get_serialized((ciphertext_message *)message); ck_assert_ptr_ne(serialized, 0); result = sender_key_message_deserialize(&result_message, signal_buffer_data(serialized), signal_buffer_len(serialized), global_context); ck_assert_int_eq(result, 0); result = sender_key_message_verify_signature(result_message, ec_key_pair_get_public(signature_key_pair)); ck_assert_int_eq(result, 0); int key_id1 = sender_key_message_get_key_id(message); int key_id2 = sender_key_message_get_key_id(result_message); ck_assert_int_eq(key_id1, key_id2); int iteration1 = sender_key_message_get_iteration(message); int iteration2 = sender_key_message_get_iteration(result_message); ck_assert_int_eq(iteration1, iteration2); signal_buffer *ciphertext1 = sender_key_message_get_ciphertext(message); signal_buffer *ciphertext2 = sender_key_message_get_ciphertext(result_message); ck_assert_int_eq(signal_buffer_compare(ciphertext1, ciphertext2), 0); /* Cleanup */ SIGNAL_UNREF(message); SIGNAL_UNREF(result_message); SIGNAL_UNREF(signature_key_pair); } END_TEST START_TEST(test_serialize_sender_key_distribution_message) { int result = 0; sender_key_distribution_message *message = 0; sender_key_distribution_message *result_message = 0; static const char chain_key[] = "WhisperChainKey"; ec_public_key *signature_key = create_test_ec_public_key(global_context); result = sender_key_distribution_message_create(&message, 10, /* id */ 1, /* iteration */ (uint8_t *)chain_key, sizeof(chain_key) - 1, signature_key, global_context); ck_assert_int_eq(result, 0); signal_buffer *serialized = ciphertext_message_get_serialized((ciphertext_message *)message); ck_assert_ptr_ne(serialized, 0); result = sender_key_distribution_message_deserialize(&result_message, signal_buffer_data(serialized), signal_buffer_len(serialized), global_context); ck_assert_int_eq(result, 0); int id1 = sender_key_distribution_message_get_id(message); int id2 = sender_key_distribution_message_get_id(result_message); ck_assert_int_eq(id1, id2); int iteration1 = sender_key_distribution_message_get_iteration(message); int iteration2 = sender_key_distribution_message_get_iteration(result_message); ck_assert_int_eq(iteration1, iteration2); signal_buffer *chain_key1 = sender_key_distribution_message_get_chain_key(message); signal_buffer *chain_key2 = sender_key_distribution_message_get_chain_key(result_message); ck_assert_int_eq(signal_buffer_compare(chain_key1, chain_key2), 0); ec_public_key *signature_key1 = sender_key_distribution_message_get_signature_key(message); ec_public_key *signature_key2 = sender_key_distribution_message_get_signature_key(result_message); ck_assert_int_eq(ec_public_key_compare(signature_key1, signature_key2), 0); /* Cleanup */ SIGNAL_UNREF(message); SIGNAL_UNREF(result_message); SIGNAL_UNREF(signature_key); } END_TEST Suite *protocol_suite(void) { Suite *suite = suite_create("protocol"); TCase *tcase = tcase_create("case"); tcase_add_checked_fixture(tcase, test_setup, test_teardown); tcase_add_test(tcase, test_serialize_signal_message); tcase_add_test(tcase, test_serialize_pre_key_signal_message); tcase_add_test(tcase, test_serialize_sender_key_message); tcase_add_test(tcase, test_serialize_sender_key_distribution_message); suite_add_tcase(suite, tcase); return suite; } int main(void) { int number_failed; Suite *suite; SRunner *runner; suite = protocol_suite(); runner = srunner_create(suite); srunner_run_all(runner, CK_VERBOSE); number_failed = srunner_ntests_failed(runner); srunner_free(runner); return (number_failed == 0) ? EXIT_SUCCESS : EXIT_FAILURE; } libsignal-protocol-c-2.3.3/tests/test_ratchet.c000066400000000000000000000627751363751346500215770ustar00rootroot00000000000000#include #include #include "../src/signal_protocol.h" #include "hkdf.h" #include "ratchet.h" #include "session_state.h" #include "test_common.h" signal_context *global_context; void test_setup() { int result; result = signal_context_create(&global_context, 0); ck_assert_int_eq(result, 0); signal_context_set_log_function(global_context, test_log); setup_test_crypto_provider(global_context); } void test_teardown() { signal_context_destroy(global_context); } static uint8_t seed[] = { 0x8a, 0xb7, 0x2d, 0x6f, 0x4c, 0xc5, 0xac, 0x0d, 0x38, 0x7e, 0xaf, 0x46, 0x33, 0x78, 0xdd, 0xb2, 0x8e, 0xdd, 0x07, 0x38, 0x5b, 0x1c, 0xb0, 0x12, 0x50, 0xc7, 0x15, 0x98, 0x2e, 0x7a, 0xd4, 0x8f}; START_TEST(test_chain_key_derivation_v2) { int result = 0; uint8_t messageKey[] = { 0x02, 0xa9, 0xaa, 0x6c, 0x7d, 0xbd, 0x64, 0xf9, 0xd3, 0xaa, 0x92, 0xf9, 0x2a, 0x27, 0x7b, 0xf5, 0x46, 0x09, 0xda, 0xdf, 0x0b, 0x00, 0x82, 0x8a, 0xcf, 0xc6, 0x1e, 0x3c, 0x72, 0x4b, 0x84, 0xa7}; uint8_t macKey[] = { 0xbf, 0xbe, 0x5e, 0xfb, 0x60, 0x30, 0x30, 0x52, 0x67, 0x42, 0xe3, 0xee, 0x89, 0xc7, 0x02, 0x4e, 0x88, 0x4e, 0x44, 0x0f, 0x1f, 0xf3, 0x76, 0xbb, 0x23, 0x17, 0xb2, 0xd6, 0x4d, 0xeb, 0x7c, 0x83}; uint8_t nextChainKey[] = { 0x28, 0xe8, 0xf8, 0xfe, 0xe5, 0x4b, 0x80, 0x1e, 0xef, 0x7c, 0x5c, 0xfb, 0x2f, 0x17, 0xf3, 0x2c, 0x7b, 0x33, 0x44, 0x85, 0xbb, 0xb7, 0x0f, 0xac, 0x6e, 0xc1, 0x03, 0x42, 0xa2, 0x46, 0xd1, 0x5d}; hkdf_context *kdf; result = hkdf_create(&kdf, 2, global_context); ck_assert_int_eq(result, 0); ratchet_chain_key *chain_key; result = ratchet_chain_key_create(&chain_key, kdf, seed, sizeof(seed), 0, global_context); ck_assert_int_eq(result, 0); SIGNAL_UNREF(kdf); signal_buffer *actual_key; result = ratchet_chain_key_get_key(chain_key, &actual_key); ck_assert_int_eq(result, 0); int actual_key_len = signal_buffer_len(actual_key); ck_assert_int_eq(actual_key_len, sizeof(seed)); ck_assert_int_eq(memcmp(signal_buffer_data(actual_key), seed, actual_key_len), 0); signal_buffer_free(actual_key); ratchet_message_keys message_keys; result = ratchet_chain_key_get_message_keys(chain_key, &message_keys); ck_assert_int_eq(result, 0); ck_assert_int_eq(memcmp(message_keys.cipher_key, messageKey, sizeof(messageKey)), 0); ck_assert_int_eq(memcmp(message_keys.mac_key, macKey, sizeof(macKey)), 0); ck_assert_int_eq(message_keys.counter, 0); ratchet_chain_key *next_chain_key; result = ratchet_chain_key_create_next(chain_key, &next_chain_key); ck_assert_int_eq(result, 0); result = ratchet_chain_key_get_key(next_chain_key, &actual_key); ck_assert_int_eq(result, 0); actual_key_len = signal_buffer_len(actual_key); ck_assert_int_eq(actual_key_len, sizeof(nextChainKey)); ck_assert_int_eq(memcmp(signal_buffer_data(actual_key), nextChainKey, actual_key_len), 0); signal_buffer_free(actual_key); ck_assert_int_eq(ratchet_chain_key_get_index(chain_key), 0); ck_assert_int_eq(ratchet_chain_key_get_index(next_chain_key), 1); ratchet_message_keys next_message_keys; result = ratchet_chain_key_get_message_keys(next_chain_key, &next_message_keys); ck_assert_int_eq(result, 0); ck_assert_int_eq(next_message_keys.counter, 1); SIGNAL_UNREF(chain_key); SIGNAL_UNREF(next_chain_key); } END_TEST START_TEST(test_chain_key_derivation_v3) { int result = 0; uint8_t messageKey[] = { 0xbf, 0x51, 0xe9, 0xd7, 0x5e, 0x0e, 0x31, 0x03, 0x10, 0x51, 0xf8, 0x2a, 0x24, 0x91, 0xff, 0xc0, 0x84, 0xfa, 0x29, 0x8b, 0x77, 0x93, 0xbd, 0x9d, 0xb6, 0x20, 0x05, 0x6f, 0xeb, 0xf4, 0x52, 0x17}; uint8_t macKey[] = { 0xc6, 0xc7, 0x7d, 0x6a, 0x73, 0xa3, 0x54, 0x33, 0x7a, 0x56, 0x43, 0x5e, 0x34, 0x60, 0x7d, 0xfe, 0x48, 0xe3, 0xac, 0xe1, 0x4e, 0x77, 0x31, 0x4d, 0xc6, 0xab, 0xc1, 0x72, 0xe7, 0xa7, 0x03, 0x0b}; uint8_t nextChainKey[] = { 0x28, 0xe8, 0xf8, 0xfe, 0xe5, 0x4b, 0x80, 0x1e, 0xef, 0x7c, 0x5c, 0xfb, 0x2f, 0x17, 0xf3, 0x2c, 0x7b, 0x33, 0x44, 0x85, 0xbb, 0xb7, 0x0f, 0xac, 0x6e, 0xc1, 0x03, 0x42, 0xa2, 0x46, 0xd1, 0x5d}; hkdf_context *kdf; result = hkdf_create(&kdf, 3, global_context); ck_assert_int_eq(result, 0); ratchet_chain_key *chain_key; result = ratchet_chain_key_create(&chain_key, kdf, seed, sizeof(seed), 0, global_context); ck_assert_int_eq(result, 0); SIGNAL_UNREF(kdf); signal_buffer *actual_key; result = ratchet_chain_key_get_key(chain_key, &actual_key); ck_assert_int_eq(result, 0); int actual_key_len = signal_buffer_len(actual_key); ck_assert_int_eq(actual_key_len, sizeof(seed)); ck_assert_int_eq(memcmp(signal_buffer_data(actual_key), seed, actual_key_len), 0); signal_buffer_free(actual_key); ratchet_message_keys message_keys; result = ratchet_chain_key_get_message_keys(chain_key, &message_keys); ck_assert_int_eq(result, 0); ck_assert_int_eq(memcmp(message_keys.cipher_key, messageKey, sizeof(messageKey)), 0); ck_assert_int_eq(memcmp(message_keys.mac_key, macKey, sizeof(macKey)), 0); ck_assert_int_eq(message_keys.counter, 0); ratchet_chain_key *next_chain_key; result = ratchet_chain_key_create_next(chain_key, &next_chain_key); ck_assert_int_eq(result, 0); result = ratchet_chain_key_get_key(next_chain_key, &actual_key); ck_assert_int_eq(result, 0); actual_key_len = signal_buffer_len(actual_key); ck_assert_int_eq(actual_key_len, sizeof(nextChainKey)); ck_assert_int_eq(memcmp(signal_buffer_data(actual_key), nextChainKey, actual_key_len), 0); signal_buffer_free(actual_key); ck_assert_int_eq(ratchet_chain_key_get_index(chain_key), 0); ck_assert_int_eq(ratchet_chain_key_get_index(next_chain_key), 1); ratchet_message_keys next_message_keys; result = ratchet_chain_key_get_message_keys(next_chain_key, &next_message_keys); ck_assert_int_eq(result, 0); ck_assert_int_eq(next_message_keys.counter, 1); SIGNAL_UNREF(chain_key); SIGNAL_UNREF(next_chain_key); } END_TEST START_TEST(test_root_key_derivation_v2) { int result = 0; uint8_t rootKeySeed[] = { 0x7b, 0xa6, 0xde, 0xbc, 0x2b, 0xc1, 0xbb, 0xf9, 0x1a, 0xbb, 0xc1, 0x36, 0x74, 0x04, 0x17, 0x6c, 0xa6, 0x23, 0x09, 0x5b, 0x7e, 0xc6, 0x6b, 0x45, 0xf6, 0x02, 0xd9, 0x35, 0x38, 0x94, 0x2d, 0xcc}; uint8_t alicePrivate[] = { 0x21, 0x68, 0x22, 0xec, 0x67, 0xeb, 0x38, 0x04, 0x9e, 0xba, 0xe7, 0xb9, 0x39, 0xba, 0xea, 0xeb, 0xb1, 0x51, 0xbb, 0xb3, 0x2d, 0xb8, 0x0f, 0xd3, 0x89, 0x24, 0x5a, 0xc3, 0x7a, 0x94, 0x8e, 0x50}; uint8_t bobPublic[] = { 0x05, 0xab, 0xb8, 0xeb, 0x29, 0xcc, 0x80, 0xb4, 0x71, 0x09, 0xa2, 0x26, 0x5a, 0xbe, 0x97, 0x98, 0x48, 0x54, 0x06, 0xe3, 0x2d, 0xa2, 0x68, 0x93, 0x4a, 0x95, 0x55, 0xe8, 0x47, 0x57, 0x70, 0x8a, 0x30}; uint8_t nextRoot[] = { 0xb1, 0x14, 0xf5, 0xde, 0x28, 0x01, 0x19, 0x85, 0xe6, 0xeb, 0xa2, 0x5d, 0x50, 0xe7, 0xec, 0x41, 0xa9, 0xb0, 0x2f, 0x56, 0x93, 0xc5, 0xc7, 0x88, 0xa6, 0x3a, 0x06, 0xd2, 0x12, 0xa2, 0xf7, 0x31}; uint8_t nextChain[] = { 0x9d, 0x7d, 0x24, 0x69, 0xbc, 0x9a, 0xe5, 0x3e, 0xe9, 0x80, 0x5a, 0xa3, 0x26, 0x4d, 0x24, 0x99, 0xa3, 0xac, 0xe8, 0x0f, 0x4c, 0xca, 0xe2, 0xda, 0x13, 0x43, 0x0c, 0x5c, 0x55, 0xb5, 0xca, 0x5f}; ec_private_key *alice_private_key = 0; ec_public_key *bob_public_key = 0; /* Initialize Alice's private key */ result = curve_decode_private_point(&alice_private_key, alicePrivate, sizeof(alicePrivate), global_context); ck_assert_int_eq(result, 0); ck_assert_ptr_ne(alice_private_key, 0); /* Initialize Bob's public key */ result = curve_decode_point(&bob_public_key, bobPublic, sizeof(bobPublic), global_context); ck_assert_int_eq(result, 0); ck_assert_ptr_ne(bob_public_key, 0); hkdf_context *kdf; result = hkdf_create(&kdf, 2, global_context); ck_assert_int_eq(result, 0); ratchet_root_key *root_key; result = ratchet_root_key_create(&root_key, kdf, rootKeySeed, sizeof(rootKeySeed), global_context); ck_assert_int_eq(result, 0); SIGNAL_UNREF(kdf); /* Get the next key pair in the chain */ ratchet_root_key *next_root_key; ratchet_chain_key *next_chain_key; result = ratchet_root_key_create_chain(root_key, &next_root_key, &next_chain_key, bob_public_key, alice_private_key); ck_assert_int_eq(result, 0); /* Check the value of the root key */ signal_buffer *root_bytes; result = ratchet_root_key_get_key(root_key, &root_bytes); ck_assert_int_eq(result, 0); int root_len = signal_buffer_len(root_bytes); ck_assert_int_eq(root_len, sizeof(rootKeySeed)); ck_assert_int_eq(memcmp(signal_buffer_data(root_bytes), rootKeySeed, root_len), 0); signal_buffer_free(root_bytes); /* Check the value of the next root key */ signal_buffer *next_root_bytes; result = ratchet_root_key_get_key(next_root_key, &next_root_bytes); ck_assert_int_eq(result, 0); int next_root_len = signal_buffer_len(next_root_bytes); ck_assert_int_eq(next_root_len, sizeof(nextRoot)); ck_assert_int_eq(memcmp(signal_buffer_data(next_root_bytes), nextRoot, next_root_len), 0); signal_buffer_free(next_root_bytes); /* Check the value of the next chain key */ signal_buffer *next_chain_bytes; result = ratchet_chain_key_get_key(next_chain_key, &next_chain_bytes); ck_assert_int_eq(result, 0); int next_chain_len = signal_buffer_len(next_chain_bytes); ck_assert_int_eq(next_chain_len, sizeof(nextChain)); ck_assert_int_eq(memcmp(signal_buffer_data(next_chain_bytes), nextChain, next_chain_len), 0); signal_buffer_free(next_chain_bytes); /* Cleanup */ SIGNAL_UNREF(next_root_key); SIGNAL_UNREF(next_chain_key); SIGNAL_UNREF(root_key); SIGNAL_UNREF(alice_private_key); SIGNAL_UNREF(bob_public_key); } END_TEST START_TEST(test_identity_key_serialize) { int result = 0; ec_key_pair *key_pair = 0; ratchet_identity_key_pair *identity_key_pair = 0; ratchet_identity_key_pair *result_identity_key_pair = 0; signal_buffer *buffer = 0; result = curve_generate_key_pair(global_context, &key_pair); ck_assert_int_eq(result, 0); ec_public_key *public_key = ec_key_pair_get_public(key_pair); ec_private_key *private_key = ec_key_pair_get_private(key_pair); result = ratchet_identity_key_pair_create( &identity_key_pair, public_key, private_key); ck_assert_int_eq(result, 0); result = ratchet_identity_key_pair_serialize(&buffer, identity_key_pair); ck_assert_int_ge(result, 0); result = ratchet_identity_key_pair_deserialize(&result_identity_key_pair, signal_buffer_data(buffer), signal_buffer_len(buffer), global_context); ck_assert_int_eq(result, 0); ec_public_key *result_public_key = ratchet_identity_key_pair_get_public(result_identity_key_pair); ck_assert_int_eq(ec_public_key_compare(public_key, result_public_key), 0); ec_private_key *result_private_key = ratchet_identity_key_pair_get_private(result_identity_key_pair); ck_assert_int_eq(ec_private_key_compare(private_key, result_private_key), 0); /* Cleanup */ SIGNAL_UNREF(key_pair); SIGNAL_UNREF(identity_key_pair); SIGNAL_UNREF(result_identity_key_pair); signal_buffer_free(buffer); } END_TEST static uint8_t bobPublic[] = { 0x05, 0x2c, 0xb4, 0x97, 0x76, 0xb8, 0x77, 0x02, 0x05, 0x74, 0x5a, 0x3a, 0x6e, 0x24, 0xf5, 0x79, 0xcd, 0xb4, 0xba, 0x7a, 0x89, 0x04, 0x10, 0x05, 0x92, 0x8e, 0xbb, 0xad, 0xc9, 0xc0, 0x5a, 0xd4, 0x58}; static uint8_t bobIdentityPublic[] = { 0x05, 0xf1, 0xf4, 0x38, 0x74, 0xf6, 0x96, 0x69, 0x56, 0xc2, 0xdd, 0x47, 0x3f, 0x8f, 0xa1, 0x5a, 0xde, 0xb7, 0x1d, 0x1c, 0xb9, 0x91, 0xb2, 0x34, 0x16, 0x92, 0x32, 0x4c, 0xef, 0xb1, 0xc5, 0xe6, 0x26}; static uint8_t aliceBasePublic[] = { 0x05, 0x47, 0x2d, 0x1f, 0xb1, 0xa9, 0x86, 0x2c, 0x3a, 0xf6, 0xbe, 0xac, 0xa8, 0x92, 0x02, 0x77, 0xe2, 0xb2, 0x6f, 0x4a, 0x79, 0x21, 0x3e, 0xc7, 0xc9, 0x06, 0xae, 0xb3, 0x5e, 0x03, 0xcf, 0x89, 0x50}; static uint8_t aliceIdentityPublic[] = { 0x05, 0xb4, 0xa8, 0x45, 0x56, 0x60, 0xad, 0xa6, 0x5b, 0x40, 0x10, 0x07, 0xf6, 0x15, 0xe6, 0x54, 0x04, 0x17, 0x46, 0x43, 0x2e, 0x33, 0x39, 0xc6, 0x87, 0x51, 0x49, 0xbc, 0xee, 0xfc, 0xb4, 0x2b, 0x4a}; static uint8_t bobSignedPreKeyPublic[] = { 0x05, 0xac, 0x24, 0x8a, 0x8f, 0x26, 0x3b, 0xe6, 0x86, 0x35, 0x76, 0xeb, 0x03, 0x62, 0xe2, 0x8c, 0x82, 0x8f, 0x01, 0x07, 0xa3, 0x37, 0x9d, 0x34, 0xba, 0xb1, 0x58, 0x6b, 0xf8, 0xc7, 0x70, 0xcd, 0x67}; static uint8_t receiverAndSenderChain[] = { 0x97, 0x97, 0xca, 0xca, 0x53, 0xc9, 0x89, 0xbb, 0xe2, 0x29, 0xa4, 0x0c, 0xa7, 0x72, 0x70, 0x10, 0xeb, 0x26, 0x04, 0xfc, 0x14, 0x94, 0x5d, 0x77, 0x95, 0x8a, 0x0a, 0xed, 0xa0, 0x88, 0xb4, 0x4d}; START_TEST(test_ratcheting_session_as_bob) { int result = 0; uint8_t bobPrivate[] = { 0xa1, 0xca, 0xb4, 0x8f, 0x7c, 0x89, 0x3f, 0xaf, 0xa9, 0x88, 0x0a, 0x28, 0xc3, 0xb4, 0x99, 0x9d, 0x28, 0xd6, 0x32, 0x95, 0x62, 0xd2, 0x7a, 0x4e, 0xa4, 0xe2, 0x2e, 0x9f, 0xf1, 0xbd, 0xd6, 0x5a}; uint8_t bobIdentityPrivate[] = { 0x48, 0x75, 0xcc, 0x69, 0xdd, 0xf8, 0xea, 0x07, 0x19, 0xec, 0x94, 0x7d, 0x61, 0x08, 0x11, 0x35, 0x86, 0x8d, 0x5f, 0xd8, 0x01, 0xf0, 0x2c, 0x02, 0x25, 0xe5, 0x16, 0xdf, 0x21, 0x56, 0x60, 0x5e}; uint8_t bobSignedPreKeyPrivate[] = { 0x58, 0x39, 0x00, 0x13, 0x1f, 0xb7, 0x27, 0x99, 0x8b, 0x78, 0x03, 0xfe, 0x6a, 0xc2, 0x2c, 0xc5, 0x91, 0xf3, 0x42, 0xe4, 0xe4, 0x2a, 0x8c, 0x8d, 0x5d, 0x78, 0x19, 0x42, 0x09, 0xb8, 0xd2, 0x53}; /* Create Bob's public identity key */ ec_public_key *bob_identity_key_public; result = curve_decode_point(&bob_identity_key_public, bobIdentityPublic, sizeof(bobIdentityPublic), global_context); ck_assert_int_eq(result, 0); /* Create Bob's private identity key */ ec_private_key *bob_identity_key_private; result = curve_decode_private_point(&bob_identity_key_private, bobIdentityPrivate, sizeof(bobIdentityPrivate), global_context); ck_assert_int_eq(result, 0); /* Create Bob's identity key pair */ ratchet_identity_key_pair *bob_identity_key_pair; result = ratchet_identity_key_pair_create(&bob_identity_key_pair, bob_identity_key_public, bob_identity_key_private); ck_assert_int_eq(result, 0); SIGNAL_UNREF(bob_identity_key_public); SIGNAL_UNREF(bob_identity_key_private); /* Create Bob's public ephemeral key */ ec_public_key *bob_ephemeral_key_public; result = curve_decode_point(&bob_ephemeral_key_public, bobPublic, sizeof(bobPublic), global_context); ck_assert_int_eq(result, 0); /* Create Bob's private ephemeral key */ ec_private_key *bob_ephemeral_key_private; result = curve_decode_private_point(&bob_ephemeral_key_private, bobPrivate, sizeof(bobPrivate), global_context); ck_assert_int_eq(result, 0); /* Create Bob's ephemeral key pair */ ec_key_pair *bob_ephemeral_key_pair; result = ec_key_pair_create(&bob_ephemeral_key_pair, bob_ephemeral_key_public, bob_ephemeral_key_private); ck_assert_int_eq(result, 0); SIGNAL_UNREF(bob_ephemeral_key_public); SIGNAL_UNREF(bob_ephemeral_key_private); /* Create Bob's public signed pre key */ ec_public_key *bob_signed_pre_key_public; result = curve_decode_point(&bob_signed_pre_key_public, bobSignedPreKeyPublic, sizeof(bobSignedPreKeyPublic), global_context); ck_assert_int_eq(result, 0); /* Create Bob's private signed pre key */ ec_private_key *bob_signed_pre_key_private; result = curve_decode_private_point(&bob_signed_pre_key_private, bobSignedPreKeyPrivate, sizeof(bobSignedPreKeyPrivate), global_context); ck_assert_int_eq(result, 0); /* Create Bob's signed pre key pair */ ec_key_pair *bob_signed_pre_key_pair; result = ec_key_pair_create(&bob_signed_pre_key_pair, bob_signed_pre_key_public, bob_signed_pre_key_private); ck_assert_int_eq(result, 0); SIGNAL_UNREF(bob_signed_pre_key_public); SIGNAL_UNREF(bob_signed_pre_key_private); /* Create Alice's base public key */ ec_public_key *alice_base_key_public; result = curve_decode_point(&alice_base_key_public, aliceBasePublic, sizeof(aliceBasePublic), global_context); ck_assert_int_eq(result, 0); /* Create Alice's public identity key */ ec_public_key *alice_identity_key_public; result = curve_decode_point(&alice_identity_key_public, aliceIdentityPublic, sizeof(aliceIdentityPublic), global_context); ck_assert_int_eq(result, 0); /* Create Bob's Signal Protocol parameters */ bob_signal_protocol_parameters *bob_parameters; result = bob_signal_protocol_parameters_create(&bob_parameters, bob_identity_key_pair, bob_signed_pre_key_pair, 0, /* our_one_time_pre_key */ bob_ephemeral_key_pair, alice_identity_key_public, alice_base_key_public); ck_assert_int_eq(result, 0); SIGNAL_UNREF(bob_signed_pre_key_pair); SIGNAL_UNREF(bob_ephemeral_key_pair); SIGNAL_UNREF(alice_base_key_public); /* * Not unref'ing the following items that are needed for assertions: * bob_identity_key_pair * alice_identity_key_public */ /* Create the session state */ session_state *test_session_state; result = session_state_create(&test_session_state, global_context); ck_assert_int_eq(result, 0); result = ratcheting_session_bob_initialize(test_session_state, bob_parameters, global_context); ck_assert_int_eq(result, 0); ck_assert_int_eq(ec_public_key_compare( ratchet_identity_key_pair_get_public(bob_identity_key_pair), session_state_get_local_identity_key(test_session_state)), 0); ck_assert_int_eq(ec_public_key_compare( alice_identity_key_public, session_state_get_remote_identity_key(test_session_state)), 0); ratchet_chain_key *sender_chain_key = session_state_get_sender_chain_key(test_session_state); signal_buffer *sender_chain_key_data; result = ratchet_chain_key_get_key(sender_chain_key, &sender_chain_key_data); ck_assert_int_eq(result, 0); int sender_chain_key_size = signal_buffer_len(sender_chain_key_data); ck_assert_int_eq(sender_chain_key_size, sizeof(receiverAndSenderChain)); ck_assert_int_eq(memcmp(signal_buffer_data(sender_chain_key_data), receiverAndSenderChain, sizeof(receiverAndSenderChain)), 0); signal_buffer_free(sender_chain_key_data); /* Cleanup */ SIGNAL_UNREF(bob_identity_key_pair); SIGNAL_UNREF(alice_identity_key_public); SIGNAL_UNREF(bob_parameters); SIGNAL_UNREF(test_session_state); } END_TEST START_TEST(test_ratcheting_session_as_alice) { int result = 0; uint8_t aliceBasePrivate[] = { 0x11, 0xae, 0x7c, 0x64, 0xd1, 0xe6, 0x1c, 0xd5, 0x96, 0xb7, 0x6a, 0x0d, 0xb5, 0x01, 0x26, 0x73, 0x39, 0x1c, 0xae, 0x66, 0xed, 0xbf, 0xcf, 0x07, 0x3b, 0x4d, 0xa8, 0x05, 0x16, 0xa4, 0x74, 0x49}; uint8_t aliceIdentityPrivate[] = { 0x90, 0x40, 0xf0, 0xd4, 0xe0, 0x9c, 0xf3, 0x8f, 0x6d, 0xc7, 0xc1, 0x37, 0x79, 0xc9, 0x08, 0xc0, 0x15, 0xa1, 0xda, 0x4f, 0xa7, 0x87, 0x37, 0xa0, 0x80, 0xeb, 0x0a, 0x6f, 0x4f, 0x5f, 0x8f, 0x58}; /* Create Bob's public identity key */ ec_public_key *bob_identity_key_public; result = curve_decode_point(&bob_identity_key_public, bobIdentityPublic, sizeof(bobIdentityPublic), global_context); ck_assert_int_eq(result, 0); /* Create Bob's public ephemeral key */ ec_public_key *bob_ephemeral_key_public; result = curve_decode_point(&bob_ephemeral_key_public, bobPublic, sizeof(bobPublic), global_context); ck_assert_int_eq(result, 0); /* Create Bob's public signed pre key */ ec_public_key *bob_signed_pre_key; result = curve_decode_point(&bob_signed_pre_key, bobSignedPreKeyPublic, sizeof(bobSignedPreKeyPublic), global_context); ck_assert_int_eq(result, 0); /* Create Alice's base public key */ ec_public_key *alice_base_public_key; result = curve_decode_point(&alice_base_public_key, aliceBasePublic, sizeof(aliceBasePublic), global_context); ck_assert_int_eq(result, 0); /* Create Alice's base private key */ ec_private_key *alice_base_private_key; result = curve_decode_private_point(&alice_base_private_key, aliceBasePrivate, sizeof(aliceBasePrivate), global_context); ck_assert_int_eq(result, 0); /* Create Alice's base key pair */ ec_key_pair *alice_base_key; result = ec_key_pair_create(&alice_base_key, alice_base_public_key, alice_base_private_key); ck_assert_int_eq(result, 0); SIGNAL_UNREF(alice_base_public_key); SIGNAL_UNREF(alice_base_private_key); /* Create Alice's identity public key */ ec_public_key *alice_identity_public_key; result = curve_decode_point(&alice_identity_public_key, aliceIdentityPublic, sizeof(aliceIdentityPublic), global_context); ck_assert_int_eq(result, 0); /* Create Alice's identity private key */ ec_private_key *alice_identity_private_key; result = curve_decode_private_point(&alice_identity_private_key, aliceIdentityPrivate, sizeof(aliceIdentityPrivate), global_context); ck_assert_int_eq(result, 0); /* Create Alice's identity key pair */ ratchet_identity_key_pair *alice_identity_key_pair; result = ratchet_identity_key_pair_create(&alice_identity_key_pair, alice_identity_public_key, alice_identity_private_key); ck_assert_int_eq(result, 0); SIGNAL_UNREF(alice_identity_public_key); SIGNAL_UNREF(alice_identity_private_key); /* Create the session state */ session_state *test_session_state; result = session_state_create(&test_session_state, global_context); ck_assert_int_eq(result, 0); /* Create Alice's Signal Protocol parameters */ alice_signal_protocol_parameters *alice_parameters; result = alice_signal_protocol_parameters_create(&alice_parameters, alice_identity_key_pair, alice_base_key, bob_identity_key_public, bob_signed_pre_key, 0, bob_ephemeral_key_public); ck_assert_int_eq(result, 0); result = ratcheting_session_alice_initialize(test_session_state, alice_parameters, global_context); ck_assert_int_eq(result, 0); ck_assert_int_eq(ec_public_key_compare( ratchet_identity_key_pair_get_public(alice_identity_key_pair), session_state_get_local_identity_key(test_session_state)), 0); ck_assert_int_eq(ec_public_key_compare( bob_identity_key_public, session_state_get_remote_identity_key(test_session_state)), 0); ratchet_chain_key *receiver_chain_actual = session_state_get_receiver_chain_key(test_session_state, bob_ephemeral_key_public); ck_assert_ptr_ne(receiver_chain_actual, 0); signal_buffer *receiver_chain_actual_data = 0; result = ratchet_chain_key_get_key(receiver_chain_actual, &receiver_chain_actual_data); ck_assert_int_eq(result, 0); int receiver_chain_actual_data_len = signal_buffer_len(receiver_chain_actual_data); ck_assert_int_eq(receiver_chain_actual_data_len, sizeof(receiverAndSenderChain)); ck_assert_int_eq(memcmp(signal_buffer_data(receiver_chain_actual_data), receiverAndSenderChain, receiver_chain_actual_data_len), 0); signal_buffer_free(receiver_chain_actual_data); /* Cleanup */ SIGNAL_UNREF(bob_identity_key_public); SIGNAL_UNREF(bob_ephemeral_key_public); SIGNAL_UNREF(bob_signed_pre_key); SIGNAL_UNREF(alice_base_key); SIGNAL_UNREF(alice_identity_key_pair); SIGNAL_UNREF(alice_parameters); SIGNAL_UNREF(test_session_state); } END_TEST Suite *ratchet_suite(void) { Suite *suite = suite_create("ratchet"); TCase *tcase_chain_key = tcase_create("chain_key"); tcase_add_checked_fixture(tcase_chain_key, test_setup, test_teardown); tcase_add_test(tcase_chain_key, test_chain_key_derivation_v2); tcase_add_test(tcase_chain_key, test_chain_key_derivation_v3); suite_add_tcase(suite, tcase_chain_key); TCase *tcase_root_key = tcase_create("root_key"); tcase_add_checked_fixture(tcase_root_key, test_setup, test_teardown); tcase_add_test(tcase_root_key, test_root_key_derivation_v2); suite_add_tcase(suite, tcase_root_key); TCase *tcase_identity_key = tcase_create("identity_key"); tcase_add_checked_fixture(tcase_identity_key, test_setup, test_teardown); tcase_add_test(tcase_identity_key, test_identity_key_serialize); suite_add_tcase(suite, tcase_identity_key); TCase *tcase_ratcheting_session = tcase_create("ratcheting_session"); tcase_add_checked_fixture(tcase_ratcheting_session, test_setup, test_teardown); tcase_add_test(tcase_ratcheting_session, test_ratcheting_session_as_bob); tcase_add_test(tcase_ratcheting_session, test_ratcheting_session_as_alice); suite_add_tcase(suite, tcase_ratcheting_session); return suite; } int main(void) { int number_failed; Suite *suite; SRunner *runner; suite = ratchet_suite(); runner = srunner_create(suite); srunner_run_all(runner, CK_VERBOSE); number_failed = srunner_ntests_failed(runner); srunner_free(runner); return (number_failed == 0) ? EXIT_SUCCESS : EXIT_FAILURE; } libsignal-protocol-c-2.3.3/tests/test_sender_key_record.c000066400000000000000000000274731363751346500236270ustar00rootroot00000000000000#include #include #include #include "../src/signal_protocol.h" #include "key_helper.h" #include "curve.h" #include "sender_key.h" #include "sender_key_state.h" #include "sender_key_record.h" #include "test_common.h" signal_context *global_context; void test_setup() { int result; result = signal_context_create(&global_context, 0); ck_assert_int_eq(result, 0); signal_context_set_log_function(global_context, test_log); setup_test_crypto_provider(global_context); } void test_teardown() { signal_context_destroy(global_context); } sender_key_state *create_test_sender_key_state(int id, int iteration) { int result = 0; sender_key_state *state = 0; signal_buffer *buffer = 0; sender_chain_key *chain_key = 0; ec_key_pair *key_pair = 0; result = signal_protocol_key_helper_generate_sender_key(&buffer, global_context); ck_assert_int_eq(result, 0); result = sender_chain_key_create(&chain_key, iteration, buffer, global_context); ck_assert_int_eq(result, 0); result = signal_protocol_key_helper_generate_sender_signing_key(&key_pair, global_context); ck_assert_int_eq(result, 0); result = sender_key_state_create(&state, id, chain_key, ec_key_pair_get_public(key_pair), ec_key_pair_get_private(key_pair), global_context); ck_assert_int_eq(result, 0); /* Cleanup */ signal_buffer_free(buffer); SIGNAL_UNREF(chain_key); SIGNAL_UNREF(key_pair); return state; } void compare_sender_chain_keys(sender_chain_key *chain_key1, sender_chain_key *chain_key2) { int iteration1 = sender_chain_key_get_iteration(chain_key1); int iteration2 = sender_chain_key_get_iteration(chain_key2); ck_assert_int_eq(iteration1, iteration2); signal_buffer *seed1 = sender_chain_key_get_seed(chain_key1); signal_buffer *seed2 = sender_chain_key_get_seed(chain_key2); ck_assert_int_eq(signal_buffer_compare(seed1, seed2), 0); } void compare_sender_key_states(sender_key_state *state1, sender_key_state *state2) { /* Compare key IDs */ int key_id1 = sender_key_state_get_key_id(state1); int key_id2 = sender_key_state_get_key_id(state2); ck_assert_int_eq(key_id1, key_id2); /* Compare chain keys */ sender_chain_key *chain_key1 = sender_key_state_get_chain_key(state1); sender_chain_key *chain_key2 = sender_key_state_get_chain_key(state2); compare_sender_chain_keys(chain_key1, chain_key2); /* Compare public signing keys */ ec_public_key *key_public1 = sender_key_state_get_signing_key_public(state1); ec_public_key *key_public2 = sender_key_state_get_signing_key_public(state2); ck_assert_int_eq(ec_public_key_compare(key_public1, key_public2), 0); /* Compare private signing keys */ ec_private_key *key_private1 = sender_key_state_get_signing_key_private(state1); ec_private_key *key_private2 = sender_key_state_get_signing_key_private(state2); ck_assert_int_eq(ec_private_key_compare(key_private1, key_private2), 0); /* Message keys are not compared here */ } void compare_sender_message_keys(sender_message_key *message_key1, sender_message_key *message_key2) { int iteration1 = sender_message_key_get_iteration(message_key1); int iteration2 = sender_message_key_get_iteration(message_key1); ck_assert_int_eq(iteration1, iteration2); signal_buffer *iv1 = sender_message_key_get_iv(message_key1); signal_buffer *iv2 = sender_message_key_get_iv(message_key2); ck_assert_int_eq(signal_buffer_compare(iv1, iv2), 0); signal_buffer *cipher_key1 = sender_message_key_get_cipher_key(message_key1); signal_buffer *cipher_key2 = sender_message_key_get_cipher_key(message_key2); ck_assert_int_eq(signal_buffer_compare(cipher_key1, cipher_key2), 0); signal_buffer *seed1 = sender_message_key_get_seed(message_key1); signal_buffer *seed2 = sender_message_key_get_seed(message_key2); ck_assert_int_eq(signal_buffer_compare(seed1, seed2), 0); } START_TEST(test_serialize_sender_key_state) { int result = 0; sender_key_state *state = create_test_sender_key_state(1234, 1); sender_message_key *message_key = 0; /* Create and add a message key */ result = sender_chain_key_create_message_key(sender_key_state_get_chain_key(state), &message_key); ck_assert_int_ge(result, 0); result = sender_key_state_add_sender_message_key(state, message_key); ck_assert_int_eq(result, 0); /* Serialize the state */ signal_buffer *buffer = 0; result = sender_key_state_serialize(&buffer, state); ck_assert_int_ge(result, 0); /* Deserialize the state */ uint8_t *data = signal_buffer_data(buffer); int len = signal_buffer_len(buffer); sender_key_state *state_deserialized = 0; result = sender_key_state_deserialize(&state_deserialized, data, len, global_context); ck_assert_int_eq(result, 0); /* Verify that the initial and deserialized states match */ compare_sender_key_states(state, state_deserialized); /* Remove the message key from the deserialized state for comparison */ sender_message_key *message_key_deserialized = sender_key_state_remove_sender_message_key(state_deserialized, 1); ck_assert_ptr_ne(message_key_deserialized, 0); /* Verify that the initial and deserialized message keys match */ compare_sender_message_keys(message_key, message_key_deserialized); /* Cleanup */ SIGNAL_UNREF(state); SIGNAL_UNREF(message_key); signal_buffer_free(buffer); SIGNAL_UNREF(state_deserialized); SIGNAL_UNREF(message_key_deserialized); } END_TEST void compare_sender_key_records(sender_key_record *record1, sender_key_record *record2) { int empty1 = sender_key_record_is_empty(record1); int empty2 = sender_key_record_is_empty(record2); ck_assert_int_eq(empty1, empty2); /* Sender key states not compared, since there is no way to iterate across them */ } void compare_sender_key_record_states(sender_key_record *record1, sender_key_record *record2, int id) { int result = 0; sender_key_state *state1 = 0; sender_key_state *state2 = 0; result = sender_key_record_get_sender_key_state_by_id(record1, &state1, id); ck_assert_int_eq(result, 0); ck_assert_ptr_ne(state1, 0); result = sender_key_record_get_sender_key_state_by_id(record2, &state2, id); ck_assert_int_eq(result, 0); ck_assert_ptr_ne(state2, 0); ck_assert_ptr_ne(state1, state2); compare_sender_key_states(state1, state2); } START_TEST(test_serialize_sender_key_record) { int result = 0; sender_key_record *record = 0; result = sender_key_record_create(&record, global_context); ck_assert_int_eq(result, 0); /* Serialize the record */ signal_buffer *buffer = 0; result = sender_key_record_serialize(&buffer, record); ck_assert_int_ge(result, 0); /* Deserialize the record */ uint8_t *data = signal_buffer_data(buffer); int len = signal_buffer_len(buffer); sender_key_record *record_deserialized = 0; result = sender_key_record_deserialize(&record_deserialized, data, len, global_context); ck_assert_int_eq(result, 0); /* Verify that the initial and deserialized records match */ compare_sender_key_records(record, record_deserialized); /* Cleanup */ SIGNAL_UNREF(record); signal_buffer_free(buffer); SIGNAL_UNREF(record_deserialized); } END_TEST START_TEST(test_serialize_sender_key_record_with_states) { int result = 0; sender_key_record *record = 0; signal_buffer *buffer = 0; ec_key_pair *key_pair = 0; /* Create the record */ result = sender_key_record_create(&record, global_context); ck_assert_int_eq(result, 0); /* Create and set state id=1000, iteration=1 */ result = signal_protocol_key_helper_generate_sender_key(&buffer, global_context); ck_assert_int_eq(result, 0); result = signal_protocol_key_helper_generate_sender_signing_key(&key_pair, global_context); ck_assert_int_eq(result, 0); result = sender_key_record_set_sender_key_state(record, 1000, 1, buffer, key_pair); ck_assert_int_eq(result, 0); signal_buffer_free(buffer); SIGNAL_UNREF(key_pair); /* Create and add state id=1001, iteration=2 */ result = signal_protocol_key_helper_generate_sender_key(&buffer, global_context); ck_assert_int_eq(result, 0); result = signal_protocol_key_helper_generate_sender_signing_key(&key_pair, global_context); ck_assert_int_eq(result, 0); sender_key_record_add_sender_key_state(record, 1001, 2, buffer, ec_key_pair_get_public(key_pair)); ck_assert_int_eq(result, 0); signal_buffer_free(buffer); SIGNAL_UNREF(key_pair); /* Serialize the record */ result = sender_key_record_serialize(&buffer, record); ck_assert_int_ge(result, 0); /* Deserialize the record */ uint8_t *data = signal_buffer_data(buffer); int len = signal_buffer_len(buffer); sender_key_record *record_deserialized = 0; result = sender_key_record_deserialize(&record_deserialized, data, len, global_context); ck_assert_int_eq(result, 0); /* Verify that the initial and deserialized records match */ compare_sender_key_records(record, record_deserialized); compare_sender_key_record_states(record, record_deserialized, 1000); compare_sender_key_record_states(record, record_deserialized, 1001); /* Cleanup */ SIGNAL_UNREF(record); signal_buffer_free(buffer); SIGNAL_UNREF(record_deserialized); } END_TEST START_TEST(test_sender_key_record_too_many_states) { int result = 0; int i; sender_key_record *record = 0; sender_key_state *state = 0; signal_buffer *buffer = 0; ec_key_pair *key_pair = 0; /* Create the record */ result = sender_key_record_create(&record, global_context); ck_assert_int_eq(result, 0); /* Create and set state id=1000, iteration=1 */ result = signal_protocol_key_helper_generate_sender_key(&buffer, global_context); ck_assert_int_eq(result, 0); result = signal_protocol_key_helper_generate_sender_signing_key(&key_pair, global_context); ck_assert_int_eq(result, 0); result = sender_key_record_set_sender_key_state(record, 1000, 1, buffer, key_pair); ck_assert_int_eq(result, 0); signal_buffer_free(buffer); SIGNAL_UNREF(key_pair); /* Create and set states id=1001..1010, iteration=2..11 */ for(i = 0; i < 10; i++) { result = signal_protocol_key_helper_generate_sender_key(&buffer, global_context); ck_assert_int_eq(result, 0); result = signal_protocol_key_helper_generate_sender_signing_key(&key_pair, global_context); ck_assert_int_eq(result, 0); sender_key_record_add_sender_key_state(record, 1001 + i, 2 + i, buffer, ec_key_pair_get_public(key_pair)); ck_assert_int_eq(result, 0); signal_buffer_free(buffer); SIGNAL_UNREF(key_pair); } /* Get the latest state from the record */ result = sender_key_record_get_sender_key_state(record, &state); ck_assert_int_eq(result, 0); ck_assert_int_eq(sender_key_state_get_key_id(state), 1010); /* Cleanup */ SIGNAL_UNREF(record); } END_TEST Suite *sender_key_record_suite(void) { Suite *suite = suite_create("sender_key_record"); TCase *tcase = tcase_create("case"); tcase_add_checked_fixture(tcase, test_setup, test_teardown); tcase_add_test(tcase, test_serialize_sender_key_state); tcase_add_test(tcase, test_serialize_sender_key_record); tcase_add_test(tcase, test_serialize_sender_key_record_with_states); tcase_add_test(tcase, test_sender_key_record_too_many_states); suite_add_tcase(suite, tcase); return suite; } int main(void) { int number_failed; Suite *suite; SRunner *runner; suite = sender_key_record_suite(); runner = srunner_create(suite); srunner_run_all(runner, CK_VERBOSE); number_failed = srunner_ntests_failed(runner); srunner_free(runner); return (number_failed == 0) ? EXIT_SUCCESS : EXIT_FAILURE; } libsignal-protocol-c-2.3.3/tests/test_session_builder.c000066400000000000000000001776511363751346500233360ustar00rootroot00000000000000#include #include #include #include #include "../src/signal_protocol.h" #include "session_record.h" #include "session_state.h" #include "session_cipher.h" #include "session_builder.h" #include "session_pre_key.h" #include "curve.h" #include "ratchet.h" #include "protocol.h" #include "test_common.h" static signal_protocol_address alice_address = { "+14151111111", 12, 1 }; static signal_protocol_address bob_address = { "+14152222222", 12, 1 }; signal_context *global_context; pthread_mutex_t global_mutex; pthread_mutexattr_t global_mutex_attr; void run_interaction(signal_protocol_store_context *alice_store, signal_protocol_store_context *bob_store); int test_basic_pre_key_v3_decrypt_callback(session_cipher *cipher, signal_buffer *plaintext, void *decrypt_context); void test_lock(void *user_data) { pthread_mutex_lock(&global_mutex); } void test_unlock(void *user_data) { pthread_mutex_unlock(&global_mutex); } void test_setup() { int result; pthread_mutexattr_init(&global_mutex_attr); pthread_mutexattr_settype(&global_mutex_attr, PTHREAD_MUTEX_RECURSIVE); pthread_mutex_init(&global_mutex, &global_mutex_attr); result = signal_context_create(&global_context, 0); ck_assert_int_eq(result, 0); signal_context_set_log_function(global_context, test_log); setup_test_crypto_provider(global_context); result = signal_context_set_locking_functions(global_context, test_lock, test_unlock); ck_assert_int_eq(result, 0); } void test_teardown() { signal_context_destroy(global_context); pthread_mutex_destroy(&global_mutex); pthread_mutexattr_destroy(&global_mutex_attr); } START_TEST(test_basic_pre_key_v2) { int result = 0; /* Create Alice's data store and session builder */ signal_protocol_store_context *alice_store = 0; setup_test_store_context(&alice_store, global_context); session_builder *alice_session_builder = 0; result = session_builder_create(&alice_session_builder, alice_store, &bob_address, global_context); ck_assert_int_eq(result, 0); /* Create Bob's data store and pre key bundle */ signal_protocol_store_context *bob_store = 0; setup_test_store_context(&bob_store, global_context); uint32_t bob_local_registration_id = 0; result = signal_protocol_identity_get_local_registration_id(bob_store, &bob_local_registration_id); ck_assert_int_eq(result, 0); ec_key_pair *bob_pre_key_pair = 0; result = curve_generate_key_pair(global_context, &bob_pre_key_pair); ck_assert_int_eq(result, 0); ratchet_identity_key_pair *bob_identity_key_pair = 0; result = signal_protocol_identity_get_key_pair(bob_store, &bob_identity_key_pair); ck_assert_int_eq(result, 0); session_pre_key_bundle *bob_pre_key = 0; result = session_pre_key_bundle_create(&bob_pre_key, bob_local_registration_id, 1, /* device ID */ 31337, /* pre key ID */ ec_key_pair_get_public(bob_pre_key_pair), 0, 0, 0, 0, /* no signed pre key or signature */ ratchet_identity_key_pair_get_public(bob_identity_key_pair)); ck_assert_int_eq(result, 0); /* * Have Alice process Bob's pre key bundle, which should fail due to a * missing unsigned pre key. */ result = session_builder_process_pre_key_bundle(alice_session_builder, bob_pre_key); ck_assert_int_eq(result, SG_ERR_INVALID_KEY); /* Final cleanup */ SIGNAL_UNREF(bob_pre_key); SIGNAL_UNREF(bob_pre_key_pair); SIGNAL_UNREF(bob_identity_key_pair); signal_protocol_store_context_destroy(bob_store); session_builder_free(alice_session_builder); signal_protocol_store_context_destroy(alice_store); } END_TEST typedef struct { const char *original_message; size_t original_message_len; signal_protocol_store_context *bob_store; } test_basic_pre_key_v3_callback_data; START_TEST(test_basic_pre_key_v3) { int result = 0; /* Create Alice's data store and session builder */ signal_protocol_store_context *alice_store = 0; setup_test_store_context(&alice_store, global_context); session_builder *alice_session_builder = 0; result = session_builder_create(&alice_session_builder, alice_store, &bob_address, global_context); ck_assert_int_eq(result, 0); /* Create Bob's data store and pre key bundle */ signal_protocol_store_context *bob_store = 0; setup_test_store_context(&bob_store, global_context); uint32_t bob_local_registration_id = 0; result = signal_protocol_identity_get_local_registration_id(bob_store, &bob_local_registration_id); ck_assert_int_eq(result, 0); ec_key_pair *bob_pre_key_pair = 0; result = curve_generate_key_pair(global_context, &bob_pre_key_pair); ck_assert_int_eq(result, 0); ec_key_pair *bob_signed_pre_key_pair = 0; result = curve_generate_key_pair(global_context, &bob_signed_pre_key_pair); ck_assert_int_eq(result, 0); ratchet_identity_key_pair *bob_identity_key_pair = 0; result = signal_protocol_identity_get_key_pair(bob_store, &bob_identity_key_pair); ck_assert_int_eq(result, 0); signal_buffer *bob_signed_pre_key_public_serialized = 0; result = ec_public_key_serialize(&bob_signed_pre_key_public_serialized, ec_key_pair_get_public(bob_signed_pre_key_pair)); ck_assert_int_eq(result, 0); signal_buffer *bob_signed_pre_key_signature = 0; result = curve_calculate_signature(global_context, &bob_signed_pre_key_signature, ratchet_identity_key_pair_get_private(bob_identity_key_pair), signal_buffer_data(bob_signed_pre_key_public_serialized), signal_buffer_len(bob_signed_pre_key_public_serialized)); ck_assert_int_eq(result, 0); session_pre_key_bundle *bob_pre_key = 0; result = session_pre_key_bundle_create(&bob_pre_key, bob_local_registration_id, 1, /* device ID */ 31337, /* pre key ID */ ec_key_pair_get_public(bob_pre_key_pair), 22, /* signed pre key ID */ ec_key_pair_get_public(bob_signed_pre_key_pair), signal_buffer_data(bob_signed_pre_key_signature), signal_buffer_len(bob_signed_pre_key_signature), ratchet_identity_key_pair_get_public(bob_identity_key_pair)); ck_assert_int_eq(result, 0); signal_buffer_free(bob_signed_pre_key_public_serialized); /* Have Alice process Bob's pre key bundle */ result = session_builder_process_pre_key_bundle(alice_session_builder, bob_pre_key); ck_assert_int_eq(result, 0); /* Check that we can load the session state and verify its version */ result = signal_protocol_session_contains_session(alice_store, &bob_address); ck_assert_int_eq(result, 1); session_record *loaded_record = 0; session_state *loaded_record_state = 0; result = signal_protocol_session_load_session(alice_store, &loaded_record, &bob_address); ck_assert_int_eq(result, 0); loaded_record_state = session_record_get_state(loaded_record); ck_assert_ptr_ne(loaded_record_state, 0); ck_assert_int_eq(session_state_get_session_version(loaded_record_state), 3); SIGNAL_UNREF(loaded_record); loaded_record = 0; loaded_record_state = 0; /* Encrypt an outgoing message to send to Bob */ static const char original_message[] = "L'homme est condamné à être libre"; size_t original_message_len = sizeof(original_message) - 1; session_cipher *alice_session_cipher = 0; result = session_cipher_create(&alice_session_cipher, alice_store, &bob_address, global_context); ck_assert_int_eq(result, 0); ciphertext_message *outgoing_message = 0; result = session_cipher_encrypt(alice_session_cipher, (uint8_t *)original_message, original_message_len, &outgoing_message); ck_assert_int_eq(result, 0); ck_assert_int_eq(ciphertext_message_get_type(outgoing_message), CIPHERTEXT_PREKEY_TYPE); /* Convert to an incoming message for Bob */ signal_buffer *outgoing_serialized = ciphertext_message_get_serialized(outgoing_message); pre_key_signal_message *incoming_message = 0; result = pre_key_signal_message_deserialize(&incoming_message, signal_buffer_data(outgoing_serialized), signal_buffer_len(outgoing_serialized), global_context); ck_assert_int_eq(result, 0); /* Save the pre key and signed pre key in Bob's data store */ session_pre_key *bob_pre_key_record = 0; result = session_pre_key_create(&bob_pre_key_record, session_pre_key_bundle_get_pre_key_id(bob_pre_key), bob_pre_key_pair); ck_assert_int_eq(result, 0); result = signal_protocol_pre_key_store_key(bob_store, bob_pre_key_record); ck_assert_int_eq(result, 0); session_signed_pre_key *bob_signed_pre_key_record = 0; result = session_signed_pre_key_create(&bob_signed_pre_key_record, 22, time(0), bob_signed_pre_key_pair, signal_buffer_data(bob_signed_pre_key_signature), signal_buffer_len(bob_signed_pre_key_signature)); ck_assert_int_eq(result, 0); result = signal_protocol_signed_pre_key_store_key(bob_store, bob_signed_pre_key_record); ck_assert_int_eq(result, 0); /* Create Bob's session cipher and decrypt the message from Alice */ session_cipher *bob_session_cipher = 0; result = session_cipher_create(&bob_session_cipher, bob_store, &alice_address, global_context); ck_assert_int_eq(result, 0); /* Prepare the data for the callback test */ int callback_context = 1234; test_basic_pre_key_v3_callback_data callback_data = { .original_message = original_message, .original_message_len = original_message_len, .bob_store = bob_store }; session_cipher_set_user_data(bob_session_cipher, &callback_data); session_cipher_set_decryption_callback(bob_session_cipher, test_basic_pre_key_v3_decrypt_callback); signal_buffer *plaintext = 0; result = session_cipher_decrypt_pre_key_signal_message(bob_session_cipher, incoming_message, &callback_context, &plaintext); ck_assert_int_eq(result, 0); /* Clean up callback data */ session_cipher_set_user_data(bob_session_cipher, 0); session_cipher_set_decryption_callback(bob_session_cipher, 0); /* Verify Bob's session state and the decrypted message */ ck_assert_int_eq(signal_protocol_session_contains_session(bob_store, &alice_address), 1); session_record *alice_recipient_session_record = 0; signal_protocol_session_load_session(bob_store, &alice_recipient_session_record, &alice_address); session_state *alice_recipient_session_state = session_record_get_state(alice_recipient_session_record); ck_assert_int_eq(session_state_get_session_version(alice_recipient_session_state), 3); ck_assert_ptr_ne(session_state_get_alice_base_key(alice_recipient_session_state), 0); uint8_t *plaintext_data = signal_buffer_data(plaintext); size_t plaintext_len = signal_buffer_len(plaintext); ck_assert_int_eq(original_message_len, plaintext_len); ck_assert_int_eq(memcmp(original_message, plaintext_data, plaintext_len), 0); /* Have Bob send a reply to Alice */ ciphertext_message *bob_outgoing_message = 0; result = session_cipher_encrypt(bob_session_cipher, (uint8_t *)original_message, original_message_len, &bob_outgoing_message); ck_assert_int_eq(result, 0); ck_assert_int_eq(ciphertext_message_get_type(bob_outgoing_message), CIPHERTEXT_SIGNAL_TYPE); /* Verify that Alice can decrypt it */ signal_message *bob_outgoing_message_copy = 0; result = signal_message_copy(&bob_outgoing_message_copy, (signal_message *)bob_outgoing_message, global_context); ck_assert_int_eq(result, 0); signal_buffer *alice_plaintext = 0; result = session_cipher_decrypt_signal_message(alice_session_cipher, bob_outgoing_message_copy, 0, &alice_plaintext); ck_assert_int_eq(result, 0); uint8_t *alice_plaintext_data = signal_buffer_data(alice_plaintext); size_t alice_plaintext_len = signal_buffer_len(alice_plaintext); ck_assert_int_eq(original_message_len, alice_plaintext_len); ck_assert_int_eq(memcmp(original_message, alice_plaintext_data, alice_plaintext_len), 0); signal_buffer_free(alice_plaintext); alice_plaintext = 0; SIGNAL_UNREF(bob_outgoing_message); bob_outgoing_message = 0; SIGNAL_UNREF(bob_outgoing_message_copy); bob_outgoing_message_copy = 0; SIGNAL_UNREF(alice_recipient_session_record); alice_recipient_session_record = 0; signal_buffer_free(plaintext); plaintext = 0; SIGNAL_UNREF(incoming_message); incoming_message = 0; SIGNAL_UNREF(outgoing_message); outgoing_message = 0; SIGNAL_UNREF(bob_pre_key); bob_pre_key = 0; session_cipher_free(alice_session_cipher); alice_session_cipher = 0; session_builder_free(alice_session_builder); alice_session_builder = 0; fprintf(stderr, "Pre-interaction tests complete\n"); /* Interaction tests */ run_interaction(alice_store, bob_store); /* Cleanup state from previous tests that we need to replace */ signal_protocol_store_context_destroy(alice_store); alice_store = 0; SIGNAL_UNREF(bob_pre_key_pair); bob_pre_key_pair = 0; SIGNAL_UNREF(bob_signed_pre_key_pair); bob_signed_pre_key_pair = 0; SIGNAL_UNREF(bob_identity_key_pair); bob_identity_key_pair = 0; signal_buffer_free(bob_signed_pre_key_signature); bob_signed_pre_key_signature = 0; SIGNAL_UNREF(bob_pre_key_record); bob_pre_key_record = 0; SIGNAL_UNREF(bob_signed_pre_key_record); bob_signed_pre_key_record = 0; /* Create Alice's new session data */ setup_test_store_context(&alice_store, global_context); result = session_builder_create(&alice_session_builder, alice_store, &bob_address, global_context); ck_assert_int_eq(result, 0); result = session_cipher_create(&alice_session_cipher, alice_store, &bob_address, global_context); ck_assert_int_eq(result, 0); /* Create Bob's new pre key bundle */ result = curve_generate_key_pair(global_context, &bob_pre_key_pair); ck_assert_int_eq(result, 0); result = curve_generate_key_pair(global_context, &bob_signed_pre_key_pair); ck_assert_int_eq(result, 0); result = signal_protocol_identity_get_key_pair(bob_store, &bob_identity_key_pair); ck_assert_int_eq(result, 0); result = ec_public_key_serialize(&bob_signed_pre_key_public_serialized, ec_key_pair_get_public(bob_signed_pre_key_pair)); ck_assert_int_eq(result, 0); result = curve_calculate_signature(global_context, &bob_signed_pre_key_signature, ratchet_identity_key_pair_get_private(bob_identity_key_pair), signal_buffer_data(bob_signed_pre_key_public_serialized), signal_buffer_len(bob_signed_pre_key_public_serialized)); ck_assert_int_eq(result, 0); result = session_pre_key_bundle_create(&bob_pre_key, bob_local_registration_id, 1, /* device ID */ 31338, /* pre key ID */ ec_key_pair_get_public(bob_pre_key_pair), 23, /* signed pre key ID */ ec_key_pair_get_public(bob_signed_pre_key_pair), signal_buffer_data(bob_signed_pre_key_signature), signal_buffer_len(bob_signed_pre_key_signature), ratchet_identity_key_pair_get_public(bob_identity_key_pair)); ck_assert_int_eq(result, 0); signal_buffer_free(bob_signed_pre_key_public_serialized); /* Save the new pre key and signed pre key in Bob's data store */ result = session_pre_key_create(&bob_pre_key_record, session_pre_key_bundle_get_pre_key_id(bob_pre_key), bob_pre_key_pair); ck_assert_int_eq(result, 0); result = signal_protocol_pre_key_store_key(bob_store, bob_pre_key_record); ck_assert_int_eq(result, 0); result = session_signed_pre_key_create(&bob_signed_pre_key_record, 23, time(0), bob_signed_pre_key_pair, signal_buffer_data(bob_signed_pre_key_signature), signal_buffer_len(bob_signed_pre_key_signature)); ck_assert_int_eq(result, 0); result = signal_protocol_signed_pre_key_store_key(bob_store, bob_signed_pre_key_record); ck_assert_int_eq(result, 0); /* Have Alice process Bob's pre key bundle */ result = session_builder_process_pre_key_bundle(alice_session_builder, bob_pre_key); ck_assert_int_eq(result, 0); /* Have Alice encrypt a message for Bob */ result = session_cipher_encrypt(alice_session_cipher, (uint8_t *)original_message, original_message_len, &outgoing_message); ck_assert_int_eq(result, 0); ck_assert_int_eq(ciphertext_message_get_type(outgoing_message), CIPHERTEXT_PREKEY_TYPE); /* Have Bob try to decrypt the message */ pre_key_signal_message *outgoing_message_copy = 0; result = pre_key_signal_message_copy(&outgoing_message_copy, (pre_key_signal_message *)outgoing_message, global_context); ck_assert_int_eq(result, 0); /* The decrypt should fail with a specific error */ result = session_cipher_decrypt_pre_key_signal_message(bob_session_cipher, outgoing_message_copy, 0, &plaintext); ck_assert_int_eq(result, SG_ERR_UNTRUSTED_IDENTITY); SIGNAL_UNREF(outgoing_message_copy); outgoing_message_copy = 0; signal_buffer_free(plaintext); plaintext = 0; result = pre_key_signal_message_copy(&outgoing_message_copy, (pre_key_signal_message *)outgoing_message, global_context); ck_assert_int_eq(result, 0); /* Save the identity key to Bob's store */ result = signal_protocol_identity_save_identity(bob_store, &alice_address, pre_key_signal_message_get_identity_key(outgoing_message_copy)); ck_assert_int_eq(result, 0); SIGNAL_UNREF(outgoing_message_copy); outgoing_message_copy = 0; /* Try the decrypt again, this time it should succeed */ result = pre_key_signal_message_copy(&outgoing_message_copy, (pre_key_signal_message *)outgoing_message, global_context); ck_assert_int_eq(result, 0); result = session_cipher_decrypt_pre_key_signal_message(bob_session_cipher, outgoing_message_copy, 0, &plaintext); ck_assert_int_eq(result, SG_SUCCESS); SIGNAL_UNREF(outgoing_message_copy); outgoing_message_copy = 0; plaintext_data = signal_buffer_data(plaintext); plaintext_len = signal_buffer_len(plaintext); ck_assert_int_eq(original_message_len, plaintext_len); ck_assert_int_eq(memcmp(original_message, plaintext_data, plaintext_len), 0); SIGNAL_UNREF(bob_pre_key); bob_pre_key = 0; /* Create a new pre key for Bob */ ec_public_key *test_public_key = create_test_ec_public_key(global_context); ratchet_identity_key_pair *alice_identity_key_pair = 0; result = signal_protocol_identity_get_key_pair(alice_store, &alice_identity_key_pair); ck_assert_int_eq(result, 0); result = session_pre_key_bundle_create(&bob_pre_key, bob_local_registration_id, 1, /* device ID */ 31337, /* pre key ID */ test_public_key, 23, /* signed pre key ID */ ec_key_pair_get_public(bob_signed_pre_key_pair), signal_buffer_data(bob_signed_pre_key_signature), signal_buffer_len(bob_signed_pre_key_signature), ratchet_identity_key_pair_get_public(alice_identity_key_pair)); ck_assert_int_eq(result, 0); /* Have Alice process Bob's new pre key bundle, which should fail */ result = session_builder_process_pre_key_bundle(alice_session_builder, bob_pre_key); ck_assert_int_eq(result, SG_ERR_UNTRUSTED_IDENTITY); fprintf(stderr, "Post-interaction tests complete\n"); /* Cleanup */ SIGNAL_UNREF(alice_identity_key_pair); SIGNAL_UNREF(test_public_key); SIGNAL_UNREF(bob_pre_key); signal_buffer_free(plaintext); SIGNAL_UNREF(outgoing_message); SIGNAL_UNREF(outgoing_message_copy); SIGNAL_UNREF(bob_signed_pre_key_record); SIGNAL_UNREF(bob_pre_key_record); signal_buffer_free(bob_signed_pre_key_signature); SIGNAL_UNREF(bob_pre_key_pair); SIGNAL_UNREF(bob_signed_pre_key_pair); SIGNAL_UNREF(bob_identity_key_pair); session_cipher_free(bob_session_cipher); signal_protocol_store_context_destroy(bob_store); session_builder_free(alice_session_builder); session_cipher_free(alice_session_cipher); signal_protocol_store_context_destroy(alice_store); } END_TEST int test_basic_pre_key_v3_decrypt_callback(session_cipher *cipher, signal_buffer *plaintext, void *decrypt_context) { test_basic_pre_key_v3_callback_data *callback_data = session_cipher_get_user_data(cipher); int callback_context = *(int*)decrypt_context; /* Make sure we got the same decrypt context value we passed in */ ck_assert_int_eq(callback_context, 1234); /* Verify that the plaintext matches what we expected */ uint8_t *plaintext_data = signal_buffer_data(plaintext); size_t plaintext_len = signal_buffer_len(plaintext); ck_assert_int_eq(callback_data->original_message_len, plaintext_len); ck_assert_int_eq(memcmp(callback_data->original_message, plaintext_data, plaintext_len), 0); /* Verify that Bob's session state has not yet been updated */ ck_assert_int_eq(signal_protocol_session_contains_session(callback_data->bob_store, &alice_address), 0); return 0; } START_TEST(test_bad_signed_pre_key_signature) { int result = 0; /* Create Alice's data store and session builder */ signal_protocol_store_context *alice_store = 0; setup_test_store_context(&alice_store, global_context); session_builder *alice_session_builder = 0; result = session_builder_create(&alice_session_builder, alice_store, &bob_address, global_context); ck_assert_int_eq(result, 0); /* Create Bob's data store */ signal_protocol_store_context *bob_store = 0; setup_test_store_context(&bob_store, global_context); uint32_t bob_local_registration_id = 0; result = signal_protocol_identity_get_local_registration_id(bob_store, &bob_local_registration_id); ck_assert_int_eq(result, 0); /* Create Bob's regular and signed pre key pairs */ ec_key_pair *bob_pre_key_pair = 0; result = curve_generate_key_pair(global_context, &bob_pre_key_pair); ck_assert_int_eq(result, 0); ec_key_pair *bob_signed_pre_key_pair = 0; result = curve_generate_key_pair(global_context, &bob_signed_pre_key_pair); ck_assert_int_eq(result, 0); /* Create Bob's signed pre key signature */ ratchet_identity_key_pair *bob_identity_key_pair = 0; result = signal_protocol_identity_get_key_pair(bob_store, &bob_identity_key_pair); ck_assert_int_eq(result, 0); signal_buffer *bob_signed_pre_key_public_serialized = 0; result = ec_public_key_serialize(&bob_signed_pre_key_public_serialized, ec_key_pair_get_public(bob_signed_pre_key_pair)); ck_assert_int_eq(result, 0); signal_buffer *bob_signed_pre_key_signature = 0; result = curve_calculate_signature(global_context, &bob_signed_pre_key_signature, ratchet_identity_key_pair_get_private(bob_identity_key_pair), signal_buffer_data(bob_signed_pre_key_public_serialized), signal_buffer_len(bob_signed_pre_key_public_serialized)); ck_assert_int_eq(result, 0); size_t signature_len = signal_buffer_len(bob_signed_pre_key_signature); int i; for(i = 0; i < signature_len * 8; i++) { signal_buffer *modified_signature = signal_buffer_copy(bob_signed_pre_key_signature); uint8_t *modified_signature_data = signal_buffer_data(modified_signature); /* Intentionally corrupt the signature data */ modified_signature_data[i / 8] ^= (0x01 << ((uint8_t)i % 8)); /* Create a pre key bundle */ session_pre_key_bundle *bob_pre_key = 0; result = session_pre_key_bundle_create(&bob_pre_key, bob_local_registration_id, 1, /* device ID */ 31337, /* pre key ID */ ec_key_pair_get_public(bob_pre_key_pair), 22, /* signed pre key ID */ ec_key_pair_get_public(bob_signed_pre_key_pair), modified_signature_data, signature_len, ratchet_identity_key_pair_get_public(bob_identity_key_pair)); ck_assert_int_eq(result, 0); /* Process the bundle and make sure we fail with an invalid key error */ result = session_builder_process_pre_key_bundle(alice_session_builder, bob_pre_key); ck_assert_int_eq(result, SG_ERR_INVALID_KEY); signal_buffer_free(modified_signature); SIGNAL_UNREF(bob_pre_key); } /* Create a correct pre key bundle */ session_pre_key_bundle *bob_pre_key = 0; result = session_pre_key_bundle_create(&bob_pre_key, bob_local_registration_id, 1, /* device ID */ 31337, /* pre key ID */ ec_key_pair_get_public(bob_pre_key_pair), 22, /* signed pre key ID */ ec_key_pair_get_public(bob_signed_pre_key_pair), signal_buffer_data(bob_signed_pre_key_signature), signature_len, ratchet_identity_key_pair_get_public(bob_identity_key_pair)); ck_assert_int_eq(result, 0); /* Process the bundle and make sure we do not fail */ result = session_builder_process_pre_key_bundle(alice_session_builder, bob_pre_key); ck_assert_int_eq(result, SG_SUCCESS); /* Cleanup */ SIGNAL_UNREF(bob_pre_key); SIGNAL_UNREF(bob_pre_key_pair); SIGNAL_UNREF(bob_signed_pre_key_pair); SIGNAL_UNREF(bob_identity_key_pair); signal_buffer_free(bob_signed_pre_key_signature); signal_buffer_free(bob_signed_pre_key_public_serialized); session_builder_free(alice_session_builder); signal_protocol_store_context_destroy(alice_store); signal_protocol_store_context_destroy(bob_store); } END_TEST START_TEST(test_repeat_bundle_message_v2) { int result = 0; /* Create Alice's data store and session builder */ signal_protocol_store_context *alice_store = 0; setup_test_store_context(&alice_store, global_context); session_builder *alice_session_builder = 0; result = session_builder_create(&alice_session_builder, alice_store, &bob_address, global_context); ck_assert_int_eq(result, 0); /* Create Bob's data store and pre key bundle */ signal_protocol_store_context *bob_store = 0; setup_test_store_context(&bob_store, global_context); uint32_t bob_local_registration_id = 0; result = signal_protocol_identity_get_local_registration_id(bob_store, &bob_local_registration_id); ck_assert_int_eq(result, 0); ec_key_pair *bob_pre_key_pair = 0; result = curve_generate_key_pair(global_context, &bob_pre_key_pair); ck_assert_int_eq(result, 0); ec_key_pair *bob_signed_pre_key_pair = 0; result = curve_generate_key_pair(global_context, &bob_signed_pre_key_pair); ck_assert_int_eq(result, 0); ratchet_identity_key_pair *bob_identity_key_pair = 0; result = signal_protocol_identity_get_key_pair(bob_store, &bob_identity_key_pair); ck_assert_int_eq(result, 0); signal_buffer *bob_signed_pre_key_public_serialized = 0; result = ec_public_key_serialize(&bob_signed_pre_key_public_serialized, ec_key_pair_get_public(bob_signed_pre_key_pair)); ck_assert_int_eq(result, 0); signal_buffer *bob_signed_pre_key_signature = 0; result = curve_calculate_signature(global_context, &bob_signed_pre_key_signature, ratchet_identity_key_pair_get_private(bob_identity_key_pair), signal_buffer_data(bob_signed_pre_key_public_serialized), signal_buffer_len(bob_signed_pre_key_public_serialized)); ck_assert_int_eq(result, 0); session_pre_key_bundle *bob_pre_key = 0; result = session_pre_key_bundle_create(&bob_pre_key, bob_local_registration_id, 1, /* device ID */ 31337, /* pre key ID */ ec_key_pair_get_public(bob_pre_key_pair), 0, 0, 0, 0, ratchet_identity_key_pair_get_public(bob_identity_key_pair)); ck_assert_int_eq(result, 0); /* Add Bob's pre keys to Bob's data store */ session_pre_key *bob_pre_key_record = 0; result = session_pre_key_create(&bob_pre_key_record, session_pre_key_bundle_get_pre_key_id(bob_pre_key), bob_pre_key_pair); ck_assert_int_eq(result, 0); result = signal_protocol_pre_key_store_key(bob_store, bob_pre_key_record); ck_assert_int_eq(result, 0); session_signed_pre_key *bob_signed_pre_key_record = 0; result = session_signed_pre_key_create(&bob_signed_pre_key_record, 22, time(0), bob_signed_pre_key_pair, signal_buffer_data(bob_signed_pre_key_signature), signal_buffer_len(bob_signed_pre_key_signature)); ck_assert_int_eq(result, 0); result = signal_protocol_signed_pre_key_store_key(bob_store, bob_signed_pre_key_record); ck_assert_int_eq(result, 0); /* * Have Alice process Bob's pre key bundle, which should fail due to a * missing signed pre key. */ result = session_builder_process_pre_key_bundle(alice_session_builder, bob_pre_key); ck_assert_int_eq(result, SG_ERR_INVALID_KEY); /* Cleanup */ signal_buffer_free(bob_signed_pre_key_public_serialized); signal_buffer_free(bob_signed_pre_key_signature); SIGNAL_UNREF(bob_pre_key); SIGNAL_UNREF(bob_signed_pre_key_record); SIGNAL_UNREF(bob_pre_key_record); SIGNAL_UNREF(bob_pre_key_pair); SIGNAL_UNREF(bob_signed_pre_key_pair); SIGNAL_UNREF(bob_identity_key_pair); session_builder_free(alice_session_builder); signal_protocol_store_context_destroy(alice_store); signal_protocol_store_context_destroy(bob_store); } END_TEST START_TEST(test_repeat_bundle_message_v3) { int result = 0; /* Create Alice's data store and session builder */ signal_protocol_store_context *alice_store = 0; setup_test_store_context(&alice_store, global_context); session_builder *alice_session_builder = 0; result = session_builder_create(&alice_session_builder, alice_store, &bob_address, global_context); ck_assert_int_eq(result, 0); /* Create Bob's data store and pre key bundle */ signal_protocol_store_context *bob_store = 0; setup_test_store_context(&bob_store, global_context); uint32_t bob_local_registration_id = 0; result = signal_protocol_identity_get_local_registration_id(bob_store, &bob_local_registration_id); ck_assert_int_eq(result, 0); ec_key_pair *bob_pre_key_pair = 0; result = curve_generate_key_pair(global_context, &bob_pre_key_pair); ck_assert_int_eq(result, 0); ec_key_pair *bob_signed_pre_key_pair = 0; result = curve_generate_key_pair(global_context, &bob_signed_pre_key_pair); ck_assert_int_eq(result, 0); ratchet_identity_key_pair *bob_identity_key_pair = 0; result = signal_protocol_identity_get_key_pair(bob_store, &bob_identity_key_pair); ck_assert_int_eq(result, 0); signal_buffer *bob_signed_pre_key_public_serialized = 0; result = ec_public_key_serialize(&bob_signed_pre_key_public_serialized, ec_key_pair_get_public(bob_signed_pre_key_pair)); ck_assert_int_eq(result, 0); signal_buffer *bob_signed_pre_key_signature = 0; result = curve_calculate_signature(global_context, &bob_signed_pre_key_signature, ratchet_identity_key_pair_get_private(bob_identity_key_pair), signal_buffer_data(bob_signed_pre_key_public_serialized), signal_buffer_len(bob_signed_pre_key_public_serialized)); ck_assert_int_eq(result, 0); session_pre_key_bundle *bob_pre_key = 0; result = session_pre_key_bundle_create(&bob_pre_key, bob_local_registration_id, 1, /* device ID */ 31337, /* pre key ID */ ec_key_pair_get_public(bob_pre_key_pair), 22, /* signed pre key ID */ ec_key_pair_get_public(bob_signed_pre_key_pair), signal_buffer_data(bob_signed_pre_key_signature), signal_buffer_len(bob_signed_pre_key_signature), ratchet_identity_key_pair_get_public(bob_identity_key_pair)); ck_assert_int_eq(result, 0); /* Add Bob's pre keys to Bob's data store */ session_pre_key *bob_pre_key_record = 0; result = session_pre_key_create(&bob_pre_key_record, session_pre_key_bundle_get_pre_key_id(bob_pre_key), bob_pre_key_pair); ck_assert_int_eq(result, 0); result = signal_protocol_pre_key_store_key(bob_store, bob_pre_key_record); ck_assert_int_eq(result, 0); session_signed_pre_key *bob_signed_pre_key_record = 0; result = session_signed_pre_key_create(&bob_signed_pre_key_record, 22, time(0), bob_signed_pre_key_pair, signal_buffer_data(bob_signed_pre_key_signature), signal_buffer_len(bob_signed_pre_key_signature)); ck_assert_int_eq(result, 0); result = signal_protocol_signed_pre_key_store_key(bob_store, bob_signed_pre_key_record); ck_assert_int_eq(result, 0); /* Have Alice process Bob's pre key bundle */ result = session_builder_process_pre_key_bundle(alice_session_builder, bob_pre_key); ck_assert_int_eq(result, 0); /* Initialize Alice's session cipher */ static const char original_message[] = "L'homme est condamné à être libre"; size_t original_message_len = sizeof(original_message) - 1; session_cipher *alice_session_cipher = 0; result = session_cipher_create(&alice_session_cipher, alice_store, &bob_address, global_context); ck_assert_int_eq(result, 0); /* Create two outgoing messages */ ciphertext_message *outgoing_message_one = 0; result = session_cipher_encrypt(alice_session_cipher, (uint8_t *)original_message, original_message_len, &outgoing_message_one); ck_assert_int_eq(result, 0); ciphertext_message *outgoing_message_two = 0; result = session_cipher_encrypt(alice_session_cipher, (uint8_t *)original_message, original_message_len, &outgoing_message_two); ck_assert_int_eq(result, 0); ck_assert_int_eq(ciphertext_message_get_type(outgoing_message_one), CIPHERTEXT_PREKEY_TYPE); ck_assert_int_eq(ciphertext_message_get_type(outgoing_message_two), CIPHERTEXT_PREKEY_TYPE); /* Copy to an incoming message */ pre_key_signal_message *incoming_message = 0; result = pre_key_signal_message_copy(&incoming_message, (pre_key_signal_message *)outgoing_message_one, global_context); ck_assert_int_eq(result, 0); /* Create Bob's session cipher */ session_cipher *bob_session_cipher = 0; result = session_cipher_create(&bob_session_cipher, bob_store, &alice_address, global_context); ck_assert_int_eq(result, 0); /* Have Bob decrypt the message, and verify that it matches */ signal_buffer *plaintext = 0; result = session_cipher_decrypt_pre_key_signal_message(bob_session_cipher, incoming_message, 0, &plaintext); ck_assert_int_eq(result, 0); uint8_t *plaintext_data = signal_buffer_data(plaintext); size_t plaintext_len = signal_buffer_len(plaintext); ck_assert_int_eq(original_message_len, plaintext_len); ck_assert_int_eq(memcmp(original_message, plaintext_data, plaintext_len), 0); signal_buffer_free(plaintext); plaintext = 0; /* Construct an outgoing message from Bob back to Alice */ ciphertext_message *bob_outgoing_message = 0; result = session_cipher_encrypt(bob_session_cipher, (uint8_t *)original_message, original_message_len, &bob_outgoing_message); ck_assert_int_eq(result, 0); /* Have Alice decrypt the message, and verify that it matches */ signal_message *bob_outgoing_message_copy = 0; result = signal_message_copy(&bob_outgoing_message_copy, (signal_message *)bob_outgoing_message, global_context); ck_assert_int_eq(result, 0); result = session_cipher_decrypt_signal_message(alice_session_cipher, bob_outgoing_message_copy, 0, &plaintext); ck_assert_int_eq(result, 0); plaintext_data = signal_buffer_data(plaintext); plaintext_len = signal_buffer_len(plaintext); ck_assert_int_eq(original_message_len, plaintext_len); ck_assert_int_eq(memcmp(original_message, plaintext_data, plaintext_len), 0); signal_buffer_free(plaintext); plaintext = 0; fprintf(stderr, "Test setup complete\n"); /* The Test */ pre_key_signal_message *incoming_message_two = 0; result = pre_key_signal_message_copy(&incoming_message_two, (pre_key_signal_message *)outgoing_message_two, global_context); result = session_cipher_decrypt_pre_key_signal_message(bob_session_cipher, incoming_message_two, 0, &plaintext); ck_assert_int_eq(result, 0); plaintext_data = signal_buffer_data(plaintext); plaintext_len = signal_buffer_len(plaintext); ck_assert_int_eq(original_message_len, plaintext_len); ck_assert_int_eq(memcmp(original_message, plaintext_data, plaintext_len), 0); signal_buffer_free(plaintext); plaintext = 0; ciphertext_message *bob_outgoing_message_two = 0; result = session_cipher_encrypt(bob_session_cipher, (uint8_t *)original_message, original_message_len, &bob_outgoing_message_two); ck_assert_int_eq(result, 0); signal_message *bob_outgoing_message_two_copy = 0; result = signal_message_copy(&bob_outgoing_message_two_copy, (signal_message *)bob_outgoing_message_two, global_context); ck_assert_int_eq(result, 0); result = session_cipher_decrypt_signal_message(alice_session_cipher, bob_outgoing_message_two_copy, 0, &plaintext); ck_assert_int_eq(result, 0); plaintext_data = signal_buffer_data(plaintext); plaintext_len = signal_buffer_len(plaintext); ck_assert_int_eq(original_message_len, plaintext_len); ck_assert_int_eq(memcmp(original_message, plaintext_data, plaintext_len), 0); signal_buffer_free(plaintext); plaintext = 0; fprintf(stderr, "Test process complete\n"); /* Cleanup */ SIGNAL_UNREF(bob_outgoing_message_two_copy); SIGNAL_UNREF(bob_outgoing_message_two); SIGNAL_UNREF(incoming_message_two); SIGNAL_UNREF(bob_outgoing_message_copy); SIGNAL_UNREF(bob_outgoing_message); SIGNAL_UNREF(incoming_message); SIGNAL_UNREF(outgoing_message_one); SIGNAL_UNREF(outgoing_message_two); session_cipher_free(alice_session_cipher); session_cipher_free(bob_session_cipher); signal_buffer_free(bob_signed_pre_key_public_serialized); signal_buffer_free(bob_signed_pre_key_signature); SIGNAL_UNREF(bob_pre_key); SIGNAL_UNREF(bob_signed_pre_key_record); SIGNAL_UNREF(bob_pre_key_record); SIGNAL_UNREF(bob_pre_key_pair); SIGNAL_UNREF(bob_signed_pre_key_pair); SIGNAL_UNREF(bob_identity_key_pair); session_builder_free(alice_session_builder); signal_protocol_store_context_destroy(alice_store); signal_protocol_store_context_destroy(bob_store); } END_TEST START_TEST(test_bad_message_bundle) { int result = 0; /* Create Alice's data store and session builder */ signal_protocol_store_context *alice_store = 0; setup_test_store_context(&alice_store, global_context); session_builder *alice_session_builder = 0; result = session_builder_create(&alice_session_builder, alice_store, &bob_address, global_context); ck_assert_int_eq(result, 0); /* Create Bob's data store and pre key bundle */ signal_protocol_store_context *bob_store = 0; setup_test_store_context(&bob_store, global_context); uint32_t bob_local_registration_id = 0; result = signal_protocol_identity_get_local_registration_id(bob_store, &bob_local_registration_id); ck_assert_int_eq(result, 0); ec_key_pair *bob_pre_key_pair = 0; result = curve_generate_key_pair(global_context, &bob_pre_key_pair); ck_assert_int_eq(result, 0); ec_key_pair *bob_signed_pre_key_pair = 0; result = curve_generate_key_pair(global_context, &bob_signed_pre_key_pair); ck_assert_int_eq(result, 0); ratchet_identity_key_pair *bob_identity_key_pair = 0; result = signal_protocol_identity_get_key_pair(bob_store, &bob_identity_key_pair); ck_assert_int_eq(result, 0); signal_buffer *bob_signed_pre_key_public_serialized = 0; result = ec_public_key_serialize(&bob_signed_pre_key_public_serialized, ec_key_pair_get_public(bob_signed_pre_key_pair)); ck_assert_int_eq(result, 0); signal_buffer *bob_signed_pre_key_signature = 0; result = curve_calculate_signature(global_context, &bob_signed_pre_key_signature, ratchet_identity_key_pair_get_private(bob_identity_key_pair), signal_buffer_data(bob_signed_pre_key_public_serialized), signal_buffer_len(bob_signed_pre_key_public_serialized)); ck_assert_int_eq(result, 0); session_pre_key_bundle *bob_pre_key = 0; result = session_pre_key_bundle_create(&bob_pre_key, bob_local_registration_id, 1, /* device ID */ 31337, /* pre key ID */ ec_key_pair_get_public(bob_pre_key_pair), 22, /* signed pre key ID */ ec_key_pair_get_public(bob_signed_pre_key_pair), signal_buffer_data(bob_signed_pre_key_signature), signal_buffer_len(bob_signed_pre_key_signature), ratchet_identity_key_pair_get_public(bob_identity_key_pair)); ck_assert_int_eq(result, 0); /* Add Bob's pre keys to Bob's data store */ session_pre_key *bob_pre_key_record = 0; result = session_pre_key_create(&bob_pre_key_record, session_pre_key_bundle_get_pre_key_id(bob_pre_key), bob_pre_key_pair); ck_assert_int_eq(result, 0); result = signal_protocol_pre_key_store_key(bob_store, bob_pre_key_record); ck_assert_int_eq(result, 0); session_signed_pre_key *bob_signed_pre_key_record = 0; result = session_signed_pre_key_create(&bob_signed_pre_key_record, 22, time(0), bob_signed_pre_key_pair, signal_buffer_data(bob_signed_pre_key_signature), signal_buffer_len(bob_signed_pre_key_signature)); ck_assert_int_eq(result, 0); result = signal_protocol_signed_pre_key_store_key(bob_store, bob_signed_pre_key_record); ck_assert_int_eq(result, 0); /* Have Alice process Bob's pre key bundle */ result = session_builder_process_pre_key_bundle(alice_session_builder, bob_pre_key); ck_assert_int_eq(result, 0); /* Encrypt an outgoing message to send to Bob */ static const char original_message[] = "L'homme est condamné à être libre"; size_t original_message_len = sizeof(original_message) - 1; session_cipher *alice_session_cipher = 0; result = session_cipher_create(&alice_session_cipher, alice_store, &bob_address, global_context); ck_assert_int_eq(result, 0); ciphertext_message *outgoing_message_one = 0; result = session_cipher_encrypt(alice_session_cipher, (uint8_t *)original_message, original_message_len, &outgoing_message_one); ck_assert_int_eq(result, 0); ck_assert_int_eq(ciphertext_message_get_type(outgoing_message_one), CIPHERTEXT_PREKEY_TYPE); signal_buffer *good_message = ciphertext_message_get_serialized(outgoing_message_one); uint8_t *good_message_data = signal_buffer_data(good_message); size_t good_message_len = signal_buffer_len(good_message); signal_buffer *bad_message = signal_buffer_copy(good_message); uint8_t *bad_message_data = signal_buffer_data(bad_message); size_t bad_message_len = signal_buffer_len(bad_message); bad_message_data[bad_message_len - 10] ^= 0x01; pre_key_signal_message *incoming_message_bad = 0; result = pre_key_signal_message_deserialize(&incoming_message_bad, bad_message_data, bad_message_len, global_context); ck_assert_int_eq(result, 0); session_cipher *bob_session_cipher = 0; result = session_cipher_create(&bob_session_cipher, bob_store, &alice_address, global_context); ck_assert_int_eq(result, 0); /* Check that the decrypt fails with an invalid message error */ signal_buffer *plaintext = 0; result = session_cipher_decrypt_pre_key_signal_message(bob_session_cipher, incoming_message_bad, 0, &plaintext); ck_assert_int_eq(result, SG_ERR_INVALID_MESSAGE); signal_buffer_free(plaintext); plaintext = 0; /* Make sure the pre key is there */ result = signal_protocol_pre_key_contains_key(bob_store, 31337); ck_assert_int_eq(result, 1); /* Check that the decrypt succeeds with the good message */ pre_key_signal_message *incoming_message_good = 0; result = pre_key_signal_message_deserialize(&incoming_message_good, good_message_data, good_message_len, global_context); ck_assert_int_eq(result, 0); result = session_cipher_decrypt_pre_key_signal_message(bob_session_cipher, incoming_message_good, 0, &plaintext); ck_assert_int_eq(result, SG_SUCCESS); uint8_t *plaintext_data = signal_buffer_data(plaintext); size_t plaintext_len = signal_buffer_len(plaintext); ck_assert_int_eq(original_message_len, plaintext_len); ck_assert_int_eq(memcmp(original_message, plaintext_data, plaintext_len), 0); signal_buffer_free(plaintext); plaintext = 0; /* Make sure the pre key is no longer there */ result = signal_protocol_pre_key_contains_key(bob_store, 31337); ck_assert_int_eq(result, 0); /* Cleanup */ SIGNAL_UNREF(incoming_message_good); session_cipher_free(bob_session_cipher); SIGNAL_UNREF(incoming_message_bad); signal_buffer_free(bad_message); SIGNAL_UNREF(outgoing_message_one); session_cipher_free(alice_session_cipher); SIGNAL_UNREF(bob_pre_key); SIGNAL_UNREF(bob_pre_key_pair); SIGNAL_UNREF(bob_signed_pre_key_pair); SIGNAL_UNREF(bob_identity_key_pair); SIGNAL_UNREF(bob_signed_pre_key_record); SIGNAL_UNREF(bob_pre_key_record); signal_buffer_free(bob_signed_pre_key_public_serialized); signal_buffer_free(bob_signed_pre_key_signature); session_builder_free(alice_session_builder); signal_protocol_store_context_destroy(alice_store); signal_protocol_store_context_destroy(bob_store); } END_TEST START_TEST(test_optional_one_time_pre_key) { int result = 0; /* Create Alice's data store and session builder */ signal_protocol_store_context *alice_store = 0; setup_test_store_context(&alice_store, global_context); session_builder *alice_session_builder = 0; result = session_builder_create(&alice_session_builder, alice_store, &bob_address, global_context); ck_assert_int_eq(result, 0); /* Create Bob's data store and pre key bundle */ signal_protocol_store_context *bob_store = 0; setup_test_store_context(&bob_store, global_context); uint32_t bob_local_registration_id = 0; result = signal_protocol_identity_get_local_registration_id(bob_store, &bob_local_registration_id); ck_assert_int_eq(result, 0); ec_key_pair *bob_pre_key_pair = 0; result = curve_generate_key_pair(global_context, &bob_pre_key_pair); ck_assert_int_eq(result, 0); ec_key_pair *bob_signed_pre_key_pair = 0; result = curve_generate_key_pair(global_context, &bob_signed_pre_key_pair); ck_assert_int_eq(result, 0); ratchet_identity_key_pair *bob_identity_key_pair = 0; result = signal_protocol_identity_get_key_pair(bob_store, &bob_identity_key_pair); ck_assert_int_eq(result, 0); signal_buffer *bob_signed_pre_key_public_serialized = 0; result = ec_public_key_serialize(&bob_signed_pre_key_public_serialized, ec_key_pair_get_public(bob_signed_pre_key_pair)); ck_assert_int_eq(result, 0); signal_buffer *bob_signed_pre_key_signature = 0; result = curve_calculate_signature(global_context, &bob_signed_pre_key_signature, ratchet_identity_key_pair_get_private(bob_identity_key_pair), signal_buffer_data(bob_signed_pre_key_public_serialized), signal_buffer_len(bob_signed_pre_key_public_serialized)); ck_assert_int_eq(result, 0); session_pre_key_bundle *bob_pre_key = 0; result = session_pre_key_bundle_create(&bob_pre_key, bob_local_registration_id, 1, /* device ID */ 0, 0, 22, /* signed pre key ID */ ec_key_pair_get_public(bob_signed_pre_key_pair), signal_buffer_data(bob_signed_pre_key_signature), signal_buffer_len(bob_signed_pre_key_signature), ratchet_identity_key_pair_get_public(bob_identity_key_pair)); ck_assert_int_eq(result, 0); /* Have Alice process Bob's pre key bundle */ result = session_builder_process_pre_key_bundle(alice_session_builder, bob_pre_key); ck_assert_int_eq(result, 0); /* Find and verify the session version in Alice's store */ result = signal_protocol_session_contains_session(alice_store, &bob_address); ck_assert_int_eq(result, 1); session_record *record = 0; result = signal_protocol_session_load_session(alice_store, &record, &bob_address); ck_assert_int_eq(result, 0); session_state *state = 0; state = session_record_get_state(record); ck_assert_int_eq(session_state_get_session_version(state), 3); SIGNAL_UNREF(record); static const char original_message[] = "L'homme est condamné à être libre"; size_t original_message_len = sizeof(original_message) - 1; /* Create Alice's session cipher */ session_cipher *alice_session_cipher = 0; result = session_cipher_create(&alice_session_cipher, alice_store, &bob_address, global_context); ck_assert_int_eq(result, 0); /* Create an outgoing message */ ciphertext_message *outgoing_message = 0; result = session_cipher_encrypt(alice_session_cipher, (uint8_t *)original_message, original_message_len, &outgoing_message); ck_assert_int_eq(result, 0); ck_assert_int_eq(ciphertext_message_get_type(outgoing_message), CIPHERTEXT_PREKEY_TYPE); /* Convert to an incoming message */ pre_key_signal_message *incoming_message = 0; result = pre_key_signal_message_copy(&incoming_message, (pre_key_signal_message *)outgoing_message, global_context); ck_assert_int_eq(result, 0); /* Make sure the pre key ID is not present */ ck_assert_int_eq(pre_key_signal_message_has_pre_key_id(incoming_message), 0); /* Add Bob's pre keys to Bob's data store */ session_pre_key *bob_pre_key_record = 0; result = session_pre_key_create(&bob_pre_key_record, session_pre_key_bundle_get_pre_key_id(bob_pre_key), bob_pre_key_pair); ck_assert_int_eq(result, 0); result = signal_protocol_pre_key_store_key(bob_store, bob_pre_key_record); ck_assert_int_eq(result, 0); session_signed_pre_key *bob_signed_pre_key_record = 0; result = session_signed_pre_key_create(&bob_signed_pre_key_record, 22, time(0), bob_signed_pre_key_pair, signal_buffer_data(bob_signed_pre_key_signature), signal_buffer_len(bob_signed_pre_key_signature)); ck_assert_int_eq(result, 0); result = signal_protocol_signed_pre_key_store_key(bob_store, bob_signed_pre_key_record); ck_assert_int_eq(result, 0); /* Create Bob's session cipher */ session_cipher *bob_session_cipher = 0; result = session_cipher_create(&bob_session_cipher, bob_store, &alice_address, global_context); ck_assert_int_eq(result, 0); signal_buffer *plaintext = 0; result = session_cipher_decrypt_pre_key_signal_message(bob_session_cipher, incoming_message, 0, &plaintext); ck_assert_int_eq(result, 0); ck_assert_int_eq(signal_protocol_session_contains_session(bob_store, &alice_address), 1); result = signal_protocol_session_load_session(bob_store, &record, &alice_address); ck_assert_int_eq(result, 0); state = session_record_get_state(record); ck_assert_int_eq(session_state_get_session_version(state), 3); ck_assert_ptr_ne(session_state_get_alice_base_key(state), 0); uint8_t *plaintext_data = signal_buffer_data(plaintext); size_t plaintext_len = signal_buffer_len(plaintext); ck_assert_int_eq(original_message_len, plaintext_len); ck_assert_int_eq(memcmp(original_message, plaintext_data, plaintext_len), 0); signal_buffer_free(plaintext); plaintext = 0; SIGNAL_UNREF(record); /* Cleanup */ signal_buffer_free(plaintext); session_cipher_free(bob_session_cipher); SIGNAL_UNREF(bob_signed_pre_key_record); SIGNAL_UNREF(bob_pre_key_record); SIGNAL_UNREF(incoming_message); SIGNAL_UNREF(outgoing_message); session_cipher_free(alice_session_cipher); SIGNAL_UNREF(bob_pre_key); SIGNAL_UNREF(bob_pre_key_pair); SIGNAL_UNREF(bob_signed_pre_key_pair); SIGNAL_UNREF(bob_identity_key_pair); signal_buffer_free(bob_signed_pre_key_public_serialized); signal_buffer_free(bob_signed_pre_key_signature); session_builder_free(alice_session_builder); signal_protocol_store_context_destroy(alice_store); signal_protocol_store_context_destroy(bob_store); } END_TEST signal_buffer *create_looping_message(int index) { static const char looping_message[] = "You can only desire based on what you know: "; signal_buffer *buffer = signal_buffer_create((uint8_t *)looping_message, sizeof(looping_message) - 1); uint8_t *data = signal_buffer_data(buffer); size_t len = signal_buffer_len(buffer); data[len - 1] = (uint8_t)index; return buffer; } signal_buffer *create_looping_message_short(int index) { static const char looping_message[] = "What do we mean by saying that existence precedes essence? " "We mean that man first of all exists, encounters himself, " "surges up in the world--and defines himself aftward. "; signal_buffer *buffer = signal_buffer_create((uint8_t *)looping_message, sizeof(looping_message) - 1); uint8_t *data = signal_buffer_data(buffer); size_t len = signal_buffer_len(buffer); data[len - 1] = (uint8_t)index; return buffer; } void run_interaction(signal_protocol_store_context *alice_store, signal_protocol_store_context *bob_store) { int result = 0; /* Create the session ciphers */ session_cipher *alice_session_cipher = 0; result = session_cipher_create(&alice_session_cipher, alice_store, &bob_address, global_context); ck_assert_int_eq(result, 0); session_cipher *bob_session_cipher = 0; result = session_cipher_create(&bob_session_cipher, bob_store, &alice_address, global_context); ck_assert_int_eq(result, 0); /* Create a test message */ static const char original_message[] = "smert ze smert"; size_t original_message_len = sizeof(original_message) - 1; /* Simulate Alice sending a message to Bob */ ciphertext_message *alice_message = 0; result = session_cipher_encrypt(alice_session_cipher, (uint8_t *)original_message, original_message_len, &alice_message); ck_assert_int_eq(result, 0); ck_assert_int_eq(ciphertext_message_get_type(alice_message), CIPHERTEXT_SIGNAL_TYPE); signal_message *alice_message_copy = 0; result = signal_message_copy(&alice_message_copy, (signal_message *)alice_message, global_context); ck_assert_int_eq(result, 0); signal_buffer *plaintext = 0; result = session_cipher_decrypt_signal_message(bob_session_cipher, alice_message_copy, 0, &plaintext); ck_assert_int_eq(result, 0); uint8_t *plaintext_data = signal_buffer_data(plaintext); size_t plaintext_len = signal_buffer_len(plaintext); ck_assert_int_eq(original_message_len, plaintext_len); ck_assert_int_eq(memcmp(original_message, plaintext_data, plaintext_len), 0); signal_buffer_free(plaintext); plaintext = 0; fprintf(stderr, "Interaction complete: Alice -> Bob\n"); /* Simulate Bob sending a message to Alice */ ciphertext_message *bob_message = 0; result = session_cipher_encrypt(bob_session_cipher, (uint8_t *)original_message, original_message_len, &bob_message); ck_assert_int_eq(result, 0); ck_assert_int_eq(ciphertext_message_get_type(bob_message), CIPHERTEXT_SIGNAL_TYPE); signal_message *bob_message_copy = 0; result = signal_message_copy(&bob_message_copy, (signal_message *)bob_message, global_context); ck_assert_int_eq(result, 0); result = session_cipher_decrypt_signal_message(alice_session_cipher, bob_message_copy, 0, &plaintext); ck_assert_int_eq(result, 0); plaintext_data = signal_buffer_data(plaintext); plaintext_len = signal_buffer_len(plaintext); ck_assert_int_eq(original_message_len, plaintext_len); ck_assert_int_eq(memcmp(original_message, plaintext_data, plaintext_len), 0); signal_buffer_free(plaintext); plaintext = 0; fprintf(stderr, "Interaction complete: Bob -> Alice\n"); /* Cleanup */ SIGNAL_UNREF(bob_message_copy); SIGNAL_UNREF(bob_message); SIGNAL_UNREF(alice_message_copy); SIGNAL_UNREF(alice_message); int i; /* Looping Alice -> Bob */ for(i = 0; i < 10; i++) { signal_buffer *looping_message = create_looping_message(i); ciphertext_message *alice_looping_message = 0; result = session_cipher_encrypt(alice_session_cipher, signal_buffer_data(looping_message), signal_buffer_len(looping_message), &alice_looping_message); ck_assert_int_eq(result, 0); signal_message *alice_looping_message_message_copy = 0; result = signal_message_copy(&alice_looping_message_message_copy, (signal_message *)alice_looping_message, global_context); ck_assert_int_eq(result, 0); signal_buffer *looping_plaintext = 0; result = session_cipher_decrypt_signal_message(bob_session_cipher, alice_looping_message_message_copy, 0, &looping_plaintext); ck_assert_int_eq(result, 0); ck_assert_int_eq(signal_buffer_compare(looping_message, looping_plaintext), 0); signal_buffer_free(looping_plaintext); signal_buffer_free(looping_message); SIGNAL_UNREF(alice_looping_message); SIGNAL_UNREF(alice_looping_message_message_copy); } fprintf(stderr, "Interaction complete: Alice -> Bob (looping)\n"); /* Looping Bob -> Alice */ for(i = 0; i < 10; i++) { signal_buffer *looping_message = create_looping_message(i); ciphertext_message *bob_looping_message = 0; result = session_cipher_encrypt(bob_session_cipher, signal_buffer_data(looping_message), signal_buffer_len(looping_message), &bob_looping_message); ck_assert_int_eq(result, 0); signal_message *bob_looping_message_message_copy = 0; result = signal_message_copy(&bob_looping_message_message_copy, (signal_message *)bob_looping_message, global_context); ck_assert_int_eq(result, 0); signal_buffer *looping_plaintext = 0; result = session_cipher_decrypt_signal_message(alice_session_cipher, bob_looping_message_message_copy, 0, &looping_plaintext); ck_assert_int_eq(result, 0); ck_assert_int_eq(signal_buffer_compare(looping_message, looping_plaintext), 0); signal_buffer_free(looping_plaintext); signal_buffer_free(looping_message); SIGNAL_UNREF(bob_looping_message); SIGNAL_UNREF(bob_looping_message_message_copy); } fprintf(stderr, "Interaction complete: Bob -> Alice (looping)\n"); /* Generate a shuffled list of encrypted messages for later use */ signal_buffer *alice_ooo_plaintext[10]; signal_buffer *alice_ooo_ciphertext[10]; for(i = 0; i < 10; i++) { signal_buffer *looping_message = create_looping_message(i); ciphertext_message *alice_looping_message = 0; result = session_cipher_encrypt(alice_session_cipher, signal_buffer_data(looping_message), signal_buffer_len(looping_message), &alice_looping_message); ck_assert_int_eq(result, 0); signal_buffer *alice_looping_message_serialized = ciphertext_message_get_serialized(alice_looping_message); alice_ooo_plaintext[i] = looping_message; alice_ooo_ciphertext[i] = signal_buffer_copy(alice_looping_message_serialized); SIGNAL_UNREF(alice_looping_message); } time_t seed = time(0); srand_deterministic(seed); shuffle_buffers(alice_ooo_plaintext, 10); srand_deterministic(seed); shuffle_buffers(alice_ooo_ciphertext, 10); fprintf(stderr, "Shuffled Alice->Bob messages created\n"); /* Looping Alice -> Bob (repeated) */ for(i = 0; i < 10; i++) { signal_buffer *looping_message = create_looping_message(i); ciphertext_message *alice_looping_message = 0; result = session_cipher_encrypt(alice_session_cipher, signal_buffer_data(looping_message), signal_buffer_len(looping_message), &alice_looping_message); ck_assert_int_eq(result, 0); signal_message *alice_looping_message_message_copy = 0; result = signal_message_copy(&alice_looping_message_message_copy, (signal_message *)alice_looping_message, global_context); ck_assert_int_eq(result, 0); signal_buffer *looping_plaintext = 0; result = session_cipher_decrypt_signal_message(bob_session_cipher, alice_looping_message_message_copy, 0, &looping_plaintext); ck_assert_int_eq(result, 0); ck_assert_int_eq(signal_buffer_compare(looping_message, looping_plaintext), 0); signal_buffer_free(looping_plaintext); signal_buffer_free(looping_message); SIGNAL_UNREF(alice_looping_message); SIGNAL_UNREF(alice_looping_message_message_copy); } fprintf(stderr, "Interaction complete: Alice -> Bob (looping, repeated)\n"); /* Looping Bob -> Alice (repeated) */ for(i = 0; i < 10; i++) { signal_buffer *looping_message = create_looping_message_short(i); ciphertext_message *bob_looping_message = 0; result = session_cipher_encrypt(bob_session_cipher, signal_buffer_data(looping_message), signal_buffer_len(looping_message), &bob_looping_message); ck_assert_int_eq(result, 0); signal_message *bob_looping_message_message_copy = 0; result = signal_message_copy(&bob_looping_message_message_copy, (signal_message *)bob_looping_message, global_context); ck_assert_int_eq(result, 0); signal_buffer *looping_plaintext = 0; result = session_cipher_decrypt_signal_message(alice_session_cipher, bob_looping_message_message_copy, 0, &looping_plaintext); ck_assert_int_eq(result, 0); ck_assert_int_eq(signal_buffer_compare(looping_message, looping_plaintext), 0); signal_buffer_free(looping_plaintext); signal_buffer_free(looping_message); SIGNAL_UNREF(bob_looping_message); SIGNAL_UNREF(bob_looping_message_message_copy); } fprintf(stderr, "Interaction complete: Bob -> Alice (looping, repeated)\n"); /* Shuffled Alice -> Bob */ for(i = 0; i < 10; i++) { signal_message *ooo_message_deserialized = 0; result = signal_message_deserialize(&ooo_message_deserialized, signal_buffer_data(alice_ooo_ciphertext[i]), signal_buffer_len(alice_ooo_ciphertext[i]), global_context); ck_assert_int_eq(result, 0); signal_buffer *ooo_plaintext = 0; result = session_cipher_decrypt_signal_message(bob_session_cipher, ooo_message_deserialized, 0, &ooo_plaintext); ck_assert_int_eq(result, 0); ck_assert_int_eq(signal_buffer_compare(alice_ooo_plaintext[i], ooo_plaintext), 0); signal_buffer_free(ooo_plaintext); SIGNAL_UNREF(ooo_message_deserialized); } fprintf(stderr, "Interaction complete: Alice -> Bob (shuffled)\n"); /* Cleanup */ for(i = 0; i < 10; i++) { signal_buffer_free(alice_ooo_plaintext[i]); signal_buffer_free(alice_ooo_ciphertext[i]); } session_cipher_free(alice_session_cipher); session_cipher_free(bob_session_cipher); } Suite *session_builder_suite(void) { Suite *suite = suite_create("session_builder"); TCase *tcase = tcase_create("case"); tcase_add_checked_fixture(tcase, test_setup, test_teardown); tcase_add_test(tcase, test_basic_pre_key_v2); tcase_add_test(tcase, test_basic_pre_key_v3); tcase_add_test(tcase, test_bad_signed_pre_key_signature); tcase_add_test(tcase, test_repeat_bundle_message_v2); tcase_add_test(tcase, test_repeat_bundle_message_v3); tcase_add_test(tcase, test_bad_message_bundle); tcase_add_test(tcase, test_optional_one_time_pre_key); suite_add_tcase(suite, tcase); return suite; } int main(void) { int number_failed; Suite *suite; SRunner *runner; suite = session_builder_suite(); runner = srunner_create(suite); srunner_run_all(runner, CK_VERBOSE); number_failed = srunner_ntests_failed(runner); srunner_free(runner); return (number_failed == 0) ? EXIT_SUCCESS : EXIT_FAILURE; } libsignal-protocol-c-2.3.3/tests/test_session_cipher.c000066400000000000000000000445561363751346500231570ustar00rootroot00000000000000#include #include #include #include #include "../src/signal_protocol.h" #include "session_record.h" #include "session_state.h" #include "session_cipher.h" #include "curve.h" #include "ratchet.h" #include "protocol.h" #include "test_common.h" signal_context *global_context; pthread_mutex_t global_mutex; pthread_mutexattr_t global_mutex_attr; void test_lock(void *user_data) { pthread_mutex_lock(&global_mutex); } void test_unlock(void *user_data) { pthread_mutex_unlock(&global_mutex); } void test_setup() { int result; pthread_mutexattr_init(&global_mutex_attr); pthread_mutexattr_settype(&global_mutex_attr, PTHREAD_MUTEX_RECURSIVE); pthread_mutex_init(&global_mutex, &global_mutex_attr); result = signal_context_create(&global_context, 0); ck_assert_int_eq(result, 0); signal_context_set_log_function(global_context, test_log); setup_test_crypto_provider(global_context); result = signal_context_set_locking_functions(global_context, test_lock, test_unlock); ck_assert_int_eq(result, 0); } void test_teardown() { signal_context_destroy(global_context); pthread_mutex_destroy(&global_mutex); pthread_mutexattr_destroy(&global_mutex_attr); } void initialize_sessions_v3(session_state *alice_state, session_state *bob_state); void run_interaction(session_record *alice_session_record, session_record *bob_session_record); START_TEST(test_basic_session_v3) { int result = 0; /* Create Alice's session record */ session_record *alice_session_record = 0; result = session_record_create(&alice_session_record, 0, global_context); ck_assert_int_eq(result, 0); /* Create Bob's session record */ session_record *bob_session_record = 0; result = session_record_create(&bob_session_record, 0, global_context); ck_assert_int_eq(result, 0); initialize_sessions_v3( session_record_get_state(alice_session_record), session_record_get_state(bob_session_record)); run_interaction(alice_session_record, bob_session_record); /* Cleanup */ SIGNAL_UNREF(alice_session_record); SIGNAL_UNREF(bob_session_record); } END_TEST void initialize_sessions_v3(session_state *alice_state, session_state *bob_state) { int result = 0; /* Generate Alice's identity key */ ec_key_pair *alice_identity_key_pair = 0; result = curve_generate_key_pair(global_context, &alice_identity_key_pair); ck_assert_int_eq(result, 0); ratchet_identity_key_pair *alice_identity_key = 0; result = ratchet_identity_key_pair_create(&alice_identity_key, ec_key_pair_get_public(alice_identity_key_pair), ec_key_pair_get_private(alice_identity_key_pair)); ck_assert_int_eq(result, 0); SIGNAL_UNREF(alice_identity_key_pair); /* Generate Alice's base key */ ec_key_pair *alice_base_key = 0; result = curve_generate_key_pair(global_context, &alice_base_key); ck_assert_int_eq(result, 0); /* Generate Alice's pre-key */ ec_key_pair *alice_pre_key = alice_base_key; SIGNAL_REF(alice_base_key); /* Generate Bob's identity key */ ec_key_pair *bob_identity_key_pair = 0; result = curve_generate_key_pair(global_context, &bob_identity_key_pair); ck_assert_int_eq(result, 0); ratchet_identity_key_pair *bob_identity_key = 0; result = ratchet_identity_key_pair_create(&bob_identity_key, ec_key_pair_get_public(bob_identity_key_pair), ec_key_pair_get_private(bob_identity_key_pair)); ck_assert_int_eq(result, 0); SIGNAL_UNREF(bob_identity_key_pair); /* Generate Bob's base key */ ec_key_pair *bob_base_key = 0; result = curve_generate_key_pair(global_context, &bob_base_key); ck_assert_int_eq(result, 0); /* Generate Bob's ephemeral key */ ec_key_pair *bob_ephemeral_key = bob_base_key; SIGNAL_REF(bob_base_key); /* Create Alice's parameters */ alice_signal_protocol_parameters *alice_parameters = 0; result = alice_signal_protocol_parameters_create(&alice_parameters, /* our_identity_key */ alice_identity_key, /* our_base_key */ alice_base_key, /* their_identity_key */ ratchet_identity_key_pair_get_public(bob_identity_key), /* their_signed_pre_key */ ec_key_pair_get_public(bob_base_key), /* their_one_time_pre_key */ 0, /* their_ratchet_key */ ec_key_pair_get_public(bob_ephemeral_key)); ck_assert_int_eq(result, 0); /* Create Bob's parameters */ bob_signal_protocol_parameters *bob_parameters = 0; result = bob_signal_protocol_parameters_create(&bob_parameters, /* our_identity_key */ bob_identity_key, /* our_signed_pre_key */ bob_base_key, /* our_one_time_pre_key */ 0, /* our_ratchet_key */ bob_ephemeral_key, /* their_identity_key */ ratchet_identity_key_pair_get_public(alice_identity_key), /* their_base_key */ ec_key_pair_get_public(alice_base_key)); ck_assert_int_eq(result, 0); /* Initialize the ratcheting sessions */ result = ratcheting_session_alice_initialize(alice_state, alice_parameters, global_context); ck_assert_int_eq(result, 0); result = ratcheting_session_bob_initialize(bob_state, bob_parameters, global_context); ck_assert_int_eq(result, 0); /* Unref cleanup */ SIGNAL_UNREF(alice_identity_key); SIGNAL_UNREF(alice_base_key); SIGNAL_UNREF(alice_pre_key); SIGNAL_UNREF(bob_identity_key); SIGNAL_UNREF(bob_base_key); SIGNAL_UNREF(bob_ephemeral_key); SIGNAL_UNREF(alice_parameters); SIGNAL_UNREF(bob_parameters); } void generate_test_message_collections(session_cipher *cipher, signal_buffer **plaintext_messages, signal_buffer **ciphertext_messages, int size) { /* * This test message is kept here as a byte array constant, rather than * a string literal, since it contains characters not valid in ASCII. * A null placeholder is located at the end, which is replaced with an * index value when generated derived test messages. */ uint8_t testMessage[] = { 0xD1, 0x81, 0xD0, 0xBC, 0xD0, 0xB5, 0xD1, 0x80, 0xD1, 0x82, 0xD1, 0x8C, 0x20, 0xD0, 0xB7, 0xD0, 0xB0, 0x20, 0xD1, 0x81, 0xD0, 0xBC, 0xD0, 0xB5, 0xD1, 0x80, 0xD1, 0x82, 0xD1, 0x8C, 0x20, 0x00 }; int result = 0; int i; for(i = 0; i < size; i++) { /* Generate the plaintext */ signal_buffer *plain_buf = signal_buffer_create(testMessage, sizeof(testMessage)); uint8_t *plain_buf_data = signal_buffer_data(plain_buf); size_t plain_buf_len = signal_buffer_len(plain_buf); plain_buf_data[plain_buf_len - 1] = (uint8_t)i; /* Generate the ciphertext */ ciphertext_message *encrypted_message = 0; result = session_cipher_encrypt(cipher, plain_buf_data, plain_buf_len, &encrypted_message); ck_assert_int_eq(result, 0); signal_buffer *cipher_buf = ciphertext_message_get_serialized(encrypted_message); /* Add the generated messages to the arrays */ plaintext_messages[i] = plain_buf; ciphertext_messages[i] = signal_buffer_copy(cipher_buf); /* Cleanup */ SIGNAL_UNREF(encrypted_message); } /* Randomize the two arrays using the same seed */ time_t seed = time(0); srand_deterministic(seed); shuffle_buffers(plaintext_messages, size); srand_deterministic(seed); shuffle_buffers(ciphertext_messages, size); } void decrypt_and_compare_messages(session_cipher *cipher, signal_buffer *ciphertext, signal_buffer *plaintext) { int result = 0; /* Create a signal_message from the ciphertext */ signal_message *index_message_deserialized = 0; result = signal_message_deserialize(&index_message_deserialized, signal_buffer_data(ciphertext), signal_buffer_len(ciphertext), global_context); ck_assert_int_eq(result, 0); /* Decrypt the message */ signal_buffer *index_plaintext = 0; result = session_cipher_decrypt_signal_message(cipher, index_message_deserialized, 0, &index_plaintext); ck_assert_int_eq(result, 0); /* Compare the messages */ ck_assert_int_eq(signal_buffer_compare(index_plaintext, plaintext), 0); /* Cleanup */ SIGNAL_UNREF(index_message_deserialized); signal_buffer_free(index_plaintext); } void run_interaction(session_record *alice_session_record, session_record *bob_session_record) { int result = 0; signal_protocol_address alice_address = { "+14159999999", 12, 1 }; signal_protocol_address bob_address = { "+14158888888", 12, 1 }; /* Create the test data stores */ signal_protocol_store_context *alice_store = 0; setup_test_store_context(&alice_store, global_context); signal_protocol_store_context *bob_store = 0; setup_test_store_context(&bob_store, global_context); /* Store the two sessions in their data stores */ result = signal_protocol_session_store_session(alice_store, &bob_address, alice_session_record); ck_assert_int_eq(result, 0); result = signal_protocol_session_store_session(bob_store, &alice_address, bob_session_record); ck_assert_int_eq(result, 0); /* Create two session cipher instances */ session_cipher *alice_cipher = 0; result = session_cipher_create(&alice_cipher, alice_store, &bob_address, global_context); ck_assert_int_eq(result, 0); session_cipher *bob_cipher = 0; result = session_cipher_create(&bob_cipher, bob_store, &alice_address, global_context); ck_assert_int_eq(result, 0); /* Encrypt a test message from Alice */ static const char alice_plaintext[] = "This is a plaintext message."; size_t alice_plaintext_len = sizeof(alice_plaintext) - 1; ciphertext_message *alice_message = 0; result = session_cipher_encrypt(alice_cipher, (uint8_t *)alice_plaintext, alice_plaintext_len, &alice_message); ck_assert_int_eq(result, 0); /* Serialize the test message to create a fresh instance */ signal_buffer *alice_message_serialized = ciphertext_message_get_serialized(alice_message); ck_assert_ptr_ne(alice_message_serialized, 0); /* Have Bob decrypt the test message */ signal_buffer *alice_plaintext_buffer = signal_buffer_create((uint8_t*) alice_plaintext, alice_plaintext_len); decrypt_and_compare_messages(bob_cipher, alice_message_serialized, alice_plaintext_buffer); fprintf(stderr, "Interaction complete: Alice -> Bob\n"); /* Encrypt a reply from Bob */ static const char bob_reply[] = "This is a message from Bob."; size_t bob_reply_len = sizeof(bob_reply) - 1; ciphertext_message *reply_message = 0; result = session_cipher_encrypt(bob_cipher, (uint8_t *)bob_reply, bob_reply_len, &reply_message); ck_assert_int_eq(result, 0); /* Serialize the reply message to create a fresh instance */ signal_buffer *reply_message_serialized = ciphertext_message_get_serialized(reply_message); ck_assert_ptr_ne(reply_message_serialized, 0); /* Have Alice decrypt the reply message */ signal_buffer *bob_plaintext_buffer = signal_buffer_create((uint8_t*) bob_reply, bob_reply_len); decrypt_and_compare_messages(alice_cipher, reply_message_serialized, bob_plaintext_buffer); fprintf(stderr, "Interaction complete: Bob -> Alice\n"); int i; /* Generate 50 indexed Alice test messages */ signal_buffer *alice_plaintext_messages[50]; signal_buffer *alice_ciphertext_messages[50]; generate_test_message_collections(alice_cipher, alice_plaintext_messages, alice_ciphertext_messages, 50); /* Iterate through half the collection and try to decrypt messages */ for(i = 0; i < 25; i++) { decrypt_and_compare_messages(bob_cipher, alice_ciphertext_messages[i], alice_plaintext_messages[i]); } fprintf(stderr, "Interaction complete: Alice -> Bob (randomized, 0-24)\n"); /* Generate 50 indexed Bob test messages */ signal_buffer *bob_plaintext_messages[50]; signal_buffer *bob_ciphertext_messages[50]; generate_test_message_collections(bob_cipher, bob_plaintext_messages, bob_ciphertext_messages, 50); /* Iterate through half the collection and try to decrypt messages */ for(i = 0; i < 25; i++) { decrypt_and_compare_messages(alice_cipher, bob_ciphertext_messages[i], bob_plaintext_messages[i]); } fprintf(stderr, "Interaction complete: Bob -> Alice (randomized, 0-24)\n"); /* Iterate through the second half of the collection and try to decrypt messages */ for(i = 25; i < 50; i++) { decrypt_and_compare_messages(bob_cipher, alice_ciphertext_messages[i], alice_plaintext_messages[i]); } fprintf(stderr, "Interaction complete: Alice -> Bob (randomized, 25-49)\n"); /* Iterate through the second half of the collection and try to decrypt messages */ for(i = 25; i < 50; i++) { decrypt_and_compare_messages(alice_cipher, bob_ciphertext_messages[i], bob_plaintext_messages[i]); } fprintf(stderr, "Interaction complete: Bob -> Alice (randomized, 25-49)\n"); /* Cleanup */ for(i = 0; i < 50; i++) { signal_buffer_free(alice_plaintext_messages[i]); signal_buffer_free(alice_ciphertext_messages[i]); } for(i = 0; i < 50; i++) { signal_buffer_free(bob_plaintext_messages[i]); signal_buffer_free(bob_ciphertext_messages[i]); } SIGNAL_UNREF(alice_message); SIGNAL_UNREF(reply_message); signal_buffer_free(alice_plaintext_buffer); signal_buffer_free(bob_plaintext_buffer); session_cipher_free(alice_cipher); session_cipher_free(bob_cipher); signal_protocol_store_context_destroy(alice_store); signal_protocol_store_context_destroy(bob_store); } START_TEST(test_message_key_limits) { int i; int result = 0; signal_protocol_address alice_address = { "+14159999999", 12, 1 }; signal_protocol_address bob_address = { "+14158888888", 12, 1 }; /* Create Alice's session record */ session_record *alice_session_record = 0; result = session_record_create(&alice_session_record, 0, global_context); ck_assert_int_eq(result, 0); /* Create Bob's session record */ session_record *bob_session_record = 0; result = session_record_create(&bob_session_record, 0, global_context); ck_assert_int_eq(result, 0); /* Initialize the sessions */ initialize_sessions_v3( session_record_get_state(alice_session_record), session_record_get_state(bob_session_record)); /* Create Alice's data store */ signal_protocol_store_context *alice_store = 0; setup_test_store_context(&alice_store, global_context); /* Create Bob's data store */ signal_protocol_store_context *bob_store = 0; setup_test_store_context(&bob_store, global_context); /* Store the sessions */ result = signal_protocol_session_store_session(alice_store, &alice_address, alice_session_record); ck_assert_int_eq(result, 0); result = signal_protocol_session_store_session(bob_store, &bob_address, bob_session_record); ck_assert_int_eq(result, 0); /* Create Alice's session cipher */ session_cipher *alice_cipher = 0; result = session_cipher_create(&alice_cipher, alice_store, &alice_address, global_context); ck_assert_int_eq(result, 0); /* Create Bob's session cipher */ session_cipher *bob_cipher = 0; result = session_cipher_create(&bob_cipher, bob_store, &bob_address, global_context); ck_assert_int_eq(result, 0); signal_message *inflight[2010]; memset(inflight, 0, sizeof(inflight)); /* Encrypt enough messages to go past our limit */ for(i = 0; i < 2010; i++) { static const char alice_plaintext[] = "you've never been so hungry, you've never been so cold"; size_t alice_plaintext_len = sizeof(alice_plaintext) - 1; ciphertext_message *alice_message = 0; result = session_cipher_encrypt(alice_cipher, (uint8_t *)alice_plaintext, alice_plaintext_len, &alice_message); ck_assert_int_eq(result, 0); ck_assert_int_eq(ciphertext_message_get_type(alice_message), CIPHERTEXT_SIGNAL_TYPE); inflight[i] = (signal_message *)alice_message; } signal_message *message_copy = 0; signal_buffer *buffer = 0; /* Try decrypting in-flight message 1000 */ result = signal_message_copy(&message_copy, inflight[1000], global_context); ck_assert_int_eq(result, 0); result = session_cipher_decrypt_signal_message(bob_cipher, message_copy, 0, &buffer); ck_assert_int_eq(result, 0); ck_assert_ptr_ne(buffer, 0); signal_buffer_free(buffer); buffer = 0; SIGNAL_UNREF(message_copy); /* Try decrypting in-flight message 2009 */ result = signal_message_copy(&message_copy, inflight[2009], global_context); ck_assert_int_eq(result, 0); result = session_cipher_decrypt_signal_message(bob_cipher, message_copy, 0, &buffer); ck_assert_int_eq(result, 0); ck_assert_ptr_ne(buffer, 0); signal_buffer_free(buffer); buffer = 0; SIGNAL_UNREF(message_copy); /* Try decrypting in-flight message 0, which should fail */ result = signal_message_copy(&message_copy, inflight[0], global_context); ck_assert_int_eq(result, 0); result = session_cipher_decrypt_signal_message(bob_cipher, message_copy, 0, &buffer); ck_assert_int_eq(result, SG_ERR_DUPLICATE_MESSAGE); signal_buffer_free(buffer); buffer = 0; SIGNAL_UNREF(message_copy); /* Cleanup */ for(i = 0; i < 2010; i++) { if(inflight[i]) { SIGNAL_UNREF(inflight[i]); } } SIGNAL_UNREF(alice_session_record); SIGNAL_UNREF(bob_session_record); session_cipher_free(alice_cipher); session_cipher_free(bob_cipher); signal_protocol_store_context_destroy(alice_store); signal_protocol_store_context_destroy(bob_store); } END_TEST Suite *session_cipher_suite(void) { Suite *suite = suite_create("session_cipher"); TCase *tcase = tcase_create("case"); tcase_add_checked_fixture(tcase, test_setup, test_teardown); tcase_add_test(tcase, test_basic_session_v3); tcase_add_test(tcase, test_message_key_limits); suite_add_tcase(suite, tcase); return suite; } int main(void) { int number_failed; Suite *suite; SRunner *runner; suite = session_cipher_suite(); runner = srunner_create(suite); srunner_run_all(runner, CK_VERBOSE); number_failed = srunner_ntests_failed(runner); srunner_free(runner); return (number_failed == 0) ? EXIT_SUCCESS : EXIT_FAILURE; } libsignal-protocol-c-2.3.3/tests/test_session_record.c000066400000000000000000000631021363751346500231470ustar00rootroot00000000000000#include #include #include #include "../src/signal_protocol.h" #include "hkdf.h" #include "session_record.h" #include "session_state.h" #include "test_common.h" signal_context *global_context; void test_setup() { int result; result = signal_context_create(&global_context, 0); ck_assert_int_eq(result, 0); signal_context_set_log_function(global_context, test_log); setup_test_crypto_provider(global_context); } void test_teardown() { signal_context_destroy(global_context); } void fill_test_session_state(session_state *state, ec_public_key *receiver_chain_ratchet_key1, ec_public_key *receiver_chain_ratchet_key2) { int result = 0; hkdf_context *kdf = 0; result = hkdf_create(&kdf, 2, global_context); ck_assert_int_eq(result, 0); uint8_t keySeed[32]; memset(keySeed, 0x42, sizeof(keySeed)); /* Set the session version */ session_state_set_session_version(state, 2); /* Set local and remote identity keys */ ec_public_key *local_identity_key = create_test_ec_public_key(global_context); ec_public_key *remote_identity_key = create_test_ec_public_key(global_context); session_state_set_local_identity_key(state, local_identity_key); session_state_set_remote_identity_key(state, remote_identity_key); SIGNAL_UNREF(local_identity_key); SIGNAL_UNREF(remote_identity_key); /* Set the root key */ ratchet_root_key *root_key; result = ratchet_root_key_create(&root_key, kdf, keySeed, sizeof(keySeed), global_context); ck_assert_int_eq(result, 0); session_state_set_root_key(state, root_key); SIGNAL_UNREF(root_key); /* Set the previous counter */ session_state_set_previous_counter(state, 4); /* Set the sender chain */ ec_key_pair *sender_ratchet_key_pair; result = curve_generate_key_pair(global_context, &sender_ratchet_key_pair); ck_assert_int_eq(result, 0); ratchet_chain_key *sender_chain_key; result = ratchet_chain_key_create(&sender_chain_key, kdf, keySeed, sizeof(keySeed), 0, global_context); ck_assert_int_eq(result, 0); session_state_set_sender_chain(state, sender_ratchet_key_pair, sender_chain_key); SIGNAL_UNREF(sender_ratchet_key_pair); SIGNAL_UNREF(sender_chain_key); /* Set the receiver chains */ if(receiver_chain_ratchet_key1) { ratchet_chain_key *receiver_chain_chain_key1; result = ratchet_chain_key_create(&receiver_chain_chain_key1, kdf, keySeed, sizeof(keySeed), 0, global_context); ck_assert_int_eq(result, 0); result = session_state_add_receiver_chain(state, receiver_chain_ratchet_key1, receiver_chain_chain_key1); ck_assert_int_eq(result, 0); ratchet_message_keys message_keys; result = ratchet_chain_key_get_message_keys(receiver_chain_chain_key1, &message_keys); ck_assert_int_eq(result, 0); result = session_state_set_message_keys(state, receiver_chain_ratchet_key1, &message_keys); ck_assert_int_eq(result, 0); SIGNAL_UNREF(receiver_chain_chain_key1); } if(receiver_chain_ratchet_key2) { ratchet_chain_key *receiver_chain_chain_key2; result = ratchet_chain_key_create(&receiver_chain_chain_key2, kdf, keySeed, sizeof(keySeed), 0, global_context); ck_assert_int_eq(result, 0); result = session_state_add_receiver_chain(state, receiver_chain_ratchet_key2, receiver_chain_chain_key2); ck_assert_int_eq(result, 0); ratchet_message_keys message_keys; result = ratchet_chain_key_get_message_keys(receiver_chain_chain_key2, &message_keys); ck_assert_int_eq(result, 0); result = session_state_set_message_keys(state, receiver_chain_ratchet_key2, &message_keys); ck_assert_int_eq(result, 0); SIGNAL_UNREF(receiver_chain_chain_key2); } /* Set pending key exchange */ ec_key_pair *our_base_key; result = curve_generate_key_pair(global_context, &our_base_key); ck_assert_int_eq(result, 0); ec_key_pair *our_ratchet_key; result = curve_generate_key_pair(global_context, &our_ratchet_key); ck_assert_int_eq(result, 0); ec_key_pair *our_identity_key_pair; result = curve_generate_key_pair(global_context, &our_identity_key_pair); ck_assert_int_eq(result, 0); ratchet_identity_key_pair *our_identity_key; result = ratchet_identity_key_pair_create(&our_identity_key, ec_key_pair_get_public(our_identity_key_pair), ec_key_pair_get_private(our_identity_key_pair)); ck_assert_int_eq(result, 0); SIGNAL_UNREF(our_identity_key_pair); session_state_set_pending_key_exchange(state, 42, our_base_key, our_ratchet_key, our_identity_key); SIGNAL_UNREF(our_base_key); SIGNAL_UNREF(our_ratchet_key); SIGNAL_UNREF(our_identity_key); /* Set pending pre-key */ ec_public_key *pending_pre_key_base_key = create_test_ec_public_key(global_context); uint32_t pre_key_id = 1234; session_state_set_unacknowledged_pre_key_message(state, &pre_key_id, 5678, pending_pre_key_base_key); SIGNAL_UNREF(pending_pre_key_base_key); session_state_set_remote_registration_id(state, 0xDEADBEEF); session_state_set_local_registration_id(state, 0xBAADF00D); session_state_set_needs_refresh(state, 0); ec_public_key *alice_base_key = create_test_ec_public_key(global_context); session_state_set_alice_base_key(state, alice_base_key); SIGNAL_UNREF(alice_base_key); SIGNAL_UNREF(kdf); } session_state *create_test_session_state(ec_public_key *receiver_chain_ratchet_key1, ec_public_key *receiver_chain_ratchet_key2) { int result = 0; session_state *state = 0; result = session_state_create(&state, global_context); ck_assert_int_eq(result, 0); fill_test_session_state(state, receiver_chain_ratchet_key1, receiver_chain_ratchet_key2); return state; } void compare_session_states_receiver_chain(session_state *state1, session_state *state2, ec_public_key *sender_ephemeral); void compare_session_states(session_state *state1, session_state *state2, ec_public_key *receiver_chain_ratchet_key1, ec_public_key *receiver_chain_ratchet_key2) { int result = 0; /* Compare session versions */ int version1 = session_state_get_session_version(state1); int version2 = session_state_get_session_version(state2); ck_assert_int_eq(version1, version2); /* Compare local identity keys */ ec_public_key *local_identity_key1 = session_state_get_local_identity_key(state1); ec_public_key *local_identity_key2 = session_state_get_local_identity_key(state2); ck_assert_int_eq(ec_public_key_compare(local_identity_key1, local_identity_key2), 0); /* Compare remote identity keys */ ec_public_key *remote_identity_key1 = session_state_get_remote_identity_key(state1); ec_public_key *remote_identity_key2 = session_state_get_remote_identity_key(state2); ck_assert_int_eq(ec_public_key_compare(remote_identity_key1, remote_identity_key2), 0); /* Compare root keys */ ratchet_root_key *root_key1 = session_state_get_root_key(state1); ratchet_root_key *root_key2 = session_state_get_root_key(state2); ck_assert_int_eq(ratchet_root_key_compare(root_key1, root_key2), 0); /* Compare previous counters */ int previous_counter1 = session_state_get_previous_counter(state1); int previous_counter2 = session_state_get_previous_counter(state2); ck_assert_int_eq(previous_counter1, previous_counter2); /* Compare sender chain */ int has_sender_chain1 = session_state_has_sender_chain(state1); int has_sender_chain2 = session_state_has_sender_chain(state2); ck_assert_int_eq(has_sender_chain1, has_sender_chain2); if(has_sender_chain1 == 1) { /* Compare sender ratchet keys */ ec_key_pair *sender_ratchet_key_pair1 = session_state_get_sender_ratchet_key_pair(state1); ec_key_pair *sender_ratchet_key_pair2 = session_state_get_sender_ratchet_key_pair(state2); ec_public_key *sender_ratchet_key_public1 = ec_key_pair_get_public(sender_ratchet_key_pair1); ec_public_key *sender_ratchet_key_public2 = ec_key_pair_get_public(sender_ratchet_key_pair2); ck_assert_int_eq(ec_public_key_compare(sender_ratchet_key_public1, sender_ratchet_key_public2), 0); ec_private_key *sender_ratchet_key_private1 = ec_key_pair_get_private(sender_ratchet_key_pair1); ec_private_key *sender_ratchet_key_private2 = ec_key_pair_get_private(sender_ratchet_key_pair2); ck_assert_int_eq(ec_private_key_compare(sender_ratchet_key_private1, sender_ratchet_key_private2), 0); /* Compare sender chain keys */ ratchet_chain_key *sender_chain_key1 = session_state_get_sender_chain_key(state1); ratchet_chain_key *sender_chain_key2 = session_state_get_sender_chain_key(state2); signal_buffer *sender_chain_key_buf1; signal_buffer *sender_chain_key_buf2; result = ratchet_chain_key_get_key(sender_chain_key1, &sender_chain_key_buf1); ck_assert_int_eq(result, 0); result = ratchet_chain_key_get_key(sender_chain_key2, &sender_chain_key_buf2); ck_assert_int_eq(result, 0); ck_assert_int_eq(signal_buffer_compare(sender_chain_key_buf1, sender_chain_key_buf2), 0); signal_buffer_free(sender_chain_key_buf1); signal_buffer_free(sender_chain_key_buf2); int sender_chain_key_index1 = ratchet_chain_key_get_index(sender_chain_key1); int sender_chain_key_index2 = ratchet_chain_key_get_index(sender_chain_key2); ck_assert_int_eq(sender_chain_key_index1, sender_chain_key_index2); } /* Compare receiver chains */ if(receiver_chain_ratchet_key1) { compare_session_states_receiver_chain(state1, state2, receiver_chain_ratchet_key1); } if(receiver_chain_ratchet_key2) { compare_session_states_receiver_chain(state1, state2, receiver_chain_ratchet_key2); } /* Compare pending key exchange */ int has_pending_key_exchange1 = session_state_has_pending_key_exchange(state1); int has_pending_key_exchange2 = session_state_has_pending_key_exchange(state2); ck_assert_int_eq(has_pending_key_exchange1, has_pending_key_exchange2); if(has_pending_key_exchange1 == 1) { /* Compare sequence numbers */ int sequence1 = session_state_get_pending_key_exchange_sequence(state1); int sequence2 = session_state_get_pending_key_exchange_sequence(state2); ck_assert_int_eq(sequence1, sequence2); /* Compare base keys */ ec_key_pair *base_key1 = session_state_get_pending_key_exchange_base_key(state1); ec_key_pair *base_key2 = session_state_get_pending_key_exchange_base_key(state2); ec_public_key *base_key_public1 = ec_key_pair_get_public(base_key1); ec_public_key *base_key_public2 = ec_key_pair_get_public(base_key2); ck_assert_int_eq(ec_public_key_compare(base_key_public1, base_key_public2), 0); ec_private_key *base_key_private1 = ec_key_pair_get_private(base_key1); ec_private_key *base_key_private2 = ec_key_pair_get_private(base_key2); ck_assert_int_eq(ec_private_key_compare(base_key_private1, base_key_private2), 0); /* Compare ratchet keys */ ec_key_pair *ratchet_key1 = session_state_get_pending_key_exchange_ratchet_key(state1); ec_key_pair *ratchet_key2 = session_state_get_pending_key_exchange_ratchet_key(state2); ec_public_key *ratchet_key_public1 = ec_key_pair_get_public(ratchet_key1); ec_public_key *ratchet_key_public2 = ec_key_pair_get_public(ratchet_key2); ck_assert_int_eq(ec_public_key_compare(ratchet_key_public1, ratchet_key_public2), 0); ec_private_key *ratchet_key_private1 = ec_key_pair_get_private(ratchet_key1); ec_private_key *ratchet_key_private2 = ec_key_pair_get_private(ratchet_key2); ck_assert_int_eq(ec_private_key_compare(ratchet_key_private1, ratchet_key_private2), 0); /* Compare identity keys */ ratchet_identity_key_pair *identity_key1 = session_state_get_pending_key_exchange_identity_key(state1); ratchet_identity_key_pair *identity_key2 = session_state_get_pending_key_exchange_identity_key(state2); ec_public_key *identity_key_public1 = ratchet_identity_key_pair_get_public(identity_key1); ec_public_key *identity_key_public2 = ratchet_identity_key_pair_get_public(identity_key2); ck_assert_int_eq(ec_public_key_compare(identity_key_public1, identity_key_public2), 0); ec_private_key *identity_key_private1 = ratchet_identity_key_pair_get_private(identity_key1); ec_private_key *identity_key_private2 = ratchet_identity_key_pair_get_private(identity_key2); ck_assert_int_eq(ec_private_key_compare(identity_key_private1, identity_key_private2), 0); } /* Compare pending pre-key */ int has_pending_pre_key1 = session_state_has_unacknowledged_pre_key_message(state1); int has_pending_pre_key2 = session_state_has_unacknowledged_pre_key_message(state2); ck_assert_int_eq(has_pending_pre_key1, has_pending_pre_key2); if(has_pending_pre_key1 == 1) { int has_key_id1 = session_state_unacknowledged_pre_key_message_has_pre_key_id(state1); int has_key_id2 = session_state_unacknowledged_pre_key_message_has_pre_key_id(state2); ck_assert_int_eq(has_key_id1, has_key_id2); if(has_key_id1) { /* Compare pre-key IDs */ uint32_t pre_key_id1 = session_state_unacknowledged_pre_key_message_get_pre_key_id(state1); uint32_t pre_key_id2 = session_state_unacknowledged_pre_key_message_get_pre_key_id(state2); ck_assert_int_eq(pre_key_id1, pre_key_id2); /* Compare signed pre-key IDs */ int32_t signed_pre_key_id1 = session_state_unacknowledged_pre_key_message_get_signed_pre_key_id(state1); int32_t signed_pre_key_id2 = session_state_unacknowledged_pre_key_message_get_signed_pre_key_id(state2); ck_assert_int_eq(signed_pre_key_id1, signed_pre_key_id2); /* Compare base keys */ ec_public_key *base_key1 = session_state_unacknowledged_pre_key_message_get_base_key(state1); ec_public_key *base_key2 = session_state_unacknowledged_pre_key_message_get_base_key(state2); ck_assert_int_eq(ec_public_key_compare(base_key1, base_key2), 0); } } /* Compare remote registration IDs */ uint32_t remote_registration_id1 = session_state_get_remote_registration_id(state1); uint32_t remote_registration_id2 = session_state_get_remote_registration_id(state2); ck_assert_int_eq(remote_registration_id1, remote_registration_id2); /* Compare local registration IDs */ uint32_t local_registration_id1 = session_state_get_local_registration_id(state1); uint32_t local_registration_id2 = session_state_get_local_registration_id(state2); ck_assert_int_eq(local_registration_id1, local_registration_id2); /* Compare refresh flags */ int needs_refresh1 = session_state_get_needs_refresh(state1); int needs_refresh2 = session_state_get_needs_refresh(state2); ck_assert_int_eq(needs_refresh1, needs_refresh2); /* Compare Alice base keys */ ec_public_key *alice_base_key1 = session_state_get_alice_base_key(state1); ec_public_key *alice_base_key2 = session_state_get_alice_base_key(state2); ck_assert_int_eq(ec_public_key_compare(alice_base_key1, alice_base_key2), 0); } void compare_session_states_receiver_chain(session_state *state1, session_state *state2, ec_public_key *sender_ephemeral) { int result = 0; ratchet_chain_key *receiver_chain_key1 = session_state_get_receiver_chain_key(state1, sender_ephemeral); ck_assert_ptr_ne(receiver_chain_key1, 0); ratchet_chain_key *receiver_chain_key2 = session_state_get_receiver_chain_key(state2, sender_ephemeral); ck_assert_ptr_ne(receiver_chain_key2, 0); ck_assert_ptr_ne(receiver_chain_key1, receiver_chain_key2); signal_buffer *receiver_chain_key_buf1; signal_buffer *receiver_chain_key_buf2; result = ratchet_chain_key_get_key(receiver_chain_key1, &receiver_chain_key_buf1); ck_assert_int_eq(result, 0); result = ratchet_chain_key_get_key(receiver_chain_key2, &receiver_chain_key_buf2); ck_assert_int_eq(result, 0); ck_assert_int_eq(signal_buffer_compare(receiver_chain_key_buf1, receiver_chain_key_buf2), 0); signal_buffer_free(receiver_chain_key_buf1); signal_buffer_free(receiver_chain_key_buf2); int receiver_chain_key_index1 = ratchet_chain_key_get_index(receiver_chain_key1); int receiver_chain_key_index2 = ratchet_chain_key_get_index(receiver_chain_key2); ck_assert_int_eq(receiver_chain_key_index1, receiver_chain_key_index2); int has_message_keys1 = session_state_has_message_keys(state1, sender_ephemeral, 0); ck_assert_int_eq(has_message_keys1, 1); int has_message_keys2 = session_state_has_message_keys(state2, sender_ephemeral, 0); ck_assert_int_eq(has_message_keys2, 1); ratchet_message_keys message_keys1; result = session_state_remove_message_keys(state1, &message_keys1, sender_ephemeral, 0); ck_assert_int_eq(result, 1); ratchet_message_keys message_keys2; result = session_state_remove_message_keys(state2, &message_keys2, sender_ephemeral, 0); ck_assert_int_eq(result, 1); ck_assert_int_eq(memcmp(&message_keys1, &message_keys2, sizeof(ratchet_message_keys)), 0); } START_TEST(test_serialize_single_session) { int result = 0; ec_public_key *receiver_chain_ratchet_key1 = create_test_ec_public_key(global_context); ec_public_key *receiver_chain_ratchet_key2 = create_test_ec_public_key(global_context); session_state *state = create_test_session_state(receiver_chain_ratchet_key1, receiver_chain_ratchet_key2); session_record *record = 0; result = session_record_create(&record, state, global_context); ck_assert_int_eq(result, 0); signal_buffer *buffer = 0; result = session_record_serialize(&buffer, record); ck_assert_int_ge(result, 0); uint8_t *data = signal_buffer_data(buffer); int len = signal_buffer_len(buffer); /* Deserialize the record */ session_record *record_deserialized = 0; result = session_record_deserialize(&record_deserialized, data, len, global_context); ck_assert_int_ge(result, 0); session_state *state_deserialized = session_record_get_state(record_deserialized); ck_assert_ptr_ne(state_deserialized, 0); ck_assert_ptr_ne(state_deserialized, state); /* Verify that the initial and deserialized states match */ compare_session_states(state, state_deserialized, receiver_chain_ratchet_key1, receiver_chain_ratchet_key2); /* Verify that there aren't any previous states */ session_record_state_node *previous_node = session_record_get_previous_states_head(record_deserialized); ck_assert_ptr_eq(previous_node, 0); /* Cleanup */ SIGNAL_UNREF(state); signal_buffer_free(buffer); SIGNAL_UNREF(receiver_chain_ratchet_key1); SIGNAL_UNREF(receiver_chain_ratchet_key2); SIGNAL_UNREF(record); SIGNAL_UNREF(record_deserialized); } END_TEST START_TEST(test_serialize_multiple_sessions) { int result = 0; /* Create several test keys */ ec_public_key *receiver_chain_ratchet_key1a = create_test_ec_public_key(global_context); ec_public_key *receiver_chain_ratchet_key1b = create_test_ec_public_key(global_context); ec_public_key *receiver_chain_ratchet_key2a = create_test_ec_public_key(global_context); ec_public_key *receiver_chain_ratchet_key2b = create_test_ec_public_key(global_context); ec_public_key *receiver_chain_ratchet_key3a = create_test_ec_public_key(global_context); ec_public_key *receiver_chain_ratchet_key3b = create_test_ec_public_key(global_context); /* Create the session record with the first state */ session_state *state1 = create_test_session_state(receiver_chain_ratchet_key1a, receiver_chain_ratchet_key1b); session_record *record = 0; result = session_record_create(&record, state1, global_context); ck_assert_int_eq(result, 0); /* Archive the current state and fill the new state */ result = session_record_archive_current_state(record); ck_assert_int_eq(result, 0); session_state *state2 = session_record_get_state(record); ck_assert_ptr_ne(state1, state2); fill_test_session_state(state2, receiver_chain_ratchet_key2a, receiver_chain_ratchet_key2b); /* Archive the current state and fill the new state */ result = session_record_archive_current_state(record); ck_assert_int_eq(result, 0); session_state *state3 = session_record_get_state(record); ck_assert_ptr_ne(state1, state2); ck_assert_ptr_ne(state1, state3); fill_test_session_state(state3, receiver_chain_ratchet_key3a, receiver_chain_ratchet_key3b); signal_buffer *buffer = 0; result = session_record_serialize(&buffer, record); ck_assert_int_ge(result, 0); uint8_t *data = signal_buffer_data(buffer); int len = signal_buffer_len(buffer); /* Deserialize the record */ session_record *record_deserialized = 0; result = session_record_deserialize(&record_deserialized, data, len, global_context); ck_assert_int_ge(result, 0); session_state *state_deserialized3 = session_record_get_state(record_deserialized); ck_assert_ptr_ne(state_deserialized3, 0); ck_assert_ptr_ne(state_deserialized3, state3); /* Verify that the expected and actual current states match */ compare_session_states(state3, state_deserialized3, receiver_chain_ratchet_key3a, receiver_chain_ratchet_key3b); /* Verify that we have the expected number of previous states */ session_record_state_node *previous_node = session_record_get_previous_states_head(record_deserialized); ck_assert_ptr_ne(previous_node, 0); session_state *state_deserialized2 = session_record_get_previous_states_element(previous_node); ck_assert_ptr_ne(state_deserialized2, 0); previous_node = session_record_get_previous_states_next(previous_node); ck_assert_ptr_ne(previous_node, 0); session_state *state_deserialized1 = session_record_get_previous_states_element(previous_node); ck_assert_ptr_ne(state_deserialized1, 0); previous_node = session_record_get_previous_states_next(previous_node); ck_assert_ptr_eq(previous_node, 0); /* Verify that the expected and actual previous states match */ compare_session_states(state2, state_deserialized2, receiver_chain_ratchet_key2a, receiver_chain_ratchet_key2b); compare_session_states(state1, state_deserialized1, receiver_chain_ratchet_key1a, receiver_chain_ratchet_key1b); /* Cleanup */ SIGNAL_UNREF(state1); signal_buffer_free(buffer); SIGNAL_UNREF(receiver_chain_ratchet_key1a); SIGNAL_UNREF(receiver_chain_ratchet_key1b); SIGNAL_UNREF(receiver_chain_ratchet_key2a); SIGNAL_UNREF(receiver_chain_ratchet_key2b); SIGNAL_UNREF(receiver_chain_ratchet_key3a); SIGNAL_UNREF(receiver_chain_ratchet_key3b); SIGNAL_UNREF(record); SIGNAL_UNREF(record_deserialized); } END_TEST START_TEST(test_session_receiver_chain_count) { int result = 0; int i = 0; hkdf_context *kdf = 0; session_state *state = 0; ratchet_chain_key *chain_key[7]; ec_public_key *ratchet_key[7]; result = hkdf_create(&kdf, 2, global_context); ck_assert_int_eq(result, 0); uint8_t keySeed[32]; memset(keySeed, 0x42, sizeof(keySeed)); /* Create 7 instances of receiver chain data */ for(i = 0; i < 7; i++) { result = ratchet_chain_key_create(&chain_key[i], kdf, keySeed, sizeof(keySeed), 0, global_context); ck_assert_int_eq(result, 0); ratchet_key[i] = create_test_ec_public_key(global_context); ck_assert_ptr_ne(ratchet_key[i], 0); } /* Create a new session state instance */ result = session_state_create(&state, global_context); ck_assert_int_eq(result, 0); /* Add 6 instances of receiver chain data */ for(i = 0; i < 7; i++) { result = session_state_add_receiver_chain(state, ratchet_key[i], chain_key[i]); ck_assert_int_eq(result, 0); } /* Verify that only the latter 5 are actually there */ for(i = 0; i < 7; i++) { ratchet_chain_key *cur_chain_key; signal_buffer *chain_key_buf; signal_buffer *cur_chain_key_buf; cur_chain_key = session_state_get_receiver_chain_key(state, ratchet_key[i]); if(i < 2) { ck_assert_ptr_eq(cur_chain_key, 0); } else { ck_assert_ptr_ne(cur_chain_key, 0); result = ratchet_chain_key_get_key(chain_key[i], &chain_key_buf); ck_assert_int_eq(result, 0); result = ratchet_chain_key_get_key(cur_chain_key, &cur_chain_key_buf); ck_assert_int_eq(result, 0); ck_assert_int_eq(signal_buffer_compare(chain_key_buf, cur_chain_key_buf), 0); signal_buffer_free(chain_key_buf); signal_buffer_free(cur_chain_key_buf); } } /* Cleanup */ for(i = 0; i < 7; i++) { SIGNAL_UNREF(chain_key[i]); SIGNAL_UNREF(ratchet_key[i]); } SIGNAL_UNREF(kdf); SIGNAL_UNREF(state); } END_TEST Suite *session_record_suite(void) { Suite *suite = suite_create("session_record"); TCase *tcase = tcase_create("case"); tcase_add_checked_fixture(tcase, test_setup, test_teardown); tcase_add_test(tcase, test_serialize_single_session); tcase_add_test(tcase, test_serialize_multiple_sessions); tcase_add_test(tcase, test_session_receiver_chain_count); suite_add_tcase(suite, tcase); return suite; } int main(void) { int number_failed; Suite *suite; SRunner *runner; suite = session_record_suite(); runner = srunner_create(suite); srunner_run_all(runner, CK_VERBOSE); number_failed = srunner_ntests_failed(runner); srunner_free(runner); return (number_failed == 0) ? EXIT_SUCCESS : EXIT_FAILURE; } libsignal-protocol-c-2.3.3/tests/test_simultaneous_initiate.c000066400000000000000000002234741363751346500245560ustar00rootroot00000000000000#include #include #include #include #include "../src/signal_protocol.h" #include "curve.h" #include "session_record.h" #include "session_state.h" #include "session_cipher.h" #include "session_builder.h" #include "protocol.h" #include "test_common.h" static signal_protocol_address alice_address = { "+14159998888", 12, 1 }; static signal_protocol_address bob_address = { "+14151231234", 12, 1 }; signal_context *global_context; pthread_mutex_t global_mutex; pthread_mutexattr_t global_mutex_attr; ec_key_pair *alice_signed_pre_key; ec_key_pair *bob_signed_pre_key; int32_t alice_signed_pre_key_id; int32_t bob_signed_pre_key_id; int is_session_id_equal(signal_protocol_store_context *alice_store, signal_protocol_store_context *bob_store); int current_session_version(signal_protocol_store_context *store, const signal_protocol_address *address); session_pre_key_bundle *create_alice_pre_key_bundle(signal_protocol_store_context *store); session_pre_key_bundle *create_bob_pre_key_bundle(signal_protocol_store_context *store); void test_lock(void *user_data) { pthread_mutex_lock(&global_mutex); } void test_unlock(void *user_data) { pthread_mutex_unlock(&global_mutex); } void test_setup() { int result; pthread_mutexattr_init(&global_mutex_attr); pthread_mutexattr_settype(&global_mutex_attr, PTHREAD_MUTEX_RECURSIVE); pthread_mutex_init(&global_mutex, &global_mutex_attr); result = signal_context_create(&global_context, 0); ck_assert_int_eq(result, 0); signal_context_set_log_function(global_context, test_log); setup_test_crypto_provider(global_context); result = signal_context_set_locking_functions(global_context, test_lock, test_unlock); ck_assert_int_eq(result, 0); result = curve_generate_key_pair(global_context, &alice_signed_pre_key); ck_assert_int_eq(result, 0); result = curve_generate_key_pair(global_context, &bob_signed_pre_key); ck_assert_int_eq(result, 0); alice_signed_pre_key_id = (rand() & 0x7FFFFFFF) % PRE_KEY_MEDIUM_MAX_VALUE; bob_signed_pre_key_id = (rand() & 0x7FFFFFFF) % PRE_KEY_MEDIUM_MAX_VALUE; } void test_teardown() { SIGNAL_UNREF(alice_signed_pre_key); SIGNAL_UNREF(bob_signed_pre_key); signal_context_destroy(global_context); pthread_mutex_destroy(&global_mutex); pthread_mutexattr_destroy(&global_mutex_attr); } START_TEST(test_basic_simultaneous_initiate) { int result = 0; /* Create the data stores */ signal_protocol_store_context *alice_store = 0; setup_test_store_context(&alice_store, global_context); signal_protocol_store_context *bob_store = 0; setup_test_store_context(&bob_store, global_context); /* Create the pre key bundles */ session_pre_key_bundle *alice_pre_key_bundle = create_alice_pre_key_bundle(alice_store); session_pre_key_bundle *bob_pre_key_bundle = create_bob_pre_key_bundle(bob_store); /* Create the session builders */ session_builder *alice_session_builder = 0; result = session_builder_create(&alice_session_builder, alice_store, &bob_address, global_context); ck_assert_int_eq(result, 0); session_builder *bob_session_builder = 0; result = session_builder_create(&bob_session_builder, bob_store, &alice_address, global_context); ck_assert_int_eq(result, 0); /* Create the session ciphers */ session_cipher *alice_session_cipher = 0; result = session_cipher_create(&alice_session_cipher, alice_store, &bob_address, global_context); ck_assert_int_eq(result, 0); session_cipher *bob_session_cipher = 0; result = session_cipher_create(&bob_session_cipher, bob_store, &alice_address, global_context); ck_assert_int_eq(result, 0); /* Process the pre key bundles */ result = session_builder_process_pre_key_bundle(alice_session_builder, bob_pre_key_bundle); ck_assert_int_eq(result, 0); result = session_builder_process_pre_key_bundle(bob_session_builder, alice_pre_key_bundle); ck_assert_int_eq(result, 0); /* Encrypt a pair of messages */ static const char message_for_bob_data[] = "hey there"; size_t message_for_bob_len = sizeof(message_for_bob_data) - 1; ciphertext_message *message_for_bob = 0; result = session_cipher_encrypt(alice_session_cipher, (uint8_t *)message_for_bob_data, message_for_bob_len, &message_for_bob); ck_assert_int_eq(result, 0); static const char message_for_alice_data[] = "sample message"; size_t message_for_alice_len = sizeof(message_for_alice_data) - 1; ciphertext_message *message_for_alice = 0; result = session_cipher_encrypt(bob_session_cipher, (uint8_t *)message_for_alice_data, message_for_alice_len, &message_for_alice); ck_assert_int_eq(result, 0); /* Verify message types */ ck_assert_int_eq(ciphertext_message_get_type(message_for_bob), CIPHERTEXT_PREKEY_TYPE); ck_assert_int_eq(ciphertext_message_get_type(message_for_alice), CIPHERTEXT_PREKEY_TYPE); /* Verify that the session IDs are not equal */ ck_assert_int_eq(is_session_id_equal(alice_store, bob_store), 0); /* Copy the messages before decrypting */ pre_key_signal_message *message_for_alice_copy = 0; result = pre_key_signal_message_copy(&message_for_alice_copy, (pre_key_signal_message *)message_for_alice, global_context); ck_assert_int_eq(result, 0); pre_key_signal_message *message_for_bob_copy = 0; result = pre_key_signal_message_copy(&message_for_bob_copy, (pre_key_signal_message *)message_for_bob, global_context); ck_assert_int_eq(result, 0); /* Decrypt the messages */ signal_buffer *alice_plaintext = 0; result = session_cipher_decrypt_pre_key_signal_message(alice_session_cipher, message_for_alice_copy, 0, &alice_plaintext); ck_assert_int_eq(result, 0); signal_buffer *bob_plaintext = 0; result = session_cipher_decrypt_pre_key_signal_message(bob_session_cipher, message_for_bob_copy, 0, &bob_plaintext); ck_assert_int_eq(result, 0); /* Verify that the messages decrypted correctly */ uint8_t *alice_plaintext_data = signal_buffer_data(alice_plaintext); size_t alice_plaintext_len = signal_buffer_len(alice_plaintext); ck_assert_int_eq(message_for_alice_len, alice_plaintext_len); ck_assert_int_eq(memcmp(message_for_alice_data, alice_plaintext_data, alice_plaintext_len), 0); uint8_t *bob_plaintext_data = signal_buffer_data(bob_plaintext); size_t bob_plaintext_len = signal_buffer_len(bob_plaintext); ck_assert_int_eq(message_for_bob_len, bob_plaintext_len); ck_assert_int_eq(memcmp(message_for_bob_data, bob_plaintext_data, bob_plaintext_len), 0); /* Verify that the session versions are correct and the IDs are not equal */ ck_assert_int_eq(current_session_version(alice_store, &bob_address), 3); ck_assert_int_eq(current_session_version(bob_store, &alice_address), 3); ck_assert_int_eq(is_session_id_equal(alice_store, bob_store), 0); /* Prepare Alice's response */ static const char alice_response_data[] = "second message"; size_t alice_response_len = sizeof(alice_response_data) - 1; ciphertext_message *alice_response = 0; result = session_cipher_encrypt(alice_session_cipher, (uint8_t *)alice_response_data, alice_response_len, &alice_response); ck_assert_int_eq(result, 0); /* Verify response message type */ ck_assert_int_eq(ciphertext_message_get_type(alice_response), CIPHERTEXT_SIGNAL_TYPE); /* Copy the message before decrypting */ signal_message *alice_response_copy = 0; result = signal_message_copy(&alice_response_copy, (signal_message *)alice_response, global_context); ck_assert_int_eq(result, 0); /* Have Bob decrypt the response */ signal_buffer *response_plaintext = 0; result = session_cipher_decrypt_signal_message(bob_session_cipher, alice_response_copy, 0, &response_plaintext); ck_assert_int_eq(result, 0); /* Verify that the message decrypted correctly */ uint8_t *response_plaintext_data = signal_buffer_data(response_plaintext); size_t response_plaintext_len = signal_buffer_len(response_plaintext); ck_assert_int_eq(alice_response_len, response_plaintext_len); ck_assert_int_eq(memcmp(alice_response_data, response_plaintext_data, response_plaintext_len), 0); /* Verify that the session IDs are now equal */ ck_assert_int_eq(is_session_id_equal(alice_store, bob_store), 1); /* Prepare Bob's final message */ static const char final_message_data[] = "third message"; size_t final_message_len = sizeof(final_message_data) - 1; ciphertext_message *final_message = 0; result = session_cipher_encrypt(bob_session_cipher, (uint8_t *)final_message_data, final_message_len, &final_message); ck_assert_int_eq(result, 0); /* Verify final message type */ ck_assert_int_eq(ciphertext_message_get_type(final_message), CIPHERTEXT_SIGNAL_TYPE); /* Copy the final message before decrypting */ signal_message *final_message_copy = 0; result = signal_message_copy(&final_message_copy, (signal_message *)final_message, global_context); ck_assert_int_eq(result, 0); /* Have Alice decrypt the final message */ signal_buffer *final_plaintext = 0; result = session_cipher_decrypt_signal_message(alice_session_cipher, final_message_copy, 0, &final_plaintext); ck_assert_int_eq(result, 0); /* Verify that the final message decrypted correctly */ uint8_t *final_plaintext_data = signal_buffer_data(final_plaintext); size_t final_plaintext_len = signal_buffer_len(final_plaintext); ck_assert_int_eq(final_message_len, final_plaintext_len); ck_assert_int_eq(memcmp(final_message_data, final_plaintext_data, final_plaintext_len), 0); /* Verify that the session IDs are equal */ ck_assert_int_eq(is_session_id_equal(alice_store, bob_store), 1); /* Cleanup */ signal_buffer_free(final_plaintext); SIGNAL_UNREF(final_message_copy); SIGNAL_UNREF(final_message); signal_buffer_free(response_plaintext); SIGNAL_UNREF(alice_response_copy); SIGNAL_UNREF(alice_response); signal_buffer_free(alice_plaintext); signal_buffer_free(bob_plaintext); SIGNAL_UNREF(message_for_alice_copy); SIGNAL_UNREF(message_for_bob_copy); SIGNAL_UNREF(message_for_alice); SIGNAL_UNREF(message_for_bob); session_cipher_free(alice_session_cipher); session_cipher_free(bob_session_cipher); session_builder_free(alice_session_builder); session_builder_free(bob_session_builder); SIGNAL_UNREF(alice_pre_key_bundle); SIGNAL_UNREF(bob_pre_key_bundle); signal_protocol_store_context_destroy(alice_store); signal_protocol_store_context_destroy(bob_store); } END_TEST START_TEST(test_lost_simultaneous_initiate) { int result = 0; /* Create the data stores */ signal_protocol_store_context *alice_store = 0; setup_test_store_context(&alice_store, global_context); signal_protocol_store_context *bob_store = 0; setup_test_store_context(&bob_store, global_context); /* Create the pre key bundles */ session_pre_key_bundle *alice_pre_key_bundle = create_alice_pre_key_bundle(alice_store); session_pre_key_bundle *bob_pre_key_bundle = create_bob_pre_key_bundle(bob_store); /* Create the session builders */ session_builder *alice_session_builder = 0; result = session_builder_create(&alice_session_builder, alice_store, &bob_address, global_context); ck_assert_int_eq(result, 0); session_builder *bob_session_builder = 0; result = session_builder_create(&bob_session_builder, bob_store, &alice_address, global_context); ck_assert_int_eq(result, 0); /* Create the session ciphers */ session_cipher *alice_session_cipher = 0; result = session_cipher_create(&alice_session_cipher, alice_store, &bob_address, global_context); ck_assert_int_eq(result, 0); session_cipher *bob_session_cipher = 0; result = session_cipher_create(&bob_session_cipher, bob_store, &alice_address, global_context); ck_assert_int_eq(result, 0); /* Process the pre key bundles */ result = session_builder_process_pre_key_bundle(alice_session_builder, bob_pre_key_bundle); ck_assert_int_eq(result, 0); result = session_builder_process_pre_key_bundle(bob_session_builder, alice_pre_key_bundle); ck_assert_int_eq(result, 0); /* Encrypt a pair of messages */ static const char message_for_bob_data[] = "hey there"; size_t message_for_bob_len = sizeof(message_for_bob_data) - 1; ciphertext_message *message_for_bob = 0; result = session_cipher_encrypt(alice_session_cipher, (uint8_t *)message_for_bob_data, message_for_bob_len, &message_for_bob); ck_assert_int_eq(result, 0); static const char message_for_alice_data[] = "sample message"; size_t message_for_alice_len = sizeof(message_for_alice_data) - 1; ciphertext_message *message_for_alice = 0; result = session_cipher_encrypt(bob_session_cipher, (uint8_t *)message_for_alice_data, message_for_alice_len, &message_for_alice); ck_assert_int_eq(result, 0); /* Verify message types */ ck_assert_int_eq(ciphertext_message_get_type(message_for_bob), CIPHERTEXT_PREKEY_TYPE); ck_assert_int_eq(ciphertext_message_get_type(message_for_alice), CIPHERTEXT_PREKEY_TYPE); /* Verify that the session IDs are not equal */ ck_assert_int_eq(is_session_id_equal(alice_store, bob_store), 0); /* Copy the message for Bob before decrypting */ pre_key_signal_message *message_for_bob_copy = 0; result = pre_key_signal_message_copy(&message_for_bob_copy, (pre_key_signal_message *)message_for_bob, global_context); ck_assert_int_eq(result, 0); /* Decrypt the message */ signal_buffer *bob_plaintext = 0; result = session_cipher_decrypt_pre_key_signal_message(bob_session_cipher, message_for_bob_copy, 0, &bob_plaintext); ck_assert_int_eq(result, 0); /* Verify that the message decrypted correctly */ uint8_t *bob_plaintext_data = signal_buffer_data(bob_plaintext); size_t bob_plaintext_len = signal_buffer_len(bob_plaintext); ck_assert_int_eq(message_for_bob_len, bob_plaintext_len); ck_assert_int_eq(memcmp(message_for_bob_data, bob_plaintext_data, bob_plaintext_len), 0); /* Verify that the session version is correct */ ck_assert_int_eq(current_session_version(bob_store, &alice_address), 3); /* Prepare Alice's response */ static const char alice_response_data[] = "second message"; size_t alice_response_len = sizeof(alice_response_data) - 1; ciphertext_message *alice_response = 0; result = session_cipher_encrypt(alice_session_cipher, (uint8_t *)alice_response_data, alice_response_len, &alice_response); ck_assert_int_eq(result, 0); /* Verify response message type */ ck_assert_int_eq(ciphertext_message_get_type(alice_response), CIPHERTEXT_PREKEY_TYPE); /* Copy the message before decrypting */ pre_key_signal_message *alice_response_copy = 0; result = pre_key_signal_message_copy(&alice_response_copy, (pre_key_signal_message *)alice_response, global_context); ck_assert_int_eq(result, 0); /* Have Bob decrypt the response */ signal_buffer *response_plaintext = 0; result = session_cipher_decrypt_pre_key_signal_message(bob_session_cipher, alice_response_copy, 0, &response_plaintext); ck_assert_int_eq(result, 0); /* Verify that the message decrypted correctly */ uint8_t *response_plaintext_data = signal_buffer_data(response_plaintext); size_t response_plaintext_len = signal_buffer_len(response_plaintext); ck_assert_int_eq(alice_response_len, response_plaintext_len); ck_assert_int_eq(memcmp(alice_response_data, response_plaintext_data, response_plaintext_len), 0); /* Verify that the session IDs are now equal */ ck_assert_int_eq(is_session_id_equal(alice_store, bob_store), 1); /* Prepare Bob's final message */ static const char final_message_data[] = "third message"; size_t final_message_len = sizeof(final_message_data) - 1; ciphertext_message *final_message = 0; result = session_cipher_encrypt(bob_session_cipher, (uint8_t *)final_message_data, final_message_len, &final_message); ck_assert_int_eq(result, 0); /* Verify final message type */ ck_assert_int_eq(ciphertext_message_get_type(final_message), CIPHERTEXT_SIGNAL_TYPE); /* Copy the final message before decrypting */ signal_message *final_message_copy = 0; result = signal_message_copy(&final_message_copy, (signal_message *)final_message, global_context); ck_assert_int_eq(result, 0); /* Have Alice decrypt the final message */ signal_buffer *final_plaintext = 0; result = session_cipher_decrypt_signal_message(alice_session_cipher, final_message_copy, 0, &final_plaintext); ck_assert_int_eq(result, 0); /* Verify that the final message decrypted correctly */ uint8_t *final_plaintext_data = signal_buffer_data(final_plaintext); size_t final_plaintext_len = signal_buffer_len(final_plaintext); ck_assert_int_eq(final_message_len, final_plaintext_len); ck_assert_int_eq(memcmp(final_message_data, final_plaintext_data, final_plaintext_len), 0); /* Verify that the session IDs are equal */ ck_assert_int_eq(is_session_id_equal(alice_store, bob_store), 1); /* Cleanup */ signal_buffer_free(final_plaintext); SIGNAL_UNREF(final_message_copy); SIGNAL_UNREF(final_message); signal_buffer_free(response_plaintext); SIGNAL_UNREF(alice_response_copy); SIGNAL_UNREF(alice_response); signal_buffer_free(bob_plaintext); SIGNAL_UNREF(message_for_bob_copy); SIGNAL_UNREF(message_for_alice); SIGNAL_UNREF(message_for_bob); session_cipher_free(alice_session_cipher); session_cipher_free(bob_session_cipher); session_builder_free(alice_session_builder); session_builder_free(bob_session_builder); SIGNAL_UNREF(alice_pre_key_bundle); SIGNAL_UNREF(bob_pre_key_bundle); signal_protocol_store_context_destroy(alice_store); signal_protocol_store_context_destroy(bob_store); } END_TEST START_TEST(test_simultaneous_initiate_lost_message) { int result = 0; /* Create the data stores */ signal_protocol_store_context *alice_store = 0; setup_test_store_context(&alice_store, global_context); signal_protocol_store_context *bob_store = 0; setup_test_store_context(&bob_store, global_context); /* Create the pre key bundles */ session_pre_key_bundle *alice_pre_key_bundle = create_alice_pre_key_bundle(alice_store); session_pre_key_bundle *bob_pre_key_bundle = create_bob_pre_key_bundle(bob_store); /* Create the session builders */ session_builder *alice_session_builder = 0; result = session_builder_create(&alice_session_builder, alice_store, &bob_address, global_context); ck_assert_int_eq(result, 0); session_builder *bob_session_builder = 0; result = session_builder_create(&bob_session_builder, bob_store, &alice_address, global_context); ck_assert_int_eq(result, 0); /* Create the session ciphers */ session_cipher *alice_session_cipher = 0; result = session_cipher_create(&alice_session_cipher, alice_store, &bob_address, global_context); ck_assert_int_eq(result, 0); session_cipher *bob_session_cipher = 0; result = session_cipher_create(&bob_session_cipher, bob_store, &alice_address, global_context); ck_assert_int_eq(result, 0); /* Process the pre key bundles */ result = session_builder_process_pre_key_bundle(alice_session_builder, bob_pre_key_bundle); ck_assert_int_eq(result, 0); result = session_builder_process_pre_key_bundle(bob_session_builder, alice_pre_key_bundle); ck_assert_int_eq(result, 0); /* Encrypt a pair of messages */ static const char message_for_bob_data[] = "hey there"; size_t message_for_bob_len = sizeof(message_for_bob_data) - 1; ciphertext_message *message_for_bob = 0; result = session_cipher_encrypt(alice_session_cipher, (uint8_t *)message_for_bob_data, message_for_bob_len, &message_for_bob); ck_assert_int_eq(result, 0); static const char message_for_alice_data[] = "sample message"; size_t message_for_alice_len = sizeof(message_for_alice_data) - 1; ciphertext_message *message_for_alice = 0; result = session_cipher_encrypt(bob_session_cipher, (uint8_t *)message_for_alice_data, message_for_alice_len, &message_for_alice); ck_assert_int_eq(result, 0); /* Verify message types */ ck_assert_int_eq(ciphertext_message_get_type(message_for_bob), CIPHERTEXT_PREKEY_TYPE); ck_assert_int_eq(ciphertext_message_get_type(message_for_alice), CIPHERTEXT_PREKEY_TYPE); /* Verify that the session IDs are not equal */ ck_assert_int_eq(is_session_id_equal(alice_store, bob_store), 0); /* Copy the messages before decrypting */ pre_key_signal_message *message_for_alice_copy = 0; result = pre_key_signal_message_copy(&message_for_alice_copy, (pre_key_signal_message *)message_for_alice, global_context); ck_assert_int_eq(result, 0); pre_key_signal_message *message_for_bob_copy = 0; result = pre_key_signal_message_copy(&message_for_bob_copy, (pre_key_signal_message *)message_for_bob, global_context); ck_assert_int_eq(result, 0); /* Decrypt the messages */ signal_buffer *alice_plaintext = 0; result = session_cipher_decrypt_pre_key_signal_message(alice_session_cipher, message_for_alice_copy, 0, &alice_plaintext); ck_assert_int_eq(result, 0); signal_buffer *bob_plaintext = 0; result = session_cipher_decrypt_pre_key_signal_message(bob_session_cipher, message_for_bob_copy, 0, &bob_plaintext); ck_assert_int_eq(result, 0); /* Verify that the messages decrypted correctly */ uint8_t *alice_plaintext_data = signal_buffer_data(alice_plaintext); size_t alice_plaintext_len = signal_buffer_len(alice_plaintext); ck_assert_int_eq(message_for_alice_len, alice_plaintext_len); ck_assert_int_eq(memcmp(message_for_alice_data, alice_plaintext_data, alice_plaintext_len), 0); uint8_t *bob_plaintext_data = signal_buffer_data(bob_plaintext); size_t bob_plaintext_len = signal_buffer_len(bob_plaintext); ck_assert_int_eq(message_for_bob_len, bob_plaintext_len); ck_assert_int_eq(memcmp(message_for_bob_data, bob_plaintext_data, bob_plaintext_len), 0); /* Verify that the session versions are correct and the IDs are not equal */ ck_assert_int_eq(current_session_version(alice_store, &bob_address), 3); ck_assert_int_eq(current_session_version(bob_store, &alice_address), 3); ck_assert_int_eq(is_session_id_equal(alice_store, bob_store), 0); /* Prepare Alice's response */ static const char alice_response_data[] = "second message"; size_t alice_response_len = sizeof(alice_response_data) - 1; ciphertext_message *alice_response = 0; result = session_cipher_encrypt(alice_session_cipher, (uint8_t *)alice_response_data, alice_response_len, &alice_response); ck_assert_int_eq(result, 0); /* Verify response message type */ ck_assert_int_eq(ciphertext_message_get_type(alice_response), CIPHERTEXT_SIGNAL_TYPE); /* Copy the message before decrypting */ signal_message *alice_response_copy = 0; result = signal_message_copy(&alice_response_copy, (signal_message *)alice_response, global_context); ck_assert_int_eq(result, 0); /* * Intentionally skip Bob decrypting the response, and continue * with the rest of the test. */ /* Verify that the session IDs are not equal */ ck_assert_int_eq(is_session_id_equal(alice_store, bob_store), 0); /* Prepare Bob's final message */ static const char final_message_data[] = "third message"; size_t final_message_len = sizeof(final_message_data) - 1; ciphertext_message *final_message = 0; result = session_cipher_encrypt(bob_session_cipher, (uint8_t *)final_message_data, final_message_len, &final_message); ck_assert_int_eq(result, 0); /* Verify final message type */ ck_assert_int_eq(ciphertext_message_get_type(final_message), CIPHERTEXT_SIGNAL_TYPE); /* Copy the final message before decrypting */ signal_message *final_message_copy = 0; result = signal_message_copy(&final_message_copy, (signal_message *)final_message, global_context); ck_assert_int_eq(result, 0); /* Have Alice decrypt the final message */ signal_buffer *final_plaintext = 0; result = session_cipher_decrypt_signal_message(alice_session_cipher, final_message_copy, 0, &final_plaintext); ck_assert_int_eq(result, 0); /* Verify that the final message decrypted correctly */ uint8_t *final_plaintext_data = signal_buffer_data(final_plaintext); size_t final_plaintext_len = signal_buffer_len(final_plaintext); ck_assert_int_eq(final_message_len, final_plaintext_len); ck_assert_int_eq(memcmp(final_message_data, final_plaintext_data, final_plaintext_len), 0); /* Verify that the session IDs are equal */ ck_assert_int_eq(is_session_id_equal(alice_store, bob_store), 1); /* Cleanup */ signal_buffer_free(final_plaintext); SIGNAL_UNREF(final_message_copy); SIGNAL_UNREF(final_message); SIGNAL_UNREF(alice_response_copy); SIGNAL_UNREF(alice_response); signal_buffer_free(alice_plaintext); signal_buffer_free(bob_plaintext); SIGNAL_UNREF(message_for_alice_copy); SIGNAL_UNREF(message_for_bob_copy); SIGNAL_UNREF(message_for_alice); SIGNAL_UNREF(message_for_bob); session_cipher_free(alice_session_cipher); session_cipher_free(bob_session_cipher); session_builder_free(alice_session_builder); session_builder_free(bob_session_builder); SIGNAL_UNREF(alice_pre_key_bundle); SIGNAL_UNREF(bob_pre_key_bundle); signal_protocol_store_context_destroy(alice_store); signal_protocol_store_context_destroy(bob_store); } END_TEST START_TEST(test_simultaneous_initiate_repeated_messages) { int result = 0; /* Create the data stores */ signal_protocol_store_context *alice_store = 0; setup_test_store_context(&alice_store, global_context); signal_protocol_store_context *bob_store = 0; setup_test_store_context(&bob_store, global_context); /* Create the pre key bundles */ session_pre_key_bundle *alice_pre_key_bundle = create_alice_pre_key_bundle(alice_store); session_pre_key_bundle *bob_pre_key_bundle = create_bob_pre_key_bundle(bob_store); /* Create the session builders */ session_builder *alice_session_builder = 0; result = session_builder_create(&alice_session_builder, alice_store, &bob_address, global_context); ck_assert_int_eq(result, 0); session_builder *bob_session_builder = 0; result = session_builder_create(&bob_session_builder, bob_store, &alice_address, global_context); ck_assert_int_eq(result, 0); /* Create the session ciphers */ session_cipher *alice_session_cipher = 0; result = session_cipher_create(&alice_session_cipher, alice_store, &bob_address, global_context); ck_assert_int_eq(result, 0); session_cipher *bob_session_cipher = 0; result = session_cipher_create(&bob_session_cipher, bob_store, &alice_address, global_context); ck_assert_int_eq(result, 0); /* Process the pre key bundles */ result = session_builder_process_pre_key_bundle(alice_session_builder, bob_pre_key_bundle); ck_assert_int_eq(result, 0); result = session_builder_process_pre_key_bundle(bob_session_builder, alice_pre_key_bundle); ck_assert_int_eq(result, 0); /* Encrypt a pair of messages */ static const char message_for_bob_data[] = "hey there"; size_t message_for_bob_len = sizeof(message_for_bob_data) - 1; ciphertext_message *message_for_bob = 0; result = session_cipher_encrypt(alice_session_cipher, (uint8_t *)message_for_bob_data, message_for_bob_len, &message_for_bob); ck_assert_int_eq(result, 0); static const char message_for_alice_data[] = "sample message"; size_t message_for_alice_len = sizeof(message_for_alice_data) - 1; ciphertext_message *message_for_alice = 0; result = session_cipher_encrypt(bob_session_cipher, (uint8_t *)message_for_alice_data, message_for_alice_len, &message_for_alice); ck_assert_int_eq(result, 0); /* Verify message types */ ck_assert_int_eq(ciphertext_message_get_type(message_for_bob), CIPHERTEXT_PREKEY_TYPE); ck_assert_int_eq(ciphertext_message_get_type(message_for_alice), CIPHERTEXT_PREKEY_TYPE); /* Verify that the session IDs are not equal */ ck_assert_int_eq(is_session_id_equal(alice_store, bob_store), 0); /* Copy the messages before decrypting */ pre_key_signal_message *message_for_alice_copy = 0; result = pre_key_signal_message_copy(&message_for_alice_copy, (pre_key_signal_message *)message_for_alice, global_context); ck_assert_int_eq(result, 0); pre_key_signal_message *message_for_bob_copy = 0; result = pre_key_signal_message_copy(&message_for_bob_copy, (pre_key_signal_message *)message_for_bob, global_context); ck_assert_int_eq(result, 0); /* Decrypt the messages */ signal_buffer *alice_plaintext = 0; result = session_cipher_decrypt_pre_key_signal_message(alice_session_cipher, message_for_alice_copy, 0, &alice_plaintext); ck_assert_int_eq(result, 0); signal_buffer *bob_plaintext = 0; result = session_cipher_decrypt_pre_key_signal_message(bob_session_cipher, message_for_bob_copy, 0, &bob_plaintext); ck_assert_int_eq(result, 0); /* Verify that the messages decrypted correctly */ uint8_t *alice_plaintext_data = signal_buffer_data(alice_plaintext); size_t alice_plaintext_len = signal_buffer_len(alice_plaintext); ck_assert_int_eq(message_for_alice_len, alice_plaintext_len); ck_assert_int_eq(memcmp(message_for_alice_data, alice_plaintext_data, alice_plaintext_len), 0); uint8_t *bob_plaintext_data = signal_buffer_data(bob_plaintext); size_t bob_plaintext_len = signal_buffer_len(bob_plaintext); ck_assert_int_eq(message_for_bob_len, bob_plaintext_len); ck_assert_int_eq(memcmp(message_for_bob_data, bob_plaintext_data, bob_plaintext_len), 0); /* Verify that the session versions are correct and the IDs are not equal */ ck_assert_int_eq(current_session_version(alice_store, &bob_address), 3); ck_assert_int_eq(current_session_version(bob_store, &alice_address), 3); ck_assert_int_eq(is_session_id_equal(alice_store, bob_store), 0); int i; for(i = 0; i < 50; i++) { fprintf(stderr, "Simultaneous initiate tests, iteration: %d\n", i); /* Encrypt a pair of messages */ static const char message_for_bob_repeat_data[] = "hey there"; size_t message_for_bob_repeat_len = sizeof(message_for_bob_repeat_data) - 1; ciphertext_message *message_for_bob_repeat = 0; result = session_cipher_encrypt(alice_session_cipher, (uint8_t *)message_for_bob_repeat_data, message_for_bob_repeat_len, &message_for_bob_repeat); ck_assert_int_eq(result, 0); static const char message_for_alice_repeat_data[] = "sample message"; size_t message_for_alice_repeat_len = sizeof(message_for_alice_repeat_data) - 1; ciphertext_message *message_for_alice_repeat = 0; result = session_cipher_encrypt(bob_session_cipher, (uint8_t *)message_for_alice_repeat_data, message_for_alice_repeat_len, &message_for_alice_repeat); ck_assert_int_eq(result, 0); /* Verify message types */ ck_assert_int_eq(ciphertext_message_get_type(message_for_bob_repeat), CIPHERTEXT_SIGNAL_TYPE); ck_assert_int_eq(ciphertext_message_get_type(message_for_alice_repeat), CIPHERTEXT_SIGNAL_TYPE); /* Verify that the session IDs are not equal */ ck_assert_int_eq(is_session_id_equal(alice_store, bob_store), 0); /* Copy the messages before decrypting */ signal_message *message_for_alice_repeat_copy = 0; result = signal_message_copy(&message_for_alice_repeat_copy, (signal_message *)message_for_alice_repeat, global_context); ck_assert_int_eq(result, 0); signal_message *message_for_bob_repeat_copy = 0; result = signal_message_copy(&message_for_bob_repeat_copy, (signal_message *)message_for_bob_repeat, global_context); ck_assert_int_eq(result, 0); /* Decrypt the messages */ signal_buffer *alice_repeat_plaintext = 0; result = session_cipher_decrypt_signal_message(alice_session_cipher, message_for_alice_repeat_copy, 0, &alice_repeat_plaintext); ck_assert_int_eq(result, 0); signal_buffer *bob_repeat_plaintext = 0; result = session_cipher_decrypt_signal_message(bob_session_cipher, message_for_bob_repeat_copy, 0, &bob_repeat_plaintext); ck_assert_int_eq(result, 0); /* Verify that the messages decrypted correctly */ uint8_t *alice_repeat_plaintext_data = signal_buffer_data(alice_repeat_plaintext); size_t alice_repeat_plaintext_len = signal_buffer_len(alice_repeat_plaintext); ck_assert_int_eq(message_for_alice_repeat_len, alice_repeat_plaintext_len); ck_assert_int_eq(memcmp(message_for_alice_repeat_data, alice_repeat_plaintext_data, alice_repeat_plaintext_len), 0); uint8_t *bob_repeat_plaintext_data = signal_buffer_data(bob_repeat_plaintext); size_t bob_repeat_plaintext_len = signal_buffer_len(bob_repeat_plaintext); ck_assert_int_eq(message_for_bob_repeat_len, bob_repeat_plaintext_len); ck_assert_int_eq(memcmp(message_for_bob_repeat_data, bob_repeat_plaintext_data, bob_repeat_plaintext_len), 0); /* Verify that the session IDs are not equal */ ck_assert_int_eq(is_session_id_equal(alice_store, bob_store), 0); /* Cleanup */ signal_buffer_free(bob_repeat_plaintext); signal_buffer_free(alice_repeat_plaintext); SIGNAL_UNREF(message_for_bob_repeat_copy); SIGNAL_UNREF(message_for_alice_repeat_copy); SIGNAL_UNREF(message_for_bob_repeat); SIGNAL_UNREF(message_for_alice_repeat); } /* Prepare Alice's response */ static const char alice_response_data[] = "second message"; size_t alice_response_len = sizeof(alice_response_data) - 1; ciphertext_message *alice_response = 0; result = session_cipher_encrypt(alice_session_cipher, (uint8_t *)alice_response_data, alice_response_len, &alice_response); ck_assert_int_eq(result, 0); /* Verify response message type */ ck_assert_int_eq(ciphertext_message_get_type(alice_response), CIPHERTEXT_SIGNAL_TYPE); /* Copy the message before decrypting */ signal_message *alice_response_copy = 0; result = signal_message_copy(&alice_response_copy, (signal_message *)alice_response, global_context); ck_assert_int_eq(result, 0); /* Have Bob decrypt the response */ signal_buffer *response_plaintext = 0; result = session_cipher_decrypt_signal_message(bob_session_cipher, alice_response_copy, 0, &response_plaintext); ck_assert_int_eq(result, 0); /* Verify that the message decrypted correctly */ uint8_t *response_plaintext_data = signal_buffer_data(response_plaintext); size_t response_plaintext_len = signal_buffer_len(response_plaintext); ck_assert_int_eq(alice_response_len, response_plaintext_len); ck_assert_int_eq(memcmp(alice_response_data, response_plaintext_data, response_plaintext_len), 0); /* Verify that the session IDs are now equal */ ck_assert_int_eq(is_session_id_equal(alice_store, bob_store), 1); /* Prepare Bob's final message */ static const char final_message_data[] = "third message"; size_t final_message_len = sizeof(final_message_data) - 1; ciphertext_message *final_message = 0; result = session_cipher_encrypt(bob_session_cipher, (uint8_t *)final_message_data, final_message_len, &final_message); ck_assert_int_eq(result, 0); /* Verify final message type */ ck_assert_int_eq(ciphertext_message_get_type(final_message), CIPHERTEXT_SIGNAL_TYPE); /* Copy the final message before decrypting */ signal_message *final_message_copy = 0; result = signal_message_copy(&final_message_copy, (signal_message *)final_message, global_context); ck_assert_int_eq(result, 0); /* Have Alice decrypt the final message */ signal_buffer *final_plaintext = 0; result = session_cipher_decrypt_signal_message(alice_session_cipher, final_message_copy, 0, &final_plaintext); ck_assert_int_eq(result, 0); /* Verify that the final message decrypted correctly */ uint8_t *final_plaintext_data = signal_buffer_data(final_plaintext); size_t final_plaintext_len = signal_buffer_len(final_plaintext); ck_assert_int_eq(final_message_len, final_plaintext_len); ck_assert_int_eq(memcmp(final_message_data, final_plaintext_data, final_plaintext_len), 0); /* Verify that the session IDs are equal */ ck_assert_int_eq(is_session_id_equal(alice_store, bob_store), 1); /* Cleanup */ signal_buffer_free(final_plaintext); SIGNAL_UNREF(final_message_copy); SIGNAL_UNREF(final_message); signal_buffer_free(response_plaintext); SIGNAL_UNREF(alice_response_copy); SIGNAL_UNREF(alice_response); signal_buffer_free(alice_plaintext); signal_buffer_free(bob_plaintext); SIGNAL_UNREF(message_for_alice_copy); SIGNAL_UNREF(message_for_bob_copy); SIGNAL_UNREF(message_for_alice); SIGNAL_UNREF(message_for_bob); session_cipher_free(alice_session_cipher); session_cipher_free(bob_session_cipher); session_builder_free(alice_session_builder); session_builder_free(bob_session_builder); SIGNAL_UNREF(alice_pre_key_bundle); SIGNAL_UNREF(bob_pre_key_bundle); signal_protocol_store_context_destroy(alice_store); signal_protocol_store_context_destroy(bob_store); } END_TEST START_TEST(test_repeated_simultaneous_initiate_repeated_messages) { int result = 0; int i; /* Create the data stores */ signal_protocol_store_context *alice_store = 0; setup_test_store_context(&alice_store, global_context); signal_protocol_store_context *bob_store = 0; setup_test_store_context(&bob_store, global_context); /* Create the session builders */ session_builder *alice_session_builder = 0; result = session_builder_create(&alice_session_builder, alice_store, &bob_address, global_context); ck_assert_int_eq(result, 0); session_builder *bob_session_builder = 0; result = session_builder_create(&bob_session_builder, bob_store, &alice_address, global_context); ck_assert_int_eq(result, 0); /* Create the session ciphers */ session_cipher *alice_session_cipher = 0; result = session_cipher_create(&alice_session_cipher, alice_store, &bob_address, global_context); ck_assert_int_eq(result, 0); session_cipher *bob_session_cipher = 0; result = session_cipher_create(&bob_session_cipher, bob_store, &alice_address, global_context); ck_assert_int_eq(result, 0); for(i = 0; i < 15; i++) { /* Create the pre key bundles */ session_pre_key_bundle *alice_pre_key_bundle = create_alice_pre_key_bundle(alice_store); session_pre_key_bundle *bob_pre_key_bundle = create_bob_pre_key_bundle(bob_store); /* Process the pre key bundles */ result = session_builder_process_pre_key_bundle(alice_session_builder, bob_pre_key_bundle); ck_assert_int_eq(result, 0); result = session_builder_process_pre_key_bundle(bob_session_builder, alice_pre_key_bundle); ck_assert_int_eq(result, 0); /* Encrypt a pair of messages */ static const char message_for_bob_data[] = "hey there"; size_t message_for_bob_len = sizeof(message_for_bob_data) - 1; ciphertext_message *message_for_bob = 0; result = session_cipher_encrypt(alice_session_cipher, (uint8_t *)message_for_bob_data, message_for_bob_len, &message_for_bob); ck_assert_int_eq(result, 0); static const char message_for_alice_data[] = "sample message"; size_t message_for_alice_len = sizeof(message_for_alice_data) - 1; ciphertext_message *message_for_alice = 0; result = session_cipher_encrypt(bob_session_cipher, (uint8_t *)message_for_alice_data, message_for_alice_len, &message_for_alice); ck_assert_int_eq(result, 0); /* Verify message types */ ck_assert_int_eq(ciphertext_message_get_type(message_for_bob), CIPHERTEXT_PREKEY_TYPE); ck_assert_int_eq(ciphertext_message_get_type(message_for_alice), CIPHERTEXT_PREKEY_TYPE); /* Verify that the session IDs are not equal */ ck_assert_int_eq(is_session_id_equal(alice_store, bob_store), 0); /* Copy the messages before decrypting */ pre_key_signal_message *message_for_alice_copy = 0; result = pre_key_signal_message_copy(&message_for_alice_copy, (pre_key_signal_message *)message_for_alice, global_context); ck_assert_int_eq(result, 0); pre_key_signal_message *message_for_bob_copy = 0; result = pre_key_signal_message_copy(&message_for_bob_copy, (pre_key_signal_message *)message_for_bob, global_context); ck_assert_int_eq(result, 0); /* Decrypt the messages */ signal_buffer *alice_plaintext = 0; result = session_cipher_decrypt_pre_key_signal_message(alice_session_cipher, message_for_alice_copy, 0, &alice_plaintext); ck_assert_int_eq(result, 0); signal_buffer *bob_plaintext = 0; result = session_cipher_decrypt_pre_key_signal_message(bob_session_cipher, message_for_bob_copy, 0, &bob_plaintext); ck_assert_int_eq(result, 0); /* Verify that the messages decrypted correctly */ uint8_t *alice_plaintext_data = signal_buffer_data(alice_plaintext); size_t alice_plaintext_len = signal_buffer_len(alice_plaintext); ck_assert_int_eq(message_for_alice_len, alice_plaintext_len); ck_assert_int_eq(memcmp(message_for_alice_data, alice_plaintext_data, alice_plaintext_len), 0); uint8_t *bob_plaintext_data = signal_buffer_data(bob_plaintext); size_t bob_plaintext_len = signal_buffer_len(bob_plaintext); ck_assert_int_eq(message_for_bob_len, bob_plaintext_len); ck_assert_int_eq(memcmp(message_for_bob_data, bob_plaintext_data, bob_plaintext_len), 0); /* Verify that the session versions are correct and the IDs are not equal */ ck_assert_int_eq(current_session_version(alice_store, &bob_address), 3); ck_assert_int_eq(current_session_version(bob_store, &alice_address), 3); ck_assert_int_eq(is_session_id_equal(alice_store, bob_store), 0); /* Cleanup */ signal_buffer_free(alice_plaintext); signal_buffer_free(bob_plaintext); SIGNAL_UNREF(message_for_alice_copy); SIGNAL_UNREF(message_for_bob_copy); SIGNAL_UNREF(message_for_alice); SIGNAL_UNREF(message_for_bob); SIGNAL_UNREF(alice_pre_key_bundle); SIGNAL_UNREF(bob_pre_key_bundle); } for(i = 0; i < 50; i++) { fprintf(stderr, "Simultaneous initiate tests, iteration: %d\n", i); /* Encrypt a pair of messages */ static const char message_for_bob_repeat_data[] = "hey there"; size_t message_for_bob_repeat_len = sizeof(message_for_bob_repeat_data) - 1; ciphertext_message *message_for_bob_repeat = 0; result = session_cipher_encrypt(alice_session_cipher, (uint8_t *)message_for_bob_repeat_data, message_for_bob_repeat_len, &message_for_bob_repeat); ck_assert_int_eq(result, 0); static const char message_for_alice_repeat_data[] = "sample message"; size_t message_for_alice_repeat_len = sizeof(message_for_alice_repeat_data) - 1; ciphertext_message *message_for_alice_repeat = 0; result = session_cipher_encrypt(bob_session_cipher, (uint8_t *)message_for_alice_repeat_data, message_for_alice_repeat_len, &message_for_alice_repeat); ck_assert_int_eq(result, 0); /* Verify message types */ ck_assert_int_eq(ciphertext_message_get_type(message_for_bob_repeat), CIPHERTEXT_SIGNAL_TYPE); ck_assert_int_eq(ciphertext_message_get_type(message_for_alice_repeat), CIPHERTEXT_SIGNAL_TYPE); /* Verify that the session IDs are not equal */ ck_assert_int_eq(is_session_id_equal(alice_store, bob_store), 0); /* Copy the messages before decrypting */ signal_message *message_for_alice_repeat_copy = 0; result = signal_message_copy(&message_for_alice_repeat_copy, (signal_message *)message_for_alice_repeat, global_context); ck_assert_int_eq(result, 0); signal_message *message_for_bob_repeat_copy = 0; result = signal_message_copy(&message_for_bob_repeat_copy, (signal_message *)message_for_bob_repeat, global_context); ck_assert_int_eq(result, 0); /* Decrypt the messages */ signal_buffer *alice_repeat_plaintext = 0; result = session_cipher_decrypt_signal_message(alice_session_cipher, message_for_alice_repeat_copy, 0, &alice_repeat_plaintext); ck_assert_int_eq(result, 0); signal_buffer *bob_repeat_plaintext = 0; result = session_cipher_decrypt_signal_message(bob_session_cipher, message_for_bob_repeat_copy, 0, &bob_repeat_plaintext); ck_assert_int_eq(result, 0); /* Verify that the messages decrypted correctly */ uint8_t *alice_repeat_plaintext_data = signal_buffer_data(alice_repeat_plaintext); size_t alice_repeat_plaintext_len = signal_buffer_len(alice_repeat_plaintext); ck_assert_int_eq(message_for_alice_repeat_len, alice_repeat_plaintext_len); ck_assert_int_eq(memcmp(message_for_alice_repeat_data, alice_repeat_plaintext_data, alice_repeat_plaintext_len), 0); uint8_t *bob_repeat_plaintext_data = signal_buffer_data(bob_repeat_plaintext); size_t bob_repeat_plaintext_len = signal_buffer_len(bob_repeat_plaintext); ck_assert_int_eq(message_for_bob_repeat_len, bob_repeat_plaintext_len); ck_assert_int_eq(memcmp(message_for_bob_repeat_data, bob_repeat_plaintext_data, bob_repeat_plaintext_len), 0); /* Verify that the session IDs are not equal */ ck_assert_int_eq(is_session_id_equal(alice_store, bob_store), 0); /* Cleanup */ signal_buffer_free(bob_repeat_plaintext); signal_buffer_free(alice_repeat_plaintext); SIGNAL_UNREF(message_for_bob_repeat_copy); SIGNAL_UNREF(message_for_alice_repeat_copy); SIGNAL_UNREF(message_for_bob_repeat); SIGNAL_UNREF(message_for_alice_repeat); } /* Prepare Alice's response */ static const char alice_response_data[] = "second message"; size_t alice_response_len = sizeof(alice_response_data) - 1; ciphertext_message *alice_response = 0; result = session_cipher_encrypt(alice_session_cipher, (uint8_t *)alice_response_data, alice_response_len, &alice_response); ck_assert_int_eq(result, 0); /* Verify response message type */ ck_assert_int_eq(ciphertext_message_get_type(alice_response), CIPHERTEXT_SIGNAL_TYPE); /* Copy the message before decrypting */ signal_message *alice_response_copy = 0; result = signal_message_copy(&alice_response_copy, (signal_message *)alice_response, global_context); ck_assert_int_eq(result, 0); /* Have Bob decrypt the response */ signal_buffer *response_plaintext = 0; result = session_cipher_decrypt_signal_message(bob_session_cipher, alice_response_copy, 0, &response_plaintext); ck_assert_int_eq(result, 0); /* Verify that the message decrypted correctly */ uint8_t *response_plaintext_data = signal_buffer_data(response_plaintext); size_t response_plaintext_len = signal_buffer_len(response_plaintext); ck_assert_int_eq(alice_response_len, response_plaintext_len); ck_assert_int_eq(memcmp(alice_response_data, response_plaintext_data, response_plaintext_len), 0); /* Verify that the session IDs are now equal */ ck_assert_int_eq(is_session_id_equal(alice_store, bob_store), 1); /* Prepare Bob's final message */ static const char final_message_data[] = "third message"; size_t final_message_len = sizeof(final_message_data) - 1; ciphertext_message *final_message = 0; result = session_cipher_encrypt(bob_session_cipher, (uint8_t *)final_message_data, final_message_len, &final_message); ck_assert_int_eq(result, 0); /* Verify final message type */ ck_assert_int_eq(ciphertext_message_get_type(final_message), CIPHERTEXT_SIGNAL_TYPE); /* Copy the final message before decrypting */ signal_message *final_message_copy = 0; result = signal_message_copy(&final_message_copy, (signal_message *)final_message, global_context); ck_assert_int_eq(result, 0); /* Have Alice decrypt the final message */ signal_buffer *final_plaintext = 0; result = session_cipher_decrypt_signal_message(alice_session_cipher, final_message_copy, 0, &final_plaintext); ck_assert_int_eq(result, 0); /* Verify that the final message decrypted correctly */ uint8_t *final_plaintext_data = signal_buffer_data(final_plaintext); size_t final_plaintext_len = signal_buffer_len(final_plaintext); ck_assert_int_eq(final_message_len, final_plaintext_len); ck_assert_int_eq(memcmp(final_message_data, final_plaintext_data, final_plaintext_len), 0); /* Verify that the session IDs are equal */ ck_assert_int_eq(is_session_id_equal(alice_store, bob_store), 1); /* Cleanup */ signal_buffer_free(final_plaintext); SIGNAL_UNREF(final_message_copy); SIGNAL_UNREF(final_message); signal_buffer_free(response_plaintext); SIGNAL_UNREF(alice_response_copy); SIGNAL_UNREF(alice_response); session_cipher_free(alice_session_cipher); session_cipher_free(bob_session_cipher); session_builder_free(alice_session_builder); session_builder_free(bob_session_builder); signal_protocol_store_context_destroy(alice_store); signal_protocol_store_context_destroy(bob_store); } END_TEST START_TEST(test_repeated_simultaneous_initiate_lost_message_repeated_messages) { int result = 0; int i; /* Create the data stores */ signal_protocol_store_context *alice_store = 0; setup_test_store_context(&alice_store, global_context); signal_protocol_store_context *bob_store = 0; setup_test_store_context(&bob_store, global_context); /* Create the session builders */ session_builder *alice_session_builder = 0; result = session_builder_create(&alice_session_builder, alice_store, &bob_address, global_context); ck_assert_int_eq(result, 0); session_builder *bob_session_builder = 0; result = session_builder_create(&bob_session_builder, bob_store, &alice_address, global_context); ck_assert_int_eq(result, 0); /* Create the session ciphers */ session_cipher *alice_session_cipher = 0; result = session_cipher_create(&alice_session_cipher, alice_store, &bob_address, global_context); ck_assert_int_eq(result, 0); session_cipher *bob_session_cipher = 0; result = session_cipher_create(&bob_session_cipher, bob_store, &alice_address, global_context); ck_assert_int_eq(result, 0); /* Create the pre key bundles, intentionally skipping Alice's */ session_pre_key_bundle *bob_lost_pre_key_bundle = create_bob_pre_key_bundle(bob_store); /* Process the pre key bundles, intentionally skipping Alice's */ result = session_builder_process_pre_key_bundle(alice_session_builder, bob_lost_pre_key_bundle); ck_assert_int_eq(result, 0); /* Encrypt a pair of messages, intentionally skipping Alice's */ static const char lost_message_for_bob_data[] = "hey there"; size_t lost_message_for_bob_len = sizeof(lost_message_for_bob_data) - 1; ciphertext_message *lost_message_for_bob = 0; result = session_cipher_encrypt(alice_session_cipher, (uint8_t *)lost_message_for_bob_data, lost_message_for_bob_len, &lost_message_for_bob); ck_assert_int_eq(result, 0); for(i = 0; i < 15; i++) { /* Create the pre key bundles */ session_pre_key_bundle *alice_pre_key_bundle = create_alice_pre_key_bundle(alice_store); session_pre_key_bundle *bob_pre_key_bundle = create_bob_pre_key_bundle(bob_store); /* Process the pre key bundles */ result = session_builder_process_pre_key_bundle(alice_session_builder, bob_pre_key_bundle); ck_assert_int_eq(result, 0); result = session_builder_process_pre_key_bundle(bob_session_builder, alice_pre_key_bundle); ck_assert_int_eq(result, 0); /* Encrypt a pair of messages */ static const char message_for_bob_data[] = "hey there"; size_t message_for_bob_len = sizeof(message_for_bob_data) - 1; ciphertext_message *message_for_bob = 0; result = session_cipher_encrypt(alice_session_cipher, (uint8_t *)message_for_bob_data, message_for_bob_len, &message_for_bob); ck_assert_int_eq(result, 0); static const char message_for_alice_data[] = "sample message"; size_t message_for_alice_len = sizeof(message_for_alice_data) - 1; ciphertext_message *message_for_alice = 0; result = session_cipher_encrypt(bob_session_cipher, (uint8_t *)message_for_alice_data, message_for_alice_len, &message_for_alice); ck_assert_int_eq(result, 0); /* Verify message types */ ck_assert_int_eq(ciphertext_message_get_type(message_for_bob), CIPHERTEXT_PREKEY_TYPE); ck_assert_int_eq(ciphertext_message_get_type(message_for_alice), CIPHERTEXT_PREKEY_TYPE); /* Verify that the session IDs are not equal */ ck_assert_int_eq(is_session_id_equal(alice_store, bob_store), 0); /* Copy the messages before decrypting */ pre_key_signal_message *message_for_alice_copy = 0; result = pre_key_signal_message_copy(&message_for_alice_copy, (pre_key_signal_message *)message_for_alice, global_context); ck_assert_int_eq(result, 0); pre_key_signal_message *message_for_bob_copy = 0; result = pre_key_signal_message_copy(&message_for_bob_copy, (pre_key_signal_message *)message_for_bob, global_context); ck_assert_int_eq(result, 0); /* Decrypt the messages */ signal_buffer *alice_plaintext = 0; result = session_cipher_decrypt_pre_key_signal_message(alice_session_cipher, message_for_alice_copy, 0, &alice_plaintext); ck_assert_int_eq(result, 0); signal_buffer *bob_plaintext = 0; result = session_cipher_decrypt_pre_key_signal_message(bob_session_cipher, message_for_bob_copy, 0, &bob_plaintext); ck_assert_int_eq(result, 0); /* Verify that the messages decrypted correctly */ uint8_t *alice_plaintext_data = signal_buffer_data(alice_plaintext); size_t alice_plaintext_len = signal_buffer_len(alice_plaintext); ck_assert_int_eq(message_for_alice_len, alice_plaintext_len); ck_assert_int_eq(memcmp(message_for_alice_data, alice_plaintext_data, alice_plaintext_len), 0); uint8_t *bob_plaintext_data = signal_buffer_data(bob_plaintext); size_t bob_plaintext_len = signal_buffer_len(bob_plaintext); ck_assert_int_eq(message_for_bob_len, bob_plaintext_len); ck_assert_int_eq(memcmp(message_for_bob_data, bob_plaintext_data, bob_plaintext_len), 0); /* Verify that the session versions are correct and the IDs are not equal */ ck_assert_int_eq(current_session_version(alice_store, &bob_address), 3); ck_assert_int_eq(current_session_version(bob_store, &alice_address), 3); ck_assert_int_eq(is_session_id_equal(alice_store, bob_store), 0); /* Cleanup */ signal_buffer_free(alice_plaintext); signal_buffer_free(bob_plaintext); SIGNAL_UNREF(message_for_alice_copy); SIGNAL_UNREF(message_for_bob_copy); SIGNAL_UNREF(message_for_alice); SIGNAL_UNREF(message_for_bob); SIGNAL_UNREF(alice_pre_key_bundle); SIGNAL_UNREF(bob_pre_key_bundle); } for(i = 0; i < 50; i++) { fprintf(stderr, "Simultaneous initiate tests, iteration: %d\n", i); /* Encrypt a pair of messages */ static const char message_for_bob_repeat_data[] = "hey there"; size_t message_for_bob_repeat_len = sizeof(message_for_bob_repeat_data) - 1; ciphertext_message *message_for_bob_repeat = 0; result = session_cipher_encrypt(alice_session_cipher, (uint8_t *)message_for_bob_repeat_data, message_for_bob_repeat_len, &message_for_bob_repeat); ck_assert_int_eq(result, 0); static const char message_for_alice_repeat_data[] = "sample message"; size_t message_for_alice_repeat_len = sizeof(message_for_alice_repeat_data) - 1; ciphertext_message *message_for_alice_repeat = 0; result = session_cipher_encrypt(bob_session_cipher, (uint8_t *)message_for_alice_repeat_data, message_for_alice_repeat_len, &message_for_alice_repeat); ck_assert_int_eq(result, 0); /* Verify message types */ ck_assert_int_eq(ciphertext_message_get_type(message_for_bob_repeat), CIPHERTEXT_SIGNAL_TYPE); ck_assert_int_eq(ciphertext_message_get_type(message_for_alice_repeat), CIPHERTEXT_SIGNAL_TYPE); /* Verify that the session IDs are not equal */ ck_assert_int_eq(is_session_id_equal(alice_store, bob_store), 0); /* Copy the messages before decrypting */ signal_message *message_for_alice_repeat_copy = 0; result = signal_message_copy(&message_for_alice_repeat_copy, (signal_message *)message_for_alice_repeat, global_context); ck_assert_int_eq(result, 0); signal_message *message_for_bob_repeat_copy = 0; result = signal_message_copy(&message_for_bob_repeat_copy, (signal_message *)message_for_bob_repeat, global_context); ck_assert_int_eq(result, 0); /* Decrypt the messages */ signal_buffer *alice_repeat_plaintext = 0; result = session_cipher_decrypt_signal_message(alice_session_cipher, message_for_alice_repeat_copy, 0, &alice_repeat_plaintext); ck_assert_int_eq(result, 0); signal_buffer *bob_repeat_plaintext = 0; result = session_cipher_decrypt_signal_message(bob_session_cipher, message_for_bob_repeat_copy, 0, &bob_repeat_plaintext); ck_assert_int_eq(result, 0); /* Verify that the messages decrypted correctly */ uint8_t *alice_repeat_plaintext_data = signal_buffer_data(alice_repeat_plaintext); size_t alice_repeat_plaintext_len = signal_buffer_len(alice_repeat_plaintext); ck_assert_int_eq(message_for_alice_repeat_len, alice_repeat_plaintext_len); ck_assert_int_eq(memcmp(message_for_alice_repeat_data, alice_repeat_plaintext_data, alice_repeat_plaintext_len), 0); uint8_t *bob_repeat_plaintext_data = signal_buffer_data(bob_repeat_plaintext); size_t bob_repeat_plaintext_len = signal_buffer_len(bob_repeat_plaintext); ck_assert_int_eq(message_for_bob_repeat_len, bob_repeat_plaintext_len); ck_assert_int_eq(memcmp(message_for_bob_repeat_data, bob_repeat_plaintext_data, bob_repeat_plaintext_len), 0); /* Verify that the session IDs are not equal */ ck_assert_int_eq(is_session_id_equal(alice_store, bob_store), 0); /* Cleanup */ signal_buffer_free(bob_repeat_plaintext); signal_buffer_free(alice_repeat_plaintext); SIGNAL_UNREF(message_for_bob_repeat_copy); SIGNAL_UNREF(message_for_alice_repeat_copy); SIGNAL_UNREF(message_for_bob_repeat); SIGNAL_UNREF(message_for_alice_repeat); } /* Prepare Alice's response */ static const char alice_response_data[] = "second message"; size_t alice_response_len = sizeof(alice_response_data) - 1; ciphertext_message *alice_response = 0; result = session_cipher_encrypt(alice_session_cipher, (uint8_t *)alice_response_data, alice_response_len, &alice_response); ck_assert_int_eq(result, 0); /* Verify response message type */ ck_assert_int_eq(ciphertext_message_get_type(alice_response), CIPHERTEXT_SIGNAL_TYPE); /* Copy the message before decrypting */ signal_message *alice_response_copy = 0; result = signal_message_copy(&alice_response_copy, (signal_message *)alice_response, global_context); ck_assert_int_eq(result, 0); /* Have Bob decrypt the response */ signal_buffer *response_plaintext = 0; result = session_cipher_decrypt_signal_message(bob_session_cipher, alice_response_copy, 0, &response_plaintext); ck_assert_int_eq(result, 0); /* Verify that the message decrypted correctly */ uint8_t *response_plaintext_data = signal_buffer_data(response_plaintext); size_t response_plaintext_len = signal_buffer_len(response_plaintext); ck_assert_int_eq(alice_response_len, response_plaintext_len); ck_assert_int_eq(memcmp(alice_response_data, response_plaintext_data, response_plaintext_len), 0); /* Verify that the session IDs are now equal */ ck_assert_int_eq(is_session_id_equal(alice_store, bob_store), 1); /* Prepare Bob's final message */ static const char final_message_data[] = "third message"; size_t final_message_len = sizeof(final_message_data) - 1; ciphertext_message *final_message = 0; result = session_cipher_encrypt(bob_session_cipher, (uint8_t *)final_message_data, final_message_len, &final_message); ck_assert_int_eq(result, 0); /* Verify final message type */ ck_assert_int_eq(ciphertext_message_get_type(final_message), CIPHERTEXT_SIGNAL_TYPE); /* Copy the final message before decrypting */ signal_message *final_message_copy = 0; result = signal_message_copy(&final_message_copy, (signal_message *)final_message, global_context); ck_assert_int_eq(result, 0); /* Have Alice decrypt the final message */ signal_buffer *final_plaintext = 0; result = session_cipher_decrypt_signal_message(alice_session_cipher, final_message_copy, 0, &final_plaintext); ck_assert_int_eq(result, 0); /* Verify that the final message decrypted correctly */ uint8_t *final_plaintext_data = signal_buffer_data(final_plaintext); size_t final_plaintext_len = signal_buffer_len(final_plaintext); ck_assert_int_eq(final_message_len, final_plaintext_len); ck_assert_int_eq(memcmp(final_message_data, final_plaintext_data, final_plaintext_len), 0); /* Verify that the session IDs are equal */ ck_assert_int_eq(is_session_id_equal(alice_store, bob_store), 1); /* Copy the lost message before decrypting */ pre_key_signal_message *lost_message_for_bob_copy = 0; result = pre_key_signal_message_copy(&lost_message_for_bob_copy, (pre_key_signal_message *)lost_message_for_bob, global_context); ck_assert_int_eq(result, 0); /* Decrypt the lost message */ signal_buffer *lost_message_for_bob_plaintext = 0; result = session_cipher_decrypt_pre_key_signal_message(bob_session_cipher, lost_message_for_bob_copy, 0, &lost_message_for_bob_plaintext); ck_assert_int_eq(result, 0); /* Verify that the lost message decrypted correctly */ uint8_t *lost_bob_plaintext_data = signal_buffer_data(lost_message_for_bob_plaintext); size_t lost_bob_plaintext_len = signal_buffer_len(lost_message_for_bob_plaintext); ck_assert_int_eq(lost_message_for_bob_len, lost_bob_plaintext_len); ck_assert_int_eq(memcmp(lost_message_for_bob_data, lost_bob_plaintext_data, lost_bob_plaintext_len), 0); /* Verify that the session IDs are not equal */ ck_assert_int_eq(is_session_id_equal(alice_store, bob_store), 0); /* Encrypt an unexpected final message */ static const char blast_from_the_past_data[] = "unexpected!"; size_t blast_from_the_past_len = sizeof(blast_from_the_past_data) - 1; ciphertext_message *blast_from_the_past = 0; result = session_cipher_encrypt(bob_session_cipher, (uint8_t *)blast_from_the_past_data, blast_from_the_past_len, &blast_from_the_past); ck_assert_int_eq(result, 0); /* Copy the unexpected message before decrypting */ signal_message *blast_from_the_past_copy = 0; result = signal_message_copy(&blast_from_the_past_copy, (signal_message *)blast_from_the_past, global_context); ck_assert_int_eq(result, 0); /* Decrypt the unexpected message */ signal_buffer *blast_from_the_past_plaintext = 0; result = session_cipher_decrypt_signal_message(alice_session_cipher, blast_from_the_past_copy, 0, &blast_from_the_past_plaintext); ck_assert_int_eq(result, 0); /* Verify that the unexpected message decrypted correctly */ uint8_t *blast_from_the_past_decrypted_data = signal_buffer_data(blast_from_the_past_plaintext); size_t blast_from_the_past_decrypted_len = signal_buffer_len(blast_from_the_past_plaintext); ck_assert_int_eq(blast_from_the_past_len, blast_from_the_past_decrypted_len); ck_assert_int_eq(memcmp(blast_from_the_past_data, blast_from_the_past_decrypted_data, blast_from_the_past_decrypted_len), 0); /* Verify that the session IDs are equal */ ck_assert_int_eq(is_session_id_equal(alice_store, bob_store), 1); /* Cleanup */ signal_buffer_free(blast_from_the_past_plaintext); SIGNAL_UNREF(blast_from_the_past_copy); SIGNAL_UNREF(blast_from_the_past); signal_buffer_free(lost_message_for_bob_plaintext); SIGNAL_UNREF(lost_message_for_bob_copy); signal_buffer_free(final_plaintext); SIGNAL_UNREF(final_message_copy); SIGNAL_UNREF(final_message); signal_buffer_free(response_plaintext); SIGNAL_UNREF(alice_response_copy); SIGNAL_UNREF(alice_response); SIGNAL_UNREF(bob_lost_pre_key_bundle); SIGNAL_UNREF(lost_message_for_bob); session_cipher_free(alice_session_cipher); session_cipher_free(bob_session_cipher); session_builder_free(alice_session_builder); session_builder_free(bob_session_builder); signal_protocol_store_context_destroy(alice_store); signal_protocol_store_context_destroy(bob_store); } END_TEST int is_session_id_equal(signal_protocol_store_context *alice_store, signal_protocol_store_context *bob_store) { int result = 0; session_record *alice_store_record = 0; session_record *bob_store_record = 0; ec_public_key *alice_store_alice_base_key = 0; ec_public_key *bob_store_alice_base_key = 0; result = signal_protocol_session_load_session(alice_store, &alice_store_record, &bob_address); ck_assert_int_eq(result, 0); result = signal_protocol_session_load_session(bob_store, &bob_store_record, &alice_address); ck_assert_int_eq(result, 0); alice_store_alice_base_key = session_state_get_alice_base_key(session_record_get_state(alice_store_record)); bob_store_alice_base_key = session_state_get_alice_base_key(session_record_get_state(bob_store_record)); if(ec_public_key_compare(alice_store_alice_base_key, bob_store_alice_base_key) == 0) { result = 1; } else { result = 0; } SIGNAL_UNREF(alice_store_record); SIGNAL_UNREF(bob_store_record); return result; } int current_session_version(signal_protocol_store_context *store, const signal_protocol_address *address) { int result = 0; session_record *record = 0; session_state *state = 0; result = signal_protocol_session_load_session(store, &record, address); ck_assert_int_eq(result, 0); state = session_record_get_state(record); result = session_state_get_session_version(state); SIGNAL_UNREF(record); return result; } session_pre_key_bundle *create_alice_pre_key_bundle(signal_protocol_store_context *store) { int result = 0; ec_key_pair *alice_unsigned_pre_key = 0; curve_generate_key_pair(global_context, &alice_unsigned_pre_key); ck_assert_int_eq(result, 0); int alice_unsigned_pre_key_id = (rand() & 0x7FFFFFFF) % PRE_KEY_MEDIUM_MAX_VALUE; ratchet_identity_key_pair *alice_identity_key_pair = 0; result = signal_protocol_identity_get_key_pair(store, &alice_identity_key_pair); ck_assert_int_eq(result, 0); ec_public_key *alice_signed_pre_key_public = ec_key_pair_get_public(alice_signed_pre_key); signal_buffer *alice_signed_pre_key_public_serialized = 0; result = ec_public_key_serialize(&alice_signed_pre_key_public_serialized, alice_signed_pre_key_public); ck_assert_int_eq(result, 0); signal_buffer *signature = 0; result = curve_calculate_signature(global_context, &signature, ratchet_identity_key_pair_get_private(alice_identity_key_pair), signal_buffer_data(alice_signed_pre_key_public_serialized), signal_buffer_len(alice_signed_pre_key_public_serialized)); ck_assert_int_eq(result, 0); session_pre_key_bundle *alice_pre_key_bundle = 0; result = session_pre_key_bundle_create(&alice_pre_key_bundle, 1, 1, alice_unsigned_pre_key_id, ec_key_pair_get_public(alice_unsigned_pre_key), alice_signed_pre_key_id, alice_signed_pre_key_public, signal_buffer_data(signature), signal_buffer_len(signature), ratchet_identity_key_pair_get_public(alice_identity_key_pair)); ck_assert_int_eq(result, 0); session_signed_pre_key *signed_pre_key_record = 0; result = session_signed_pre_key_create(&signed_pre_key_record, alice_signed_pre_key_id, time(0), alice_signed_pre_key, signal_buffer_data(signature), signal_buffer_len(signature)); ck_assert_int_eq(result, 0); result = signal_protocol_signed_pre_key_store_key(store, signed_pre_key_record); ck_assert_int_eq(result, 0); session_pre_key *pre_key_record = 0; result = session_pre_key_create(&pre_key_record, alice_unsigned_pre_key_id, alice_unsigned_pre_key); ck_assert_int_eq(result, 0); result = signal_protocol_pre_key_store_key(store, pre_key_record); ck_assert_int_eq(result, 0); SIGNAL_UNREF(pre_key_record); SIGNAL_UNREF(signed_pre_key_record); SIGNAL_UNREF(alice_identity_key_pair); SIGNAL_UNREF(alice_unsigned_pre_key); signal_buffer_free(alice_signed_pre_key_public_serialized); signal_buffer_free(signature); return alice_pre_key_bundle; } session_pre_key_bundle *create_bob_pre_key_bundle(signal_protocol_store_context *store) { int result = 0; ec_key_pair *bob_unsigned_pre_key = 0; curve_generate_key_pair(global_context, &bob_unsigned_pre_key); ck_assert_int_eq(result, 0); int bob_unsigned_pre_key_id = (rand() & 0x7FFFFFFF) % PRE_KEY_MEDIUM_MAX_VALUE; ratchet_identity_key_pair *bob_identity_key_pair = 0; result = signal_protocol_identity_get_key_pair(store, &bob_identity_key_pair); ck_assert_int_eq(result, 0); ec_public_key *bob_signed_pre_key_public = ec_key_pair_get_public(bob_signed_pre_key); signal_buffer *bob_signed_pre_key_public_serialized = 0; result = ec_public_key_serialize(&bob_signed_pre_key_public_serialized, bob_signed_pre_key_public); ck_assert_int_eq(result, 0); signal_buffer *signature = 0; result = curve_calculate_signature(global_context, &signature, ratchet_identity_key_pair_get_private(bob_identity_key_pair), signal_buffer_data(bob_signed_pre_key_public_serialized), signal_buffer_len(bob_signed_pre_key_public_serialized)); ck_assert_int_eq(result, 0); session_pre_key_bundle *bob_pre_key_bundle = 0; result = session_pre_key_bundle_create(&bob_pre_key_bundle, 1, 1, bob_unsigned_pre_key_id, ec_key_pair_get_public(bob_unsigned_pre_key), bob_signed_pre_key_id, bob_signed_pre_key_public, signal_buffer_data(signature), signal_buffer_len(signature), ratchet_identity_key_pair_get_public(bob_identity_key_pair)); ck_assert_int_eq(result, 0); session_signed_pre_key *signed_pre_key_record = 0; result = session_signed_pre_key_create(&signed_pre_key_record, bob_signed_pre_key_id, time(0), bob_signed_pre_key, signal_buffer_data(signature), signal_buffer_len(signature)); ck_assert_int_eq(result, 0); result = signal_protocol_signed_pre_key_store_key(store, signed_pre_key_record); ck_assert_int_eq(result, 0); session_pre_key *pre_key_record = 0; result = session_pre_key_create(&pre_key_record, bob_unsigned_pre_key_id, bob_unsigned_pre_key); ck_assert_int_eq(result, 0); result = signal_protocol_pre_key_store_key(store, pre_key_record); ck_assert_int_eq(result, 0); SIGNAL_UNREF(pre_key_record); SIGNAL_UNREF(signed_pre_key_record); SIGNAL_UNREF(bob_identity_key_pair); SIGNAL_UNREF(bob_unsigned_pre_key); signal_buffer_free(bob_signed_pre_key_public_serialized); signal_buffer_free(signature); return bob_pre_key_bundle; } Suite *simultaneous_initiate_suite(void) { Suite *suite = suite_create("simultaneous_initiate"); TCase *tcase = tcase_create("case"); tcase_add_checked_fixture(tcase, test_setup, test_teardown); tcase_add_test(tcase, test_basic_simultaneous_initiate); tcase_add_test(tcase, test_lost_simultaneous_initiate); tcase_add_test(tcase, test_simultaneous_initiate_lost_message); tcase_add_test(tcase, test_simultaneous_initiate_repeated_messages); tcase_add_test(tcase, test_repeated_simultaneous_initiate_repeated_messages); tcase_add_test(tcase, test_repeated_simultaneous_initiate_lost_message_repeated_messages); suite_add_tcase(suite, tcase); return suite; } int main(void) { int number_failed; Suite *suite; SRunner *runner; suite = simultaneous_initiate_suite(); runner = srunner_create(suite); srunner_run_all(runner, CK_VERBOSE); number_failed = srunner_ntests_failed(runner); srunner_free(runner); return (number_failed == 0) ? EXIT_SUCCESS : EXIT_FAILURE; } libsignal-protocol-c-2.3.3/tests/test_utarray.h000066400000000000000000000002171363751346500216200ustar00rootroot00000000000000#ifndef TEST_UTARRAY_H #define TEST_UTARRAY_H #include #define oom() ck_abort() #include "utarray.h" #endif /* TEST_UTARRAY_H */