Compare commits
85 commits
openssl-li
...
master
Author | SHA1 | Date | |
---|---|---|---|
fd10167985 | |||
cb3fe622ae | |||
|
7e0c827703 | ||
|
972faaadd5 | ||
|
807b252331 | ||
|
bbdac4045d | ||
|
4beb2487ce | ||
|
b54fa37fae | ||
|
66294cf7f6 | ||
|
366520ebfd | ||
|
d27f162316 | ||
|
4b69958c95 | ||
|
5cfe6c3dbd | ||
|
bbdc12c569 | ||
|
afb3d403e1 | ||
|
418656ee9f | ||
|
0d367baa5b | ||
|
8cbb60e476 | ||
|
0880461134 | ||
|
8f4b81b512 | ||
|
ab4cbcd01a | ||
|
704b198f5a | ||
|
0eb4550a8f | ||
|
249acc9e0b | ||
|
5efd38c990 | ||
|
ad76fc1570 | ||
|
b5d68376b5 | ||
|
dbd8a44fa2 | ||
|
722f4df4aa | ||
|
6d767aaf29 | ||
|
21e84095e6 | ||
|
464e193dad | ||
|
df2cfcb6d0 | ||
|
ed94b56d16 | ||
|
f52d179c18 | ||
|
85c0be5fbc | ||
|
203083cdd4 | ||
|
983e78dc53 | ||
|
92769cec71 | ||
|
d18d12d379 | ||
|
14c5ea70d4 | ||
|
ee1b0c8a9a | ||
|
84807125c0 | ||
|
eb21951124 | ||
|
39252b012b | ||
|
86a3d95855 | ||
|
81f5c4a3cd | ||
|
d0b2b8702f | ||
|
e000c33a58 | ||
|
43672251e4 | ||
|
e116efa752 | ||
|
a4a700739e | ||
|
b8990d90f0 | ||
|
99d635779c | ||
|
b65ab350f0 | ||
|
c9e6bf9263 | ||
|
727722d7a8 | ||
|
8510b2f601 | ||
|
7bf6fb553e | ||
|
1c7df35c5f | ||
|
2f23d99424 | ||
|
0a6a5a5caf | ||
|
b5dfa28f3b | ||
|
3c91c66ee2 | ||
|
dcf5582f8a | ||
|
9d66965962 | ||
|
dd1905454b | ||
|
9908862979 | ||
|
7d0a69a099 | ||
|
2c6b9d5e3a | ||
|
0dde38bd4f | ||
|
b3478a526b | ||
|
b11f555b01 | ||
|
23380ca331 | ||
|
1c3af112c8 | ||
|
55c976d4f6 | ||
|
db90ce6b62 | ||
|
96407493d1 | ||
|
9b2c116fbd | ||
|
cbc6886a37 | ||
|
c172ab6236 | ||
|
9946acac23 | ||
|
60122a2c2d | ||
|
8475061136 | ||
|
e197cd76d6 |
427 changed files with 47941 additions and 1101 deletions
9
.gitignore
vendored
9
.gitignore
vendored
|
@ -9,9 +9,13 @@
|
|||
/python/dist
|
||||
/javascript/checksums.txt
|
||||
/javascript/checksums.txt.asc
|
||||
/javascript/olm_prefix.js
|
||||
/compile_commands.json
|
||||
/.clang-format
|
||||
.ccls-cache/
|
||||
/python/.eggs
|
||||
/python/install-temp
|
||||
/result
|
||||
|
||||
# Xcode
|
||||
build/
|
||||
|
@ -33,4 +37,7 @@ xcuserdata/
|
|||
*.dSYM.zip
|
||||
*.dSYM
|
||||
Pods/
|
||||
*.xcworkspace
|
||||
*.xcworkspace
|
||||
|
||||
# JetBrains tools
|
||||
.idea/
|
||||
|
|
|
@ -1,3 +1,82 @@
|
|||
Changes in `3.2.16 <https://gitlab.matrix.org/matrix-org/olm/tags/3.2.16>`_
|
||||
===========================================================================
|
||||
|
||||
This release includes the following changes since 3.2.15:
|
||||
|
||||
* Fix and modernize the Python packaging (thanks to Alfred Wingate)
|
||||
|
||||
Changes in `3.2.15 <https://gitlab.matrix.org/matrix-org/olm/tags/3.2.15>`_
|
||||
===========================================================================
|
||||
|
||||
This release includes the following changes since 3.2.14:
|
||||
|
||||
* Improvements to Python packaging
|
||||
* No longer depend on ``future`` since Python 2 is no longer supported.
|
||||
* Improve compatibility with tox 4.
|
||||
* Add support for making standalone sdist.
|
||||
* Improvements to Nix flake (Thanks to Jon Ringer)
|
||||
* Improve structure.
|
||||
* Enable Darwin builds.
|
||||
* Typescript type fix.
|
||||
|
||||
Changes in `3.2.14 <https://gitlab.matrix.org/matrix-org/olm/tags/3.2.14>`_
|
||||
===========================================================================
|
||||
|
||||
This release includes the following changes since 3.2.13:
|
||||
|
||||
* TypeScript type improvements.
|
||||
* Improvements to Python packaging
|
||||
* Documentation improvements.
|
||||
|
||||
Changes in `3.2.13 <https://gitlab.matrix.org/matrix-org/olm/tags/3.2.13>`_
|
||||
===========================================================================
|
||||
|
||||
This release includes the following changes since 3.2.12:
|
||||
|
||||
* Fix compilation with newer versions of emscripten.
|
||||
* The npm package is compiled with emscripten 3.1.17 to fix compatibility with
|
||||
node 18.
|
||||
* Add py.typed to Python wheels.
|
||||
* Some documentation fixes and updates.
|
||||
* Improve the pkgconfig file.
|
||||
|
||||
Changes in `3.2.12 <https://gitlab.matrix.org/matrix-org/olm/tags/3.2.12>`_
|
||||
===========================================================================
|
||||
|
||||
This release includes the following changes since 3.2.11:
|
||||
|
||||
* Expose olm_sas_calculate_mac_fixed_base64 in the bindings.
|
||||
* Allow memory to grow in wasm. Thanks to benkuly for the suggestion.
|
||||
* Fix Python type hints.
|
||||
* Some Python build fixes.
|
||||
* Initial work on a Nix flake for building and testing.
|
||||
|
||||
Changes in `3.2.11 <https://gitlab.matrix.org/matrix-org/olm/tags/3.2.11>`_
|
||||
===========================================================================
|
||||
|
||||
This release includes the following changes since 3.2.10:
|
||||
|
||||
* Fix building documentation. Thanks to Jonas Smedegaard. The documents
|
||||
written in Markdown are now converted to HTML using Pandoc.
|
||||
* Add methods for getting unpublished fallback key in Objective-C binding.
|
||||
* Add public pickle/unpickle methods to Java binding.
|
||||
* Add wrapper for olm_session_describe to Java binding. Thanks to Alex Baker.
|
||||
|
||||
Changes in `3.2.10 <https://gitlab.matrix.org/matrix-org/olm/tags/3.2.10>`_
|
||||
===========================================================================
|
||||
|
||||
This release includes no change since 3.2.9, but is created to be able to
|
||||
publish again the Android library on MavenCentral.
|
||||
|
||||
Changes in `3.2.9 <https://gitlab.matrix.org/matrix-org/olm/tags/3.2.9>`_
|
||||
=========================================================================
|
||||
|
||||
This release includes the following changes since 3.2.8:
|
||||
|
||||
* Switch C++ tests to use doctest. Thanks to Nicolas Werner.
|
||||
* Switch JavaScript tests to use jasmine instead of deprecated jasmine-node.
|
||||
* Add session describe function to Python binding. Thanks to Tulir Asokan.
|
||||
|
||||
Changes in `3.2.8 <https://gitlab.matrix.org/matrix-org/olm/tags/3.2.8>`_
|
||||
=========================================================================
|
||||
|
||||
|
@ -98,11 +177,13 @@ Changes in `3.1.5 <https://gitlab.matrix.org/matrix-org/olm/tags/3.1.5>`_
|
|||
This release includes the following changes since 3.1.4:
|
||||
|
||||
* Build improvements:
|
||||
|
||||
* Fix CMake handling when installing in a non-standard location. Thanks to
|
||||
Alexey Rusakov.
|
||||
* Add support in the Makefile for creating a WASM-ready archive. Thanks to
|
||||
stoically.
|
||||
* Improve support for LLVM is Makefile. Thanks to caywin25 for reporting.
|
||||
|
||||
* Add a TypeScript definition file.
|
||||
* Some documentation and example fixes.
|
||||
* Add list of bindings to the README.
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
cmake_minimum_required(VERSION 3.4)
|
||||
|
||||
project(olm VERSION 3.2.8 LANGUAGES CXX C)
|
||||
project(olm VERSION 3.2.16 LANGUAGES CXX C)
|
||||
|
||||
option(OLM_TESTS "Build tests" ON)
|
||||
option(BUILD_SHARED_LIBS "Build as a shared library" ON)
|
||||
|
@ -45,11 +45,12 @@ add_library(olm
|
|||
src/megolm.c
|
||||
src/olm.cpp
|
||||
src/outbound_group_session.c
|
||||
src/pickle_encoding.c)
|
||||
add_library(Olm::Olm ALIAS olm)
|
||||
src/pickle_encoding.c
|
||||
|
||||
find_package(OpenSSL REQUIRED)
|
||||
target_link_libraries(olm OpenSSL::Crypto)
|
||||
lib/crypto-algorithms/aes.c
|
||||
lib/crypto-algorithms/sha256.c
|
||||
lib/curve25519-donna/curve25519-donna.c)
|
||||
add_library(Olm::Olm ALIAS olm)
|
||||
|
||||
# restrict the exported symbols
|
||||
include(GenerateExportHeader)
|
||||
|
|
17
Makefile
17
Makefile
|
@ -5,10 +5,9 @@ VERSION := $(MAJOR).$(MINOR).$(PATCH)
|
|||
PREFIX ?= /usr/local
|
||||
BUILD_DIR := build
|
||||
RELEASE_OPTIMIZE_FLAGS ?= -O3
|
||||
DEBUG_OPTIMIZE_FLAGS ?= -g -O0
|
||||
DEBUG_OPTIMIZE_FLAGS ?= -g -O0 -U_FORTIFY_SOURCE
|
||||
JS_OPTIMIZE_FLAGS ?= -O3
|
||||
FUZZER_OPTIMIZE_FLAGS ?= -O3
|
||||
CC = gcc
|
||||
EMCC = emcc
|
||||
EMAR = emar
|
||||
AR = ar
|
||||
|
@ -31,12 +30,15 @@ JS_ASMJS_TARGET := javascript/olm_legacy.js
|
|||
WASM_TARGET := $(BUILD_DIR)/wasm/libolm.a
|
||||
|
||||
JS_EXPORTED_FUNCTIONS := javascript/exported_functions.json
|
||||
JS_EXPORTED_RUNTIME_METHODS := [ALLOC_STACK]
|
||||
JS_EXPORTED_RUNTIME_METHODS := [ALLOC_STACK,writeAsciiToMemory,intArrayFromString,UTF8ToString,stringToUTF8]
|
||||
JS_EXTERNS := javascript/externs.js
|
||||
|
||||
PUBLIC_HEADERS := include/olm/olm.h include/olm/outbound_group_session.h include/olm/inbound_group_session.h include/olm/pk.h include/olm/sas.h include/olm/error.h include/olm/olm_export.h
|
||||
|
||||
SOURCES := $(wildcard src/*.cpp) $(wildcard src/*.c) \
|
||||
lib/crypto-algorithms/sha256.c \
|
||||
lib/crypto-algorithms/aes.c \
|
||||
lib/curve25519-donna/curve25519-donna.c
|
||||
|
||||
FUZZER_SOURCES := $(wildcard fuzzing/fuzzers/fuzz_*.cpp) $(wildcard fuzzing/fuzzers/fuzz_*.c)
|
||||
TEST_SOURCES := $(wildcard tests/test_*.cpp) $(wildcard tests/test_*.c)
|
||||
|
@ -86,12 +88,12 @@ CPPFLAGS += -Iinclude -Ilib \
|
|||
# we rely on <stdint.h>, which was introduced in C99
|
||||
CFLAGS += -Wall -Werror -std=c99
|
||||
CXXFLAGS += -Wall -Werror -std=c++11
|
||||
LDFLAGS += -Wall -Werror -lcrypto
|
||||
LDFLAGS += -Wall -Werror
|
||||
|
||||
CFLAGS_NATIVE = -fPIC
|
||||
CXXFLAGS_NATIVE = -fPIC
|
||||
|
||||
EMCCFLAGS = --closure 1 --memory-init-file 0 -s NO_FILESYSTEM=1 -s INVOKE_RUN=0 -s MODULARIZE=1
|
||||
EMCCFLAGS = --closure 1 --memory-init-file 0 -s NO_FILESYSTEM=1 -s INVOKE_RUN=0 -s MODULARIZE=1 -Wno-error=closure
|
||||
|
||||
# Olm generally doesn't need a lot of memory to encrypt / decrypt its usual
|
||||
# payloads (ie. Matrix messages), but we do need about 128K of heap to encrypt
|
||||
|
@ -101,7 +103,7 @@ EMCCFLAGS = --closure 1 --memory-init-file 0 -s NO_FILESYSTEM=1 -s INVOKE_RUN=0
|
|||
# (This can't be changed by the app with wasm since it's baked into the wasm).
|
||||
# (emscripten also mandates at least 16MB of memory for asm.js now, so
|
||||
# we don't use this for the legacy build.)
|
||||
EMCCFLAGS_WASM += -s TOTAL_STACK=65536 -s TOTAL_MEMORY=262144
|
||||
EMCCFLAGS_WASM += -s TOTAL_STACK=65536 -s TOTAL_MEMORY=262144 -s ALLOW_MEMORY_GROWTH
|
||||
|
||||
EMCCFLAGS_ASMJS += -s WASM=0
|
||||
|
||||
|
@ -398,6 +400,9 @@ $(BUILD_DIR)/fuzzers/fuzz_%_msan: fuzzing/fuzzers/fuzz_%.cpp $(FUZZER_MSAN_OBJEC
|
|||
%.html: %.rst
|
||||
rst2html $< $@
|
||||
|
||||
%.html: %.md
|
||||
pandoc --from markdown --to html5 --standalone --lua-filter gitlab-math.lua --katex -o $@ $<
|
||||
|
||||
### dependencies
|
||||
|
||||
-include $(RELEASE_OBJECTS:.o=.d)
|
||||
|
|
|
@ -3,7 +3,7 @@ Pod::Spec.new do |s|
|
|||
# The libolm version
|
||||
MAJOR = 3
|
||||
MINOR = 2
|
||||
PATCH = 8
|
||||
PATCH = 16
|
||||
|
||||
s.name = "OLMKit"
|
||||
s.version = "#{MAJOR}.#{MINOR}.#{PATCH}"
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
import PackageDescription
|
||||
|
||||
let major = 3, minor = 2, patch = 8
|
||||
let major = 3, minor = 2, patch = 16
|
||||
|
||||
let package = Package(
|
||||
name: "Olm",
|
||||
|
|
104
README.md
104
README.md
|
@ -9,6 +9,69 @@ The specification of the Olm ratchet can be found in [docs/olm.md](docs/olm.md).
|
|||
This library also includes an implementation of the Megolm cryptographic
|
||||
ratchet, as specified in [docs/megolm.md](docs/megolm.md).
|
||||
|
||||
## Installing
|
||||
|
||||
### Linux and other Unix-like systems
|
||||
|
||||
Your distribution may have pre-compiled packages available. If not, or if you
|
||||
need a newer version, you will need to compile from source. See the "Building"
|
||||
section below for more details.
|
||||
|
||||
### macOS
|
||||
|
||||
The easiest way to install on macOS is via Homebrew. If you do not have
|
||||
Homebrew installed, follow the instructions at https://brew.sh/ to install it.
|
||||
|
||||
You can then install libolm by running
|
||||
|
||||
```bash
|
||||
brew install libolm
|
||||
```
|
||||
|
||||
If you also need the Python packages, you can run
|
||||
|
||||
```bash
|
||||
pip3 install python-olm --global-option="build_ext" --global-option="--include-dirs="`brew --prefix libolm`"/include" --global-option="--library-dirs="`brew --prefix libolm`"/lib"
|
||||
```
|
||||
|
||||
Note that this will install an older version of the Python bindings, which may
|
||||
be missing some functions. If you need the latest version, you will need to
|
||||
build from source.
|
||||
|
||||
### Windows
|
||||
|
||||
You will need to build from source. See the "Building" section below for more
|
||||
details.
|
||||
|
||||
### Bindings
|
||||
|
||||
#### JavaScript
|
||||
|
||||
You can use pre-built npm packages, available at
|
||||
<https://gitlab.matrix.org/matrix-org/olm/-/packages?type=npm>.
|
||||
|
||||
#### Python
|
||||
|
||||
A Python source package and pre-built packages for certain architectures from
|
||||
<https://pypi.org/project/python-olm/>. If a pre-built package is not
|
||||
available for your architecture, you will need:
|
||||
|
||||
- cmake (recommended) or GNU make
|
||||
- a C/C++ compiler
|
||||
|
||||
to build the source package.
|
||||
|
||||
You can then run `pip install python-olm`.
|
||||
|
||||
Currently, we try to provide packages for all supported versions of Python on
|
||||
x86-64, i686, and aarch64, but we cannot guarantee that packages for all
|
||||
versions will be available on all architectures.
|
||||
|
||||
#### Android
|
||||
|
||||
Pre-built Android bindings are available at
|
||||
<https://gitlab.matrix.org/matrix-org/olm/-/packages?type=Maven>.
|
||||
|
||||
## Building
|
||||
|
||||
To build olm as a shared library run:
|
||||
|
@ -41,22 +104,38 @@ target_link_libraries(my_exe Olm::Olm)
|
|||
|
||||
### Bindings
|
||||
|
||||
To build the JavaScript bindings, install emscripten from https://emscripten.org/ and then run:
|
||||
#### JavaScript
|
||||
|
||||
The recommended way to build the JavaScript bindings is using
|
||||
[Nix](https://nixos.org/). With Nix, you can run
|
||||
|
||||
```bash
|
||||
nix build .\#javascript
|
||||
```
|
||||
|
||||
to build the bindings.
|
||||
|
||||
If you do not have Nix you can, install emscripten from https://emscripten.org/
|
||||
and then run:
|
||||
|
||||
```bash
|
||||
make js
|
||||
```
|
||||
|
||||
Note that if you run emscripten in a docker container, you need to pass through
|
||||
Emscripten can also be run via Docker, in which case, you need to pass through
|
||||
the EMCC_CLOSURE_ARGS environment variable.
|
||||
|
||||
#### Android
|
||||
|
||||
To build the android project for Android bindings, run:
|
||||
|
||||
```bash
|
||||
cd android
|
||||
./gradlew clean assembleRelease
|
||||
./gradlew clean build
|
||||
```
|
||||
|
||||
#### Objective-C
|
||||
|
||||
To build the Xcode workspace for Objective-C bindings, run:
|
||||
|
||||
```bash
|
||||
|
@ -65,7 +144,9 @@ pod install
|
|||
open OLMKit.xcworkspace
|
||||
```
|
||||
|
||||
To build the Python bindings, first build olm as a shared library as above, and
|
||||
#### Python
|
||||
|
||||
To build the Python 3 bindings, first build olm as a library as above, and
|
||||
then run:
|
||||
|
||||
```bash
|
||||
|
@ -73,9 +154,6 @@ cd python
|
|||
make
|
||||
```
|
||||
|
||||
to make both the Python 2 and Python 3 bindings. To make only one version, use
|
||||
``make olm-python2`` or ``make olm-python3`` instead of just ``make``.
|
||||
|
||||
### Using make instead of cmake
|
||||
|
||||
**WARNING:** Using cmake is the preferred method for building the olm library;
|
||||
|
@ -119,6 +197,8 @@ repository, some bindings are (in alphabetical order):
|
|||
- [nim-olm](https://codeberg.org/BarrOff/nim-olm) (MIT) Nim bindings
|
||||
- [olm-sys](https://gitlab.gnome.org/BrainBlasted/olm-sys) (Apache-2.0) Rust
|
||||
bindings
|
||||
- [Trixnity](https://gitlab.com/trixnity/trixnity) (Apache-2.0) Kotlin SDK for
|
||||
Matrix, including Olm bindings
|
||||
|
||||
Note that bindings may have a different license from libolm, and are *not*
|
||||
endorsed by the Matrix.org Foundation C.I.C.
|
||||
|
@ -126,7 +206,7 @@ endorsed by the Matrix.org Foundation C.I.C.
|
|||
## Release process
|
||||
|
||||
First: bump version numbers in ``common.mk``, ``CMakeLists.txt``,
|
||||
``javascript/package.json``, ``python/olm/__version__.py``, ``OLMKit.podspec``,
|
||||
``javascript/package.json``, ``python/pyproject.toml``, ``OLMKit.podspec``,
|
||||
``Package.swift``, and ``android/gradle.properties``.
|
||||
|
||||
Also, ensure the changelog is up to date, and that everything is committed to
|
||||
|
@ -167,6 +247,14 @@ Python and JavaScript packages are published to the registry at
|
|||
documentation contains instructions on how to set up twine (Python) and npm
|
||||
(JavaScript) to upload to the registry.
|
||||
|
||||
To publish the Android library to MavenCentral (you will need some secrets), in the /android folder:
|
||||
- Run the command `./gradlew clean build publish --no-daemon --no-parallel --stacktrace`. The generated AAR must be approx 500 kb.
|
||||
- Connect to https://s01.oss.sonatype.org
|
||||
- Click on Staging Repositories and check the the files have been uploaded
|
||||
- Click on close
|
||||
- Wait (check Activity tab until step "Repository closed" is displayed)
|
||||
- Click on release. The staging repository will disappear
|
||||
- Check that the release is available in https://repo1.maven.org/maven2/org/matrix/android/olm-sdk/ (it can take a few minutes)
|
||||
|
||||
## Design
|
||||
|
||||
|
|
|
@ -11,8 +11,8 @@
|
|||
SET(CMAKE_SYSTEM_NAME Windows)
|
||||
|
||||
# which compilers to use for C and C++
|
||||
SET(CMAKE_C_COMPILER x86_64-w64-mingw32-gcc)
|
||||
SET(CMAKE_CXX_COMPILER x86_64-w64-mingw32-g++)
|
||||
SET(CMAKE_C_COMPILER x86_64-w64-mingw32-gcc-posix)
|
||||
SET(CMAKE_CXX_COMPILER x86_64-w64-mingw32-g++-posix)
|
||||
SET(CMAKE_RC_COMPILER x86_64-w64-mingw32-windres)
|
||||
|
||||
# here is the target environment located
|
||||
|
|
BIN
android/.DS_Store
vendored
BIN
android/.DS_Store
vendored
Binary file not shown.
|
@ -5,20 +5,16 @@ OlmLibSdk exposes an android wrapper to libolm.
|
|||
|
||||
Installation
|
||||
------------
|
||||
Create a libs directory in your project directory
|
||||
Copy the olm-sdk.aar into it.
|
||||
|
||||
In your build.gradle file, add in the android section::
|
||||
Android Olm library is released on MavenCentral.
|
||||
|
||||
repositories {
|
||||
flatDir {
|
||||
dir 'libs'
|
||||
}
|
||||
}
|
||||
Add this dependency to your project:
|
||||
|
||||
Add in the dependencies category::
|
||||
```groovy
|
||||
implementation "org.matrix.android:olm:3.2.8"
|
||||
```
|
||||
|
||||
compile(name: 'olm-sdk', ext: 'aar')
|
||||
Latest version: ![Latest version](https://img.shields.io/maven-central/v/org.matrix.android/olm)
|
||||
|
||||
Development
|
||||
-----------
|
||||
|
|
|
@ -6,8 +6,10 @@ buildscript {
|
|||
google()
|
||||
}
|
||||
dependencies {
|
||||
classpath 'com.android.tools.build:gradle:4.1.3'
|
||||
|
||||
// Release notes of Android Gradle Plugin (AGP):
|
||||
// https://developer.android.com/studio/releases/gradle-plugin
|
||||
classpath 'com.android.tools.build:gradle:7.0.4'
|
||||
classpath 'com.vanniktech:gradle-maven-publish-plugin:0.18.0'
|
||||
// NOTE: Do not place your application dependencies here; they belong
|
||||
// in the individual module build.gradle files
|
||||
}
|
||||
|
@ -18,6 +20,17 @@ allprojects {
|
|||
mavenCentral()
|
||||
google()
|
||||
}
|
||||
|
||||
plugins.withId("com.vanniktech.maven.publish.base") {
|
||||
group = project.getProperties().getOrDefault("GROUP", "0.0.0")
|
||||
version = project.getProperties().getOrDefault("VERSION_NAME", "name")
|
||||
|
||||
mavenPublishing {
|
||||
publishToMavenCentral("S01")
|
||||
pomFromGradleProperties()
|
||||
signAllPublications()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
task clean(type: Delete) {
|
||||
|
|
|
@ -22,6 +22,28 @@
|
|||
android.useAndroidX=true
|
||||
org.gradle.configureondemand=false
|
||||
|
||||
# Maven publication
|
||||
# Ref: https://github.com/vanniktech/gradle-maven-publish-plugin
|
||||
GROUP=org.matrix.android
|
||||
ARTIFACT_ID=olm
|
||||
VERSION_NAME=3.2.8
|
||||
POM_ARTIFACT_ID=olm
|
||||
VERSION_NAME=3.2.16
|
||||
|
||||
POM_PACKAGING=aar
|
||||
|
||||
POM_NAME=Olm Android wrapper
|
||||
POM_DESCRIPTION=An Android wrapper to libolm.
|
||||
POM_INCEPTION_YEAR=2021
|
||||
POM_URL=https://gitlab.matrix.org/matrix-org/olm
|
||||
|
||||
POM_LICENSE_NAME=The Apache Software License, Version 2.0
|
||||
POM_LICENCE_URL=https://www.apache.org/licenses/LICENSE-2.0.txt
|
||||
POM_LICENCE_DIST=repo
|
||||
|
||||
POM_SCM_URL=https://gitlab.matrix.org/matrix-org/olm
|
||||
POM_SCM_CONNECTION=scm:git:https://gitlab.matrix.org/matrix-org/olm.git
|
||||
POM_SCM_DEV_CONNECTION=scm:git:ssh://git@gitlab.int.matrix.org:matrix-org/olm.git
|
||||
|
||||
POM_DEVELOPER_ID=matrixdev
|
||||
POM_DEVELOPER_NAME=matrixdev
|
||||
POM_DEVELOPER_URL=https://gitlab.matrix.org/matrix-org
|
||||
POM_DEVELOPER_EMAIL=android@element.io
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
#Thu Oct 13 09:38:01 CEST 2016
|
||||
distributionBase=GRADLE_USER_HOME
|
||||
distributionPath=wrapper/dists
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-7.0-all.zip
|
||||
distributionSha256Sum=81003f83b0056d20eedf48cddd4f52a9813163d4ba185bcf8abd34b8eeea4cbd
|
||||
distributionSha256Sum=c9490e938b221daf0094982288e4038deed954a3f12fb54cbf270ddf4e37d879
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-7.3.3-all.zip
|
||||
zipStoreBase=GRADLE_USER_HOME
|
||||
zipStorePath=wrapper/dists
|
||||
|
|
|
@ -1,3 +0,0 @@
|
|||
install:
|
||||
- ./gradlew :olm-sdk:build :olm-sdk:publishToMavenLocal -x :olm-sdk:test
|
||||
- find . -name "*.aar"
|
|
@ -1,17 +1,20 @@
|
|||
import org.apache.tools.ant.taskdefs.condition.Os
|
||||
import com.vanniktech.maven.publish.AndroidLibrary
|
||||
import com.vanniktech.maven.publish.JavadocJar
|
||||
|
||||
apply plugin: 'com.android.library'
|
||||
apply plugin: 'maven-publish'
|
||||
apply plugin: 'signing'
|
||||
apply plugin: "com.vanniktech.maven.publish.base"
|
||||
|
||||
android {
|
||||
compileSdkVersion 30
|
||||
compileSdk 31
|
||||
|
||||
defaultConfig {
|
||||
minSdkVersion 14
|
||||
targetSdkVersion 30
|
||||
minSdk 14
|
||||
targetSdk 31
|
||||
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
|
||||
|
||||
buildConfigField "String", "OLM_VERSION", "\"${project.getProperties().getOrDefault("VERSION_NAME", "0.0.0")}\""
|
||||
|
||||
// The following argument makes the Android Test Orchestrator run its
|
||||
// "pm clear" command after each test invocation. This command ensures
|
||||
// that the app's state is completely cleared between tests.
|
||||
|
@ -109,6 +112,11 @@ android {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
compileOptions {
|
||||
sourceCompatibility JavaVersion.VERSION_11
|
||||
targetCompatibility JavaVersion.VERSION_11
|
||||
}
|
||||
}
|
||||
|
||||
def getNdkFolder() {
|
||||
|
@ -148,40 +156,12 @@ dependencies {
|
|||
testImplementation 'junit:junit:4.13.2'
|
||||
androidTestImplementation 'junit:junit:4.13.2'
|
||||
|
||||
androidTestImplementation 'androidx.test:core:1.3.0'
|
||||
androidTestImplementation 'androidx.test:runner:1.3.0'
|
||||
androidTestImplementation 'androidx.test:rules:1.3.0'
|
||||
androidTestImplementation 'androidx.test.ext:junit:1.1.2'
|
||||
androidTestImplementation 'androidx.test:core:1.4.0'
|
||||
androidTestImplementation 'androidx.test:runner:1.4.0'
|
||||
androidTestImplementation 'androidx.test:rules:1.4.0'
|
||||
androidTestImplementation 'androidx.test.ext:junit:1.1.3'
|
||||
}
|
||||
|
||||
project.afterEvaluate {
|
||||
publishing {
|
||||
publications {
|
||||
release(MavenPublication) {
|
||||
from components.release
|
||||
artifact androidJavadocsJar
|
||||
artifact androidSourcesJar
|
||||
groupId = project.getProperties().getOrDefault("GROUP", "org.matrix.android")
|
||||
artifactId = project.getProperties().getOrDefault("ARTIFACT_ID", "olm")
|
||||
version = project.getProperties().getOrDefault("VERSION_NAME", "0.0.0")
|
||||
}
|
||||
}
|
||||
repositories {
|
||||
maven {
|
||||
url "https://gitlab.matrix.org/api/v4/projects/27/packages/maven"
|
||||
credentials(HttpHeaderCredentials) {
|
||||
name = System.getenv("REPO_TOKEN_TYPE")
|
||||
value = System.getenv("REPO_TOKEN")
|
||||
}
|
||||
authentication {
|
||||
header(HttpHeaderAuthentication)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
signing {
|
||||
useGpgCmd()
|
||||
sign publishing.publications.release
|
||||
}
|
||||
mavenPublishing {
|
||||
configure(new AndroidLibrary(new JavadocJar.Empty(), false))
|
||||
}
|
||||
|
|
|
@ -1011,4 +1011,75 @@ public class OlmSessionTest {
|
|||
assertTrue(bobSession.isReleased());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test07AliceBobSessionDescribe() {
|
||||
// creates alice & bob accounts
|
||||
OlmAccount aliceAccount = null;
|
||||
OlmAccount bobAccount = null;
|
||||
try {
|
||||
aliceAccount = new OlmAccount();
|
||||
bobAccount = new OlmAccount();
|
||||
} catch (OlmException e) {
|
||||
fail(e.getMessage());
|
||||
}
|
||||
|
||||
// test accounts creation
|
||||
assertTrue(0 != bobAccount.getOlmAccountId());
|
||||
assertTrue(0 != aliceAccount.getOlmAccountId());
|
||||
|
||||
// CREATE ALICE SESSION
|
||||
|
||||
OlmSession aliceSession = null;
|
||||
try {
|
||||
aliceSession = new OlmSession();
|
||||
} catch (OlmException e) {
|
||||
fail("Exception Msg=" + e.getMessage());
|
||||
}
|
||||
assertTrue(0 != aliceSession.getOlmSessionId());
|
||||
|
||||
// CREATE ALICE SESSION
|
||||
OlmSession bobSession = null;
|
||||
try {
|
||||
bobSession = new OlmSession();
|
||||
} catch (OlmException e) {
|
||||
e.printStackTrace();
|
||||
fail(e.getMessage());
|
||||
}
|
||||
assertTrue(0 != bobSession.getOlmSessionId());
|
||||
|
||||
String aliceSessionDescribe = null;
|
||||
try {
|
||||
aliceSessionDescribe = aliceSession.sessionDescribe();
|
||||
} catch (Exception e) {
|
||||
fail(e.getMessage());
|
||||
}
|
||||
|
||||
assertNotNull(aliceSessionDescribe);
|
||||
|
||||
String bobSessionDescribe = null;
|
||||
try {
|
||||
bobSessionDescribe = bobSession.sessionDescribe();
|
||||
} catch (Exception e) {
|
||||
fail(e.getMessage());
|
||||
}
|
||||
assertNotNull(bobSessionDescribe);
|
||||
|
||||
// must be the same for both ends of the conversation
|
||||
assertEquals(aliceSessionDescribe, bobSessionDescribe);
|
||||
|
||||
assertEquals(
|
||||
"sender chain index: 0 receiver chain indices: skipped message keys:",
|
||||
aliceSessionDescribe
|
||||
);
|
||||
|
||||
aliceAccount.releaseAccount();
|
||||
bobAccount.releaseAccount();
|
||||
assertTrue(aliceAccount.isReleased());
|
||||
assertTrue(bobAccount.isReleased());
|
||||
|
||||
bobSession.releaseSession();
|
||||
aliceSession.releaseSession();
|
||||
assertTrue(bobSession.isReleased());
|
||||
assertTrue(aliceSession.isReleased());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -60,6 +60,7 @@ public class OlmException extends IOException {
|
|||
public static final int EXCEPTION_CODE_SESSION_ENCRYPT_MESSAGE = 404;
|
||||
public static final int EXCEPTION_CODE_SESSION_DECRYPT_MESSAGE = 405;
|
||||
public static final int EXCEPTION_CODE_SESSION_SESSION_IDENTIFIER = 406;
|
||||
public static final int EXCEPTION_CODE_SESSION_SESSION_DESCRIBE = 407;
|
||||
|
||||
public static final int EXCEPTION_CODE_UTILITY_CREATION = 500;
|
||||
public static final int EXCEPTION_CODE_UTILITY_VERIFY_SIGNATURE = 501;
|
||||
|
|
|
@ -369,4 +369,29 @@ public class OlmInboundGroupSession extends CommonSerializeUtils implements Seri
|
|||
* @return the deserialized session
|
||||
**/
|
||||
private native long deserializeJni(byte[] aSerializedData, byte[] aKey);
|
||||
|
||||
/**
|
||||
* Return a pickled inbound group session as a bytes buffer.<br>
|
||||
* The session is serialized and encrypted with aKey.
|
||||
* In case of failure, an error human readable
|
||||
* description is provide in aErrorMsg.
|
||||
* @param aKey encryption key
|
||||
* @param aErrorMsg error message description
|
||||
* @return the pickled inbound group session as bytes buffer
|
||||
*/
|
||||
public byte[] pickle(byte[] aKey, StringBuffer aErrorMsg) {
|
||||
return serialize(aKey, aErrorMsg);
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads an inbound group session from a pickled bytes buffer.<br>
|
||||
* See {@link #serialize(byte[], StringBuffer)}
|
||||
* @param aSerializedData bytes buffer
|
||||
* @param aKey key used to encrypted
|
||||
* @exception Exception the exception
|
||||
*/
|
||||
public void unpickle(byte[] aSerializedData, byte[] aKey) throws Exception {
|
||||
deserialize(aSerializedData, aKey);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -293,4 +293,28 @@ public class OlmOutboundGroupSession extends CommonSerializeUtils implements Ser
|
|||
**/
|
||||
private native long deserializeJni(byte[] aSerializedData, byte[] aKey);
|
||||
|
||||
/**
|
||||
* Return a pickled outbound group session as a bytes buffer.<br>
|
||||
* The session is serialized and encrypted with aKey.
|
||||
* In case of failure, an error human readable
|
||||
* description is provide in aErrorMsg.
|
||||
* @param aKey encryption key
|
||||
* @param aErrorMsg error message description
|
||||
* @return the pickled outbound group session as bytes buffer
|
||||
*/
|
||||
public byte[] pickle(byte[] aKey, StringBuffer aErrorMsg) {
|
||||
return serialize(aKey, aErrorMsg);
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads an outbound group session from a pickled bytes buffer.<br>
|
||||
* See {@link #serialize(byte[], StringBuffer)}
|
||||
* @param aSerializedData bytes buffer
|
||||
* @param aKey key used to encrypted
|
||||
* @exception Exception the exception
|
||||
*/
|
||||
public void unpickle(byte[] aSerializedData, byte[] aKey) throws Exception {
|
||||
deserialize(aSerializedData, aKey);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -106,6 +106,16 @@ public class OlmSAS {
|
|||
return null;
|
||||
}
|
||||
|
||||
public String calculateMacFixedBase64(String message, String info) throws OlmException {
|
||||
try {
|
||||
byte[] bytes = calculateMacFixedBase64Jni(message.getBytes("UTF-8"), info.getBytes("UTF-8"));
|
||||
if (bytes != null) return new String(bytes, "UTF-8");
|
||||
} catch (UnsupportedEncodingException e) {
|
||||
throw new OlmException(OlmException.EXCEPTION_CODE_SAS_ERROR, e.getMessage());
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public String calculateMacLongKdf(String message, String info) throws OlmException {
|
||||
try {
|
||||
byte[] bytes = calculateMacLongKdfJni(message.getBytes("UTF-8"), info.getBytes("UTF-8"));
|
||||
|
@ -140,6 +150,8 @@ public class OlmSAS {
|
|||
|
||||
private native byte[] calculateMacJni(byte[] message, byte[] info);
|
||||
|
||||
private native byte[] calculateMacFixedBase64Jni(byte[] message, byte[] info);
|
||||
|
||||
private native byte[] calculateMacLongKdfJni(byte[] message, byte[] info);
|
||||
|
||||
/**
|
||||
|
|
|
@ -223,6 +223,23 @@ public class OlmSession extends CommonSerializeUtils implements Serializable {
|
|||
*/
|
||||
private native byte[] getSessionIdentifierJni();
|
||||
|
||||
public String sessionDescribe() throws OlmException {
|
||||
try {
|
||||
byte[] buffer = olmSessionDescribeJni();
|
||||
|
||||
if (null != buffer) {
|
||||
return new String(buffer, "UTF-8");
|
||||
}
|
||||
} catch (Exception e) {
|
||||
Log.e(LOG_TAG, "## sessionDescribe(): " + e.getMessage());
|
||||
throw new OlmException(OlmException.EXCEPTION_CODE_SESSION_SESSION_DESCRIBE, e.getMessage());
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private native byte[] olmSessionDescribeJni();
|
||||
|
||||
/**
|
||||
* Checks if the PRE_KEY({@link OlmMessage#MESSAGE_TYPE_PRE_KEY}) message is for this in-bound session.<br>
|
||||
* This API may be used to process a "m.room.encrypted" event when type = 1 (PRE_KEY).
|
||||
|
@ -448,5 +465,30 @@ public class OlmSession extends CommonSerializeUtils implements Serializable {
|
|||
* @return the deserialized session
|
||||
**/
|
||||
private native long deserializeJni(byte[] aSerializedData, byte[] aKey);
|
||||
|
||||
/**
|
||||
* Return a pickled session as a bytes buffer.<br>
|
||||
* The session is serialized and encrypted with aKey.
|
||||
* In case of failure, an error human readable
|
||||
* description is provide in aErrorMsg.
|
||||
* @param aKey encryption key
|
||||
* @param aErrorMsg error message description
|
||||
* @return the pickled session as bytes buffer
|
||||
*/
|
||||
public byte[] pickle(byte[] aKey, StringBuffer aErrorMsg) {
|
||||
return serialize(aKey, aErrorMsg);
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads a session from a pickled bytes buffer.<br>
|
||||
* See {@link #serialize(byte[], StringBuffer)}
|
||||
* @param aSerializedData bytes buffer
|
||||
* @param aKey key used to encrypted
|
||||
* @exception Exception the exception
|
||||
*/
|
||||
public void unpickle(byte[] aSerializedData, byte[] aKey) throws Exception {
|
||||
deserialize(aSerializedData, aKey);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
|
|
@ -309,6 +309,86 @@ JNIEXPORT jbyteArray OLM_SAS_FUNC_DEF(calculateMacJni)(JNIEnv *env, jobject thiz
|
|||
return returnValue;
|
||||
}
|
||||
|
||||
JNIEXPORT jbyteArray OLM_SAS_FUNC_DEF(calculateMacFixedBase64Jni)(JNIEnv *env, jobject thiz,jbyteArray messageBuffer,jbyteArray infoBuffer) {
|
||||
LOGD("## calculateMacFixedBase64Jni(): IN");
|
||||
const char* errorMessage = NULL;
|
||||
jbyteArray returnValue = 0;
|
||||
OlmSAS* sasPtr = getOlmSasInstanceId(env, thiz);
|
||||
|
||||
jbyte *messagePtr = NULL;
|
||||
jboolean messageWasCopied = JNI_FALSE;
|
||||
|
||||
jbyte *infoPtr = NULL;
|
||||
jboolean infoWasCopied = JNI_FALSE;
|
||||
|
||||
if (!sasPtr)
|
||||
{
|
||||
LOGE("## calculateMacFixedBase64Jni(): failure - invalid SAS ptr=NULL");
|
||||
errorMessage = "invalid SAS ptr=NULL";
|
||||
} else if(!messageBuffer) {
|
||||
LOGE("## calculateMacFixedBase64Jni(): failure - invalid message");
|
||||
errorMessage = "invalid info";
|
||||
}
|
||||
else if (!(messagePtr = env->GetByteArrayElements(messageBuffer, &messageWasCopied)))
|
||||
{
|
||||
LOGE(" ## calculateMacFixedBase64Jni(): failure - message JNI allocation OOM");
|
||||
errorMessage = "message JNI allocation OOM";
|
||||
}
|
||||
else if (!(infoPtr = env->GetByteArrayElements(infoBuffer, &infoWasCopied)))
|
||||
{
|
||||
LOGE(" ## calculateMacFixedBase64Jni(): failure - info JNI allocation OOM");
|
||||
errorMessage = "info JNI allocation OOM";
|
||||
} else {
|
||||
|
||||
size_t infoLength = (size_t)env->GetArrayLength(infoBuffer);
|
||||
size_t messageLength = (size_t)env->GetArrayLength(messageBuffer);
|
||||
size_t macLength = olm_sas_mac_length(sasPtr);
|
||||
|
||||
void *macPtr = malloc(macLength*sizeof(uint8_t));
|
||||
|
||||
size_t result = olm_sas_calculate_mac_fixed_base64(sasPtr,messagePtr,messageLength,infoPtr,infoLength,macPtr,macLength);
|
||||
if (result == olm_error())
|
||||
{
|
||||
errorMessage = (const char *)olm_sas_last_error(sasPtr);
|
||||
LOGE("## calculateMacFixedBase64Jni(): failure - error calculating SAS mac Msg=%s", errorMessage);
|
||||
}
|
||||
else
|
||||
{
|
||||
returnValue = env->NewByteArray(macLength);
|
||||
env->SetByteArrayRegion(returnValue, 0 , macLength, (jbyte*)macPtr);
|
||||
}
|
||||
|
||||
if (macPtr) {
|
||||
free(macPtr);
|
||||
}
|
||||
}
|
||||
|
||||
// free alloc
|
||||
if (infoPtr)
|
||||
{
|
||||
if (infoWasCopied)
|
||||
{
|
||||
memset(infoPtr, 0, (size_t)env->GetArrayLength(infoBuffer));
|
||||
}
|
||||
env->ReleaseByteArrayElements(infoBuffer, infoPtr, JNI_ABORT);
|
||||
}
|
||||
if (messagePtr)
|
||||
{
|
||||
if (messageWasCopied)
|
||||
{
|
||||
memset(messagePtr, 0, (size_t)env->GetArrayLength(messageBuffer));
|
||||
}
|
||||
env->ReleaseByteArrayElements(messageBuffer, messagePtr, JNI_ABORT);
|
||||
}
|
||||
|
||||
if (errorMessage)
|
||||
{
|
||||
env->ThrowNew(env->FindClass("java/lang/Exception"), errorMessage);
|
||||
}
|
||||
|
||||
return returnValue;
|
||||
}
|
||||
|
||||
JNIEXPORT jbyteArray OLM_SAS_FUNC_DEF(calculateMacLongKdfJni)(JNIEnv *env, jobject thiz,jbyteArray messageBuffer,jbyteArray infoBuffer) {
|
||||
LOGD("## calculateMacLongKdfJni(): IN");
|
||||
const char* errorMessage = NULL;
|
||||
|
@ -387,4 +467,4 @@ JNIEXPORT jbyteArray OLM_SAS_FUNC_DEF(calculateMacLongKdfJni)(JNIEnv *env, jobje
|
|||
}
|
||||
|
||||
return returnValue;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -32,6 +32,7 @@ JNIEXPORT jbyteArray OLM_SAS_FUNC_DEF(getPubKeyJni)(JNIEnv *env, jobject thiz);
|
|||
JNIEXPORT void OLM_SAS_FUNC_DEF(setTheirPubKey)(JNIEnv *env, jobject thiz,jbyteArray pubKey);
|
||||
JNIEXPORT jbyteArray OLM_SAS_FUNC_DEF(generateShortCodeJni)(JNIEnv *env, jobject thiz, jbyteArray infoStringBytes, jint byteNb);
|
||||
JNIEXPORT jbyteArray OLM_SAS_FUNC_DEF(calculateMacJni)(JNIEnv *env, jobject thiz, jbyteArray messageBuffer, jbyteArray infoBuffer);
|
||||
JNIEXPORT jbyteArray OLM_SAS_FUNC_DEF(calculateMacFixedBase64Jni)(JNIEnv *env, jobject thiz, jbyteArray messageBuffer, jbyteArray infoBuffer);
|
||||
JNIEXPORT jbyteArray OLM_SAS_FUNC_DEF(calculateMacLongKdfJni)(JNIEnv *env, jobject thiz, jbyteArray messageBuffer, jbyteArray infoBuffer);
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
|
|
@ -798,6 +798,58 @@ JNIEXPORT jbyteArray OLM_SESSION_FUNC_DEF(getSessionIdentifierJni)(JNIEnv *env,
|
|||
return returnValue;
|
||||
}
|
||||
|
||||
JNIEXPORT jbyteArray OLM_SESSION_FUNC_DEF(olmSessionDescribeJni(JNIEnv *env, jobject thiz))
|
||||
{
|
||||
const char* errorMessage = NULL;
|
||||
jbyteArray returnValue = 0;
|
||||
|
||||
LOGD("## olmSessionDescribeJni(): IN ");
|
||||
|
||||
OlmSession *sessionPtr = getSessionInstanceId(env, thiz);
|
||||
|
||||
if (!sessionPtr)
|
||||
{
|
||||
LOGE("## olmSessionDescribeJni(): failure - invalid Session ptr=NULL");
|
||||
errorMessage = "invalid Session ptr=NULL";
|
||||
}
|
||||
else
|
||||
{
|
||||
int maxLength = 600;
|
||||
char* describePtr = NULL;
|
||||
describePtr = (char*) malloc(maxLength * sizeof *describePtr);
|
||||
if (!describePtr)
|
||||
{
|
||||
LOGE("## olmSessionDescribeJni(): failure - describe allocation OOM");
|
||||
errorMessage = "describe allocation OOM";
|
||||
}
|
||||
else
|
||||
{
|
||||
olm_session_describe(sessionPtr, describePtr, maxLength);
|
||||
int length = strlen(describePtr);
|
||||
if (length == 0)
|
||||
{
|
||||
LOGE("## olmSessionDescribeJni(): failure - get session describe");
|
||||
}
|
||||
else
|
||||
{
|
||||
LOGD("## olmSessionDescribeJni(): success - describe=%.*s", (char*)describePtr);
|
||||
|
||||
returnValue = env->NewByteArray(length);
|
||||
env->SetByteArrayRegion(returnValue, 0, length, (jbyte*)describePtr);
|
||||
}
|
||||
|
||||
free(describePtr);
|
||||
}
|
||||
}
|
||||
|
||||
if (errorMessage)
|
||||
{
|
||||
env->ThrowNew(env->FindClass("java/lang/Exception"), errorMessage);
|
||||
}
|
||||
|
||||
return returnValue;
|
||||
}
|
||||
|
||||
/**
|
||||
* Serialize and encrypt session instance.<br>
|
||||
* An exception is thrown if the operation fails.
|
||||
|
|
|
@ -47,6 +47,7 @@ JNIEXPORT jbyteArray OLM_SESSION_FUNC_DEF(encryptMessageJni)(JNIEnv *env, jobjec
|
|||
JNIEXPORT jbyteArray OLM_SESSION_FUNC_DEF(decryptMessageJni)(JNIEnv *env, jobject thiz, jobject aEncryptedMsg);
|
||||
|
||||
JNIEXPORT jbyteArray OLM_SESSION_FUNC_DEF(getSessionIdentifierJni)(JNIEnv *env, jobject thiz);
|
||||
JNIEXPORT jbyteArray OLM_SESSION_FUNC_DEF(olmSessionDescribeJni)(JNIEnv *env, jobject thiz);
|
||||
|
||||
// serialization
|
||||
JNIEXPORT jbyteArray OLM_SESSION_FUNC_DEF(serializeJni)(JNIEnv *env, jobject thiz, jbyteArray aKey);
|
||||
|
|
|
@ -1,227 +0,0 @@
|
|||
#[=======================================================================[
|
||||
|
||||
Copyright (c) 2019 John Norrbin <jlnorrbin@johnex.se>
|
||||
|
||||
Permission to use, copy, modify, and 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.
|
||||
|
||||
FindLibreSSL
|
||||
------------
|
||||
|
||||
Find the LibreSSL encryption library.
|
||||
|
||||
Optional Components
|
||||
^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
This module supports two optional components: SSL and TLS. Both
|
||||
components have associated imported targets, as described below.
|
||||
|
||||
Imported Targets
|
||||
^^^^^^^^^^^^^^^^
|
||||
|
||||
This module defines the following imported targets:
|
||||
|
||||
LibreSSL::Crypto
|
||||
The LibreSSL crypto library, if found.
|
||||
|
||||
LibreSSL::SSL
|
||||
The LibreSSL ssl library, if found. Requires and includes LibreSSL::Crypto automatically.
|
||||
|
||||
LibreSSL::TLS
|
||||
The LibreSSL tls library, if found. Requires and includes LibreSSL::SSL and LibreSSL::Crypto automatically.
|
||||
|
||||
Result Variables
|
||||
^^^^^^^^^^^^^^^^
|
||||
|
||||
This module will set the following variables in your project:
|
||||
|
||||
LIBRESSL_FOUND
|
||||
System has the LibreSSL library. If no components are requested it only requires the crypto library.
|
||||
LIBRESSL_INCLUDE_DIR
|
||||
The LibreSSL include directory.
|
||||
LIBRESSL_CRYPTO_LIBRARY
|
||||
The LibreSSL crypto library.
|
||||
LIBRESSL_SSL_LIBRARY
|
||||
The LibreSSL SSL library.
|
||||
LIBRESSL_TLS_LIBRARY
|
||||
The LibreSSL TLS library.
|
||||
LIBRESSL_LIBRARIES
|
||||
All LibreSSL libraries.
|
||||
LIBRESSL_VERSION
|
||||
This is set to $major.$minor.$revision (e.g. 2.6.8).
|
||||
|
||||
Hints
|
||||
^^^^^
|
||||
|
||||
Set LIBRESSL_ROOT_DIR to the root directory of an LibreSSL installation.
|
||||
|
||||
]=======================================================================]
|
||||
|
||||
INCLUDE(FindPackageHandleStandardArgs)
|
||||
|
||||
# Set Hints
|
||||
set(_LIBRESSL_ROOT_HINTS
|
||||
${LIBRESSL_ROOT_DIR}
|
||||
ENV LIBRESSL_ROOT_DIR
|
||||
)
|
||||
|
||||
# Set Paths
|
||||
if (WIN32)
|
||||
file(TO_CMAKE_PATH "$ENV{PROGRAMFILES}" _programfiles)
|
||||
set(_LIBRESSL_ROOT_PATHS
|
||||
"${_programfiles}/LibreSSL"
|
||||
)
|
||||
unset(_programfiles)
|
||||
else()
|
||||
set(_LIBRESSL_ROOT_PATHS
|
||||
"/usr/local/"
|
||||
)
|
||||
endif()
|
||||
|
||||
# Combine
|
||||
set(_LIBRESSL_ROOT_HINTS_AND_PATHS
|
||||
HINTS ${_LIBRESSL_ROOT_HINTS}
|
||||
PATHS ${_LIBRESSL_ROOT_PATHS}
|
||||
)
|
||||
|
||||
# Find Include Path
|
||||
find_path(LIBRESSL_INCLUDE_DIR
|
||||
NAMES
|
||||
tls.h
|
||||
${_LIBRESSL_ROOT_HINTS_AND_PATHS}
|
||||
PATH_SUFFIXES
|
||||
include
|
||||
)
|
||||
|
||||
# Find Crypto Library
|
||||
find_library(LIBRESSL_CRYPTO_LIBRARY
|
||||
NAMES
|
||||
libcrypto
|
||||
crypto
|
||||
NAMES_PER_DIR
|
||||
${_LIBRESSL_ROOT_HINTS_AND_PATHS}
|
||||
PATH_SUFFIXES
|
||||
lib
|
||||
)
|
||||
|
||||
# Find SSL Library
|
||||
find_library(LIBRESSL_SSL_LIBRARY
|
||||
NAMES
|
||||
libssl
|
||||
ssl
|
||||
NAMES_PER_DIR
|
||||
${_LIBRESSL_ROOT_HINTS_AND_PATHS}
|
||||
PATH_SUFFIXES
|
||||
lib
|
||||
)
|
||||
|
||||
# Find TLS Library
|
||||
find_library(LIBRESSL_TLS_LIBRARY
|
||||
NAMES
|
||||
libtls
|
||||
tls
|
||||
NAMES_PER_DIR
|
||||
${_LIBRESSL_ROOT_HINTS_AND_PATHS}
|
||||
PATH_SUFFIXES
|
||||
lib
|
||||
)
|
||||
|
||||
# Set Libraries
|
||||
set(LIBRESSL_LIBRARIES ${LIBRESSL_CRYPTO_LIBRARY} ${LIBRESSL_SSL_LIBRARY} ${LIBRESSL_TLS_LIBRARY})
|
||||
|
||||
# Mark Variables As Advanced
|
||||
mark_as_advanced(LIBRESSL_INCLUDE_DIR LIBRESSL_LIBRARIES LIBRESSL_CRYPTO_LIBRARY LIBRESSL_SSL_LIBRARY LIBRESSL_TLS_LIBRARY)
|
||||
|
||||
# Find Version File
|
||||
if(LIBRESSL_INCLUDE_DIR AND EXISTS "${LIBRESSL_INCLUDE_DIR}/openssl/opensslv.h")
|
||||
|
||||
# Get Version From File
|
||||
file(STRINGS "${LIBRESSL_INCLUDE_DIR}/openssl/opensslv.h" OPENSSLV.H REGEX "#define LIBRESSL_VERSION_TEXT[ ]+\".*\"")
|
||||
|
||||
# Match Version String
|
||||
string(REGEX REPLACE ".*\".*([0-9]+)\\.([0-9]+)\\.([0-9]+)\"" "\\1;\\2;\\3" LIBRESSL_VERSION_LIST "${OPENSSLV.H}")
|
||||
|
||||
# Split Parts
|
||||
list(GET LIBRESSL_VERSION_LIST 0 LIBRESSL_VERSION_MAJOR)
|
||||
list(GET LIBRESSL_VERSION_LIST 1 LIBRESSL_VERSION_MINOR)
|
||||
list(GET LIBRESSL_VERSION_LIST 2 LIBRESSL_VERSION_REVISION)
|
||||
|
||||
# Set Version String
|
||||
set(LIBRESSL_VERSION "${LIBRESSL_VERSION_MAJOR}.${LIBRESSL_VERSION_MINOR}.${LIBRESSL_VERSION_REVISION}")
|
||||
|
||||
endif()
|
||||
|
||||
# Set Find Package Arguments
|
||||
find_package_handle_standard_args(LibreSSL
|
||||
REQUIRED_VARS
|
||||
LIBRESSL_CRYPTO_LIBRARY
|
||||
LIBRESSL_INCLUDE_DIR
|
||||
VERSION_VAR
|
||||
LIBRESSL_VERSION
|
||||
HANDLE_COMPONENTS
|
||||
FAIL_MESSAGE
|
||||
"Could NOT find LibreSSL, try setting the path to LibreSSL using the LIBRESSL_ROOT_DIR environment variable"
|
||||
)
|
||||
|
||||
# LibreSSL Found
|
||||
if(LIBRESSL_FOUND)
|
||||
|
||||
# Set LibreSSL::Crypto
|
||||
if(NOT TARGET LibreSSL::Crypto AND EXISTS "${LIBRESSL_CRYPTO_LIBRARY}")
|
||||
|
||||
# Add Library
|
||||
add_library(LibreSSL::Crypto UNKNOWN IMPORTED)
|
||||
|
||||
# Set Properties
|
||||
set_target_properties(
|
||||
LibreSSL::Crypto
|
||||
PROPERTIES
|
||||
INTERFACE_INCLUDE_DIRECTORIES "${LIBRESSL_INCLUDE_DIR}"
|
||||
IMPORTED_LINK_INTERFACE_LANGUAGES "C"
|
||||
IMPORTED_LOCATION "${LIBRESSL_CRYPTO_LIBRARY}"
|
||||
)
|
||||
|
||||
endif() # LibreSSL::Crypto
|
||||
|
||||
# Set LibreSSL::SSL
|
||||
if(NOT TARGET LibreSSL::SSL AND EXISTS "${LIBRESSL_SSL_LIBRARY}")
|
||||
|
||||
# Add Library
|
||||
add_library(LibreSSL::SSL UNKNOWN IMPORTED)
|
||||
|
||||
# Set Properties
|
||||
set_target_properties(
|
||||
LibreSSL::SSL
|
||||
PROPERTIES
|
||||
INTERFACE_INCLUDE_DIRECTORIES "${LIBRESSL_INCLUDE_DIR}"
|
||||
IMPORTED_LINK_INTERFACE_LANGUAGES "C"
|
||||
IMPORTED_LOCATION "${LIBRESSL_SSL_LIBRARY}"
|
||||
INTERFACE_LINK_LIBRARIES LibreSSL::Crypto
|
||||
)
|
||||
|
||||
endif() # LibreSSL::SSL
|
||||
|
||||
# Set LibreSSL::TLS
|
||||
if(NOT TARGET LibreSSL::TLS AND EXISTS "${LIBRESSL_TLS_LIBRARY}")
|
||||
add_library(LibreSSL::TLS UNKNOWN IMPORTED)
|
||||
set_target_properties(
|
||||
LibreSSL::TLS
|
||||
PROPERTIES
|
||||
INTERFACE_INCLUDE_DIRECTORIES "${LIBRESSL_INCLUDE_DIR}"
|
||||
IMPORTED_LINK_INTERFACE_LANGUAGES "C"
|
||||
IMPORTED_LOCATION "${LIBRESSL_TLS_LIBRARY}"
|
||||
INTERFACE_LINK_LIBRARIES LibreSSL::SSL
|
||||
)
|
||||
|
||||
endif() # LibreSSL::TLS
|
||||
|
||||
endif(LIBRESSL_FOUND)
|
|
@ -1,4 +1,4 @@
|
|||
|
||||
MAJOR := 3
|
||||
MINOR := 2
|
||||
PATCH := 8
|
||||
PATCH := 16
|
||||
|
|
|
@ -109,7 +109,7 @@ discriminate between sessions.
|
|||
### Sharing session data
|
||||
|
||||
To allow other participants in the conversation to decrypt messages, the
|
||||
session data is formatted as described in [Session-sharing format](#Session-sharing-format). It is then
|
||||
session data is formatted as described in [Session-sharing format](#session-sharing-format). It is then
|
||||
shared with other participants in the conversation via a secure peer-to-peer
|
||||
channel (such as that provided by [Olm][]).
|
||||
|
||||
|
@ -182,9 +182,13 @@ but the decision of which ratchet states to cache is left to the application.
|
|||
|
||||
## Data exchange formats
|
||||
|
||||
### Session-sharing format
|
||||
### Session sharing format
|
||||
|
||||
The Megolm key-sharing format is as follows:
|
||||
This format is used for the initial sharing of a Megolm session with other
|
||||
group participants who need to be able to read messages encrypted by this
|
||||
session.
|
||||
|
||||
The session sharing format is as follows:
|
||||
|
||||
```
|
||||
+---+----+--------+--------+--------+--------+------+-----------+
|
||||
|
@ -202,6 +206,33 @@ part of the Ed25519 keypair $`K`$.
|
|||
The data is then signed using the Ed25519 keypair, and the 64-byte signature is
|
||||
appended.
|
||||
|
||||
### Session export format
|
||||
|
||||
Once the session is initially shared with the group participants, each
|
||||
participant needs to retain a copy of the session if they want to maintain
|
||||
their ability to decrypt messages encrypted with that session.
|
||||
|
||||
For forward-secrecy purposes, a participant may choose to store a ratcheted
|
||||
version of the session. But since the ratchet index is covered by the
|
||||
signature, this would invalidate the signature. So we define a similar format,
|
||||
called the *session export format*, which is identical to the [session sharing
|
||||
format](#session-sharing-format) except for dropping the signature.
|
||||
|
||||
The Megolm session export format is thus as follows:
|
||||
|
||||
```
|
||||
+---+----+--------+--------+--------+--------+------+
|
||||
| V | i | R(i,0) | R(i,1) | R(i,2) | R(i,3) | Kpub |
|
||||
+---+----+--------+--------+--------+--------+------+
|
||||
0 1 5 37 69 101 133 165 bytes
|
||||
```
|
||||
|
||||
The version byte, ``V``, is ``"\x01"``.
|
||||
|
||||
This is followed by the ratchet index, $`i`$, which is encoded as a
|
||||
big-endian 32-bit integer; the ratchet values $`R_{i,j}`$; and the public
|
||||
part of the Ed25519 keypair $`K`$.
|
||||
|
||||
### Message format
|
||||
|
||||
Megolm messages consist of a one byte version, followed by a variable length
|
||||
|
|
60
flake.lock
Normal file
60
flake.lock
Normal file
|
@ -0,0 +1,60 @@
|
|||
{
|
||||
"nodes": {
|
||||
"flake-utils": {
|
||||
"locked": {
|
||||
"lastModified": 1659877975,
|
||||
"narHash": "sha256-zllb8aq3YO3h8B/U0/J1WBgAL8EX5yWf5pMj3G0NAmc=",
|
||||
"owner": "numtide",
|
||||
"repo": "flake-utils",
|
||||
"rev": "c0e246b9b83f637f4681389ecabcb2681b4f3af0",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "numtide",
|
||||
"repo": "flake-utils",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"nixpkgs": {
|
||||
"locked": {
|
||||
"lastModified": 1664871473,
|
||||
"narHash": "sha256-1LzbW6G6Uz8akWiOdlIi435GAm1ct5jF5tovw/9to0o=",
|
||||
"owner": "NixOS",
|
||||
"repo": "nixpkgs",
|
||||
"rev": "b7a6fde153d9470afdb6aa1da51c4117f03b84ed",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "NixOS",
|
||||
"ref": "nixos-unstable",
|
||||
"repo": "nixpkgs",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"npmlock2nix": {
|
||||
"flake": false,
|
||||
"locked": {
|
||||
"lastModified": 1654775747,
|
||||
"narHash": "sha256-9pXHDpIjmsK5390wmpGHu9aA4QOPpegPBvThHeBlef4=",
|
||||
"owner": "nix-community",
|
||||
"repo": "npmlock2nix",
|
||||
"rev": "5c4f247688fc91d665df65f71c81e0726621aaa8",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "nix-community",
|
||||
"repo": "npmlock2nix",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"root": {
|
||||
"inputs": {
|
||||
"flake-utils": "flake-utils",
|
||||
"nixpkgs": "nixpkgs",
|
||||
"npmlock2nix": "npmlock2nix"
|
||||
}
|
||||
}
|
||||
},
|
||||
"root": "root",
|
||||
"version": 7
|
||||
}
|
40
flake.nix
Normal file
40
flake.nix
Normal file
|
@ -0,0 +1,40 @@
|
|||
{
|
||||
description = "An implementation of the Double Ratchet cryptographic ratchet";
|
||||
|
||||
inputs.nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable";
|
||||
# We can't use the current stable release because of
|
||||
# https://github.com/emscripten-core/emscripten/issues/16913
|
||||
inputs.flake-utils.url = "github:numtide/flake-utils";
|
||||
inputs.npmlock2nix = {
|
||||
url = "github:nix-community/npmlock2nix";
|
||||
flake = false;
|
||||
};
|
||||
|
||||
outputs = { self, nixpkgs, flake-utils, npmlock2nix }:
|
||||
let
|
||||
localOverlay = import ./nix/overlay.nix;
|
||||
pkgsForSystem = system: import nixpkgs {
|
||||
inherit system;
|
||||
overlays = [
|
||||
(final: prev: {
|
||||
npmlock2nix = final.callPackage npmlock2nix {};
|
||||
node_modules = final.npmlock2nix.node_modules { src = ./javascript; };
|
||||
})
|
||||
localOverlay
|
||||
];
|
||||
};
|
||||
in (
|
||||
# some systems cause issues, e.g. i686-linux is unsupported by gradle,
|
||||
# which causes "nix flake check" to fail. Investigate more later, but for
|
||||
# now, we will just allow x86_64-linux
|
||||
flake-utils.lib.eachSystem [ "x86_64-linux" "x86_64-darwin" "aarch64-darwin" ] (system: rec {
|
||||
legacyPackages = pkgsForSystem system;
|
||||
checks = {
|
||||
inherit (legacyPackages) olm-gcc-cmake olm-clang-cmake olm-gcc-make;
|
||||
};
|
||||
packages = {
|
||||
javascript = legacyPackages.olm-javascript;
|
||||
};
|
||||
}
|
||||
));
|
||||
}
|
17
gitlab-math.lua
Normal file
17
gitlab-math.lua
Normal file
|
@ -0,0 +1,17 @@
|
|||
function Math(el)
|
||||
if el.mathtype == "InlineMath" then
|
||||
if el.text:sub(1,1) == '`' and el.text:sub(#el.text) == '`' then
|
||||
local text = el.text:sub(2,#el.text-1)
|
||||
return pandoc.Math(el.mathtype, text)
|
||||
else
|
||||
local cont = pandoc.read(el.text)
|
||||
return { pandoc.Str("$") } .. cont.blocks[1].content .. { pandoc.Str("$") }
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function CodeBlock(el)
|
||||
if el.classes[1] == "math" then
|
||||
return pandoc.Para({ pandoc.Math("DisplayMath", el.text) })
|
||||
end
|
||||
end
|
|
@ -99,9 +99,9 @@ public:
|
|||
return *this;
|
||||
}
|
||||
T * this_pos = _data;
|
||||
T * const other_pos = other._data;
|
||||
const T * other_pos = other._data;
|
||||
while (other_pos != other._end) {
|
||||
*this_pos = *other;
|
||||
*this_pos = *other_pos;
|
||||
++this_pos;
|
||||
++other_pos;
|
||||
}
|
||||
|
|
|
@ -9,15 +9,15 @@
|
|||
# ifndef OLM_EXPORT
|
||||
# ifdef olm_EXPORTS
|
||||
/* We are building this library */
|
||||
# define OLM_EXPORT __attribute__((visibility("default")))
|
||||
# define OLM_EXPORT
|
||||
# else
|
||||
/* We are using this library */
|
||||
# define OLM_EXPORT __attribute__((visibility("default")))
|
||||
# define OLM_EXPORT
|
||||
# endif
|
||||
# endif
|
||||
|
||||
# ifndef OLM_NO_EXPORT
|
||||
# define OLM_NO_EXPORT __attribute__((visibility("hidden")))
|
||||
# define OLM_NO_EXPORT
|
||||
# endif
|
||||
#endif
|
||||
|
||||
|
|
37
javascript/index.d.ts
vendored
37
javascript/index.d.ts
vendored
|
@ -18,28 +18,28 @@ export as namespace Olm;
|
|||
|
||||
declare class Account {
|
||||
constructor();
|
||||
free();
|
||||
create();
|
||||
free(): void;
|
||||
create(): void;
|
||||
identity_keys(): string;
|
||||
sign(message: string | Uint8Array): string;
|
||||
one_time_keys(): string;
|
||||
mark_keys_as_published();
|
||||
mark_keys_as_published(): void;
|
||||
max_number_of_one_time_keys(): number;
|
||||
generate_one_time_keys(number_of_keys: number);
|
||||
remove_one_time_keys(session: Session);
|
||||
generate_fallback_key();
|
||||
generate_one_time_keys(number_of_keys: number): void;
|
||||
remove_one_time_keys(session: Session): void;
|
||||
generate_fallback_key(): void;
|
||||
fallback_key(): string;
|
||||
unpublished_fallback_key(): string;
|
||||
forget_old_fallback_key(): void;
|
||||
pickle(key: string | Uint8Array): string;
|
||||
unpickle(key: string | Uint8Array, pickle: string);
|
||||
unpickle(key: string | Uint8Array, pickle: string): void;
|
||||
}
|
||||
|
||||
declare class Session {
|
||||
constructor();
|
||||
free(): void;
|
||||
pickle(key: string | Uint8Array): string;
|
||||
unpickle(key: string | Uint8Array, pickle: string);
|
||||
unpickle(key: string | Uint8Array, pickle: string): void;
|
||||
create_outbound(
|
||||
account: Account, their_identity_key: string, their_one_time_key: string,
|
||||
): void;
|
||||
|
@ -51,7 +51,10 @@ declare class Session {
|
|||
has_received_message(): boolean;
|
||||
matches_inbound(one_time_key_message: string): boolean;
|
||||
matches_inbound_from(identity_key: string, one_time_key_message: string): boolean;
|
||||
encrypt(plaintext: string): object;
|
||||
encrypt(plaintext: string): {
|
||||
type: 0 | 1; // 0: PreKey, 1: Message
|
||||
body: string;
|
||||
};
|
||||
decrypt(message_type: number, message: string): string;
|
||||
describe(): string;
|
||||
}
|
||||
|
@ -67,10 +70,13 @@ declare class InboundGroupSession {
|
|||
constructor();
|
||||
free(): void;
|
||||
pickle(key: string | Uint8Array): string;
|
||||
unpickle(key: string | Uint8Array, pickle: string);
|
||||
unpickle(key: string | Uint8Array, pickle: string): void;
|
||||
create(session_key: string): string;
|
||||
import_session(session_key: string): string;
|
||||
decrypt(message: string): object;
|
||||
decrypt(message: string): {
|
||||
message_index: number;
|
||||
plaintext: string;
|
||||
};
|
||||
session_id(): string;
|
||||
first_known_index(): number;
|
||||
export_session(message_index: number): string;
|
||||
|
@ -80,7 +86,7 @@ declare class OutboundGroupSession {
|
|||
constructor();
|
||||
free(): void;
|
||||
pickle(key: string | Uint8Array): string;
|
||||
unpickle(key: string | Uint8Array, pickle: string);
|
||||
unpickle(key: string | Uint8Array, pickle: string): void;
|
||||
create(): void;
|
||||
encrypt(plaintext: string): string;
|
||||
session_id(): string;
|
||||
|
@ -92,7 +98,11 @@ declare class PkEncryption {
|
|||
constructor();
|
||||
free(): void;
|
||||
set_recipient_key(key: string): void;
|
||||
encrypt(plaintext: string): object;
|
||||
encrypt(plaintext: string): {
|
||||
ciphertext: string;
|
||||
mac: string;
|
||||
ephemeral: string;
|
||||
};
|
||||
}
|
||||
|
||||
declare class PkDecryption {
|
||||
|
@ -121,6 +131,7 @@ declare class SAS {
|
|||
set_their_key(their_key: string): void;
|
||||
generate_bytes(info: string, length: number): Uint8Array;
|
||||
calculate_mac(input: string, info: string): string;
|
||||
calculate_mac_fixed_base64(input: string, info: string): string;
|
||||
calculate_mac_long_kdf(input: string, info: string): string;
|
||||
}
|
||||
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
/** @constructor */
|
||||
function InboundGroupSession() {
|
||||
var size = Module['_olm_inbound_group_session_size']();
|
||||
this.buf = malloc(size);
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
/** @constructor */
|
||||
function OutboundGroupSession() {
|
||||
var size = Module['_olm_outbound_group_session_size']();
|
||||
this.buf = malloc(size);
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
/** @constructor */
|
||||
function PkEncryption() {
|
||||
var size = Module['_olm_pk_encryption_size']();
|
||||
this.buf = malloc(size);
|
||||
|
@ -98,6 +99,7 @@ PkEncryption.prototype['encrypt'] = restore_stack(function(
|
|||
});
|
||||
|
||||
|
||||
/** @constructor */
|
||||
function PkDecryption() {
|
||||
var size = Module['_olm_pk_decryption_size']();
|
||||
this.buf = malloc(size);
|
||||
|
@ -273,6 +275,7 @@ PkDecryption.prototype['decrypt'] = restore_stack(function (
|
|||
})
|
||||
|
||||
|
||||
/** @constructor */
|
||||
function PkSigning() {
|
||||
var size = Module['_olm_pk_signing_size']();
|
||||
this.buf = malloc(size);
|
||||
|
|
|
@ -44,6 +44,7 @@ function bzero(ptr, n) {
|
|||
}
|
||||
}
|
||||
|
||||
/** @constructor */
|
||||
function Account() {
|
||||
var size = Module['_olm_account_size']();
|
||||
this.buf = malloc(size);
|
||||
|
@ -244,6 +245,7 @@ Account.prototype['unpickle'] = restore_stack(function(key, pickle) {
|
|||
}
|
||||
});
|
||||
|
||||
/** @constructor */
|
||||
function Session() {
|
||||
var size = Module['_olm_session_size']();
|
||||
this.buf = malloc(size);
|
||||
|
@ -530,6 +532,7 @@ Session.prototype['describe'] = restore_stack(function() {
|
|||
}
|
||||
});
|
||||
|
||||
/** @constructor */
|
||||
function Utility() {
|
||||
var size = Module['_olm_utility_size']();
|
||||
this.buf = malloc(size);
|
||||
|
|
|
@ -14,7 +14,6 @@ if (typeof(window) !== 'undefined') {
|
|||
var bytes = nodeCrypto['randomBytes'](buf.length);
|
||||
buf.set(bytes);
|
||||
};
|
||||
process = global["process"];
|
||||
} else {
|
||||
throw new Error("Cannot find global to attach library to");
|
||||
}
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
/** @constructor */
|
||||
function SAS() {
|
||||
var size = Module['_olm_sas_size']();
|
||||
var random_length = Module['_olm_create_sas_random_length']();
|
||||
|
@ -82,6 +83,22 @@ SAS.prototype['calculate_mac'] = restore_stack(function(input, info) {
|
|||
return UTF8ToString(mac_buffer, mac_length);
|
||||
});
|
||||
|
||||
SAS.prototype['calculate_mac_fixed_base64'] = restore_stack(function(input, info) {
|
||||
var input_array = array_from_string(input);
|
||||
var input_buffer = stack(input_array);
|
||||
var info_array = array_from_string(info);
|
||||
var info_buffer = stack(info_array);
|
||||
var mac_length = sas_method(Module['_olm_sas_mac_length'])(this.ptr);
|
||||
var mac_buffer = stack(mac_length + NULL_BYTE_PADDING_LENGTH);
|
||||
sas_method(Module['_olm_sas_calculate_mac_fixed_base64'])(
|
||||
this.ptr,
|
||||
input_buffer, input_array.length,
|
||||
info_buffer, info_array.length,
|
||||
mac_buffer, mac_length
|
||||
);
|
||||
return UTF8ToString(mac_buffer, mac_length);
|
||||
});
|
||||
|
||||
SAS.prototype['calculate_mac_long_kdf'] = restore_stack(function(input, info) {
|
||||
var input_array = array_from_string(input);
|
||||
var input_buffer = stack(input_array);
|
||||
|
|
241
javascript/package-lock.json
generated
Normal file
241
javascript/package-lock.json
generated
Normal file
|
@ -0,0 +1,241 @@
|
|||
{
|
||||
"name": "@matrix-org/olm",
|
||||
"version": "3.2.11",
|
||||
"lockfileVersion": 2,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "@matrix-org/olm",
|
||||
"version": "3.2.11",
|
||||
"license": "Apache-2.0",
|
||||
"devDependencies": {
|
||||
"jasmine": "^3.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/balanced-match": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz",
|
||||
"integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/brace-expansion": {
|
||||
"version": "1.1.11",
|
||||
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
|
||||
"integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"balanced-match": "^1.0.0",
|
||||
"concat-map": "0.0.1"
|
||||
}
|
||||
},
|
||||
"node_modules/concat-map": {
|
||||
"version": "0.0.1",
|
||||
"resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
|
||||
"integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/fs.realpath": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz",
|
||||
"integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/glob": {
|
||||
"version": "7.2.0",
|
||||
"resolved": "https://registry.npmjs.org/glob/-/glob-7.2.0.tgz",
|
||||
"integrity": "sha512-lmLf6gtyrPq8tTjSmrO94wBeQbFR3HbLHbuyD69wuyQkImp2hWqMGB47OX65FBkPffO641IP9jWa1z4ivqG26Q==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"fs.realpath": "^1.0.0",
|
||||
"inflight": "^1.0.4",
|
||||
"inherits": "2",
|
||||
"minimatch": "^3.0.4",
|
||||
"once": "^1.3.0",
|
||||
"path-is-absolute": "^1.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": "*"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/isaacs"
|
||||
}
|
||||
},
|
||||
"node_modules/inflight": {
|
||||
"version": "1.0.6",
|
||||
"resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz",
|
||||
"integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"once": "^1.3.0",
|
||||
"wrappy": "1"
|
||||
}
|
||||
},
|
||||
"node_modules/inherits": {
|
||||
"version": "2.0.4",
|
||||
"resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz",
|
||||
"integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/jasmine": {
|
||||
"version": "3.99.0",
|
||||
"resolved": "https://registry.npmjs.org/jasmine/-/jasmine-3.99.0.tgz",
|
||||
"integrity": "sha512-YIThBuHzaIIcjxeuLmPD40SjxkEcc8i//sGMDKCgkRMVgIwRJf5qyExtlJpQeh7pkeoBSOe6lQEdg+/9uKg9mw==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"glob": "^7.1.6",
|
||||
"jasmine-core": "~3.99.0"
|
||||
},
|
||||
"bin": {
|
||||
"jasmine": "bin/jasmine.js"
|
||||
}
|
||||
},
|
||||
"node_modules/jasmine-core": {
|
||||
"version": "3.99.1",
|
||||
"resolved": "https://registry.npmjs.org/jasmine-core/-/jasmine-core-3.99.1.tgz",
|
||||
"integrity": "sha512-Hu1dmuoGcZ7AfyynN3LsfruwMbxMALMka+YtZeGoLuDEySVmVAPaonkNoBRIw/ectu8b9tVQCJNgp4a4knp+tg==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/minimatch": {
|
||||
"version": "3.1.2",
|
||||
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz",
|
||||
"integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"brace-expansion": "^1.1.7"
|
||||
},
|
||||
"engines": {
|
||||
"node": "*"
|
||||
}
|
||||
},
|
||||
"node_modules/once": {
|
||||
"version": "1.4.0",
|
||||
"resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
|
||||
"integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"wrappy": "1"
|
||||
}
|
||||
},
|
||||
"node_modules/path-is-absolute": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz",
|
||||
"integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=",
|
||||
"dev": true,
|
||||
"engines": {
|
||||
"node": ">=0.10.0"
|
||||
}
|
||||
},
|
||||
"node_modules/wrappy": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
|
||||
"integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=",
|
||||
"dev": true
|
||||
}
|
||||
},
|
||||
"dependencies": {
|
||||
"balanced-match": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz",
|
||||
"integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==",
|
||||
"dev": true
|
||||
},
|
||||
"brace-expansion": {
|
||||
"version": "1.1.11",
|
||||
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
|
||||
"integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"balanced-match": "^1.0.0",
|
||||
"concat-map": "0.0.1"
|
||||
}
|
||||
},
|
||||
"concat-map": {
|
||||
"version": "0.0.1",
|
||||
"resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
|
||||
"integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=",
|
||||
"dev": true
|
||||
},
|
||||
"fs.realpath": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz",
|
||||
"integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=",
|
||||
"dev": true
|
||||
},
|
||||
"glob": {
|
||||
"version": "7.2.0",
|
||||
"resolved": "https://registry.npmjs.org/glob/-/glob-7.2.0.tgz",
|
||||
"integrity": "sha512-lmLf6gtyrPq8tTjSmrO94wBeQbFR3HbLHbuyD69wuyQkImp2hWqMGB47OX65FBkPffO641IP9jWa1z4ivqG26Q==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"fs.realpath": "^1.0.0",
|
||||
"inflight": "^1.0.4",
|
||||
"inherits": "2",
|
||||
"minimatch": "^3.0.4",
|
||||
"once": "^1.3.0",
|
||||
"path-is-absolute": "^1.0.0"
|
||||
}
|
||||
},
|
||||
"inflight": {
|
||||
"version": "1.0.6",
|
||||
"resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz",
|
||||
"integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"once": "^1.3.0",
|
||||
"wrappy": "1"
|
||||
}
|
||||
},
|
||||
"inherits": {
|
||||
"version": "2.0.4",
|
||||
"resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz",
|
||||
"integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==",
|
||||
"dev": true
|
||||
},
|
||||
"jasmine": {
|
||||
"version": "3.99.0",
|
||||
"resolved": "https://registry.npmjs.org/jasmine/-/jasmine-3.99.0.tgz",
|
||||
"integrity": "sha512-YIThBuHzaIIcjxeuLmPD40SjxkEcc8i//sGMDKCgkRMVgIwRJf5qyExtlJpQeh7pkeoBSOe6lQEdg+/9uKg9mw==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"glob": "^7.1.6",
|
||||
"jasmine-core": "~3.99.0"
|
||||
}
|
||||
},
|
||||
"jasmine-core": {
|
||||
"version": "3.99.1",
|
||||
"resolved": "https://registry.npmjs.org/jasmine-core/-/jasmine-core-3.99.1.tgz",
|
||||
"integrity": "sha512-Hu1dmuoGcZ7AfyynN3LsfruwMbxMALMka+YtZeGoLuDEySVmVAPaonkNoBRIw/ectu8b9tVQCJNgp4a4knp+tg==",
|
||||
"dev": true
|
||||
},
|
||||
"minimatch": {
|
||||
"version": "3.1.2",
|
||||
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz",
|
||||
"integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"brace-expansion": "^1.1.7"
|
||||
}
|
||||
},
|
||||
"once": {
|
||||
"version": "1.4.0",
|
||||
"resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
|
||||
"integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"wrappy": "1"
|
||||
}
|
||||
},
|
||||
"path-is-absolute": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz",
|
||||
"integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=",
|
||||
"dev": true
|
||||
},
|
||||
"wrappy": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
|
||||
"integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=",
|
||||
"dev": true
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "@matrix-org/olm",
|
||||
"version": "3.2.8",
|
||||
"version": "3.2.16",
|
||||
"description": "An implementation of the Double Ratchet cryptographic ratchet",
|
||||
"main": "olm.js",
|
||||
"files": [
|
||||
|
@ -14,7 +14,7 @@
|
|||
],
|
||||
"scripts": {
|
||||
"build": "make -C .. js",
|
||||
"test": "jasmine-node test --verbose --junitreport --captureExceptions"
|
||||
"test": "jasmine --config=test/jasmine.json"
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
|
@ -30,9 +30,6 @@
|
|||
},
|
||||
"homepage": "https://gitlab.matrix.org/matrix-org/olm",
|
||||
"devDependencies": {
|
||||
"jasmine-node": "^1.14.5"
|
||||
},
|
||||
"publishConfig": {
|
||||
"@matrix-org:registry":"https://gitlab.matrix.org/api/v4/projects/27/packages/npm/"
|
||||
"jasmine": "^3.0.0"
|
||||
}
|
||||
}
|
||||
|
|
6
javascript/test/jasmine.json
Normal file
6
javascript/test/jasmine.json
Normal file
|
@ -0,0 +1,6 @@
|
|||
{
|
||||
"spec_dir": "test",
|
||||
"spec_files": [
|
||||
"**/*.spec.js"
|
||||
]
|
||||
}
|
|
@ -19,7 +19,7 @@ var Olm = require('../olm');
|
|||
describe("sas", function() {
|
||||
var alice, bob;
|
||||
|
||||
beforeEach(async function(done) {
|
||||
beforeEach(function(done) {
|
||||
Olm.init().then(function() {
|
||||
alice = new Olm.SAS();
|
||||
bob = new Olm.SAS();
|
||||
|
|
17
lib/crypto-algorithms/README.md
Normal file
17
lib/crypto-algorithms/README.md
Normal file
|
@ -0,0 +1,17 @@
|
|||
crypto-algorithms
|
||||
=================
|
||||
|
||||
|
||||
About
|
||||
---
|
||||
These are basic implementations of standard cryptography algorithms, written by Brad Conte (brad@bradconte.com) from scratch and without any cross-licensing. They exist to provide publically accessible, restriction-free implementations of popular cryptographic algorithms, like AES and SHA-1. These are primarily intended for educational and pragmatic purposes (such as comparing a specification to actual implementation code, or for building an internal application that computes test vectors for a product). The algorithms have been tested against standard test vectors.
|
||||
|
||||
This code is released into the public domain free of any restrictions. The author requests acknowledgement if the code is used, but does not require it. This code is provided free of any liability and without any quality claims by the author.
|
||||
|
||||
Note that these are *not* cryptographically secure implementations. They have no resistence to side-channel attacks and should not be used in contexts that need cryptographically secure implementations.
|
||||
|
||||
These algorithms are not optimized for speed or space. They are primarily designed to be easy to read, although some basic optimization techniques have been employed.
|
||||
|
||||
Building
|
||||
---
|
||||
The source code for each algorithm will come in a pair of a source code file and a header file. There should be no inter-header file dependencies, no additional libraries, no platform-specific header files, or any other complicating matters. Compiling them should be as easy as adding the relevent source code to the project.
|
1073
lib/crypto-algorithms/aes.c
Normal file
1073
lib/crypto-algorithms/aes.c
Normal file
File diff suppressed because it is too large
Load diff
123
lib/crypto-algorithms/aes.h
Normal file
123
lib/crypto-algorithms/aes.h
Normal file
|
@ -0,0 +1,123 @@
|
|||
/*********************************************************************
|
||||
* Filename: aes.h
|
||||
* Author: Brad Conte (brad AT bradconte.com)
|
||||
* Copyright:
|
||||
* Disclaimer: This code is presented "as is" without any guarantees.
|
||||
* Details: Defines the API for the corresponding AES implementation.
|
||||
*********************************************************************/
|
||||
|
||||
#ifndef AES_H
|
||||
#define AES_H
|
||||
|
||||
/*************************** HEADER FILES ***************************/
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
/****************************** MACROS ******************************/
|
||||
#define AES_BLOCK_SIZE 16 // AES operates on 16 bytes at a time
|
||||
|
||||
/**************************** DATA TYPES ****************************/
|
||||
typedef uint8_t BYTE; // 8-bit byte
|
||||
typedef uint32_t WORD; // 32-bit word, change to "long" for 16-bit machines
|
||||
|
||||
/*********************** FUNCTION DECLARATIONS **********************/
|
||||
///////////////////
|
||||
// AES
|
||||
///////////////////
|
||||
// Key setup must be done before any AES en/de-cryption functions can be used.
|
||||
void aes_key_setup(const BYTE key[], // The key, must be 128, 192, or 256 bits
|
||||
WORD w[], // Output key schedule to be used later
|
||||
int keysize); // Bit length of the key, 128, 192, or 256
|
||||
|
||||
void aes_encrypt(const BYTE in[], // 16 bytes of plaintext
|
||||
BYTE out[], // 16 bytes of ciphertext
|
||||
const WORD key[], // From the key setup
|
||||
int keysize); // Bit length of the key, 128, 192, or 256
|
||||
|
||||
void aes_decrypt(const BYTE in[], // 16 bytes of ciphertext
|
||||
BYTE out[], // 16 bytes of plaintext
|
||||
const WORD key[], // From the key setup
|
||||
int keysize); // Bit length of the key, 128, 192, or 256
|
||||
|
||||
///////////////////
|
||||
// AES - CBC
|
||||
///////////////////
|
||||
int aes_encrypt_cbc(const BYTE in[], // Plaintext
|
||||
size_t in_len, // Must be a multiple of AES_BLOCK_SIZE
|
||||
BYTE out[], // Ciphertext, same length as plaintext
|
||||
const WORD key[], // From the key setup
|
||||
int keysize, // Bit length of the key, 128, 192, or 256
|
||||
const BYTE iv[]); // IV, must be AES_BLOCK_SIZE bytes long
|
||||
|
||||
// Only output the CBC-MAC of the input.
|
||||
int aes_encrypt_cbc_mac(const BYTE in[], // plaintext
|
||||
size_t in_len, // Must be a multiple of AES_BLOCK_SIZE
|
||||
BYTE out[], // Output MAC
|
||||
const WORD key[], // From the key setup
|
||||
int keysize, // Bit length of the key, 128, 192, or 256
|
||||
const BYTE iv[]); // IV, must be AES_BLOCK_SIZE bytes long
|
||||
|
||||
///////////////////
|
||||
// AES - CTR
|
||||
///////////////////
|
||||
void increment_iv(BYTE iv[], // Must be a multiple of AES_BLOCK_SIZE
|
||||
int counter_size); // Bytes of the IV used for counting (low end)
|
||||
|
||||
void aes_encrypt_ctr(const BYTE in[], // Plaintext
|
||||
size_t in_len, // Any byte length
|
||||
BYTE out[], // Ciphertext, same length as plaintext
|
||||
const WORD key[], // From the key setup
|
||||
int keysize, // Bit length of the key, 128, 192, or 256
|
||||
const BYTE iv[]); // IV, must be AES_BLOCK_SIZE bytes long
|
||||
|
||||
void aes_decrypt_ctr(const BYTE in[], // Ciphertext
|
||||
size_t in_len, // Any byte length
|
||||
BYTE out[], // Plaintext, same length as ciphertext
|
||||
const WORD key[], // From the key setup
|
||||
int keysize, // Bit length of the key, 128, 192, or 256
|
||||
const BYTE iv[]); // IV, must be AES_BLOCK_SIZE bytes long
|
||||
|
||||
///////////////////
|
||||
// AES - CCM
|
||||
///////////////////
|
||||
// Returns True if the input parameters do not violate any constraint.
|
||||
int aes_encrypt_ccm(const BYTE plaintext[], // IN - Plaintext.
|
||||
WORD plaintext_len, // IN - Plaintext length.
|
||||
const BYTE associated_data[], // IN - Associated Data included in authentication, but not encryption.
|
||||
unsigned short associated_data_len, // IN - Associated Data length in bytes.
|
||||
const BYTE nonce[], // IN - The Nonce to be used for encryption.
|
||||
unsigned short nonce_len, // IN - Nonce length in bytes.
|
||||
BYTE ciphertext[], // OUT - Ciphertext, a concatination of the plaintext and the MAC.
|
||||
WORD *ciphertext_len, // OUT - The length of the ciphertext, always plaintext_len + mac_len.
|
||||
WORD mac_len, // IN - The desired length of the MAC, must be 4, 6, 8, 10, 12, 14, or 16.
|
||||
const BYTE key[], // IN - The AES key for encryption.
|
||||
int keysize); // IN - The length of the key in bits. Valid values are 128, 192, 256.
|
||||
|
||||
// Returns True if the input parameters do not violate any constraint.
|
||||
// Use mac_auth to ensure decryption/validation was preformed correctly.
|
||||
// If authentication does not succeed, the plaintext is zeroed out. To overwride
|
||||
// this, call with mac_auth = NULL. The proper proceedure is to decrypt with
|
||||
// authentication enabled (mac_auth != NULL) and make a second call to that
|
||||
// ignores authentication explicitly if the first call failes.
|
||||
int aes_decrypt_ccm(const BYTE ciphertext[], // IN - Ciphertext, the concatination of encrypted plaintext and MAC.
|
||||
WORD ciphertext_len, // IN - Ciphertext length in bytes.
|
||||
const BYTE assoc[], // IN - The Associated Data, required for authentication.
|
||||
unsigned short assoc_len, // IN - Associated Data length in bytes.
|
||||
const BYTE nonce[], // IN - The Nonce to use for decryption, same one as for encryption.
|
||||
unsigned short nonce_len, // IN - Nonce length in bytes.
|
||||
BYTE plaintext[], // OUT - The plaintext that was decrypted. Will need to be large enough to hold ciphertext_len - mac_len.
|
||||
WORD *plaintext_len, // OUT - Length in bytes of the output plaintext, always ciphertext_len - mac_len .
|
||||
WORD mac_len, // IN - The length of the MAC that was calculated.
|
||||
int *mac_auth, // OUT - TRUE if authentication succeeded, FALSE if it did not. NULL pointer will ignore the authentication.
|
||||
const BYTE key[], // IN - The AES key for decryption.
|
||||
int keysize); // IN - The length of the key in BITS. Valid values are 128, 192, 256.
|
||||
|
||||
///////////////////
|
||||
// Test functions
|
||||
///////////////////
|
||||
int aes_test();
|
||||
int aes_ecb_test();
|
||||
int aes_cbc_test();
|
||||
int aes_ctr_test();
|
||||
int aes_ccm_test();
|
||||
|
||||
#endif // AES_H
|
276
lib/crypto-algorithms/aes_test.c
Normal file
276
lib/crypto-algorithms/aes_test.c
Normal file
|
@ -0,0 +1,276 @@
|
|||
/*********************************************************************
|
||||
* Filename: aes_test.c
|
||||
* Author: Brad Conte (brad AT bradconte.com)
|
||||
* Copyright:
|
||||
* Disclaimer: This code is presented "as is" without any guarantees.
|
||||
* Details: Performs known-answer tests on the corresponding AES
|
||||
implementation. These tests do not encompass the full
|
||||
range of available test vectors and are not sufficient
|
||||
for FIPS-140 certification. However, if the tests pass
|
||||
it is very, very likely that the code is correct and was
|
||||
compiled properly. This code also serves as
|
||||
example usage of the functions.
|
||||
*********************************************************************/
|
||||
|
||||
/*************************** HEADER FILES ***************************/
|
||||
#include <stdio.h>
|
||||
#include <memory.h>
|
||||
#include "aes.h"
|
||||
|
||||
/*********************** FUNCTION DEFINITIONS ***********************/
|
||||
void print_hex(BYTE str[], int len)
|
||||
{
|
||||
int idx;
|
||||
|
||||
for(idx = 0; idx < len; idx++)
|
||||
printf("%02x", str[idx]);
|
||||
}
|
||||
|
||||
int aes_ecb_test()
|
||||
{
|
||||
WORD key_schedule[60], idx;
|
||||
BYTE enc_buf[128];
|
||||
BYTE plaintext[2][16] = {
|
||||
{0x6b,0xc1,0xbe,0xe2,0x2e,0x40,0x9f,0x96,0xe9,0x3d,0x7e,0x11,0x73,0x93,0x17,0x2a},
|
||||
{0xae,0x2d,0x8a,0x57,0x1e,0x03,0xac,0x9c,0x9e,0xb7,0x6f,0xac,0x45,0xaf,0x8e,0x51}
|
||||
};
|
||||
BYTE ciphertext[2][16] = {
|
||||
{0xf3,0xee,0xd1,0xbd,0xb5,0xd2,0xa0,0x3c,0x06,0x4b,0x5a,0x7e,0x3d,0xb1,0x81,0xf8},
|
||||
{0x59,0x1c,0xcb,0x10,0xd4,0x10,0xed,0x26,0xdc,0x5b,0xa7,0x4a,0x31,0x36,0x28,0x70}
|
||||
};
|
||||
BYTE key[1][32] = {
|
||||
{0x60,0x3d,0xeb,0x10,0x15,0xca,0x71,0xbe,0x2b,0x73,0xae,0xf0,0x85,0x7d,0x77,0x81,0x1f,0x35,0x2c,0x07,0x3b,0x61,0x08,0xd7,0x2d,0x98,0x10,0xa3,0x09,0x14,0xdf,0xf4}
|
||||
};
|
||||
int pass = 1;
|
||||
|
||||
// Raw ECB mode.
|
||||
//printf("* ECB mode:\n");
|
||||
aes_key_setup(key[0], key_schedule, 256);
|
||||
//printf( "Key : ");
|
||||
//print_hex(key[0], 32);
|
||||
|
||||
for(idx = 0; idx < 2; idx++) {
|
||||
aes_encrypt(plaintext[idx], enc_buf, key_schedule, 256);
|
||||
//printf("\nPlaintext : ");
|
||||
//print_hex(plaintext[idx], 16);
|
||||
//printf("\n-encrypted to: ");
|
||||
//print_hex(enc_buf, 16);
|
||||
pass = pass && !memcmp(enc_buf, ciphertext[idx], 16);
|
||||
|
||||
aes_decrypt(ciphertext[idx], enc_buf, key_schedule, 256);
|
||||
//printf("\nCiphertext : ");
|
||||
//print_hex(ciphertext[idx], 16);
|
||||
//printf("\n-decrypted to: ");
|
||||
//print_hex(enc_buf, 16);
|
||||
pass = pass && !memcmp(enc_buf, plaintext[idx], 16);
|
||||
|
||||
//printf("\n\n");
|
||||
}
|
||||
|
||||
return(pass);
|
||||
}
|
||||
|
||||
int aes_cbc_test()
|
||||
{
|
||||
WORD key_schedule[60];
|
||||
BYTE enc_buf[128];
|
||||
BYTE plaintext[1][32] = {
|
||||
{0x6b,0xc1,0xbe,0xe2,0x2e,0x40,0x9f,0x96,0xe9,0x3d,0x7e,0x11,0x73,0x93,0x17,0x2a,0xae,0x2d,0x8a,0x57,0x1e,0x03,0xac,0x9c,0x9e,0xb7,0x6f,0xac,0x45,0xaf,0x8e,0x51}
|
||||
};
|
||||
BYTE ciphertext[2][32] = {
|
||||
{0xf5,0x8c,0x4c,0x04,0xd6,0xe5,0xf1,0xba,0x77,0x9e,0xab,0xfb,0x5f,0x7b,0xfb,0xd6,0x9c,0xfc,0x4e,0x96,0x7e,0xdb,0x80,0x8d,0x67,0x9f,0x77,0x7b,0xc6,0x70,0x2c,0x7d}
|
||||
};
|
||||
BYTE iv[1][16] = {
|
||||
{0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0a,0x0b,0x0c,0x0d,0x0e,0x0f}
|
||||
};
|
||||
BYTE key[1][32] = {
|
||||
{0x60,0x3d,0xeb,0x10,0x15,0xca,0x71,0xbe,0x2b,0x73,0xae,0xf0,0x85,0x7d,0x77,0x81,0x1f,0x35,0x2c,0x07,0x3b,0x61,0x08,0xd7,0x2d,0x98,0x10,0xa3,0x09,0x14,0xdf,0xf4}
|
||||
};
|
||||
int pass = 1;
|
||||
|
||||
//printf("* CBC mode:\n");
|
||||
aes_key_setup(key[0], key_schedule, 256);
|
||||
|
||||
//printf( "Key : ");
|
||||
//print_hex(key[0], 32);
|
||||
//printf("\nIV : ");
|
||||
//print_hex(iv[0], 16);
|
||||
|
||||
aes_encrypt_cbc(plaintext[0], 32, enc_buf, key_schedule, 256, iv[0]);
|
||||
//printf("\nPlaintext : ");
|
||||
//print_hex(plaintext[0], 32);
|
||||
//printf("\n-encrypted to: ");
|
||||
//print_hex(enc_buf, 32);
|
||||
//printf("\nCiphertext : ");
|
||||
//print_hex(ciphertext[0], 32);
|
||||
pass = pass && !memcmp(enc_buf, ciphertext[0], 32);
|
||||
|
||||
//printf("\n\n");
|
||||
return(pass);
|
||||
}
|
||||
|
||||
int aes_ctr_test()
|
||||
{
|
||||
WORD key_schedule[60];
|
||||
BYTE enc_buf[128];
|
||||
BYTE plaintext[1][32] = {
|
||||
{0x6b,0xc1,0xbe,0xe2,0x2e,0x40,0x9f,0x96,0xe9,0x3d,0x7e,0x11,0x73,0x93,0x17,0x2a,0xae,0x2d,0x8a,0x57,0x1e,0x03,0xac,0x9c,0x9e,0xb7,0x6f,0xac,0x45,0xaf,0x8e,0x51}
|
||||
};
|
||||
BYTE ciphertext[1][32] = {
|
||||
{0x60,0x1e,0xc3,0x13,0x77,0x57,0x89,0xa5,0xb7,0xa7,0xf5,0x04,0xbb,0xf3,0xd2,0x28,0xf4,0x43,0xe3,0xca,0x4d,0x62,0xb5,0x9a,0xca,0x84,0xe9,0x90,0xca,0xca,0xf5,0xc5}
|
||||
};
|
||||
BYTE iv[1][16] = {
|
||||
{0xf0,0xf1,0xf2,0xf3,0xf4,0xf5,0xf6,0xf7,0xf8,0xf9,0xfa,0xfb,0xfc,0xfd,0xfe,0xff},
|
||||
};
|
||||
BYTE key[1][32] = {
|
||||
{0x60,0x3d,0xeb,0x10,0x15,0xca,0x71,0xbe,0x2b,0x73,0xae,0xf0,0x85,0x7d,0x77,0x81,0x1f,0x35,0x2c,0x07,0x3b,0x61,0x08,0xd7,0x2d,0x98,0x10,0xa3,0x09,0x14,0xdf,0xf4}
|
||||
};
|
||||
int pass = 1;
|
||||
|
||||
//printf("* CTR mode:\n");
|
||||
aes_key_setup(key[0], key_schedule, 256);
|
||||
|
||||
//printf( "Key : ");
|
||||
//print_hex(key[0], 32);
|
||||
//printf("\nIV : ");
|
||||
//print_hex(iv[0], 16);
|
||||
|
||||
aes_encrypt_ctr(plaintext[0], 32, enc_buf, key_schedule, 256, iv[0]);
|
||||
//printf("\nPlaintext : ");
|
||||
//print_hex(plaintext[0], 32);
|
||||
//printf("\n-encrypted to: ");
|
||||
//print_hex(enc_buf, 32);
|
||||
pass = pass && !memcmp(enc_buf, ciphertext[0], 32);
|
||||
|
||||
aes_decrypt_ctr(ciphertext[0], 32, enc_buf, key_schedule, 256, iv[0]);
|
||||
//printf("\nCiphertext : ");
|
||||
//print_hex(ciphertext[0], 32);
|
||||
//printf("\n-decrypted to: ");
|
||||
//print_hex(enc_buf, 32);
|
||||
pass = pass && !memcmp(enc_buf, plaintext[0], 32);
|
||||
|
||||
//printf("\n\n");
|
||||
return(pass);
|
||||
}
|
||||
|
||||
int aes_ccm_test()
|
||||
{
|
||||
int mac_auth;
|
||||
WORD enc_buf_len;
|
||||
BYTE enc_buf[128];
|
||||
BYTE plaintext[3][32] = {
|
||||
{0x20,0x21,0x22,0x23},
|
||||
{0x20,0x21,0x22,0x23,0x24,0x25,0x26,0x27,0x28,0x29,0x2a,0x2b,0x2c,0x2d,0x2e,0x2f},
|
||||
{0x20,0x21,0x22,0x23,0x24,0x25,0x26,0x27,0x28,0x29,0x2a,0x2b,0x2c,0x2d,0x2e,0x2f,0x30,0x31,0x32,0x33,0x34,0x35,0x36,0x37}
|
||||
};
|
||||
BYTE assoc[3][32] = {
|
||||
{0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07},
|
||||
{0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0a,0x0b,0x0c,0x0d,0x0e,0x0f},
|
||||
{0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0a,0x0b,0x0c,0x0d,0x0e,0x0f,0x10,0x11,0x12,0x13}
|
||||
};
|
||||
BYTE ciphertext[3][32 + 16] = {
|
||||
{0x71,0x62,0x01,0x5b,0x4d,0xac,0x25,0x5d},
|
||||
{0xd2,0xa1,0xf0,0xe0,0x51,0xea,0x5f,0x62,0x08,0x1a,0x77,0x92,0x07,0x3d,0x59,0x3d,0x1f,0xc6,0x4f,0xbf,0xac,0xcd},
|
||||
{0xe3,0xb2,0x01,0xa9,0xf5,0xb7,0x1a,0x7a,0x9b,0x1c,0xea,0xec,0xcd,0x97,0xe7,0x0b,0x61,0x76,0xaa,0xd9,0xa4,0x42,0x8a,0xa5,0x48,0x43,0x92,0xfb,0xc1,0xb0,0x99,0x51}
|
||||
};
|
||||
BYTE iv[3][16] = {
|
||||
{0x10,0x11,0x12,0x13,0x14,0x15,0x16},
|
||||
{0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17},
|
||||
{0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,0x18,0x19,0x1a,0x1b}
|
||||
};
|
||||
BYTE key[1][32] = {
|
||||
{0x40,0x41,0x42,0x43,0x44,0x45,0x46,0x47,0x48,0x49,0x4a,0x4b,0x4c,0x4d,0x4e,0x4f}
|
||||
};
|
||||
int pass = 1;
|
||||
|
||||
//printf("* CCM mode:\n");
|
||||
//printf("Key : ");
|
||||
//print_hex(key[0], 16);
|
||||
|
||||
//print_hex(plaintext[0], 4);
|
||||
//print_hex(assoc[0], 8);
|
||||
//print_hex(ciphertext[0], 8);
|
||||
//print_hex(iv[0], 7);
|
||||
//print_hex(key[0], 16);
|
||||
|
||||
aes_encrypt_ccm(plaintext[0], 4, assoc[0], 8, iv[0], 7, enc_buf, &enc_buf_len, 4, key[0], 128);
|
||||
//printf("\nNONCE : ");
|
||||
//print_hex(iv[0], 7);
|
||||
//printf("\nAssoc. Data : ");
|
||||
//print_hex(assoc[0], 8);
|
||||
//printf("\nPayload : ");
|
||||
//print_hex(plaintext[0], 4);
|
||||
//printf("\n-encrypted to: ");
|
||||
//print_hex(enc_buf, enc_buf_len);
|
||||
pass = pass && !memcmp(enc_buf, ciphertext[0], enc_buf_len);
|
||||
|
||||
aes_decrypt_ccm(ciphertext[0], 8, assoc[0], 8, iv[0], 7, enc_buf, &enc_buf_len, 4, &mac_auth, key[0], 128);
|
||||
//printf("\n-Ciphertext : ");
|
||||
//print_hex(ciphertext[0], 8);
|
||||
//printf("\n-decrypted to: ");
|
||||
//print_hex(enc_buf, enc_buf_len);
|
||||
//printf("\nAuthenticated: %d ", mac_auth);
|
||||
pass = pass && !memcmp(enc_buf, plaintext[0], enc_buf_len) && mac_auth;
|
||||
|
||||
|
||||
aes_encrypt_ccm(plaintext[1], 16, assoc[1], 16, iv[1], 8, enc_buf, &enc_buf_len, 6, key[0], 128);
|
||||
//printf("\n\nNONCE : ");
|
||||
//print_hex(iv[1], 8);
|
||||
//printf("\nAssoc. Data : ");
|
||||
//print_hex(assoc[1], 16);
|
||||
//printf("\nPayload : ");
|
||||
//print_hex(plaintext[1], 16);
|
||||
//printf("\n-encrypted to: ");
|
||||
//print_hex(enc_buf, enc_buf_len);
|
||||
pass = pass && !memcmp(enc_buf, ciphertext[1], enc_buf_len);
|
||||
|
||||
aes_decrypt_ccm(ciphertext[1], 22, assoc[1], 16, iv[1], 8, enc_buf, &enc_buf_len, 6, &mac_auth, key[0], 128);
|
||||
//printf("\n-Ciphertext : ");
|
||||
//print_hex(ciphertext[1], 22);
|
||||
//printf("\n-decrypted to: ");
|
||||
//print_hex(enc_buf, enc_buf_len);
|
||||
//printf("\nAuthenticated: %d ", mac_auth);
|
||||
pass = pass && !memcmp(enc_buf, plaintext[1], enc_buf_len) && mac_auth;
|
||||
|
||||
|
||||
aes_encrypt_ccm(plaintext[2], 24, assoc[2], 20, iv[2], 12, enc_buf, &enc_buf_len, 8, key[0], 128);
|
||||
//printf("\n\nNONCE : ");
|
||||
//print_hex(iv[2], 12);
|
||||
//printf("\nAssoc. Data : ");
|
||||
//print_hex(assoc[2], 20);
|
||||
//printf("\nPayload : ");
|
||||
//print_hex(plaintext[2], 24);
|
||||
//printf("\n-encrypted to: ");
|
||||
//print_hex(enc_buf, enc_buf_len);
|
||||
pass = pass && !memcmp(enc_buf, ciphertext[2], enc_buf_len);
|
||||
|
||||
aes_decrypt_ccm(ciphertext[2], 32, assoc[2], 20, iv[2], 12, enc_buf, &enc_buf_len, 8, &mac_auth, key[0], 128);
|
||||
//printf("\n-Ciphertext : ");
|
||||
//print_hex(ciphertext[2], 32);
|
||||
//printf("\n-decrypted to: ");
|
||||
//print_hex(enc_buf, enc_buf_len);
|
||||
//printf("\nAuthenticated: %d ", mac_auth);
|
||||
pass = pass && !memcmp(enc_buf, plaintext[2], enc_buf_len) && mac_auth;
|
||||
|
||||
//printf("\n\n");
|
||||
return(pass);
|
||||
}
|
||||
|
||||
int aes_test()
|
||||
{
|
||||
int pass = 1;
|
||||
|
||||
pass = pass && aes_ecb_test();
|
||||
pass = pass && aes_cbc_test();
|
||||
pass = pass && aes_ctr_test();
|
||||
pass = pass && aes_ccm_test();
|
||||
|
||||
return(pass);
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
printf("AES Tests: %s\n", aes_test() ? "SUCCEEDED" : "FAILED");
|
||||
|
||||
return(0);
|
||||
}
|
45
lib/crypto-algorithms/arcfour.c
Normal file
45
lib/crypto-algorithms/arcfour.c
Normal file
|
@ -0,0 +1,45 @@
|
|||
/*********************************************************************
|
||||
* Filename: arcfour.c
|
||||
* Author: Brad Conte (brad AT bradconte.com)
|
||||
* Copyright:
|
||||
* Disclaimer: This code is presented "as is" without any guarantees.
|
||||
* Details: Implementation of the ARCFOUR encryption algorithm.
|
||||
Algorithm specification can be found here:
|
||||
* http://en.wikipedia.org/wiki/RC4
|
||||
*********************************************************************/
|
||||
|
||||
/*************************** HEADER FILES ***************************/
|
||||
#include <stdlib.h>
|
||||
#include "arcfour.h"
|
||||
|
||||
/*********************** FUNCTION DEFINITIONS ***********************/
|
||||
void arcfour_key_setup(BYTE state[], const BYTE key[], int len)
|
||||
{
|
||||
int i, j;
|
||||
BYTE t;
|
||||
|
||||
for (i = 0; i < 256; ++i)
|
||||
state[i] = i;
|
||||
for (i = 0, j = 0; i < 256; ++i) {
|
||||
j = (j + state[i] + key[i % len]) % 256;
|
||||
t = state[i];
|
||||
state[i] = state[j];
|
||||
state[j] = t;
|
||||
}
|
||||
}
|
||||
|
||||
void arcfour_generate_stream(BYTE state[], BYTE out[], size_t len)
|
||||
{
|
||||
int i, j;
|
||||
size_t idx;
|
||||
BYTE t;
|
||||
|
||||
for (idx = 0, i = 0, j = 0; idx < len; ++idx) {
|
||||
i = (i + 1) % 256;
|
||||
j = (j + state[i]) % 256;
|
||||
t = state[i];
|
||||
state[i] = state[j];
|
||||
state[j] = t;
|
||||
out[idx] = state[(state[i] + state[j]) % 256];
|
||||
}
|
||||
}
|
30
lib/crypto-algorithms/arcfour.h
Normal file
30
lib/crypto-algorithms/arcfour.h
Normal file
|
@ -0,0 +1,30 @@
|
|||
/*********************************************************************
|
||||
* Filename: arcfour.h
|
||||
* Author: Brad Conte (brad AT bradconte.com)
|
||||
* Copyright:
|
||||
* Disclaimer: This code is presented "as is" without any guarantees.
|
||||
* Details: Defines the API for the corresponding ARCFOUR implementation.
|
||||
*********************************************************************/
|
||||
|
||||
#ifndef ARCFOUR_H
|
||||
#define ARCFOUR_H
|
||||
|
||||
/*************************** HEADER FILES ***************************/
|
||||
#include <stddef.h>
|
||||
|
||||
/**************************** DATA TYPES ****************************/
|
||||
typedef unsigned char BYTE; // 8-bit byte
|
||||
|
||||
/*********************** FUNCTION DECLARATIONS **********************/
|
||||
// Input: state - the state used to generate the keystream
|
||||
// key - Key to use to initialize the state
|
||||
// len - length of key in bytes (valid lenth is 1 to 256)
|
||||
void arcfour_key_setup(BYTE state[], const BYTE key[], int len);
|
||||
|
||||
// Pseudo-Random Generator Algorithm
|
||||
// Input: state - the state used to generate the keystream
|
||||
// out - Must be allocated to be of at least "len" length
|
||||
// len - number of bytes to generate
|
||||
void arcfour_generate_stream(BYTE state[], BYTE out[], size_t len);
|
||||
|
||||
#endif // ARCFOUR_H
|
47
lib/crypto-algorithms/arcfour_test.c
Normal file
47
lib/crypto-algorithms/arcfour_test.c
Normal file
|
@ -0,0 +1,47 @@
|
|||
/*********************************************************************
|
||||
* Filename: arcfour_test.c
|
||||
* Author: Brad Conte (brad AT bradconte.com)
|
||||
* Copyright:
|
||||
* Disclaimer: This code is presented "as is" without any guarantees.
|
||||
* Details: Performs known-answer tests on the corresponding ARCFOUR
|
||||
implementation. These tests do not encompass the full
|
||||
range of available test vectors, however, if the tests
|
||||
pass it is very, very likely that the code is correct
|
||||
and was compiled properly. This code also serves as
|
||||
example usage of the functions.
|
||||
*********************************************************************/
|
||||
|
||||
/*************************** HEADER FILES ***************************/
|
||||
#include <stdio.h>
|
||||
#include <memory.h>
|
||||
#include "arcfour.h"
|
||||
|
||||
/*********************** FUNCTION DEFINITIONS ***********************/
|
||||
int rc4_test()
|
||||
{
|
||||
BYTE state[256];
|
||||
BYTE key[3][10] = {{"Key"}, {"Wiki"}, {"Secret"}};
|
||||
BYTE stream[3][10] = {{0xEB,0x9F,0x77,0x81,0xB7,0x34,0xCA,0x72,0xA7,0x19},
|
||||
{0x60,0x44,0xdb,0x6d,0x41,0xb7},
|
||||
{0x04,0xd4,0x6b,0x05,0x3c,0xa8,0x7b,0x59}};
|
||||
int stream_len[3] = {10,6,8};
|
||||
BYTE buf[1024];
|
||||
int idx;
|
||||
int pass = 1;
|
||||
|
||||
// Only test the output stream. Note that the state can be reused.
|
||||
for (idx = 0; idx < 3; idx++) {
|
||||
arcfour_key_setup(state, key[idx], strlen(key[idx]));
|
||||
arcfour_generate_stream(state, buf, stream_len[idx]);
|
||||
pass = pass && !memcmp(stream[idx], buf, stream_len[idx]);
|
||||
}
|
||||
|
||||
return(pass);
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
printf("ARCFOUR tests: %s\n", rc4_test() ? "SUCCEEDED" : "FAILED");
|
||||
|
||||
return(0);
|
||||
}
|
135
lib/crypto-algorithms/base64.c
Normal file
135
lib/crypto-algorithms/base64.c
Normal file
|
@ -0,0 +1,135 @@
|
|||
/*********************************************************************
|
||||
* Filename: base64.c
|
||||
* Author: Brad Conte (brad AT bradconte.com)
|
||||
* Copyright:
|
||||
* Disclaimer: This code is presented "as is" without any guarantees.
|
||||
* Details: Implementation of the Base64 encoding algorithm.
|
||||
*********************************************************************/
|
||||
|
||||
/*************************** HEADER FILES ***************************/
|
||||
#include <stdlib.h>
|
||||
#include "base64.h"
|
||||
|
||||
/****************************** MACROS ******************************/
|
||||
#define NEWLINE_INVL 76
|
||||
|
||||
/**************************** VARIABLES *****************************/
|
||||
// Note: To change the charset to a URL encoding, replace the '+' and '/' with '*' and '-'
|
||||
static const BYTE charset[]={"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"};
|
||||
|
||||
/*********************** FUNCTION DEFINITIONS ***********************/
|
||||
BYTE revchar(char ch)
|
||||
{
|
||||
if (ch >= 'A' && ch <= 'Z')
|
||||
ch -= 'A';
|
||||
else if (ch >= 'a' && ch <='z')
|
||||
ch = ch - 'a' + 26;
|
||||
else if (ch >= '0' && ch <='9')
|
||||
ch = ch - '0' + 52;
|
||||
else if (ch == '+')
|
||||
ch = 62;
|
||||
else if (ch == '/')
|
||||
ch = 63;
|
||||
|
||||
return(ch);
|
||||
}
|
||||
|
||||
size_t base64_encode(const BYTE in[], BYTE out[], size_t len, int newline_flag)
|
||||
{
|
||||
size_t idx, idx2, blks, blk_ceiling, left_over, newline_count = 0;
|
||||
|
||||
blks = (len / 3);
|
||||
left_over = len % 3;
|
||||
|
||||
if (out == NULL) {
|
||||
idx2 = blks * 4 ;
|
||||
if (left_over)
|
||||
idx2 += 4;
|
||||
if (newline_flag)
|
||||
idx2 += len / 57; // (NEWLINE_INVL / 4) * 3 = 57. One newline per 57 input bytes.
|
||||
}
|
||||
else {
|
||||
// Since 3 input bytes = 4 output bytes, determine out how many even sets of
|
||||
// 3 bytes the input has.
|
||||
blk_ceiling = blks * 3;
|
||||
for (idx = 0, idx2 = 0; idx < blk_ceiling; idx += 3, idx2 += 4) {
|
||||
out[idx2] = charset[in[idx] >> 2];
|
||||
out[idx2 + 1] = charset[((in[idx] & 0x03) << 4) | (in[idx + 1] >> 4)];
|
||||
out[idx2 + 2] = charset[((in[idx + 1] & 0x0f) << 2) | (in[idx + 2] >> 6)];
|
||||
out[idx2 + 3] = charset[in[idx + 2] & 0x3F];
|
||||
// The offical standard requires a newline every 76 characters.
|
||||
// (Eg, first newline is character 77 of the output.)
|
||||
if (((idx2 - newline_count + 4) % NEWLINE_INVL == 0) && newline_flag) {
|
||||
out[idx2 + 4] = '\n';
|
||||
idx2++;
|
||||
newline_count++;
|
||||
}
|
||||
}
|
||||
|
||||
if (left_over == 1) {
|
||||
out[idx2] = charset[in[idx] >> 2];
|
||||
out[idx2 + 1] = charset[(in[idx] & 0x03) << 4];
|
||||
out[idx2 + 2] = '=';
|
||||
out[idx2 + 3] = '=';
|
||||
idx2 += 4;
|
||||
}
|
||||
else if (left_over == 2) {
|
||||
out[idx2] = charset[in[idx] >> 2];
|
||||
out[idx2 + 1] = charset[((in[idx] & 0x03) << 4) | (in[idx + 1] >> 4)];
|
||||
out[idx2 + 2] = charset[(in[idx + 1] & 0x0F) << 2];
|
||||
out[idx2 + 3] = '=';
|
||||
idx2 += 4;
|
||||
}
|
||||
}
|
||||
|
||||
return(idx2);
|
||||
}
|
||||
|
||||
size_t base64_decode(const BYTE in[], BYTE out[], size_t len)
|
||||
{
|
||||
BYTE ch;
|
||||
size_t idx, idx2, blks, blk_ceiling, left_over;
|
||||
|
||||
if (in[len - 1] == '=')
|
||||
len--;
|
||||
if (in[len - 1] == '=')
|
||||
len--;
|
||||
|
||||
blks = len / 4;
|
||||
left_over = len % 4;
|
||||
|
||||
if (out == NULL) {
|
||||
if (len >= 77 && in[NEWLINE_INVL] == '\n') // Verify that newlines where used.
|
||||
len -= len / (NEWLINE_INVL + 1);
|
||||
blks = len / 4;
|
||||
left_over = len % 4;
|
||||
|
||||
idx = blks * 3;
|
||||
if (left_over == 2)
|
||||
idx ++;
|
||||
else if (left_over == 3)
|
||||
idx += 2;
|
||||
}
|
||||
else {
|
||||
blk_ceiling = blks * 4;
|
||||
for (idx = 0, idx2 = 0; idx2 < blk_ceiling; idx += 3, idx2 += 4) {
|
||||
if (in[idx2] == '\n')
|
||||
idx2++;
|
||||
out[idx] = (revchar(in[idx2]) << 2) | ((revchar(in[idx2 + 1]) & 0x30) >> 4);
|
||||
out[idx + 1] = (revchar(in[idx2 + 1]) << 4) | (revchar(in[idx2 + 2]) >> 2);
|
||||
out[idx + 2] = (revchar(in[idx2 + 2]) << 6) | revchar(in[idx2 + 3]);
|
||||
}
|
||||
|
||||
if (left_over == 2) {
|
||||
out[idx] = (revchar(in[idx2]) << 2) | ((revchar(in[idx2 + 1]) & 0x30) >> 4);
|
||||
idx++;
|
||||
}
|
||||
else if (left_over == 3) {
|
||||
out[idx] = (revchar(in[idx2]) << 2) | ((revchar(in[idx2 + 1]) & 0x30) >> 4);
|
||||
out[idx + 1] = (revchar(in[idx2 + 1]) << 4) | (revchar(in[idx2 + 2]) >> 2);
|
||||
idx += 2;
|
||||
}
|
||||
}
|
||||
|
||||
return(idx);
|
||||
}
|
27
lib/crypto-algorithms/base64.h
Normal file
27
lib/crypto-algorithms/base64.h
Normal file
|
@ -0,0 +1,27 @@
|
|||
/*********************************************************************
|
||||
* Filename: base64.h
|
||||
* Author: Brad Conte (brad AT bradconte.com)
|
||||
* Copyright:
|
||||
* Disclaimer: This code is presented "as is" without any guarantees.
|
||||
* Details: Defines the API for the corresponding Base64 implementation.
|
||||
*********************************************************************/
|
||||
|
||||
#ifndef BASE64_H
|
||||
#define BASE64_H
|
||||
|
||||
/*************************** HEADER FILES ***************************/
|
||||
#include <stddef.h>
|
||||
|
||||
/**************************** DATA TYPES ****************************/
|
||||
typedef unsigned char BYTE; // 8-bit byte
|
||||
|
||||
/*********************** FUNCTION DECLARATIONS **********************/
|
||||
// Returns the size of the output. If called with out = NULL, will just return
|
||||
// the size of what the output would have been (without a terminating NULL).
|
||||
size_t base64_encode(const BYTE in[], BYTE out[], size_t len, int newline_flag);
|
||||
|
||||
// Returns the size of the output. If called with out = NULL, will just return
|
||||
// the size of what the output would have been (without a terminating NULL).
|
||||
size_t base64_decode(const BYTE in[], BYTE out[], size_t len);
|
||||
|
||||
#endif // BASE64_H
|
54
lib/crypto-algorithms/base64_test.c
Normal file
54
lib/crypto-algorithms/base64_test.c
Normal file
|
@ -0,0 +1,54 @@
|
|||
/*********************************************************************
|
||||
* Filename: blowfish_test.c
|
||||
* Author: Brad Conte (brad AT bradconte.com)
|
||||
* Copyright:
|
||||
* Disclaimer: This code is presented "as is" without any guarantees.
|
||||
* Details: Performs known-answer tests on the corresponding Base64
|
||||
implementation. These tests do not encompass the full
|
||||
range of available test vectors, however, if the tests
|
||||
pass it is very, very likely that the code is correct
|
||||
and was compiled properly. This code also serves as
|
||||
example usage of the functions.
|
||||
*********************************************************************/
|
||||
|
||||
/*************************** HEADER FILES ***************************/
|
||||
#include <stdio.h>
|
||||
#include <memory.h>
|
||||
#include "base64.h"
|
||||
|
||||
/*********************** FUNCTION DEFINITIONS ***********************/
|
||||
int base64_test()
|
||||
{
|
||||
BYTE text[3][1024] = {{"fo"},
|
||||
{"foobar"},
|
||||
{"Man is distinguished, not only by his reason, but by this singular passion from other animals, which is a lust of the mind, that by a perseverance of delight in the continued and indefatigable generation of knowledge, exceeds the short vehemence of any carnal pleasure."}};
|
||||
BYTE code[3][1024] = {{"Zm8="},
|
||||
{"Zm9vYmFy"},
|
||||
{"TWFuIGlzIGRpc3Rpbmd1aXNoZWQsIG5vdCBvbmx5IGJ5IGhpcyByZWFzb24sIGJ1dCBieSB0aGlz\nIHNpbmd1bGFyIHBhc3Npb24gZnJvbSBvdGhlciBhbmltYWxzLCB3aGljaCBpcyBhIGx1c3Qgb2Yg\ndGhlIG1pbmQsIHRoYXQgYnkgYSBwZXJzZXZlcmFuY2Ugb2YgZGVsaWdodCBpbiB0aGUgY29udGlu\ndWVkIGFuZCBpbmRlZmF0aWdhYmxlIGdlbmVyYXRpb24gb2Yga25vd2xlZGdlLCBleGNlZWRzIHRo\nZSBzaG9ydCB2ZWhlbWVuY2Ugb2YgYW55IGNhcm5hbCBwbGVhc3VyZS4="}};
|
||||
BYTE buf[1024];
|
||||
size_t buf_len;
|
||||
int pass = 1;
|
||||
int idx;
|
||||
|
||||
for (idx = 0; idx < 3; idx++) {
|
||||
buf_len = base64_encode(text[idx], buf, strlen(text[idx]), 1);
|
||||
pass = pass && ((buf_len == strlen(code[idx])) &&
|
||||
(buf_len == base64_encode(text[idx], NULL, strlen(text[idx]), 1)));
|
||||
pass = pass && !strcmp(code[idx], buf);
|
||||
|
||||
memset(buf, 0, sizeof(buf));
|
||||
buf_len = base64_decode(code[idx], buf, strlen(code[idx]));
|
||||
pass = pass && ((buf_len == strlen(text[idx])) &&
|
||||
(buf_len == base64_decode(code[idx], NULL, strlen(code[idx]))));
|
||||
pass = pass && !strcmp(text[idx], buf);
|
||||
}
|
||||
|
||||
return(pass);
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
printf("Base64 tests: %s\n", base64_test() ? "PASSED" : "FAILED");
|
||||
|
||||
return 0;
|
||||
}
|
269
lib/crypto-algorithms/blowfish.c
Normal file
269
lib/crypto-algorithms/blowfish.c
Normal file
|
@ -0,0 +1,269 @@
|
|||
/*********************************************************************
|
||||
* Filename: blowfish.c
|
||||
* Author: Brad Conte (brad AT bradconte.com)
|
||||
* Copyright:
|
||||
* Disclaimer: This code is presented "as is" without any guarantees.
|
||||
* Details: Implementation of the Blowfish encryption algorithm.
|
||||
Modes of operation (such as CBC) are not included.
|
||||
Algorithm specification can be found here:
|
||||
* http://www.schneier.com/blowfish.html
|
||||
*********************************************************************/
|
||||
|
||||
/*************************** HEADER FILES ***************************/
|
||||
#include <stdlib.h>
|
||||
#include <memory.h>
|
||||
#include "blowfish.h"
|
||||
|
||||
/****************************** MACROS ******************************/
|
||||
#define F(x,t) t = keystruct->s[0][(x) >> 24]; \
|
||||
t += keystruct->s[1][((x) >> 16) & 0xff]; \
|
||||
t ^= keystruct->s[2][((x) >> 8) & 0xff]; \
|
||||
t += keystruct->s[3][(x) & 0xff];
|
||||
#define swap(r,l,t) t = l; l = r; r = t;
|
||||
#define ITERATION(l,r,t,pval) l ^= keystruct->p[pval]; F(l,t); r^= t; swap(r,l,t);
|
||||
|
||||
/**************************** VARIABLES *****************************/
|
||||
static const WORD p_perm[18] = {
|
||||
0x243F6A88,0x85A308D3,0x13198A2E,0x03707344,0xA4093822,0x299F31D0,0x082EFA98,
|
||||
0xEC4E6C89,0x452821E6,0x38D01377,0xBE5466CF,0x34E90C6C,0xC0AC29B7,0xC97C50DD,
|
||||
0x3F84D5B5,0xB5470917,0x9216D5D9,0x8979FB1B
|
||||
};
|
||||
|
||||
static const WORD s_perm[4][256] = { {
|
||||
0xD1310BA6,0x98DFB5AC,0x2FFD72DB,0xD01ADFB7,0xB8E1AFED,0x6A267E96,0xBA7C9045,0xF12C7F99,
|
||||
0x24A19947,0xB3916CF7,0x0801F2E2,0x858EFC16,0x636920D8,0x71574E69,0xA458FEA3,0xF4933D7E,
|
||||
0x0D95748F,0x728EB658,0x718BCD58,0x82154AEE,0x7B54A41D,0xC25A59B5,0x9C30D539,0x2AF26013,
|
||||
0xC5D1B023,0x286085F0,0xCA417918,0xB8DB38EF,0x8E79DCB0,0x603A180E,0x6C9E0E8B,0xB01E8A3E,
|
||||
0xD71577C1,0xBD314B27,0x78AF2FDA,0x55605C60,0xE65525F3,0xAA55AB94,0x57489862,0x63E81440,
|
||||
0x55CA396A,0x2AAB10B6,0xB4CC5C34,0x1141E8CE,0xA15486AF,0x7C72E993,0xB3EE1411,0x636FBC2A,
|
||||
0x2BA9C55D,0x741831F6,0xCE5C3E16,0x9B87931E,0xAFD6BA33,0x6C24CF5C,0x7A325381,0x28958677,
|
||||
0x3B8F4898,0x6B4BB9AF,0xC4BFE81B,0x66282193,0x61D809CC,0xFB21A991,0x487CAC60,0x5DEC8032,
|
||||
0xEF845D5D,0xE98575B1,0xDC262302,0xEB651B88,0x23893E81,0xD396ACC5,0x0F6D6FF3,0x83F44239,
|
||||
0x2E0B4482,0xA4842004,0x69C8F04A,0x9E1F9B5E,0x21C66842,0xF6E96C9A,0x670C9C61,0xABD388F0,
|
||||
0x6A51A0D2,0xD8542F68,0x960FA728,0xAB5133A3,0x6EEF0B6C,0x137A3BE4,0xBA3BF050,0x7EFB2A98,
|
||||
0xA1F1651D,0x39AF0176,0x66CA593E,0x82430E88,0x8CEE8619,0x456F9FB4,0x7D84A5C3,0x3B8B5EBE,
|
||||
0xE06F75D8,0x85C12073,0x401A449F,0x56C16AA6,0x4ED3AA62,0x363F7706,0x1BFEDF72,0x429B023D,
|
||||
0x37D0D724,0xD00A1248,0xDB0FEAD3,0x49F1C09B,0x075372C9,0x80991B7B,0x25D479D8,0xF6E8DEF7,
|
||||
0xE3FE501A,0xB6794C3B,0x976CE0BD,0x04C006BA,0xC1A94FB6,0x409F60C4,0x5E5C9EC2,0x196A2463,
|
||||
0x68FB6FAF,0x3E6C53B5,0x1339B2EB,0x3B52EC6F,0x6DFC511F,0x9B30952C,0xCC814544,0xAF5EBD09,
|
||||
0xBEE3D004,0xDE334AFD,0x660F2807,0x192E4BB3,0xC0CBA857,0x45C8740F,0xD20B5F39,0xB9D3FBDB,
|
||||
0x5579C0BD,0x1A60320A,0xD6A100C6,0x402C7279,0x679F25FE,0xFB1FA3CC,0x8EA5E9F8,0xDB3222F8,
|
||||
0x3C7516DF,0xFD616B15,0x2F501EC8,0xAD0552AB,0x323DB5FA,0xFD238760,0x53317B48,0x3E00DF82,
|
||||
0x9E5C57BB,0xCA6F8CA0,0x1A87562E,0xDF1769DB,0xD542A8F6,0x287EFFC3,0xAC6732C6,0x8C4F5573,
|
||||
0x695B27B0,0xBBCA58C8,0xE1FFA35D,0xB8F011A0,0x10FA3D98,0xFD2183B8,0x4AFCB56C,0x2DD1D35B,
|
||||
0x9A53E479,0xB6F84565,0xD28E49BC,0x4BFB9790,0xE1DDF2DA,0xA4CB7E33,0x62FB1341,0xCEE4C6E8,
|
||||
0xEF20CADA,0x36774C01,0xD07E9EFE,0x2BF11FB4,0x95DBDA4D,0xAE909198,0xEAAD8E71,0x6B93D5A0,
|
||||
0xD08ED1D0,0xAFC725E0,0x8E3C5B2F,0x8E7594B7,0x8FF6E2FB,0xF2122B64,0x8888B812,0x900DF01C,
|
||||
0x4FAD5EA0,0x688FC31C,0xD1CFF191,0xB3A8C1AD,0x2F2F2218,0xBE0E1777,0xEA752DFE,0x8B021FA1,
|
||||
0xE5A0CC0F,0xB56F74E8,0x18ACF3D6,0xCE89E299,0xB4A84FE0,0xFD13E0B7,0x7CC43B81,0xD2ADA8D9,
|
||||
0x165FA266,0x80957705,0x93CC7314,0x211A1477,0xE6AD2065,0x77B5FA86,0xC75442F5,0xFB9D35CF,
|
||||
0xEBCDAF0C,0x7B3E89A0,0xD6411BD3,0xAE1E7E49,0x00250E2D,0x2071B35E,0x226800BB,0x57B8E0AF,
|
||||
0x2464369B,0xF009B91E,0x5563911D,0x59DFA6AA,0x78C14389,0xD95A537F,0x207D5BA2,0x02E5B9C5,
|
||||
0x83260376,0x6295CFA9,0x11C81968,0x4E734A41,0xB3472DCA,0x7B14A94A,0x1B510052,0x9A532915,
|
||||
0xD60F573F,0xBC9BC6E4,0x2B60A476,0x81E67400,0x08BA6FB5,0x571BE91F,0xF296EC6B,0x2A0DD915,
|
||||
0xB6636521,0xE7B9F9B6,0xFF34052E,0xC5855664,0x53B02D5D,0xA99F8FA1,0x08BA4799,0x6E85076A
|
||||
},{
|
||||
0x4B7A70E9,0xB5B32944,0xDB75092E,0xC4192623,0xAD6EA6B0,0x49A7DF7D,0x9CEE60B8,0x8FEDB266,
|
||||
0xECAA8C71,0x699A17FF,0x5664526C,0xC2B19EE1,0x193602A5,0x75094C29,0xA0591340,0xE4183A3E,
|
||||
0x3F54989A,0x5B429D65,0x6B8FE4D6,0x99F73FD6,0xA1D29C07,0xEFE830F5,0x4D2D38E6,0xF0255DC1,
|
||||
0x4CDD2086,0x8470EB26,0x6382E9C6,0x021ECC5E,0x09686B3F,0x3EBAEFC9,0x3C971814,0x6B6A70A1,
|
||||
0x687F3584,0x52A0E286,0xB79C5305,0xAA500737,0x3E07841C,0x7FDEAE5C,0x8E7D44EC,0x5716F2B8,
|
||||
0xB03ADA37,0xF0500C0D,0xF01C1F04,0x0200B3FF,0xAE0CF51A,0x3CB574B2,0x25837A58,0xDC0921BD,
|
||||
0xD19113F9,0x7CA92FF6,0x94324773,0x22F54701,0x3AE5E581,0x37C2DADC,0xC8B57634,0x9AF3DDA7,
|
||||
0xA9446146,0x0FD0030E,0xECC8C73E,0xA4751E41,0xE238CD99,0x3BEA0E2F,0x3280BBA1,0x183EB331,
|
||||
0x4E548B38,0x4F6DB908,0x6F420D03,0xF60A04BF,0x2CB81290,0x24977C79,0x5679B072,0xBCAF89AF,
|
||||
0xDE9A771F,0xD9930810,0xB38BAE12,0xDCCF3F2E,0x5512721F,0x2E6B7124,0x501ADDE6,0x9F84CD87,
|
||||
0x7A584718,0x7408DA17,0xBC9F9ABC,0xE94B7D8C,0xEC7AEC3A,0xDB851DFA,0x63094366,0xC464C3D2,
|
||||
0xEF1C1847,0x3215D908,0xDD433B37,0x24C2BA16,0x12A14D43,0x2A65C451,0x50940002,0x133AE4DD,
|
||||
0x71DFF89E,0x10314E55,0x81AC77D6,0x5F11199B,0x043556F1,0xD7A3C76B,0x3C11183B,0x5924A509,
|
||||
0xF28FE6ED,0x97F1FBFA,0x9EBABF2C,0x1E153C6E,0x86E34570,0xEAE96FB1,0x860E5E0A,0x5A3E2AB3,
|
||||
0x771FE71C,0x4E3D06FA,0x2965DCB9,0x99E71D0F,0x803E89D6,0x5266C825,0x2E4CC978,0x9C10B36A,
|
||||
0xC6150EBA,0x94E2EA78,0xA5FC3C53,0x1E0A2DF4,0xF2F74EA7,0x361D2B3D,0x1939260F,0x19C27960,
|
||||
0x5223A708,0xF71312B6,0xEBADFE6E,0xEAC31F66,0xE3BC4595,0xA67BC883,0xB17F37D1,0x018CFF28,
|
||||
0xC332DDEF,0xBE6C5AA5,0x65582185,0x68AB9802,0xEECEA50F,0xDB2F953B,0x2AEF7DAD,0x5B6E2F84,
|
||||
0x1521B628,0x29076170,0xECDD4775,0x619F1510,0x13CCA830,0xEB61BD96,0x0334FE1E,0xAA0363CF,
|
||||
0xB5735C90,0x4C70A239,0xD59E9E0B,0xCBAADE14,0xEECC86BC,0x60622CA7,0x9CAB5CAB,0xB2F3846E,
|
||||
0x648B1EAF,0x19BDF0CA,0xA02369B9,0x655ABB50,0x40685A32,0x3C2AB4B3,0x319EE9D5,0xC021B8F7,
|
||||
0x9B540B19,0x875FA099,0x95F7997E,0x623D7DA8,0xF837889A,0x97E32D77,0x11ED935F,0x16681281,
|
||||
0x0E358829,0xC7E61FD6,0x96DEDFA1,0x7858BA99,0x57F584A5,0x1B227263,0x9B83C3FF,0x1AC24696,
|
||||
0xCDB30AEB,0x532E3054,0x8FD948E4,0x6DBC3128,0x58EBF2EF,0x34C6FFEA,0xFE28ED61,0xEE7C3C73,
|
||||
0x5D4A14D9,0xE864B7E3,0x42105D14,0x203E13E0,0x45EEE2B6,0xA3AAABEA,0xDB6C4F15,0xFACB4FD0,
|
||||
0xC742F442,0xEF6ABBB5,0x654F3B1D,0x41CD2105,0xD81E799E,0x86854DC7,0xE44B476A,0x3D816250,
|
||||
0xCF62A1F2,0x5B8D2646,0xFC8883A0,0xC1C7B6A3,0x7F1524C3,0x69CB7492,0x47848A0B,0x5692B285,
|
||||
0x095BBF00,0xAD19489D,0x1462B174,0x23820E00,0x58428D2A,0x0C55F5EA,0x1DADF43E,0x233F7061,
|
||||
0x3372F092,0x8D937E41,0xD65FECF1,0x6C223BDB,0x7CDE3759,0xCBEE7460,0x4085F2A7,0xCE77326E,
|
||||
0xA6078084,0x19F8509E,0xE8EFD855,0x61D99735,0xA969A7AA,0xC50C06C2,0x5A04ABFC,0x800BCADC,
|
||||
0x9E447A2E,0xC3453484,0xFDD56705,0x0E1E9EC9,0xDB73DBD3,0x105588CD,0x675FDA79,0xE3674340,
|
||||
0xC5C43465,0x713E38D8,0x3D28F89E,0xF16DFF20,0x153E21E7,0x8FB03D4A,0xE6E39F2B,0xDB83ADF7
|
||||
},{
|
||||
0xE93D5A68,0x948140F7,0xF64C261C,0x94692934,0x411520F7,0x7602D4F7,0xBCF46B2E,0xD4A20068,
|
||||
0xD4082471,0x3320F46A,0x43B7D4B7,0x500061AF,0x1E39F62E,0x97244546,0x14214F74,0xBF8B8840,
|
||||
0x4D95FC1D,0x96B591AF,0x70F4DDD3,0x66A02F45,0xBFBC09EC,0x03BD9785,0x7FAC6DD0,0x31CB8504,
|
||||
0x96EB27B3,0x55FD3941,0xDA2547E6,0xABCA0A9A,0x28507825,0x530429F4,0x0A2C86DA,0xE9B66DFB,
|
||||
0x68DC1462,0xD7486900,0x680EC0A4,0x27A18DEE,0x4F3FFEA2,0xE887AD8C,0xB58CE006,0x7AF4D6B6,
|
||||
0xAACE1E7C,0xD3375FEC,0xCE78A399,0x406B2A42,0x20FE9E35,0xD9F385B9,0xEE39D7AB,0x3B124E8B,
|
||||
0x1DC9FAF7,0x4B6D1856,0x26A36631,0xEAE397B2,0x3A6EFA74,0xDD5B4332,0x6841E7F7,0xCA7820FB,
|
||||
0xFB0AF54E,0xD8FEB397,0x454056AC,0xBA489527,0x55533A3A,0x20838D87,0xFE6BA9B7,0xD096954B,
|
||||
0x55A867BC,0xA1159A58,0xCCA92963,0x99E1DB33,0xA62A4A56,0x3F3125F9,0x5EF47E1C,0x9029317C,
|
||||
0xFDF8E802,0x04272F70,0x80BB155C,0x05282CE3,0x95C11548,0xE4C66D22,0x48C1133F,0xC70F86DC,
|
||||
0x07F9C9EE,0x41041F0F,0x404779A4,0x5D886E17,0x325F51EB,0xD59BC0D1,0xF2BCC18F,0x41113564,
|
||||
0x257B7834,0x602A9C60,0xDFF8E8A3,0x1F636C1B,0x0E12B4C2,0x02E1329E,0xAF664FD1,0xCAD18115,
|
||||
0x6B2395E0,0x333E92E1,0x3B240B62,0xEEBEB922,0x85B2A20E,0xE6BA0D99,0xDE720C8C,0x2DA2F728,
|
||||
0xD0127845,0x95B794FD,0x647D0862,0xE7CCF5F0,0x5449A36F,0x877D48FA,0xC39DFD27,0xF33E8D1E,
|
||||
0x0A476341,0x992EFF74,0x3A6F6EAB,0xF4F8FD37,0xA812DC60,0xA1EBDDF8,0x991BE14C,0xDB6E6B0D,
|
||||
0xC67B5510,0x6D672C37,0x2765D43B,0xDCD0E804,0xF1290DC7,0xCC00FFA3,0xB5390F92,0x690FED0B,
|
||||
0x667B9FFB,0xCEDB7D9C,0xA091CF0B,0xD9155EA3,0xBB132F88,0x515BAD24,0x7B9479BF,0x763BD6EB,
|
||||
0x37392EB3,0xCC115979,0x8026E297,0xF42E312D,0x6842ADA7,0xC66A2B3B,0x12754CCC,0x782EF11C,
|
||||
0x6A124237,0xB79251E7,0x06A1BBE6,0x4BFB6350,0x1A6B1018,0x11CAEDFA,0x3D25BDD8,0xE2E1C3C9,
|
||||
0x44421659,0x0A121386,0xD90CEC6E,0xD5ABEA2A,0x64AF674E,0xDA86A85F,0xBEBFE988,0x64E4C3FE,
|
||||
0x9DBC8057,0xF0F7C086,0x60787BF8,0x6003604D,0xD1FD8346,0xF6381FB0,0x7745AE04,0xD736FCCC,
|
||||
0x83426B33,0xF01EAB71,0xB0804187,0x3C005E5F,0x77A057BE,0xBDE8AE24,0x55464299,0xBF582E61,
|
||||
0x4E58F48F,0xF2DDFDA2,0xF474EF38,0x8789BDC2,0x5366F9C3,0xC8B38E74,0xB475F255,0x46FCD9B9,
|
||||
0x7AEB2661,0x8B1DDF84,0x846A0E79,0x915F95E2,0x466E598E,0x20B45770,0x8CD55591,0xC902DE4C,
|
||||
0xB90BACE1,0xBB8205D0,0x11A86248,0x7574A99E,0xB77F19B6,0xE0A9DC09,0x662D09A1,0xC4324633,
|
||||
0xE85A1F02,0x09F0BE8C,0x4A99A025,0x1D6EFE10,0x1AB93D1D,0x0BA5A4DF,0xA186F20F,0x2868F169,
|
||||
0xDCB7DA83,0x573906FE,0xA1E2CE9B,0x4FCD7F52,0x50115E01,0xA70683FA,0xA002B5C4,0x0DE6D027,
|
||||
0x9AF88C27,0x773F8641,0xC3604C06,0x61A806B5,0xF0177A28,0xC0F586E0,0x006058AA,0x30DC7D62,
|
||||
0x11E69ED7,0x2338EA63,0x53C2DD94,0xC2C21634,0xBBCBEE56,0x90BCB6DE,0xEBFC7DA1,0xCE591D76,
|
||||
0x6F05E409,0x4B7C0188,0x39720A3D,0x7C927C24,0x86E3725F,0x724D9DB9,0x1AC15BB4,0xD39EB8FC,
|
||||
0xED545578,0x08FCA5B5,0xD83D7CD3,0x4DAD0FC4,0x1E50EF5E,0xB161E6F8,0xA28514D9,0x6C51133C,
|
||||
0x6FD5C7E7,0x56E14EC4,0x362ABFCE,0xDDC6C837,0xD79A3234,0x92638212,0x670EFA8E,0x406000E0
|
||||
},{
|
||||
0x3A39CE37,0xD3FAF5CF,0xABC27737,0x5AC52D1B,0x5CB0679E,0x4FA33742,0xD3822740,0x99BC9BBE,
|
||||
0xD5118E9D,0xBF0F7315,0xD62D1C7E,0xC700C47B,0xB78C1B6B,0x21A19045,0xB26EB1BE,0x6A366EB4,
|
||||
0x5748AB2F,0xBC946E79,0xC6A376D2,0x6549C2C8,0x530FF8EE,0x468DDE7D,0xD5730A1D,0x4CD04DC6,
|
||||
0x2939BBDB,0xA9BA4650,0xAC9526E8,0xBE5EE304,0xA1FAD5F0,0x6A2D519A,0x63EF8CE2,0x9A86EE22,
|
||||
0xC089C2B8,0x43242EF6,0xA51E03AA,0x9CF2D0A4,0x83C061BA,0x9BE96A4D,0x8FE51550,0xBA645BD6,
|
||||
0x2826A2F9,0xA73A3AE1,0x4BA99586,0xEF5562E9,0xC72FEFD3,0xF752F7DA,0x3F046F69,0x77FA0A59,
|
||||
0x80E4A915,0x87B08601,0x9B09E6AD,0x3B3EE593,0xE990FD5A,0x9E34D797,0x2CF0B7D9,0x022B8B51,
|
||||
0x96D5AC3A,0x017DA67D,0xD1CF3ED6,0x7C7D2D28,0x1F9F25CF,0xADF2B89B,0x5AD6B472,0x5A88F54C,
|
||||
0xE029AC71,0xE019A5E6,0x47B0ACFD,0xED93FA9B,0xE8D3C48D,0x283B57CC,0xF8D56629,0x79132E28,
|
||||
0x785F0191,0xED756055,0xF7960E44,0xE3D35E8C,0x15056DD4,0x88F46DBA,0x03A16125,0x0564F0BD,
|
||||
0xC3EB9E15,0x3C9057A2,0x97271AEC,0xA93A072A,0x1B3F6D9B,0x1E6321F5,0xF59C66FB,0x26DCF319,
|
||||
0x7533D928,0xB155FDF5,0x03563482,0x8ABA3CBB,0x28517711,0xC20AD9F8,0xABCC5167,0xCCAD925F,
|
||||
0x4DE81751,0x3830DC8E,0x379D5862,0x9320F991,0xEA7A90C2,0xFB3E7BCE,0x5121CE64,0x774FBE32,
|
||||
0xA8B6E37E,0xC3293D46,0x48DE5369,0x6413E680,0xA2AE0810,0xDD6DB224,0x69852DFD,0x09072166,
|
||||
0xB39A460A,0x6445C0DD,0x586CDECF,0x1C20C8AE,0x5BBEF7DD,0x1B588D40,0xCCD2017F,0x6BB4E3BB,
|
||||
0xDDA26A7E,0x3A59FF45,0x3E350A44,0xBCB4CDD5,0x72EACEA8,0xFA6484BB,0x8D6612AE,0xBF3C6F47,
|
||||
0xD29BE463,0x542F5D9E,0xAEC2771B,0xF64E6370,0x740E0D8D,0xE75B1357,0xF8721671,0xAF537D5D,
|
||||
0x4040CB08,0x4EB4E2CC,0x34D2466A,0x0115AF84,0xE1B00428,0x95983A1D,0x06B89FB4,0xCE6EA048,
|
||||
0x6F3F3B82,0x3520AB82,0x011A1D4B,0x277227F8,0x611560B1,0xE7933FDC,0xBB3A792B,0x344525BD,
|
||||
0xA08839E1,0x51CE794B,0x2F32C9B7,0xA01FBAC9,0xE01CC87E,0xBCC7D1F6,0xCF0111C3,0xA1E8AAC7,
|
||||
0x1A908749,0xD44FBD9A,0xD0DADECB,0xD50ADA38,0x0339C32A,0xC6913667,0x8DF9317C,0xE0B12B4F,
|
||||
0xF79E59B7,0x43F5BB3A,0xF2D519FF,0x27D9459C,0xBF97222C,0x15E6FC2A,0x0F91FC71,0x9B941525,
|
||||
0xFAE59361,0xCEB69CEB,0xC2A86459,0x12BAA8D1,0xB6C1075E,0xE3056A0C,0x10D25065,0xCB03A442,
|
||||
0xE0EC6E0E,0x1698DB3B,0x4C98A0BE,0x3278E964,0x9F1F9532,0xE0D392DF,0xD3A0342B,0x8971F21E,
|
||||
0x1B0A7441,0x4BA3348C,0xC5BE7120,0xC37632D8,0xDF359F8D,0x9B992F2E,0xE60B6F47,0x0FE3F11D,
|
||||
0xE54CDA54,0x1EDAD891,0xCE6279CF,0xCD3E7E6F,0x1618B166,0xFD2C1D05,0x848FD2C5,0xF6FB2299,
|
||||
0xF523F357,0xA6327623,0x93A83531,0x56CCCD02,0xACF08162,0x5A75EBB5,0x6E163697,0x88D273CC,
|
||||
0xDE966292,0x81B949D0,0x4C50901B,0x71C65614,0xE6C6C7BD,0x327A140A,0x45E1D006,0xC3F27B9A,
|
||||
0xC9AA53FD,0x62A80F00,0xBB25BFE2,0x35BDD2F6,0x71126905,0xB2040222,0xB6CBCF7C,0xCD769C2B,
|
||||
0x53113EC0,0x1640E3D3,0x38ABBD60,0x2547ADF0,0xBA38209C,0xF746CE76,0x77AFA1C5,0x20756060,
|
||||
0x85CBFE4E,0x8AE88DD8,0x7AAAF9B0,0x4CF9AA7E,0x1948C25C,0x02FB8A8C,0x01C36AE4,0xD6EBE1F9,
|
||||
0x90D4F869,0xA65CDEA0,0x3F09252D,0xC208E69F,0xB74E6132,0xCE77E25B,0x578FDFE3,0x3AC372E6
|
||||
} };
|
||||
|
||||
/*********************** FUNCTION DEFINITIONS ***********************/
|
||||
void blowfish_encrypt(const BYTE in[], BYTE out[], const BLOWFISH_KEY *keystruct)
|
||||
{
|
||||
WORD l,r,t; //,i;
|
||||
|
||||
l = (in[0] << 24) | (in[1] << 16) | (in[2] << 8) | (in[3]);
|
||||
r = (in[4] << 24) | (in[5] << 16) | (in[6] << 8) | (in[7]);
|
||||
|
||||
ITERATION(l,r,t,0);
|
||||
ITERATION(l,r,t,1);
|
||||
ITERATION(l,r,t,2);
|
||||
ITERATION(l,r,t,3);
|
||||
ITERATION(l,r,t,4);
|
||||
ITERATION(l,r,t,5);
|
||||
ITERATION(l,r,t,6);
|
||||
ITERATION(l,r,t,7);
|
||||
ITERATION(l,r,t,8);
|
||||
ITERATION(l,r,t,9);
|
||||
ITERATION(l,r,t,10);
|
||||
ITERATION(l,r,t,11);
|
||||
ITERATION(l,r,t,12);
|
||||
ITERATION(l,r,t,13);
|
||||
ITERATION(l,r,t,14);
|
||||
l ^= keystruct->p[15]; F(l,t); r^= t; //Last iteration has no swap()
|
||||
r ^= keystruct->p[16];
|
||||
l ^= keystruct->p[17];
|
||||
|
||||
out[0] = l >> 24;
|
||||
out[1] = l >> 16;
|
||||
out[2] = l >> 8;
|
||||
out[3] = l;
|
||||
out[4] = r >> 24;
|
||||
out[5] = r >> 16;
|
||||
out[6] = r >> 8;
|
||||
out[7] = r;
|
||||
}
|
||||
|
||||
void blowfish_decrypt(const BYTE in[], BYTE out[], const BLOWFISH_KEY *keystruct)
|
||||
{
|
||||
WORD l,r,t; //,i;
|
||||
|
||||
l = (in[0] << 24) | (in[1] << 16) | (in[2] << 8) | (in[3]);
|
||||
r = (in[4] << 24) | (in[5] << 16) | (in[6] << 8) | (in[7]);
|
||||
|
||||
ITERATION(l,r,t,17);
|
||||
ITERATION(l,r,t,16);
|
||||
ITERATION(l,r,t,15);
|
||||
ITERATION(l,r,t,14);
|
||||
ITERATION(l,r,t,13);
|
||||
ITERATION(l,r,t,12);
|
||||
ITERATION(l,r,t,11);
|
||||
ITERATION(l,r,t,10);
|
||||
ITERATION(l,r,t,9);
|
||||
ITERATION(l,r,t,8);
|
||||
ITERATION(l,r,t,7);
|
||||
ITERATION(l,r,t,6);
|
||||
ITERATION(l,r,t,5);
|
||||
ITERATION(l,r,t,4);
|
||||
ITERATION(l,r,t,3);
|
||||
l ^= keystruct->p[2]; F(l,t); r^= t; //Last iteration has no swap()
|
||||
r ^= keystruct->p[1];
|
||||
l ^= keystruct->p[0];
|
||||
|
||||
out[0] = l >> 24;
|
||||
out[1] = l >> 16;
|
||||
out[2] = l >> 8;
|
||||
out[3] = l;
|
||||
out[4] = r >> 24;
|
||||
out[5] = r >> 16;
|
||||
out[6] = r >> 8;
|
||||
out[7] = r;
|
||||
}
|
||||
|
||||
void blowfish_key_setup(const BYTE user_key[], BLOWFISH_KEY *keystruct, size_t len)
|
||||
{
|
||||
BYTE block[8];
|
||||
int idx,idx2;
|
||||
|
||||
// Copy over the constant init array vals (so the originals aren't destroyed).
|
||||
memcpy(keystruct->p,p_perm,sizeof(WORD) * 18);
|
||||
memcpy(keystruct->s,s_perm,sizeof(WORD) * 1024);
|
||||
|
||||
// Combine the key with the P box. Assume key is standard 448 bits (56 bytes) or less.
|
||||
for (idx = 0, idx2 = 0; idx < 18; ++idx, idx2 += 4)
|
||||
keystruct->p[idx] ^= (user_key[idx2 % len] << 24) | (user_key[(idx2+1) % len] << 16)
|
||||
| (user_key[(idx2+2) % len] << 8) | (user_key[(idx2+3) % len]);
|
||||
// Re-calculate the P box.
|
||||
memset(block, 0, 8);
|
||||
for (idx = 0; idx < 18; idx += 2) {
|
||||
blowfish_encrypt(block,block,keystruct);
|
||||
keystruct->p[idx] = (block[0] << 24) | (block[1] << 16) | (block[2] << 8) | block[3];
|
||||
keystruct->p[idx+1]=(block[4] << 24) | (block[5] << 16) | (block[6] << 8) | block[7];
|
||||
}
|
||||
// Recalculate the S-boxes.
|
||||
for (idx = 0; idx < 4; ++idx) {
|
||||
for (idx2 = 0; idx2 < 256; idx2 += 2) {
|
||||
blowfish_encrypt(block,block,keystruct);
|
||||
keystruct->s[idx][idx2] = (block[0] << 24) | (block[1] << 16) |
|
||||
(block[2] << 8) | block[3];
|
||||
keystruct->s[idx][idx2+1] = (block[4] << 24) | (block[5] << 16) |
|
||||
(block[6] << 8) | block[7];
|
||||
}
|
||||
}
|
||||
}
|
32
lib/crypto-algorithms/blowfish.h
Normal file
32
lib/crypto-algorithms/blowfish.h
Normal file
|
@ -0,0 +1,32 @@
|
|||
/*********************************************************************
|
||||
* Filename: blowfish.h
|
||||
* Author: Brad Conte (brad AT bradconte.com)
|
||||
* Copyright:
|
||||
* Disclaimer: This code is presented "as is" without any guarantees.
|
||||
* Details: Defines the API for the corresponding Blowfish implementation.
|
||||
*********************************************************************/
|
||||
|
||||
#ifndef BLOWFISH_H
|
||||
#define BLOWFISH_H
|
||||
|
||||
/*************************** HEADER FILES ***************************/
|
||||
#include <stddef.h>
|
||||
|
||||
/****************************** MACROS ******************************/
|
||||
#define BLOWFISH_BLOCK_SIZE 8 // Blowfish operates on 8 bytes at a time
|
||||
|
||||
/**************************** DATA TYPES ****************************/
|
||||
typedef unsigned char BYTE; // 8-bit byte
|
||||
typedef unsigned int WORD; // 32-bit word, change to "long" for 16-bit machines
|
||||
|
||||
typedef struct {
|
||||
WORD p[18];
|
||||
WORD s[4][256];
|
||||
} BLOWFISH_KEY;
|
||||
|
||||
/*********************** FUNCTION DECLARATIONS **********************/
|
||||
void blowfish_key_setup(const BYTE user_key[], BLOWFISH_KEY *keystruct, size_t len);
|
||||
void blowfish_encrypt(const BYTE in[], BYTE out[], const BLOWFISH_KEY *keystruct);
|
||||
void blowfish_decrypt(const BYTE in[], BYTE out[], const BLOWFISH_KEY *keystruct);
|
||||
|
||||
#endif // BLOWFISH_H
|
68
lib/crypto-algorithms/blowfish_test.c
Normal file
68
lib/crypto-algorithms/blowfish_test.c
Normal file
|
@ -0,0 +1,68 @@
|
|||
/*********************************************************************
|
||||
* Filename: blowfish_test.c
|
||||
* Author: Brad Conte (brad AT bradconte.com)
|
||||
* Copyright:
|
||||
* Disclaimer: This code is presented "as is" without any guarantees.
|
||||
* Details: Performs known-answer tests on the corresponding Blowfish
|
||||
implementation. These tests do not encompass the full
|
||||
range of available test vectors, however, if the tests
|
||||
pass it is very, very likely that the code is correct
|
||||
and was compiled properly. This code also serves as
|
||||
example usage of the functions.
|
||||
*********************************************************************/
|
||||
|
||||
/*************************** HEADER FILES ***************************/
|
||||
#include <stdio.h>
|
||||
#include <memory.h>
|
||||
#include "blowfish.h"
|
||||
|
||||
/*********************** FUNCTION DEFINITIONS ***********************/
|
||||
int blowfish_test()
|
||||
{
|
||||
BYTE key1[8] = {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};
|
||||
BYTE key2[8] = {0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff};
|
||||
BYTE key3[24] = {0xF0,0xE1,0xD2,0xC3,0xB4,0xA5,0x96,0x87,
|
||||
0x78,0x69,0x5A,0x4B,0x3C,0x2D,0x1E,0x0F,
|
||||
0x00,0x11,0x22,0x33,0x44,0x55,0x66,0x77};
|
||||
BYTE p1[BLOWFISH_BLOCK_SIZE] = {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};
|
||||
BYTE p2[BLOWFISH_BLOCK_SIZE] = {0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff};
|
||||
BYTE p3[BLOWFISH_BLOCK_SIZE] = {0xFE,0xDC,0xBA,0x98,0x76,0x54,0x32,0x10};
|
||||
|
||||
BYTE c1[BLOWFISH_BLOCK_SIZE] = {0x4e,0xf9,0x97,0x45,0x61,0x98,0xdd,0x78};
|
||||
BYTE c2[BLOWFISH_BLOCK_SIZE] = {0x51,0x86,0x6f,0xd5,0xb8,0x5e,0xcb,0x8a};
|
||||
BYTE c3[BLOWFISH_BLOCK_SIZE] = {0x05,0x04,0x4b,0x62,0xfa,0x52,0xd0,0x80};
|
||||
|
||||
BYTE enc_buf[BLOWFISH_BLOCK_SIZE];
|
||||
BLOWFISH_KEY key;
|
||||
int pass = 1;
|
||||
|
||||
// Test vector 1.
|
||||
blowfish_key_setup(key1, &key, BLOWFISH_BLOCK_SIZE);
|
||||
blowfish_encrypt(p1, enc_buf, &key);
|
||||
pass = pass && !memcmp(c1, enc_buf, BLOWFISH_BLOCK_SIZE);
|
||||
blowfish_decrypt(c1, enc_buf, &key);
|
||||
pass = pass && !memcmp(p1, enc_buf, BLOWFISH_BLOCK_SIZE);
|
||||
|
||||
// Test vector 2.
|
||||
blowfish_key_setup(key2, &key, BLOWFISH_BLOCK_SIZE);
|
||||
blowfish_encrypt(p2, enc_buf, &key);
|
||||
pass = pass && !memcmp(c2, enc_buf, BLOWFISH_BLOCK_SIZE);
|
||||
blowfish_decrypt(c2, enc_buf, &key);
|
||||
pass = pass && !memcmp(p2, enc_buf, BLOWFISH_BLOCK_SIZE);
|
||||
|
||||
// Test vector 3.
|
||||
blowfish_key_setup(key3, &key, 24);
|
||||
blowfish_encrypt(p3, enc_buf, &key);
|
||||
pass = pass && !memcmp(c3, enc_buf, BLOWFISH_BLOCK_SIZE);
|
||||
blowfish_decrypt(c3, enc_buf, &key);
|
||||
pass = pass && !memcmp(p3, enc_buf, BLOWFISH_BLOCK_SIZE);
|
||||
|
||||
return(pass);
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
printf("Blowfish tests: %s\n", blowfish_test() ? "SUCCEEDED" : "FAILED");
|
||||
|
||||
return(0);
|
||||
}
|
269
lib/crypto-algorithms/des.c
Normal file
269
lib/crypto-algorithms/des.c
Normal file
|
@ -0,0 +1,269 @@
|
|||
/*********************************************************************
|
||||
* Filename: des.c
|
||||
* Author: Brad Conte (brad AT radconte.com)
|
||||
* Copyright:
|
||||
* Disclaimer: This code is presented "as is" without any guarantees.
|
||||
* Details: Implementation of the DES encryption algorithm.
|
||||
Modes of operation (such as CBC) are not included.
|
||||
The formal NIST algorithm specification can be found here:
|
||||
* http://csrc.nist.gov/publications/fips/fips46-3/fips46-3.pdf
|
||||
*********************************************************************/
|
||||
|
||||
/*************************** HEADER FILES ***************************/
|
||||
#include <stdlib.h>
|
||||
#include <memory.h>
|
||||
#include "des.h"
|
||||
|
||||
/****************************** MACROS ******************************/
|
||||
// Obtain bit "b" from the left and shift it "c" places from the right
|
||||
#define BITNUM(a,b,c) (((a[(b)/8] >> (7 - (b%8))) & 0x01) << (c))
|
||||
#define BITNUMINTR(a,b,c) ((((a) >> (31 - (b))) & 0x00000001) << (c))
|
||||
#define BITNUMINTL(a,b,c) ((((a) << (b)) & 0x80000000) >> (c))
|
||||
|
||||
// This macro converts a 6 bit block with the S-Box row defined as the first and last
|
||||
// bits to a 6 bit block with the row defined by the first two bits.
|
||||
#define SBOXBIT(a) (((a) & 0x20) | (((a) & 0x1f) >> 1) | (((a) & 0x01) << 4))
|
||||
|
||||
/**************************** VARIABLES *****************************/
|
||||
static const BYTE sbox1[64] = {
|
||||
14, 4, 13, 1, 2, 15, 11, 8, 3, 10, 6, 12, 5, 9, 0, 7,
|
||||
0, 15, 7, 4, 14, 2, 13, 1, 10, 6, 12, 11, 9, 5, 3, 8,
|
||||
4, 1, 14, 8, 13, 6, 2, 11, 15, 12, 9, 7, 3, 10, 5, 0,
|
||||
15, 12, 8, 2, 4, 9, 1, 7, 5, 11, 3, 14, 10, 0, 6, 13
|
||||
};
|
||||
static const BYTE sbox2[64] = {
|
||||
15, 1, 8, 14, 6, 11, 3, 4, 9, 7, 2, 13, 12, 0, 5, 10,
|
||||
3, 13, 4, 7, 15, 2, 8, 14, 12, 0, 1, 10, 6, 9, 11, 5,
|
||||
0, 14, 7, 11, 10, 4, 13, 1, 5, 8, 12, 6, 9, 3, 2, 15,
|
||||
13, 8, 10, 1, 3, 15, 4, 2, 11, 6, 7, 12, 0, 5, 14, 9
|
||||
};
|
||||
static const BYTE sbox3[64] = {
|
||||
10, 0, 9, 14, 6, 3, 15, 5, 1, 13, 12, 7, 11, 4, 2, 8,
|
||||
13, 7, 0, 9, 3, 4, 6, 10, 2, 8, 5, 14, 12, 11, 15, 1,
|
||||
13, 6, 4, 9, 8, 15, 3, 0, 11, 1, 2, 12, 5, 10, 14, 7,
|
||||
1, 10, 13, 0, 6, 9, 8, 7, 4, 15, 14, 3, 11, 5, 2, 12
|
||||
};
|
||||
static const BYTE sbox4[64] = {
|
||||
7, 13, 14, 3, 0, 6, 9, 10, 1, 2, 8, 5, 11, 12, 4, 15,
|
||||
13, 8, 11, 5, 6, 15, 0, 3, 4, 7, 2, 12, 1, 10, 14, 9,
|
||||
10, 6, 9, 0, 12, 11, 7, 13, 15, 1, 3, 14, 5, 2, 8, 4,
|
||||
3, 15, 0, 6, 10, 1, 13, 8, 9, 4, 5, 11, 12, 7, 2, 14
|
||||
};
|
||||
static const BYTE sbox5[64] = {
|
||||
2, 12, 4, 1, 7, 10, 11, 6, 8, 5, 3, 15, 13, 0, 14, 9,
|
||||
14, 11, 2, 12, 4, 7, 13, 1, 5, 0, 15, 10, 3, 9, 8, 6,
|
||||
4, 2, 1, 11, 10, 13, 7, 8, 15, 9, 12, 5, 6, 3, 0, 14,
|
||||
11, 8, 12, 7, 1, 14, 2, 13, 6, 15, 0, 9, 10, 4, 5, 3
|
||||
};
|
||||
static const BYTE sbox6[64] = {
|
||||
12, 1, 10, 15, 9, 2, 6, 8, 0, 13, 3, 4, 14, 7, 5, 11,
|
||||
10, 15, 4, 2, 7, 12, 9, 5, 6, 1, 13, 14, 0, 11, 3, 8,
|
||||
9, 14, 15, 5, 2, 8, 12, 3, 7, 0, 4, 10, 1, 13, 11, 6,
|
||||
4, 3, 2, 12, 9, 5, 15, 10, 11, 14, 1, 7, 6, 0, 8, 13
|
||||
};
|
||||
static const BYTE sbox7[64] = {
|
||||
4, 11, 2, 14, 15, 0, 8, 13, 3, 12, 9, 7, 5, 10, 6, 1,
|
||||
13, 0, 11, 7, 4, 9, 1, 10, 14, 3, 5, 12, 2, 15, 8, 6,
|
||||
1, 4, 11, 13, 12, 3, 7, 14, 10, 15, 6, 8, 0, 5, 9, 2,
|
||||
6, 11, 13, 8, 1, 4, 10, 7, 9, 5, 0, 15, 14, 2, 3, 12
|
||||
};
|
||||
static const BYTE sbox8[64] = {
|
||||
13, 2, 8, 4, 6, 15, 11, 1, 10, 9, 3, 14, 5, 0, 12, 7,
|
||||
1, 15, 13, 8, 10, 3, 7, 4, 12, 5, 6, 11, 0, 14, 9, 2,
|
||||
7, 11, 4, 1, 9, 12, 14, 2, 0, 6, 10, 13, 15, 3, 5, 8,
|
||||
2, 1, 14, 7, 4, 10, 8, 13, 15, 12, 9, 0, 3, 5, 6, 11
|
||||
};
|
||||
|
||||
/*********************** FUNCTION DEFINITIONS ***********************/
|
||||
// Initial (Inv)Permutation step
|
||||
void IP(WORD state[], const BYTE in[])
|
||||
{
|
||||
state[0] = BITNUM(in,57,31) | BITNUM(in,49,30) | BITNUM(in,41,29) | BITNUM(in,33,28) |
|
||||
BITNUM(in,25,27) | BITNUM(in,17,26) | BITNUM(in,9,25) | BITNUM(in,1,24) |
|
||||
BITNUM(in,59,23) | BITNUM(in,51,22) | BITNUM(in,43,21) | BITNUM(in,35,20) |
|
||||
BITNUM(in,27,19) | BITNUM(in,19,18) | BITNUM(in,11,17) | BITNUM(in,3,16) |
|
||||
BITNUM(in,61,15) | BITNUM(in,53,14) | BITNUM(in,45,13) | BITNUM(in,37,12) |
|
||||
BITNUM(in,29,11) | BITNUM(in,21,10) | BITNUM(in,13,9) | BITNUM(in,5,8) |
|
||||
BITNUM(in,63,7) | BITNUM(in,55,6) | BITNUM(in,47,5) | BITNUM(in,39,4) |
|
||||
BITNUM(in,31,3) | BITNUM(in,23,2) | BITNUM(in,15,1) | BITNUM(in,7,0);
|
||||
|
||||
state[1] = BITNUM(in,56,31) | BITNUM(in,48,30) | BITNUM(in,40,29) | BITNUM(in,32,28) |
|
||||
BITNUM(in,24,27) | BITNUM(in,16,26) | BITNUM(in,8,25) | BITNUM(in,0,24) |
|
||||
BITNUM(in,58,23) | BITNUM(in,50,22) | BITNUM(in,42,21) | BITNUM(in,34,20) |
|
||||
BITNUM(in,26,19) | BITNUM(in,18,18) | BITNUM(in,10,17) | BITNUM(in,2,16) |
|
||||
BITNUM(in,60,15) | BITNUM(in,52,14) | BITNUM(in,44,13) | BITNUM(in,36,12) |
|
||||
BITNUM(in,28,11) | BITNUM(in,20,10) | BITNUM(in,12,9) | BITNUM(in,4,8) |
|
||||
BITNUM(in,62,7) | BITNUM(in,54,6) | BITNUM(in,46,5) | BITNUM(in,38,4) |
|
||||
BITNUM(in,30,3) | BITNUM(in,22,2) | BITNUM(in,14,1) | BITNUM(in,6,0);
|
||||
}
|
||||
|
||||
void InvIP(WORD state[], BYTE in[])
|
||||
{
|
||||
in[0] = BITNUMINTR(state[1],7,7) | BITNUMINTR(state[0],7,6) | BITNUMINTR(state[1],15,5) |
|
||||
BITNUMINTR(state[0],15,4) | BITNUMINTR(state[1],23,3) | BITNUMINTR(state[0],23,2) |
|
||||
BITNUMINTR(state[1],31,1) | BITNUMINTR(state[0],31,0);
|
||||
|
||||
in[1] = BITNUMINTR(state[1],6,7) | BITNUMINTR(state[0],6,6) | BITNUMINTR(state[1],14,5) |
|
||||
BITNUMINTR(state[0],14,4) | BITNUMINTR(state[1],22,3) | BITNUMINTR(state[0],22,2) |
|
||||
BITNUMINTR(state[1],30,1) | BITNUMINTR(state[0],30,0);
|
||||
|
||||
in[2] = BITNUMINTR(state[1],5,7) | BITNUMINTR(state[0],5,6) | BITNUMINTR(state[1],13,5) |
|
||||
BITNUMINTR(state[0],13,4) | BITNUMINTR(state[1],21,3) | BITNUMINTR(state[0],21,2) |
|
||||
BITNUMINTR(state[1],29,1) | BITNUMINTR(state[0],29,0);
|
||||
|
||||
in[3] = BITNUMINTR(state[1],4,7) | BITNUMINTR(state[0],4,6) | BITNUMINTR(state[1],12,5) |
|
||||
BITNUMINTR(state[0],12,4) | BITNUMINTR(state[1],20,3) | BITNUMINTR(state[0],20,2) |
|
||||
BITNUMINTR(state[1],28,1) | BITNUMINTR(state[0],28,0);
|
||||
|
||||
in[4] = BITNUMINTR(state[1],3,7) | BITNUMINTR(state[0],3,6) | BITNUMINTR(state[1],11,5) |
|
||||
BITNUMINTR(state[0],11,4) | BITNUMINTR(state[1],19,3) | BITNUMINTR(state[0],19,2) |
|
||||
BITNUMINTR(state[1],27,1) | BITNUMINTR(state[0],27,0);
|
||||
|
||||
in[5] = BITNUMINTR(state[1],2,7) | BITNUMINTR(state[0],2,6) | BITNUMINTR(state[1],10,5) |
|
||||
BITNUMINTR(state[0],10,4) | BITNUMINTR(state[1],18,3) | BITNUMINTR(state[0],18,2) |
|
||||
BITNUMINTR(state[1],26,1) | BITNUMINTR(state[0],26,0);
|
||||
|
||||
in[6] = BITNUMINTR(state[1],1,7) | BITNUMINTR(state[0],1,6) | BITNUMINTR(state[1],9,5) |
|
||||
BITNUMINTR(state[0],9,4) | BITNUMINTR(state[1],17,3) | BITNUMINTR(state[0],17,2) |
|
||||
BITNUMINTR(state[1],25,1) | BITNUMINTR(state[0],25,0);
|
||||
|
||||
in[7] = BITNUMINTR(state[1],0,7) | BITNUMINTR(state[0],0,6) | BITNUMINTR(state[1],8,5) |
|
||||
BITNUMINTR(state[0],8,4) | BITNUMINTR(state[1],16,3) | BITNUMINTR(state[0],16,2) |
|
||||
BITNUMINTR(state[1],24,1) | BITNUMINTR(state[0],24,0);
|
||||
}
|
||||
|
||||
WORD f(WORD state, const BYTE key[])
|
||||
{
|
||||
BYTE lrgstate[6]; //,i;
|
||||
WORD t1,t2;
|
||||
|
||||
// Expantion Permutation
|
||||
t1 = BITNUMINTL(state,31,0) | ((state & 0xf0000000) >> 1) | BITNUMINTL(state,4,5) |
|
||||
BITNUMINTL(state,3,6) | ((state & 0x0f000000) >> 3) | BITNUMINTL(state,8,11) |
|
||||
BITNUMINTL(state,7,12) | ((state & 0x00f00000) >> 5) | BITNUMINTL(state,12,17) |
|
||||
BITNUMINTL(state,11,18) | ((state & 0x000f0000) >> 7) | BITNUMINTL(state,16,23);
|
||||
|
||||
t2 = BITNUMINTL(state,15,0) | ((state & 0x0000f000) << 15) | BITNUMINTL(state,20,5) |
|
||||
BITNUMINTL(state,19,6) | ((state & 0x00000f00) << 13) | BITNUMINTL(state,24,11) |
|
||||
BITNUMINTL(state,23,12) | ((state & 0x000000f0) << 11) | BITNUMINTL(state,28,17) |
|
||||
BITNUMINTL(state,27,18) | ((state & 0x0000000f) << 9) | BITNUMINTL(state,0,23);
|
||||
|
||||
lrgstate[0] = (t1 >> 24) & 0x000000ff;
|
||||
lrgstate[1] = (t1 >> 16) & 0x000000ff;
|
||||
lrgstate[2] = (t1 >> 8) & 0x000000ff;
|
||||
lrgstate[3] = (t2 >> 24) & 0x000000ff;
|
||||
lrgstate[4] = (t2 >> 16) & 0x000000ff;
|
||||
lrgstate[5] = (t2 >> 8) & 0x000000ff;
|
||||
|
||||
// Key XOR
|
||||
lrgstate[0] ^= key[0];
|
||||
lrgstate[1] ^= key[1];
|
||||
lrgstate[2] ^= key[2];
|
||||
lrgstate[3] ^= key[3];
|
||||
lrgstate[4] ^= key[4];
|
||||
lrgstate[5] ^= key[5];
|
||||
|
||||
// S-Box Permutation
|
||||
state = (sbox1[SBOXBIT(lrgstate[0] >> 2)] << 28) |
|
||||
(sbox2[SBOXBIT(((lrgstate[0] & 0x03) << 4) | (lrgstate[1] >> 4))] << 24) |
|
||||
(sbox3[SBOXBIT(((lrgstate[1] & 0x0f) << 2) | (lrgstate[2] >> 6))] << 20) |
|
||||
(sbox4[SBOXBIT(lrgstate[2] & 0x3f)] << 16) |
|
||||
(sbox5[SBOXBIT(lrgstate[3] >> 2)] << 12) |
|
||||
(sbox6[SBOXBIT(((lrgstate[3] & 0x03) << 4) | (lrgstate[4] >> 4))] << 8) |
|
||||
(sbox7[SBOXBIT(((lrgstate[4] & 0x0f) << 2) | (lrgstate[5] >> 6))] << 4) |
|
||||
sbox8[SBOXBIT(lrgstate[5] & 0x3f)];
|
||||
|
||||
// P-Box Permutation
|
||||
state = BITNUMINTL(state,15,0) | BITNUMINTL(state,6,1) | BITNUMINTL(state,19,2) |
|
||||
BITNUMINTL(state,20,3) | BITNUMINTL(state,28,4) | BITNUMINTL(state,11,5) |
|
||||
BITNUMINTL(state,27,6) | BITNUMINTL(state,16,7) | BITNUMINTL(state,0,8) |
|
||||
BITNUMINTL(state,14,9) | BITNUMINTL(state,22,10) | BITNUMINTL(state,25,11) |
|
||||
BITNUMINTL(state,4,12) | BITNUMINTL(state,17,13) | BITNUMINTL(state,30,14) |
|
||||
BITNUMINTL(state,9,15) | BITNUMINTL(state,1,16) | BITNUMINTL(state,7,17) |
|
||||
BITNUMINTL(state,23,18) | BITNUMINTL(state,13,19) | BITNUMINTL(state,31,20) |
|
||||
BITNUMINTL(state,26,21) | BITNUMINTL(state,2,22) | BITNUMINTL(state,8,23) |
|
||||
BITNUMINTL(state,18,24) | BITNUMINTL(state,12,25) | BITNUMINTL(state,29,26) |
|
||||
BITNUMINTL(state,5,27) | BITNUMINTL(state,21,28) | BITNUMINTL(state,10,29) |
|
||||
BITNUMINTL(state,3,30) | BITNUMINTL(state,24,31);
|
||||
|
||||
// Return the final state value
|
||||
return(state);
|
||||
}
|
||||
|
||||
void des_key_setup(const BYTE key[], BYTE schedule[][6], DES_MODE mode)
|
||||
{
|
||||
WORD i, j, to_gen, C, D;
|
||||
const WORD key_rnd_shift[16] = {1,1,2,2,2,2,2,2,1,2,2,2,2,2,2,1};
|
||||
const WORD key_perm_c[28] = {56,48,40,32,24,16,8,0,57,49,41,33,25,17,
|
||||
9,1,58,50,42,34,26,18,10,2,59,51,43,35};
|
||||
const WORD key_perm_d[28] = {62,54,46,38,30,22,14,6,61,53,45,37,29,21,
|
||||
13,5,60,52,44,36,28,20,12,4,27,19,11,3};
|
||||
const WORD key_compression[48] = {13,16,10,23,0,4,2,27,14,5,20,9,
|
||||
22,18,11,3,25,7,15,6,26,19,12,1,
|
||||
40,51,30,36,46,54,29,39,50,44,32,47,
|
||||
43,48,38,55,33,52,45,41,49,35,28,31};
|
||||
|
||||
// Permutated Choice #1 (copy the key in, ignoring parity bits).
|
||||
for (i = 0, j = 31, C = 0; i < 28; ++i, --j)
|
||||
C |= BITNUM(key,key_perm_c[i],j);
|
||||
for (i = 0, j = 31, D = 0; i < 28; ++i, --j)
|
||||
D |= BITNUM(key,key_perm_d[i],j);
|
||||
|
||||
// Generate the 16 subkeys.
|
||||
for (i = 0; i < 16; ++i) {
|
||||
C = ((C << key_rnd_shift[i]) | (C >> (28-key_rnd_shift[i]))) & 0xfffffff0;
|
||||
D = ((D << key_rnd_shift[i]) | (D >> (28-key_rnd_shift[i]))) & 0xfffffff0;
|
||||
|
||||
// Decryption subkeys are reverse order of encryption subkeys so
|
||||
// generate them in reverse if the key schedule is for decryption useage.
|
||||
if (mode == DES_DECRYPT)
|
||||
to_gen = 15 - i;
|
||||
else /*(if mode == DES_ENCRYPT)*/
|
||||
to_gen = i;
|
||||
// Initialize the array
|
||||
for (j = 0; j < 6; ++j)
|
||||
schedule[to_gen][j] = 0;
|
||||
for (j = 0; j < 24; ++j)
|
||||
schedule[to_gen][j/8] |= BITNUMINTR(C,key_compression[j],7 - (j%8));
|
||||
for ( ; j < 48; ++j)
|
||||
schedule[to_gen][j/8] |= BITNUMINTR(D,key_compression[j] - 28,7 - (j%8));
|
||||
}
|
||||
}
|
||||
|
||||
void des_crypt(const BYTE in[], BYTE out[], const BYTE key[][6])
|
||||
{
|
||||
WORD state[2],idx,t;
|
||||
|
||||
IP(state,in);
|
||||
|
||||
for (idx=0; idx < 15; ++idx) {
|
||||
t = state[1];
|
||||
state[1] = f(state[1],key[idx]) ^ state[0];
|
||||
state[0] = t;
|
||||
}
|
||||
// Perform the final loop manually as it doesn't switch sides
|
||||
state[0] = f(state[1],key[15]) ^ state[0];
|
||||
|
||||
InvIP(state,out);
|
||||
}
|
||||
|
||||
void three_des_key_setup(const BYTE key[], BYTE schedule[][16][6], DES_MODE mode)
|
||||
{
|
||||
if (mode == DES_ENCRYPT) {
|
||||
des_key_setup(&key[0],schedule[0],mode);
|
||||
des_key_setup(&key[8],schedule[1],!mode);
|
||||
des_key_setup(&key[16],schedule[2],mode);
|
||||
}
|
||||
else /*if (mode == DES_DECRYPT*/ {
|
||||
des_key_setup(&key[16],schedule[0],mode);
|
||||
des_key_setup(&key[8],schedule[1],!mode);
|
||||
des_key_setup(&key[0],schedule[2],mode);
|
||||
}
|
||||
}
|
||||
|
||||
void three_des_crypt(const BYTE in[], BYTE out[], const BYTE key[][16][6])
|
||||
{
|
||||
des_crypt(in,out,key[0]);
|
||||
des_crypt(out,out,key[1]);
|
||||
des_crypt(out,out,key[2]);
|
||||
}
|
37
lib/crypto-algorithms/des.h
Normal file
37
lib/crypto-algorithms/des.h
Normal file
|
@ -0,0 +1,37 @@
|
|||
/*********************************************************************
|
||||
* Filename: des.h
|
||||
* Author: Brad Conte (brad AT bradconte.com)
|
||||
* Copyright:
|
||||
* Disclaimer: This code is presented "as is" without any guarantees.
|
||||
* Details: Defines the API for the corresponding DES implementation.
|
||||
Note that encryption and decryption are defined by how
|
||||
the key setup is performed, the actual en/de-cryption is
|
||||
performed by the same function.
|
||||
*********************************************************************/
|
||||
|
||||
#ifndef DES_H
|
||||
#define DESH
|
||||
|
||||
/*************************** HEADER FILES ***************************/
|
||||
#include <stddef.h>
|
||||
|
||||
/****************************** MACROS ******************************/
|
||||
#define DES_BLOCK_SIZE 8 // DES operates on 8 bytes at a time
|
||||
|
||||
/**************************** DATA TYPES ****************************/
|
||||
typedef unsigned char BYTE; // 8-bit byte
|
||||
typedef unsigned int WORD; // 32-bit word, change to "long" for 16-bit machines
|
||||
|
||||
typedef enum {
|
||||
DES_ENCRYPT,
|
||||
DES_DECRYPT
|
||||
} DES_MODE;
|
||||
|
||||
/*********************** FUNCTION DECLARATIONS **********************/
|
||||
void des_key_setup(const BYTE key[], BYTE schedule[][6], DES_MODE mode);
|
||||
void des_crypt(const BYTE in[], BYTE out[], const BYTE key[][6]);
|
||||
|
||||
void three_des_key_setup(const BYTE key[], BYTE schedule[][16][6], DES_MODE mode);
|
||||
void three_des_crypt(const BYTE in[], BYTE out[], const BYTE key[][16][6]);
|
||||
|
||||
#endif // DES_H
|
83
lib/crypto-algorithms/des_test.c
Normal file
83
lib/crypto-algorithms/des_test.c
Normal file
|
@ -0,0 +1,83 @@
|
|||
/*********************************************************************
|
||||
* Filename: des_test.c
|
||||
* Author: Brad Conte (brad AT bradconte.com)
|
||||
* Copyright:
|
||||
* Disclaimer: This code is presented "as is" without any guarantees.
|
||||
* Details: Performs known-answer tests on the corresponding DES
|
||||
implementation. These tests do not encompass the full
|
||||
range of available test vectors, however, if the tests
|
||||
pass it is very, very likely that the code is correct
|
||||
and was compiled properly. This code also serves as
|
||||
example usage of the functions.
|
||||
*********************************************************************/
|
||||
|
||||
/*************************** HEADER FILES ***************************/
|
||||
#include <stdio.h>
|
||||
#include <memory.h>
|
||||
#include "des.h"
|
||||
|
||||
/*********************** FUNCTION DEFINITIONS ***********************/
|
||||
int des_test()
|
||||
{
|
||||
BYTE pt1[DES_BLOCK_SIZE] = {0x01,0x23,0x45,0x67,0x89,0xAB,0xCD,0xE7};
|
||||
BYTE pt2[DES_BLOCK_SIZE] = {0x01,0x23,0x45,0x67,0x89,0xAB,0xCD,0xEF};
|
||||
BYTE pt3[DES_BLOCK_SIZE] = {0x54,0x68,0x65,0x20,0x71,0x75,0x66,0x63};
|
||||
BYTE ct1[DES_BLOCK_SIZE] = {0xc9,0x57,0x44,0x25,0x6a,0x5e,0xd3,0x1d};
|
||||
BYTE ct2[DES_BLOCK_SIZE] = {0x85,0xe8,0x13,0x54,0x0f,0x0a,0xb4,0x05};
|
||||
BYTE ct3[DES_BLOCK_SIZE] = {0xc9,0x57,0x44,0x25,0x6a,0x5e,0xd3,0x1d};
|
||||
BYTE ct4[DES_BLOCK_SIZE] = {0xA8,0x26,0xFD,0x8C,0xE5,0x3B,0x85,0x5F};
|
||||
BYTE key1[DES_BLOCK_SIZE] = {0x01,0x23,0x45,0x67,0x89,0xAB,0xCD,0xEF};
|
||||
BYTE key2[DES_BLOCK_SIZE] = {0x13,0x34,0x57,0x79,0x9B,0xBC,0xDF,0xF1};
|
||||
BYTE three_key1[DES_BLOCK_SIZE * 3] = {0x01,0x23,0x45,0x67,0x89,0xAB,0xCD,0xEF,
|
||||
0x01,0x23,0x45,0x67,0x89,0xAB,0xCD,0xEF,
|
||||
0x01,0x23,0x45,0x67,0x89,0xAB,0xCD,0xEF};
|
||||
BYTE three_key2[DES_BLOCK_SIZE * 3] = {0x01,0x23,0x45,0x67,0x89,0xAB,0xCD,0xEF,
|
||||
0x23,0x45,0x67,0x89,0xAB,0xCD,0xEF,0x01,
|
||||
0x45,0x67,0x89,0xAB,0xCD,0xEF,0x01,0x23};
|
||||
|
||||
BYTE schedule[16][6];
|
||||
BYTE three_schedule[3][16][6];
|
||||
BYTE buf[DES_BLOCK_SIZE];
|
||||
int pass = 1;
|
||||
|
||||
des_key_setup(key1, schedule, DES_ENCRYPT);
|
||||
des_crypt(pt1, buf, schedule);
|
||||
pass = pass && !memcmp(ct1, buf, DES_BLOCK_SIZE);
|
||||
|
||||
des_key_setup(key1, schedule, DES_DECRYPT);
|
||||
des_crypt(ct1, buf, schedule);
|
||||
pass = pass && !memcmp(pt1, buf, DES_BLOCK_SIZE);
|
||||
|
||||
des_key_setup(key2, schedule, DES_ENCRYPT);
|
||||
des_crypt(pt2, buf, schedule);
|
||||
pass = pass && !memcmp(ct2, buf, DES_BLOCK_SIZE);
|
||||
|
||||
des_key_setup(key2, schedule, DES_DECRYPT);
|
||||
des_crypt(ct2, buf, schedule);
|
||||
pass = pass && !memcmp(pt2, buf, DES_BLOCK_SIZE);
|
||||
|
||||
three_des_key_setup(three_key1, three_schedule, DES_ENCRYPT);
|
||||
three_des_crypt(pt1, buf, three_schedule);
|
||||
pass = pass && !memcmp(ct3, buf, DES_BLOCK_SIZE);
|
||||
|
||||
three_des_key_setup(three_key1, three_schedule, DES_DECRYPT);
|
||||
three_des_crypt(ct3, buf, three_schedule);
|
||||
pass = pass && !memcmp(pt1, buf, DES_BLOCK_SIZE);
|
||||
|
||||
three_des_key_setup(three_key2, three_schedule, DES_ENCRYPT);
|
||||
three_des_crypt(pt3, buf, three_schedule);
|
||||
pass = pass && !memcmp(ct4, buf, DES_BLOCK_SIZE);
|
||||
|
||||
three_des_key_setup(three_key2, three_schedule, DES_DECRYPT);
|
||||
three_des_crypt(ct4, buf, three_schedule);
|
||||
pass = pass && !memcmp(pt3, buf, DES_BLOCK_SIZE);
|
||||
|
||||
return(pass);
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
printf("DES test: %s\n", des_test() ? "SUCCEEDED" : "FAILED");
|
||||
|
||||
return(0);
|
||||
}
|
104
lib/crypto-algorithms/md2.c
Normal file
104
lib/crypto-algorithms/md2.c
Normal file
|
@ -0,0 +1,104 @@
|
|||
/*********************************************************************
|
||||
* Filename: md2.c
|
||||
* Author: Brad Conte (brad AT bradconte.com)
|
||||
* Copyright:
|
||||
* Disclaimer: This code is presented "as is" without any guarantees.
|
||||
* Details: Implementation of the MD2 hashing algorithm.
|
||||
Algorithm specification can be found here:
|
||||
* http://tools.ietf.org/html/rfc1319 .
|
||||
Input is little endian byte order.
|
||||
*********************************************************************/
|
||||
|
||||
/*************************** HEADER FILES ***************************/
|
||||
#include <stdlib.h>
|
||||
#include <memory.h>
|
||||
#include "md2.h"
|
||||
|
||||
/**************************** VARIABLES *****************************/
|
||||
static const BYTE s[256] = {
|
||||
41, 46, 67, 201, 162, 216, 124, 1, 61, 54, 84, 161, 236, 240, 6,
|
||||
19, 98, 167, 5, 243, 192, 199, 115, 140, 152, 147, 43, 217, 188,
|
||||
76, 130, 202, 30, 155, 87, 60, 253, 212, 224, 22, 103, 66, 111, 24,
|
||||
138, 23, 229, 18, 190, 78, 196, 214, 218, 158, 222, 73, 160, 251,
|
||||
245, 142, 187, 47, 238, 122, 169, 104, 121, 145, 21, 178, 7, 63,
|
||||
148, 194, 16, 137, 11, 34, 95, 33, 128, 127, 93, 154, 90, 144, 50,
|
||||
39, 53, 62, 204, 231, 191, 247, 151, 3, 255, 25, 48, 179, 72, 165,
|
||||
181, 209, 215, 94, 146, 42, 172, 86, 170, 198, 79, 184, 56, 210,
|
||||
150, 164, 125, 182, 118, 252, 107, 226, 156, 116, 4, 241, 69, 157,
|
||||
112, 89, 100, 113, 135, 32, 134, 91, 207, 101, 230, 45, 168, 2, 27,
|
||||
96, 37, 173, 174, 176, 185, 246, 28, 70, 97, 105, 52, 64, 126, 15,
|
||||
85, 71, 163, 35, 221, 81, 175, 58, 195, 92, 249, 206, 186, 197,
|
||||
234, 38, 44, 83, 13, 110, 133, 40, 132, 9, 211, 223, 205, 244, 65,
|
||||
129, 77, 82, 106, 220, 55, 200, 108, 193, 171, 250, 36, 225, 123,
|
||||
8, 12, 189, 177, 74, 120, 136, 149, 139, 227, 99, 232, 109, 233,
|
||||
203, 213, 254, 59, 0, 29, 57, 242, 239, 183, 14, 102, 88, 208, 228,
|
||||
166, 119, 114, 248, 235, 117, 75, 10, 49, 68, 80, 180, 143, 237,
|
||||
31, 26, 219, 153, 141, 51, 159, 17, 131, 20
|
||||
};
|
||||
|
||||
/*********************** FUNCTION DEFINITIONS ***********************/
|
||||
void md2_transform(MD2_CTX *ctx, BYTE data[])
|
||||
{
|
||||
int j,k,t;
|
||||
|
||||
//memcpy(&ctx->state[16], data);
|
||||
for (j=0; j < 16; ++j) {
|
||||
ctx->state[j + 16] = data[j];
|
||||
ctx->state[j + 32] = (ctx->state[j+16] ^ ctx->state[j]);
|
||||
}
|
||||
|
||||
t = 0;
|
||||
for (j = 0; j < 18; ++j) {
|
||||
for (k = 0; k < 48; ++k) {
|
||||
ctx->state[k] ^= s[t];
|
||||
t = ctx->state[k];
|
||||
}
|
||||
t = (t+j) & 0xFF;
|
||||
}
|
||||
|
||||
t = ctx->checksum[15];
|
||||
for (j=0; j < 16; ++j) {
|
||||
ctx->checksum[j] ^= s[data[j] ^ t];
|
||||
t = ctx->checksum[j];
|
||||
}
|
||||
}
|
||||
|
||||
void md2_init(MD2_CTX *ctx)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i=0; i < 48; ++i)
|
||||
ctx->state[i] = 0;
|
||||
for (i=0; i < 16; ++i)
|
||||
ctx->checksum[i] = 0;
|
||||
ctx->len = 0;
|
||||
}
|
||||
|
||||
void md2_update(MD2_CTX *ctx, const BYTE data[], size_t len)
|
||||
{
|
||||
size_t i;
|
||||
|
||||
for (i = 0; i < len; ++i) {
|
||||
ctx->data[ctx->len] = data[i];
|
||||
ctx->len++;
|
||||
if (ctx->len == MD2_BLOCK_SIZE) {
|
||||
md2_transform(ctx, ctx->data);
|
||||
ctx->len = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void md2_final(MD2_CTX *ctx, BYTE hash[])
|
||||
{
|
||||
int to_pad;
|
||||
|
||||
to_pad = MD2_BLOCK_SIZE - ctx->len;
|
||||
|
||||
while (ctx->len < MD2_BLOCK_SIZE)
|
||||
ctx->data[ctx->len++] = to_pad;
|
||||
|
||||
md2_transform(ctx, ctx->data);
|
||||
md2_transform(ctx, ctx->checksum);
|
||||
|
||||
memcpy(hash, ctx->state, MD2_BLOCK_SIZE);
|
||||
}
|
33
lib/crypto-algorithms/md2.h
Normal file
33
lib/crypto-algorithms/md2.h
Normal file
|
@ -0,0 +1,33 @@
|
|||
/*********************************************************************
|
||||
* Filename: md2.h
|
||||
* Author: Brad Conte (brad AT bradconte.com)
|
||||
* Copyright:
|
||||
* Disclaimer: This code is presented "as is" without any guarantees.
|
||||
* Details: Defines the API for the corresponding MD2 implementation.
|
||||
*********************************************************************/
|
||||
|
||||
#ifndef MD2_H
|
||||
#define MD2_H
|
||||
|
||||
/*************************** HEADER FILES ***************************/
|
||||
#include <stddef.h>
|
||||
|
||||
/****************************** MACROS ******************************/
|
||||
#define MD2_BLOCK_SIZE 16
|
||||
|
||||
/**************************** DATA TYPES ****************************/
|
||||
typedef unsigned char BYTE; // 8-bit byte
|
||||
|
||||
typedef struct {
|
||||
BYTE data[16];
|
||||
BYTE state[48];
|
||||
BYTE checksum[16];
|
||||
int len;
|
||||
} MD2_CTX;
|
||||
|
||||
/*********************** FUNCTION DECLARATIONS **********************/
|
||||
void md2_init(MD2_CTX *ctx);
|
||||
void md2_update(MD2_CTX *ctx, const BYTE data[], size_t len);
|
||||
void md2_final(MD2_CTX *ctx, BYTE hash[]); // size of hash must be MD2_BLOCK_SIZE
|
||||
|
||||
#endif // MD2_H
|
58
lib/crypto-algorithms/md2_test.c
Normal file
58
lib/crypto-algorithms/md2_test.c
Normal file
|
@ -0,0 +1,58 @@
|
|||
/*********************************************************************
|
||||
* Filename: md2_test.c
|
||||
* Author: Brad Conte (brad AT bradconte.com)
|
||||
* Copyright:
|
||||
* Disclaimer: This code is presented "as is" without any guarantees.
|
||||
* Details: Performs known-answer tests on the corresponding MD2
|
||||
implementation. These tests do not encompass the full
|
||||
range of available test vectors, however, if the tests
|
||||
pass it is very, very likely that the code is correct
|
||||
and was compiled properly. This code also serves as
|
||||
example usage of the functions.
|
||||
*********************************************************************/
|
||||
|
||||
/*************************** HEADER FILES ***************************/
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <memory.h>
|
||||
#include "md2.h"
|
||||
|
||||
/*********************** FUNCTION DEFINITIONS ***********************/
|
||||
int md2_test()
|
||||
{
|
||||
BYTE text1[] = {"abc"};
|
||||
BYTE text2[] = {"abcdefghijklmnopqrstuvwxyz"};
|
||||
BYTE text3_1[] = {"ABCDEFGHIJKLMNOPQRSTUVWXYZabcde"};
|
||||
BYTE text3_2[] = {"fghijklmnopqrstuvwxyz0123456789"};
|
||||
BYTE hash1[MD2_BLOCK_SIZE] = {0xda,0x85,0x3b,0x0d,0x3f,0x88,0xd9,0x9b,0x30,0x28,0x3a,0x69,0xe6,0xde,0xd6,0xbb};
|
||||
BYTE hash2[MD2_BLOCK_SIZE] = {0x4e,0x8d,0xdf,0xf3,0x65,0x02,0x92,0xab,0x5a,0x41,0x08,0xc3,0xaa,0x47,0x94,0x0b};
|
||||
BYTE hash3[MD2_BLOCK_SIZE] = {0xda,0x33,0xde,0xf2,0xa4,0x2d,0xf1,0x39,0x75,0x35,0x28,0x46,0xc3,0x03,0x38,0xcd};
|
||||
BYTE buf[16];
|
||||
MD2_CTX ctx;
|
||||
int pass = 1;
|
||||
|
||||
md2_init(&ctx);
|
||||
md2_update(&ctx, text1, strlen(text1));
|
||||
md2_final(&ctx, buf);
|
||||
pass = pass && !memcmp(hash1, buf, MD2_BLOCK_SIZE);
|
||||
|
||||
// Note that the MD2 object can be re-used.
|
||||
md2_init(&ctx);
|
||||
md2_update(&ctx, text2, strlen(text2));
|
||||
md2_final(&ctx, buf);
|
||||
pass = pass && !memcmp(hash2, buf, MD2_BLOCK_SIZE);
|
||||
|
||||
// Note that the data is added in two chunks.
|
||||
md2_init(&ctx);
|
||||
md2_update(&ctx, text3_1, strlen(text3_1));
|
||||
md2_update(&ctx, text3_2, strlen(text3_2));
|
||||
md2_final(&ctx, buf);
|
||||
pass = pass && !memcmp(hash3, buf, MD2_BLOCK_SIZE);
|
||||
|
||||
return(pass);
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
printf("MD2 tests: %s\n", md2_test() ? "SUCCEEDED" : "FAILED");
|
||||
}
|
189
lib/crypto-algorithms/md5.c
Normal file
189
lib/crypto-algorithms/md5.c
Normal file
|
@ -0,0 +1,189 @@
|
|||
/*********************************************************************
|
||||
* Filename: md5.c
|
||||
* Author: Brad Conte (brad AT bradconte.com)
|
||||
* Copyright:
|
||||
* Disclaimer: This code is presented "as is" without any guarantees.
|
||||
* Details: Implementation of the MD5 hashing algorithm.
|
||||
Algorithm specification can be found here:
|
||||
* http://tools.ietf.org/html/rfc1321
|
||||
This implementation uses little endian byte order.
|
||||
*********************************************************************/
|
||||
|
||||
/*************************** HEADER FILES ***************************/
|
||||
#include <stdlib.h>
|
||||
#include <memory.h>
|
||||
#include "md5.h"
|
||||
|
||||
/****************************** MACROS ******************************/
|
||||
#define ROTLEFT(a,b) ((a << b) | (a >> (32-b)))
|
||||
|
||||
#define F(x,y,z) ((x & y) | (~x & z))
|
||||
#define G(x,y,z) ((x & z) | (y & ~z))
|
||||
#define H(x,y,z) (x ^ y ^ z)
|
||||
#define I(x,y,z) (y ^ (x | ~z))
|
||||
|
||||
#define FF(a,b,c,d,m,s,t) { a += F(b,c,d) + m + t; \
|
||||
a = b + ROTLEFT(a,s); }
|
||||
#define GG(a,b,c,d,m,s,t) { a += G(b,c,d) + m + t; \
|
||||
a = b + ROTLEFT(a,s); }
|
||||
#define HH(a,b,c,d,m,s,t) { a += H(b,c,d) + m + t; \
|
||||
a = b + ROTLEFT(a,s); }
|
||||
#define II(a,b,c,d,m,s,t) { a += I(b,c,d) + m + t; \
|
||||
a = b + ROTLEFT(a,s); }
|
||||
|
||||
/*********************** FUNCTION DEFINITIONS ***********************/
|
||||
void md5_transform(MD5_CTX *ctx, const BYTE data[])
|
||||
{
|
||||
WORD a, b, c, d, m[16], i, j;
|
||||
|
||||
// MD5 specifies big endian byte order, but this implementation assumes a little
|
||||
// endian byte order CPU. Reverse all the bytes upon input, and re-reverse them
|
||||
// on output (in md5_final()).
|
||||
for (i = 0, j = 0; i < 16; ++i, j += 4)
|
||||
m[i] = (data[j]) + (data[j + 1] << 8) + (data[j + 2] << 16) + (data[j + 3] << 24);
|
||||
|
||||
a = ctx->state[0];
|
||||
b = ctx->state[1];
|
||||
c = ctx->state[2];
|
||||
d = ctx->state[3];
|
||||
|
||||
FF(a,b,c,d,m[0], 7,0xd76aa478);
|
||||
FF(d,a,b,c,m[1], 12,0xe8c7b756);
|
||||
FF(c,d,a,b,m[2], 17,0x242070db);
|
||||
FF(b,c,d,a,m[3], 22,0xc1bdceee);
|
||||
FF(a,b,c,d,m[4], 7,0xf57c0faf);
|
||||
FF(d,a,b,c,m[5], 12,0x4787c62a);
|
||||
FF(c,d,a,b,m[6], 17,0xa8304613);
|
||||
FF(b,c,d,a,m[7], 22,0xfd469501);
|
||||
FF(a,b,c,d,m[8], 7,0x698098d8);
|
||||
FF(d,a,b,c,m[9], 12,0x8b44f7af);
|
||||
FF(c,d,a,b,m[10],17,0xffff5bb1);
|
||||
FF(b,c,d,a,m[11],22,0x895cd7be);
|
||||
FF(a,b,c,d,m[12], 7,0x6b901122);
|
||||
FF(d,a,b,c,m[13],12,0xfd987193);
|
||||
FF(c,d,a,b,m[14],17,0xa679438e);
|
||||
FF(b,c,d,a,m[15],22,0x49b40821);
|
||||
|
||||
GG(a,b,c,d,m[1], 5,0xf61e2562);
|
||||
GG(d,a,b,c,m[6], 9,0xc040b340);
|
||||
GG(c,d,a,b,m[11],14,0x265e5a51);
|
||||
GG(b,c,d,a,m[0], 20,0xe9b6c7aa);
|
||||
GG(a,b,c,d,m[5], 5,0xd62f105d);
|
||||
GG(d,a,b,c,m[10], 9,0x02441453);
|
||||
GG(c,d,a,b,m[15],14,0xd8a1e681);
|
||||
GG(b,c,d,a,m[4], 20,0xe7d3fbc8);
|
||||
GG(a,b,c,d,m[9], 5,0x21e1cde6);
|
||||
GG(d,a,b,c,m[14], 9,0xc33707d6);
|
||||
GG(c,d,a,b,m[3], 14,0xf4d50d87);
|
||||
GG(b,c,d,a,m[8], 20,0x455a14ed);
|
||||
GG(a,b,c,d,m[13], 5,0xa9e3e905);
|
||||
GG(d,a,b,c,m[2], 9,0xfcefa3f8);
|
||||
GG(c,d,a,b,m[7], 14,0x676f02d9);
|
||||
GG(b,c,d,a,m[12],20,0x8d2a4c8a);
|
||||
|
||||
HH(a,b,c,d,m[5], 4,0xfffa3942);
|
||||
HH(d,a,b,c,m[8], 11,0x8771f681);
|
||||
HH(c,d,a,b,m[11],16,0x6d9d6122);
|
||||
HH(b,c,d,a,m[14],23,0xfde5380c);
|
||||
HH(a,b,c,d,m[1], 4,0xa4beea44);
|
||||
HH(d,a,b,c,m[4], 11,0x4bdecfa9);
|
||||
HH(c,d,a,b,m[7], 16,0xf6bb4b60);
|
||||
HH(b,c,d,a,m[10],23,0xbebfbc70);
|
||||
HH(a,b,c,d,m[13], 4,0x289b7ec6);
|
||||
HH(d,a,b,c,m[0], 11,0xeaa127fa);
|
||||
HH(c,d,a,b,m[3], 16,0xd4ef3085);
|
||||
HH(b,c,d,a,m[6], 23,0x04881d05);
|
||||
HH(a,b,c,d,m[9], 4,0xd9d4d039);
|
||||
HH(d,a,b,c,m[12],11,0xe6db99e5);
|
||||
HH(c,d,a,b,m[15],16,0x1fa27cf8);
|
||||
HH(b,c,d,a,m[2], 23,0xc4ac5665);
|
||||
|
||||
II(a,b,c,d,m[0], 6,0xf4292244);
|
||||
II(d,a,b,c,m[7], 10,0x432aff97);
|
||||
II(c,d,a,b,m[14],15,0xab9423a7);
|
||||
II(b,c,d,a,m[5], 21,0xfc93a039);
|
||||
II(a,b,c,d,m[12], 6,0x655b59c3);
|
||||
II(d,a,b,c,m[3], 10,0x8f0ccc92);
|
||||
II(c,d,a,b,m[10],15,0xffeff47d);
|
||||
II(b,c,d,a,m[1], 21,0x85845dd1);
|
||||
II(a,b,c,d,m[8], 6,0x6fa87e4f);
|
||||
II(d,a,b,c,m[15],10,0xfe2ce6e0);
|
||||
II(c,d,a,b,m[6], 15,0xa3014314);
|
||||
II(b,c,d,a,m[13],21,0x4e0811a1);
|
||||
II(a,b,c,d,m[4], 6,0xf7537e82);
|
||||
II(d,a,b,c,m[11],10,0xbd3af235);
|
||||
II(c,d,a,b,m[2], 15,0x2ad7d2bb);
|
||||
II(b,c,d,a,m[9], 21,0xeb86d391);
|
||||
|
||||
ctx->state[0] += a;
|
||||
ctx->state[1] += b;
|
||||
ctx->state[2] += c;
|
||||
ctx->state[3] += d;
|
||||
}
|
||||
|
||||
void md5_init(MD5_CTX *ctx)
|
||||
{
|
||||
ctx->datalen = 0;
|
||||
ctx->bitlen = 0;
|
||||
ctx->state[0] = 0x67452301;
|
||||
ctx->state[1] = 0xEFCDAB89;
|
||||
ctx->state[2] = 0x98BADCFE;
|
||||
ctx->state[3] = 0x10325476;
|
||||
}
|
||||
|
||||
void md5_update(MD5_CTX *ctx, const BYTE data[], size_t len)
|
||||
{
|
||||
size_t i;
|
||||
|
||||
for (i = 0; i < len; ++i) {
|
||||
ctx->data[ctx->datalen] = data[i];
|
||||
ctx->datalen++;
|
||||
if (ctx->datalen == 64) {
|
||||
md5_transform(ctx, ctx->data);
|
||||
ctx->bitlen += 512;
|
||||
ctx->datalen = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void md5_final(MD5_CTX *ctx, BYTE hash[])
|
||||
{
|
||||
size_t i;
|
||||
|
||||
i = ctx->datalen;
|
||||
|
||||
// Pad whatever data is left in the buffer.
|
||||
if (ctx->datalen < 56) {
|
||||
ctx->data[i++] = 0x80;
|
||||
while (i < 56)
|
||||
ctx->data[i++] = 0x00;
|
||||
}
|
||||
else if (ctx->datalen >= 56) {
|
||||
ctx->data[i++] = 0x80;
|
||||
while (i < 64)
|
||||
ctx->data[i++] = 0x00;
|
||||
md5_transform(ctx, ctx->data);
|
||||
memset(ctx->data, 0, 56);
|
||||
}
|
||||
|
||||
// Append to the padding the total message's length in bits and transform.
|
||||
ctx->bitlen += ctx->datalen * 8;
|
||||
ctx->data[56] = ctx->bitlen;
|
||||
ctx->data[57] = ctx->bitlen >> 8;
|
||||
ctx->data[58] = ctx->bitlen >> 16;
|
||||
ctx->data[59] = ctx->bitlen >> 24;
|
||||
ctx->data[60] = ctx->bitlen >> 32;
|
||||
ctx->data[61] = ctx->bitlen >> 40;
|
||||
ctx->data[62] = ctx->bitlen >> 48;
|
||||
ctx->data[63] = ctx->bitlen >> 56;
|
||||
md5_transform(ctx, ctx->data);
|
||||
|
||||
// Since this implementation uses little endian byte ordering and MD uses big endian,
|
||||
// reverse all the bytes when copying the final state to the output hash.
|
||||
for (i = 0; i < 4; ++i) {
|
||||
hash[i] = (ctx->state[0] >> (i * 8)) & 0x000000ff;
|
||||
hash[i + 4] = (ctx->state[1] >> (i * 8)) & 0x000000ff;
|
||||
hash[i + 8] = (ctx->state[2] >> (i * 8)) & 0x000000ff;
|
||||
hash[i + 12] = (ctx->state[3] >> (i * 8)) & 0x000000ff;
|
||||
}
|
||||
}
|
34
lib/crypto-algorithms/md5.h
Normal file
34
lib/crypto-algorithms/md5.h
Normal file
|
@ -0,0 +1,34 @@
|
|||
/*********************************************************************
|
||||
* Filename: md5.h
|
||||
* Author: Brad Conte (brad AT bradconte.com)
|
||||
* Copyright:
|
||||
* Disclaimer: This code is presented "as is" without any guarantees.
|
||||
* Details: Defines the API for the corresponding MD5 implementation.
|
||||
*********************************************************************/
|
||||
|
||||
#ifndef MD5_H
|
||||
#define MD5_H
|
||||
|
||||
/*************************** HEADER FILES ***************************/
|
||||
#include <stddef.h>
|
||||
|
||||
/****************************** MACROS ******************************/
|
||||
#define MD5_BLOCK_SIZE 16 // MD5 outputs a 16 byte digest
|
||||
|
||||
/**************************** DATA TYPES ****************************/
|
||||
typedef unsigned char BYTE; // 8-bit byte
|
||||
typedef unsigned int WORD; // 32-bit word, change to "long" for 16-bit machines
|
||||
|
||||
typedef struct {
|
||||
BYTE data[64];
|
||||
WORD datalen;
|
||||
unsigned long long bitlen;
|
||||
WORD state[4];
|
||||
} MD5_CTX;
|
||||
|
||||
/*********************** FUNCTION DECLARATIONS **********************/
|
||||
void md5_init(MD5_CTX *ctx);
|
||||
void md5_update(MD5_CTX *ctx, const BYTE data[], size_t len);
|
||||
void md5_final(MD5_CTX *ctx, BYTE hash[]);
|
||||
|
||||
#endif // MD5_H
|
60
lib/crypto-algorithms/md5_test.c
Normal file
60
lib/crypto-algorithms/md5_test.c
Normal file
|
@ -0,0 +1,60 @@
|
|||
/*********************************************************************
|
||||
* Filename: md5_test.c
|
||||
* Author: Brad Conte (brad AT bradconte.com)
|
||||
* Copyright:
|
||||
* Disclaimer: This code is presented "as is" without any guarantees.
|
||||
* Details: Performs known-answer tests on the corresponding MD5
|
||||
implementation. These tests do not encompass the full
|
||||
range of available test vectors, however, if the tests
|
||||
pass it is very, very likely that the code is correct
|
||||
and was compiled properly. This code also serves as
|
||||
example usage of the functions.
|
||||
*********************************************************************/
|
||||
|
||||
/*************************** HEADER FILES ***************************/
|
||||
#include <stdio.h>
|
||||
#include <memory.h>
|
||||
#include <string.h>
|
||||
#include "md5.h"
|
||||
|
||||
/*********************** FUNCTION DEFINITIONS ***********************/
|
||||
int md5_test()
|
||||
{
|
||||
BYTE text1[] = {""};
|
||||
BYTE text2[] = {"abc"};
|
||||
BYTE text3_1[] = {"ABCDEFGHIJKLMNOPQRSTUVWXYZabcde"};
|
||||
BYTE text3_2[] = {"fghijklmnopqrstuvwxyz0123456789"};
|
||||
BYTE hash1[MD5_BLOCK_SIZE] = {0xd4,0x1d,0x8c,0xd9,0x8f,0x00,0xb2,0x04,0xe9,0x80,0x09,0x98,0xec,0xf8,0x42,0x7e};
|
||||
BYTE hash2[MD5_BLOCK_SIZE] = {0x90,0x01,0x50,0x98,0x3c,0xd2,0x4f,0xb0,0xd6,0x96,0x3f,0x7d,0x28,0xe1,0x7f,0x72};
|
||||
BYTE hash3[MD5_BLOCK_SIZE] = {0xd1,0x74,0xab,0x98,0xd2,0x77,0xd9,0xf5,0xa5,0x61,0x1c,0x2c,0x9f,0x41,0x9d,0x9f};
|
||||
BYTE buf[16];
|
||||
MD5_CTX ctx;
|
||||
int pass = 1;
|
||||
|
||||
md5_init(&ctx);
|
||||
md5_update(&ctx, text1, strlen(text1));
|
||||
md5_final(&ctx, buf);
|
||||
pass = pass && !memcmp(hash1, buf, MD5_BLOCK_SIZE);
|
||||
|
||||
// Note the MD5 object can be reused.
|
||||
md5_init(&ctx);
|
||||
md5_update(&ctx, text2, strlen(text2));
|
||||
md5_final(&ctx, buf);
|
||||
pass = pass && !memcmp(hash2, buf, MD5_BLOCK_SIZE);
|
||||
|
||||
// Note the data is being added in two chunks.
|
||||
md5_init(&ctx);
|
||||
md5_update(&ctx, text3_1, strlen(text3_1));
|
||||
md5_update(&ctx, text3_2, strlen(text3_2));
|
||||
md5_final(&ctx, buf);
|
||||
pass = pass && !memcmp(hash3, buf, MD5_BLOCK_SIZE);
|
||||
|
||||
return(pass);
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
printf("MD5 tests: %s\n", md5_test() ? "SUCCEEDED" : "FAILED");
|
||||
|
||||
return(0);
|
||||
}
|
35
lib/crypto-algorithms/rot-13.c
Normal file
35
lib/crypto-algorithms/rot-13.c
Normal file
|
@ -0,0 +1,35 @@
|
|||
/*********************************************************************
|
||||
* Filename: rot-13.c
|
||||
* Author: Brad Conte (brad AT bradconte.com)
|
||||
* Copyright:
|
||||
* Disclaimer: This code is presented "as is" without any guarantees.
|
||||
* Details: Implementation of the ROT-13 encryption algorithm.
|
||||
Algorithm specification can be found here:
|
||||
*
|
||||
This implementation uses little endian byte order.
|
||||
*********************************************************************/
|
||||
|
||||
/*************************** HEADER FILES ***************************/
|
||||
#include <string.h>
|
||||
#include "rot-13.h"
|
||||
|
||||
/*********************** FUNCTION DEFINITIONS ***********************/
|
||||
void rot13(char str[])
|
||||
{
|
||||
int case_type, idx, len;
|
||||
|
||||
for (idx = 0, len = strlen(str); idx < len; idx++) {
|
||||
// Only process alphabetic characters.
|
||||
if (str[idx] < 'A' || (str[idx] > 'Z' && str[idx] < 'a') || str[idx] > 'z')
|
||||
continue;
|
||||
// Determine if the char is upper or lower case.
|
||||
if (str[idx] >= 'a')
|
||||
case_type = 'a';
|
||||
else
|
||||
case_type = 'A';
|
||||
// Rotate the char's value, ensuring it doesn't accidentally "fall off" the end.
|
||||
str[idx] = (str[idx] + 13) % (case_type + 26);
|
||||
if (str[idx] < 26)
|
||||
str[idx] += case_type;
|
||||
}
|
||||
}
|
20
lib/crypto-algorithms/rot-13.h
Normal file
20
lib/crypto-algorithms/rot-13.h
Normal file
|
@ -0,0 +1,20 @@
|
|||
/*********************************************************************
|
||||
* Filename: rot-13.h
|
||||
* Author: Brad Conte (brad AT bradconte.com)
|
||||
* Copyright:
|
||||
* Disclaimer: This code is presented "as is" without any guarantees.
|
||||
* Details: Defines the API for the corresponding ROT-13 implementation.
|
||||
*********************************************************************/
|
||||
|
||||
#ifndef ROT13_H
|
||||
#define ROT13_H
|
||||
|
||||
/*************************** HEADER FILES ***************************/
|
||||
#include <stddef.h>
|
||||
|
||||
/*********************** FUNCTION DECLARATIONS **********************/
|
||||
// Performs IN PLACE rotation of the input. Assumes input is NULL terminated.
|
||||
// Preserves each charcter's case. Ignores non alphabetic characters.
|
||||
void rot13(char str[]);
|
||||
|
||||
#endif // ROT13_H
|
44
lib/crypto-algorithms/rot-13_test.c
Normal file
44
lib/crypto-algorithms/rot-13_test.c
Normal file
|
@ -0,0 +1,44 @@
|
|||
/*********************************************************************
|
||||
* Filename: rot-13_test.c
|
||||
* Author: Brad Conte (brad AT bradconte.com)
|
||||
* Copyright:
|
||||
* Disclaimer: This code is presented "as is" without any guarantees.
|
||||
* Details: Performs known-answer tests on the corresponding ROT-13
|
||||
implementation. These tests do not encompass the full
|
||||
range of available test vectors, however, if the tests
|
||||
pass it is very, very likely that the code is correct
|
||||
and was compiled properly. This code also serves as
|
||||
example usage of the functions.
|
||||
*********************************************************************/
|
||||
|
||||
/*************************** HEADER FILES ***************************/
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include "rot-13.h"
|
||||
|
||||
/*********************** FUNCTION DEFINITIONS ***********************/
|
||||
int rot13_test()
|
||||
{
|
||||
char text[] = {"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"};
|
||||
char code[] = {"NOPQRSTUVWXYZABCDEFGHIJKLMnopqrstuvwxyzabcdefghijklm"};
|
||||
char buf[1024];
|
||||
int pass = 1;
|
||||
|
||||
// To encode, just apply ROT-13.
|
||||
strcpy(buf, text);
|
||||
rot13(buf);
|
||||
pass = pass && !strcmp(code, buf);
|
||||
|
||||
// To decode, just re-apply ROT-13.
|
||||
rot13(buf);
|
||||
pass = pass && !strcmp(text, buf);
|
||||
|
||||
return(pass);
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
printf("ROT-13 tests: %s\n", rot13_test() ? "SUCCEEDED" : "FAILED");
|
||||
|
||||
return(0);
|
||||
}
|
149
lib/crypto-algorithms/sha1.c
Normal file
149
lib/crypto-algorithms/sha1.c
Normal file
|
@ -0,0 +1,149 @@
|
|||
/*********************************************************************
|
||||
* Filename: sha1.c
|
||||
* Author: Brad Conte (brad AT bradconte.com)
|
||||
* Copyright:
|
||||
* Disclaimer: This code is presented "as is" without any guarantees.
|
||||
* Details: Implementation of the SHA1 hashing algorithm.
|
||||
Algorithm specification can be found here:
|
||||
* http://csrc.nist.gov/publications/fips/fips180-2/fips180-2withchangenotice.pdf
|
||||
This implementation uses little endian byte order.
|
||||
*********************************************************************/
|
||||
|
||||
/*************************** HEADER FILES ***************************/
|
||||
#include <stdlib.h>
|
||||
#include <memory.h>
|
||||
#include "sha1.h"
|
||||
|
||||
/****************************** MACROS ******************************/
|
||||
#define ROTLEFT(a, b) ((a << b) | (a >> (32 - b)))
|
||||
|
||||
/*********************** FUNCTION DEFINITIONS ***********************/
|
||||
void sha1_transform(SHA1_CTX *ctx, const BYTE data[])
|
||||
{
|
||||
WORD a, b, c, d, e, i, j, t, m[80];
|
||||
|
||||
for (i = 0, j = 0; i < 16; ++i, j += 4)
|
||||
m[i] = (data[j] << 24) + (data[j + 1] << 16) + (data[j + 2] << 8) + (data[j + 3]);
|
||||
for ( ; i < 80; ++i) {
|
||||
m[i] = (m[i - 3] ^ m[i - 8] ^ m[i - 14] ^ m[i - 16]);
|
||||
m[i] = (m[i] << 1) | (m[i] >> 31);
|
||||
}
|
||||
|
||||
a = ctx->state[0];
|
||||
b = ctx->state[1];
|
||||
c = ctx->state[2];
|
||||
d = ctx->state[3];
|
||||
e = ctx->state[4];
|
||||
|
||||
for (i = 0; i < 20; ++i) {
|
||||
t = ROTLEFT(a, 5) + ((b & c) ^ (~b & d)) + e + ctx->k[0] + m[i];
|
||||
e = d;
|
||||
d = c;
|
||||
c = ROTLEFT(b, 30);
|
||||
b = a;
|
||||
a = t;
|
||||
}
|
||||
for ( ; i < 40; ++i) {
|
||||
t = ROTLEFT(a, 5) + (b ^ c ^ d) + e + ctx->k[1] + m[i];
|
||||
e = d;
|
||||
d = c;
|
||||
c = ROTLEFT(b, 30);
|
||||
b = a;
|
||||
a = t;
|
||||
}
|
||||
for ( ; i < 60; ++i) {
|
||||
t = ROTLEFT(a, 5) + ((b & c) ^ (b & d) ^ (c & d)) + e + ctx->k[2] + m[i];
|
||||
e = d;
|
||||
d = c;
|
||||
c = ROTLEFT(b, 30);
|
||||
b = a;
|
||||
a = t;
|
||||
}
|
||||
for ( ; i < 80; ++i) {
|
||||
t = ROTLEFT(a, 5) + (b ^ c ^ d) + e + ctx->k[3] + m[i];
|
||||
e = d;
|
||||
d = c;
|
||||
c = ROTLEFT(b, 30);
|
||||
b = a;
|
||||
a = t;
|
||||
}
|
||||
|
||||
ctx->state[0] += a;
|
||||
ctx->state[1] += b;
|
||||
ctx->state[2] += c;
|
||||
ctx->state[3] += d;
|
||||
ctx->state[4] += e;
|
||||
}
|
||||
|
||||
void sha1_init(SHA1_CTX *ctx)
|
||||
{
|
||||
ctx->datalen = 0;
|
||||
ctx->bitlen = 0;
|
||||
ctx->state[0] = 0x67452301;
|
||||
ctx->state[1] = 0xEFCDAB89;
|
||||
ctx->state[2] = 0x98BADCFE;
|
||||
ctx->state[3] = 0x10325476;
|
||||
ctx->state[4] = 0xc3d2e1f0;
|
||||
ctx->k[0] = 0x5a827999;
|
||||
ctx->k[1] = 0x6ed9eba1;
|
||||
ctx->k[2] = 0x8f1bbcdc;
|
||||
ctx->k[3] = 0xca62c1d6;
|
||||
}
|
||||
|
||||
void sha1_update(SHA1_CTX *ctx, const BYTE data[], size_t len)
|
||||
{
|
||||
size_t i;
|
||||
|
||||
for (i = 0; i < len; ++i) {
|
||||
ctx->data[ctx->datalen] = data[i];
|
||||
ctx->datalen++;
|
||||
if (ctx->datalen == 64) {
|
||||
sha1_transform(ctx, ctx->data);
|
||||
ctx->bitlen += 512;
|
||||
ctx->datalen = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void sha1_final(SHA1_CTX *ctx, BYTE hash[])
|
||||
{
|
||||
WORD i;
|
||||
|
||||
i = ctx->datalen;
|
||||
|
||||
// Pad whatever data is left in the buffer.
|
||||
if (ctx->datalen < 56) {
|
||||
ctx->data[i++] = 0x80;
|
||||
while (i < 56)
|
||||
ctx->data[i++] = 0x00;
|
||||
}
|
||||
else {
|
||||
ctx->data[i++] = 0x80;
|
||||
while (i < 64)
|
||||
ctx->data[i++] = 0x00;
|
||||
sha1_transform(ctx, ctx->data);
|
||||
memset(ctx->data, 0, 56);
|
||||
}
|
||||
|
||||
// Append to the padding the total message's length in bits and transform.
|
||||
ctx->bitlen += ctx->datalen * 8;
|
||||
ctx->data[63] = ctx->bitlen;
|
||||
ctx->data[62] = ctx->bitlen >> 8;
|
||||
ctx->data[61] = ctx->bitlen >> 16;
|
||||
ctx->data[60] = ctx->bitlen >> 24;
|
||||
ctx->data[59] = ctx->bitlen >> 32;
|
||||
ctx->data[58] = ctx->bitlen >> 40;
|
||||
ctx->data[57] = ctx->bitlen >> 48;
|
||||
ctx->data[56] = ctx->bitlen >> 56;
|
||||
sha1_transform(ctx, ctx->data);
|
||||
|
||||
// Since this implementation uses little endian byte ordering and MD uses big endian,
|
||||
// reverse all the bytes when copying the final state to the output hash.
|
||||
for (i = 0; i < 4; ++i) {
|
||||
hash[i] = (ctx->state[0] >> (24 - i * 8)) & 0x000000ff;
|
||||
hash[i + 4] = (ctx->state[1] >> (24 - i * 8)) & 0x000000ff;
|
||||
hash[i + 8] = (ctx->state[2] >> (24 - i * 8)) & 0x000000ff;
|
||||
hash[i + 12] = (ctx->state[3] >> (24 - i * 8)) & 0x000000ff;
|
||||
hash[i + 16] = (ctx->state[4] >> (24 - i * 8)) & 0x000000ff;
|
||||
}
|
||||
}
|
35
lib/crypto-algorithms/sha1.h
Normal file
35
lib/crypto-algorithms/sha1.h
Normal file
|
@ -0,0 +1,35 @@
|
|||
/*********************************************************************
|
||||
* Filename: sha1.h
|
||||
* Author: Brad Conte (brad AT bradconte.com)
|
||||
* Copyright:
|
||||
* Disclaimer: This code is presented "as is" without any guarantees.
|
||||
* Details: Defines the API for the corresponding SHA1 implementation.
|
||||
*********************************************************************/
|
||||
|
||||
#ifndef SHA1_H
|
||||
#define SHA1_H
|
||||
|
||||
/*************************** HEADER FILES ***************************/
|
||||
#include <stddef.h>
|
||||
|
||||
/****************************** MACROS ******************************/
|
||||
#define SHA1_BLOCK_SIZE 20 // SHA1 outputs a 20 byte digest
|
||||
|
||||
/**************************** DATA TYPES ****************************/
|
||||
typedef unsigned char BYTE; // 8-bit byte
|
||||
typedef unsigned int WORD; // 32-bit word, change to "long" for 16-bit machines
|
||||
|
||||
typedef struct {
|
||||
BYTE data[64];
|
||||
WORD datalen;
|
||||
unsigned long long bitlen;
|
||||
WORD state[5];
|
||||
WORD k[4];
|
||||
} SHA1_CTX;
|
||||
|
||||
/*********************** FUNCTION DECLARATIONS **********************/
|
||||
void sha1_init(SHA1_CTX *ctx);
|
||||
void sha1_update(SHA1_CTX *ctx, const BYTE data[], size_t len);
|
||||
void sha1_final(SHA1_CTX *ctx, BYTE hash[]);
|
||||
|
||||
#endif // SHA1_H
|
58
lib/crypto-algorithms/sha1_test.c
Normal file
58
lib/crypto-algorithms/sha1_test.c
Normal file
|
@ -0,0 +1,58 @@
|
|||
/*********************************************************************
|
||||
* Filename: sha1_test.c
|
||||
* Author: Brad Conte (brad AT bradconte.com)
|
||||
* Copyright:
|
||||
* Disclaimer: This code is presented "as is" without any guarantees.
|
||||
* Details: Performs known-answer tests on the corresponding SHA1
|
||||
implementation. These tests do not encompass the full
|
||||
range of available test vectors, however, if the tests
|
||||
pass it is very, very likely that the code is correct
|
||||
and was compiled properly. This code also serves as
|
||||
example usage of the functions.
|
||||
*********************************************************************/
|
||||
|
||||
/*************************** HEADER FILES ***************************/
|
||||
#include <stdio.h>
|
||||
#include <memory.h>
|
||||
#include <string.h>
|
||||
#include "sha1.h"
|
||||
|
||||
/*********************** FUNCTION DEFINITIONS ***********************/
|
||||
int sha1_test()
|
||||
{
|
||||
BYTE text1[] = {"abc"};
|
||||
BYTE text2[] = {"abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq"};
|
||||
BYTE text3[] = {"aaaaaaaaaa"};
|
||||
BYTE hash1[SHA1_BLOCK_SIZE] = {0xa9,0x99,0x3e,0x36,0x47,0x06,0x81,0x6a,0xba,0x3e,0x25,0x71,0x78,0x50,0xc2,0x6c,0x9c,0xd0,0xd8,0x9d};
|
||||
BYTE hash2[SHA1_BLOCK_SIZE] = {0x84,0x98,0x3e,0x44,0x1c,0x3b,0xd2,0x6e,0xba,0xae,0x4a,0xa1,0xf9,0x51,0x29,0xe5,0xe5,0x46,0x70,0xf1};
|
||||
BYTE hash3[SHA1_BLOCK_SIZE] = {0x34,0xaa,0x97,0x3c,0xd4,0xc4,0xda,0xa4,0xf6,0x1e,0xeb,0x2b,0xdb,0xad,0x27,0x31,0x65,0x34,0x01,0x6f};
|
||||
BYTE buf[SHA1_BLOCK_SIZE];
|
||||
int idx;
|
||||
SHA1_CTX ctx;
|
||||
int pass = 1;
|
||||
|
||||
sha1_init(&ctx);
|
||||
sha1_update(&ctx, text1, strlen(text1));
|
||||
sha1_final(&ctx, buf);
|
||||
pass = pass && !memcmp(hash1, buf, SHA1_BLOCK_SIZE);
|
||||
|
||||
sha1_init(&ctx);
|
||||
sha1_update(&ctx, text2, strlen(text2));
|
||||
sha1_final(&ctx, buf);
|
||||
pass = pass && !memcmp(hash2, buf, SHA1_BLOCK_SIZE);
|
||||
|
||||
sha1_init(&ctx);
|
||||
for (idx = 0; idx < 100000; ++idx)
|
||||
sha1_update(&ctx, text3, strlen(text3));
|
||||
sha1_final(&ctx, buf);
|
||||
pass = pass && !memcmp(hash3, buf, SHA1_BLOCK_SIZE);
|
||||
|
||||
return(pass);
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
printf("SHA1 tests: %s\n", sha1_test() ? "SUCCEEDED" : "FAILED");
|
||||
|
||||
return(0);
|
||||
}
|
159
lib/crypto-algorithms/sha256.c
Normal file
159
lib/crypto-algorithms/sha256.c
Normal file
|
@ -0,0 +1,159 @@
|
|||
/*********************************************************************
|
||||
* Filename: sha256.c
|
||||
* Author: Brad Conte (brad AT bradconte.com)
|
||||
* Copyright:
|
||||
* Disclaimer: This code is presented "as is" without any guarantees.
|
||||
* Details: Implementation of the SHA-256 hashing algorithm.
|
||||
SHA-256 is one of the three algorithms in the SHA2
|
||||
specification. The others, SHA-384 and SHA-512, are not
|
||||
offered in this implementation.
|
||||
Algorithm specification can be found here:
|
||||
* http://csrc.nist.gov/publications/fips/fips180-2/fips180-2withchangenotice.pdf
|
||||
This implementation uses little endian byte order.
|
||||
*********************************************************************/
|
||||
|
||||
/*************************** HEADER FILES ***************************/
|
||||
#include <stdlib.h>
|
||||
#include <memory.h>
|
||||
#include <string.h>
|
||||
#include "sha256.h"
|
||||
|
||||
/****************************** MACROS ******************************/
|
||||
#define ROTLEFT(a,b) (((a) << (b)) | ((a) >> (32-(b))))
|
||||
#define ROTRIGHT(a,b) (((a) >> (b)) | ((a) << (32-(b))))
|
||||
|
||||
#define CH(x,y,z) (((x) & (y)) ^ (~(x) & (z)))
|
||||
#define MAJ(x,y,z) (((x) & (y)) ^ ((x) & (z)) ^ ((y) & (z)))
|
||||
#define EP0(x) (ROTRIGHT(x,2) ^ ROTRIGHT(x,13) ^ ROTRIGHT(x,22))
|
||||
#define EP1(x) (ROTRIGHT(x,6) ^ ROTRIGHT(x,11) ^ ROTRIGHT(x,25))
|
||||
#define SIG0(x) (ROTRIGHT(x,7) ^ ROTRIGHT(x,18) ^ ((x) >> 3))
|
||||
#define SIG1(x) (ROTRIGHT(x,17) ^ ROTRIGHT(x,19) ^ ((x) >> 10))
|
||||
|
||||
/**************************** VARIABLES *****************************/
|
||||
static const WORD k[64] = {
|
||||
0x428a2f98,0x71374491,0xb5c0fbcf,0xe9b5dba5,0x3956c25b,0x59f111f1,0x923f82a4,0xab1c5ed5,
|
||||
0xd807aa98,0x12835b01,0x243185be,0x550c7dc3,0x72be5d74,0x80deb1fe,0x9bdc06a7,0xc19bf174,
|
||||
0xe49b69c1,0xefbe4786,0x0fc19dc6,0x240ca1cc,0x2de92c6f,0x4a7484aa,0x5cb0a9dc,0x76f988da,
|
||||
0x983e5152,0xa831c66d,0xb00327c8,0xbf597fc7,0xc6e00bf3,0xd5a79147,0x06ca6351,0x14292967,
|
||||
0x27b70a85,0x2e1b2138,0x4d2c6dfc,0x53380d13,0x650a7354,0x766a0abb,0x81c2c92e,0x92722c85,
|
||||
0xa2bfe8a1,0xa81a664b,0xc24b8b70,0xc76c51a3,0xd192e819,0xd6990624,0xf40e3585,0x106aa070,
|
||||
0x19a4c116,0x1e376c08,0x2748774c,0x34b0bcb5,0x391c0cb3,0x4ed8aa4a,0x5b9cca4f,0x682e6ff3,
|
||||
0x748f82ee,0x78a5636f,0x84c87814,0x8cc70208,0x90befffa,0xa4506ceb,0xbef9a3f7,0xc67178f2
|
||||
};
|
||||
|
||||
/*********************** FUNCTION DEFINITIONS ***********************/
|
||||
void sha256_transform(SHA256_CTX *ctx, const BYTE data[])
|
||||
{
|
||||
WORD a, b, c, d, e, f, g, h, i, j, t1, t2, m[64];
|
||||
|
||||
for (i = 0, j = 0; i < 16; ++i, j += 4)
|
||||
m[i] = (data[j] << 24) | (data[j + 1] << 16) | (data[j + 2] << 8) | (data[j + 3]);
|
||||
for ( ; i < 64; ++i)
|
||||
m[i] = SIG1(m[i - 2]) + m[i - 7] + SIG0(m[i - 15]) + m[i - 16];
|
||||
|
||||
a = ctx->state[0];
|
||||
b = ctx->state[1];
|
||||
c = ctx->state[2];
|
||||
d = ctx->state[3];
|
||||
e = ctx->state[4];
|
||||
f = ctx->state[5];
|
||||
g = ctx->state[6];
|
||||
h = ctx->state[7];
|
||||
|
||||
for (i = 0; i < 64; ++i) {
|
||||
t1 = h + EP1(e) + CH(e,f,g) + k[i] + m[i];
|
||||
t2 = EP0(a) + MAJ(a,b,c);
|
||||
h = g;
|
||||
g = f;
|
||||
f = e;
|
||||
e = d + t1;
|
||||
d = c;
|
||||
c = b;
|
||||
b = a;
|
||||
a = t1 + t2;
|
||||
}
|
||||
|
||||
ctx->state[0] += a;
|
||||
ctx->state[1] += b;
|
||||
ctx->state[2] += c;
|
||||
ctx->state[3] += d;
|
||||
ctx->state[4] += e;
|
||||
ctx->state[5] += f;
|
||||
ctx->state[6] += g;
|
||||
ctx->state[7] += h;
|
||||
}
|
||||
|
||||
void sha256_init(SHA256_CTX *ctx)
|
||||
{
|
||||
ctx->datalen = 0;
|
||||
ctx->bitlen = 0;
|
||||
ctx->state[0] = 0x6a09e667;
|
||||
ctx->state[1] = 0xbb67ae85;
|
||||
ctx->state[2] = 0x3c6ef372;
|
||||
ctx->state[3] = 0xa54ff53a;
|
||||
ctx->state[4] = 0x510e527f;
|
||||
ctx->state[5] = 0x9b05688c;
|
||||
ctx->state[6] = 0x1f83d9ab;
|
||||
ctx->state[7] = 0x5be0cd19;
|
||||
}
|
||||
|
||||
void sha256_update(SHA256_CTX *ctx, const BYTE data[], size_t len)
|
||||
{
|
||||
WORD i;
|
||||
|
||||
for (i = 0; i < len; ++i) {
|
||||
ctx->data[ctx->datalen] = data[i];
|
||||
ctx->datalen++;
|
||||
if (ctx->datalen == 64) {
|
||||
sha256_transform(ctx, ctx->data);
|
||||
ctx->bitlen += 512;
|
||||
ctx->datalen = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void sha256_final(SHA256_CTX *ctx, BYTE hash[])
|
||||
{
|
||||
WORD i;
|
||||
|
||||
i = ctx->datalen;
|
||||
|
||||
// Pad whatever data is left in the buffer.
|
||||
if (ctx->datalen < 56) {
|
||||
ctx->data[i++] = 0x80;
|
||||
while (i < 56)
|
||||
ctx->data[i++] = 0x00;
|
||||
}
|
||||
else {
|
||||
ctx->data[i++] = 0x80;
|
||||
while (i < 64)
|
||||
ctx->data[i++] = 0x00;
|
||||
sha256_transform(ctx, ctx->data);
|
||||
memset(ctx->data, 0, 56);
|
||||
}
|
||||
|
||||
// Append to the padding the total message's length in bits and transform.
|
||||
ctx->bitlen += ctx->datalen * 8;
|
||||
ctx->data[63] = ctx->bitlen;
|
||||
ctx->data[62] = ctx->bitlen >> 8;
|
||||
ctx->data[61] = ctx->bitlen >> 16;
|
||||
ctx->data[60] = ctx->bitlen >> 24;
|
||||
ctx->data[59] = ctx->bitlen >> 32;
|
||||
ctx->data[58] = ctx->bitlen >> 40;
|
||||
ctx->data[57] = ctx->bitlen >> 48;
|
||||
ctx->data[56] = ctx->bitlen >> 56;
|
||||
sha256_transform(ctx, ctx->data);
|
||||
|
||||
// Since this implementation uses little endian byte ordering and SHA uses big endian,
|
||||
// reverse all the bytes when copying the final state to the output hash.
|
||||
for (i = 0; i < 4; ++i) {
|
||||
hash[i] = (ctx->state[0] >> (24 - i * 8)) & 0x000000ff;
|
||||
hash[i + 4] = (ctx->state[1] >> (24 - i * 8)) & 0x000000ff;
|
||||
hash[i + 8] = (ctx->state[2] >> (24 - i * 8)) & 0x000000ff;
|
||||
hash[i + 12] = (ctx->state[3] >> (24 - i * 8)) & 0x000000ff;
|
||||
hash[i + 16] = (ctx->state[4] >> (24 - i * 8)) & 0x000000ff;
|
||||
hash[i + 20] = (ctx->state[5] >> (24 - i * 8)) & 0x000000ff;
|
||||
hash[i + 24] = (ctx->state[6] >> (24 - i * 8)) & 0x000000ff;
|
||||
hash[i + 28] = (ctx->state[7] >> (24 - i * 8)) & 0x000000ff;
|
||||
}
|
||||
}
|
35
lib/crypto-algorithms/sha256.h
Normal file
35
lib/crypto-algorithms/sha256.h
Normal file
|
@ -0,0 +1,35 @@
|
|||
/*********************************************************************
|
||||
* Filename: sha256.h
|
||||
* Author: Brad Conte (brad AT bradconte.com)
|
||||
* Copyright:
|
||||
* Disclaimer: This code is presented "as is" without any guarantees.
|
||||
* Details: Defines the API for the corresponding SHA1 implementation.
|
||||
*********************************************************************/
|
||||
|
||||
#ifndef SHA256_H
|
||||
#define SHA256_H
|
||||
|
||||
/*************************** HEADER FILES ***************************/
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
/****************************** MACROS ******************************/
|
||||
#define SHA256_BLOCK_SIZE 32 // SHA256 outputs a 32 byte digest
|
||||
|
||||
/**************************** DATA TYPES ****************************/
|
||||
typedef uint8_t BYTE; // 8-bit byte
|
||||
typedef uint32_t WORD; // 32-bit word, change to "long" for 16-bit machines
|
||||
|
||||
typedef struct {
|
||||
BYTE data[64];
|
||||
WORD datalen;
|
||||
unsigned long long bitlen;
|
||||
WORD state[8];
|
||||
} SHA256_CTX;
|
||||
|
||||
/*********************** FUNCTION DECLARATIONS **********************/
|
||||
void sha256_init(SHA256_CTX *ctx);
|
||||
void sha256_update(SHA256_CTX *ctx, const BYTE data[], size_t len);
|
||||
void sha256_final(SHA256_CTX *ctx, BYTE hash[]);
|
||||
|
||||
#endif // SHA256_H
|
61
lib/crypto-algorithms/sha256_test.c
Normal file
61
lib/crypto-algorithms/sha256_test.c
Normal file
|
@ -0,0 +1,61 @@
|
|||
/*********************************************************************
|
||||
* Filename: sha256.c
|
||||
* Author: Brad Conte (brad AT bradconte.com)
|
||||
* Copyright:
|
||||
* Disclaimer: This code is presented "as is" without any guarantees.
|
||||
* Details: Performs known-answer tests on the corresponding SHA1
|
||||
implementation. These tests do not encompass the full
|
||||
range of available test vectors, however, if the tests
|
||||
pass it is very, very likely that the code is correct
|
||||
and was compiled properly. This code also serves as
|
||||
example usage of the functions.
|
||||
*********************************************************************/
|
||||
|
||||
/*************************** HEADER FILES ***************************/
|
||||
#include <stdio.h>
|
||||
#include <memory.h>
|
||||
#include <string.h>
|
||||
#include "sha256.h"
|
||||
|
||||
/*********************** FUNCTION DEFINITIONS ***********************/
|
||||
int sha256_test()
|
||||
{
|
||||
BYTE text1[] = {"abc"};
|
||||
BYTE text2[] = {"abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq"};
|
||||
BYTE text3[] = {"aaaaaaaaaa"};
|
||||
BYTE hash1[SHA256_BLOCK_SIZE] = {0xba,0x78,0x16,0xbf,0x8f,0x01,0xcf,0xea,0x41,0x41,0x40,0xde,0x5d,0xae,0x22,0x23,
|
||||
0xb0,0x03,0x61,0xa3,0x96,0x17,0x7a,0x9c,0xb4,0x10,0xff,0x61,0xf2,0x00,0x15,0xad};
|
||||
BYTE hash2[SHA256_BLOCK_SIZE] = {0x24,0x8d,0x6a,0x61,0xd2,0x06,0x38,0xb8,0xe5,0xc0,0x26,0x93,0x0c,0x3e,0x60,0x39,
|
||||
0xa3,0x3c,0xe4,0x59,0x64,0xff,0x21,0x67,0xf6,0xec,0xed,0xd4,0x19,0xdb,0x06,0xc1};
|
||||
BYTE hash3[SHA256_BLOCK_SIZE] = {0xcd,0xc7,0x6e,0x5c,0x99,0x14,0xfb,0x92,0x81,0xa1,0xc7,0xe2,0x84,0xd7,0x3e,0x67,
|
||||
0xf1,0x80,0x9a,0x48,0xa4,0x97,0x20,0x0e,0x04,0x6d,0x39,0xcc,0xc7,0x11,0x2c,0xd0};
|
||||
BYTE buf[SHA256_BLOCK_SIZE];
|
||||
SHA256_CTX ctx;
|
||||
int idx;
|
||||
int pass = 1;
|
||||
|
||||
sha256_init(&ctx);
|
||||
sha256_update(&ctx, text1, strlen(text1));
|
||||
sha256_final(&ctx, buf);
|
||||
pass = pass && !memcmp(hash1, buf, SHA256_BLOCK_SIZE);
|
||||
|
||||
sha256_init(&ctx);
|
||||
sha256_update(&ctx, text2, strlen(text2));
|
||||
sha256_final(&ctx, buf);
|
||||
pass = pass && !memcmp(hash2, buf, SHA256_BLOCK_SIZE);
|
||||
|
||||
sha256_init(&ctx);
|
||||
for (idx = 0; idx < 100000; ++idx)
|
||||
sha256_update(&ctx, text3, strlen(text3));
|
||||
sha256_final(&ctx, buf);
|
||||
pass = pass && !memcmp(hash3, buf, SHA256_BLOCK_SIZE);
|
||||
|
||||
return(pass);
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
printf("SHA-256 tests: %s\n", sha256_test() ? "SUCCEEDED" : "FAILEd");
|
||||
|
||||
return(0);
|
||||
}
|
18
lib/curve25519-donna.h
Normal file
18
lib/curve25519-donna.h
Normal file
|
@ -0,0 +1,18 @@
|
|||
/* header file for the curve25519-donna implementation, because the
|
||||
* authors of that project don't supply one.
|
||||
*/
|
||||
#ifndef CURVE25519_DONNA_H
|
||||
#define CURVE25519_DONNA_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
extern int curve25519_donna(unsigned char *output, const unsigned char *a,
|
||||
const unsigned char *b);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
12
lib/curve25519-donna/.gitignore
vendored
Normal file
12
lib/curve25519-donna/.gitignore
vendored
Normal file
|
@ -0,0 +1,12 @@
|
|||
/curve25519-donna-c64.a
|
||||
/curve25519-donna.a
|
||||
/test-curve25519-donna
|
||||
/speed-curve25519-donna
|
||||
/test-curve25519-donna-c64
|
||||
/speed-curve25519-donna-c64
|
||||
/test-sc-curve25519-donna-c64
|
||||
/build
|
||||
*.o
|
||||
*.pyc
|
||||
/dist
|
||||
/MANIFEST
|
46
lib/curve25519-donna/LICENSE.md
Normal file
46
lib/curve25519-donna/LICENSE.md
Normal file
|
@ -0,0 +1,46 @@
|
|||
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 <agl@imperialviolet.org>
|
||||
|
||||
Derived from public domain C code by Daniel J. Bernstein <djb@cr.yp.to>
|
||||
|
||||
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.
|
56
lib/curve25519-donna/Makefile
Normal file
56
lib/curve25519-donna/Makefile
Normal file
|
@ -0,0 +1,56 @@
|
|||
CFLAGS=-Wmissing-prototypes -Wdeclaration-after-statement -O2 -Wall
|
||||
CFLAGS_32=-m32
|
||||
|
||||
targets: curve25519-donna.a curve25519-donna-c64.a
|
||||
|
||||
test: test-donna test-donna-c64
|
||||
|
||||
clean:
|
||||
rm -f *.o *.a *.pp test-curve25519-donna test-curve25519-donna-c64 speed-curve25519-donna speed-curve25519-donna-c64 test-noncanon-curve25519-donna test-noncanon-curve25519-donna-c64
|
||||
|
||||
curve25519-donna.a: curve25519-donna.o
|
||||
ar -rc curve25519-donna.a curve25519-donna.o
|
||||
ranlib curve25519-donna.a
|
||||
|
||||
curve25519-donna.o: curve25519-donna.c
|
||||
gcc -c curve25519-donna.c $(CFLAGS) $(CFLAGS_32)
|
||||
|
||||
curve25519-donna-c64.a: curve25519-donna-c64.o
|
||||
ar -rc curve25519-donna-c64.a curve25519-donna-c64.o
|
||||
ranlib curve25519-donna-c64.a
|
||||
|
||||
curve25519-donna-c64.o: curve25519-donna-c64.c
|
||||
gcc -c curve25519-donna-c64.c $(CFLAGS)
|
||||
|
||||
test-donna: test-curve25519-donna
|
||||
./test-curve25519-donna | head -123456 | tail -1
|
||||
|
||||
test-donna-c64: test-curve25519-donna-c64
|
||||
./test-curve25519-donna-c64 | head -123456 | tail -1
|
||||
|
||||
test-curve25519-donna: test-curve25519.c curve25519-donna.a
|
||||
gcc -o test-curve25519-donna test-curve25519.c curve25519-donna.a $(CFLAGS) $(CFLAGS_32)
|
||||
|
||||
test-curve25519-donna-c64: test-curve25519.c curve25519-donna-c64.a
|
||||
gcc -o test-curve25519-donna-c64 test-curve25519.c curve25519-donna-c64.a $(CFLAGS)
|
||||
|
||||
speed-curve25519-donna: speed-curve25519.c curve25519-donna.a
|
||||
gcc -o speed-curve25519-donna speed-curve25519.c curve25519-donna.a $(CFLAGS) $(CFLAGS_32)
|
||||
|
||||
speed-curve25519-donna-c64: speed-curve25519.c curve25519-donna-c64.a
|
||||
gcc -o speed-curve25519-donna-c64 speed-curve25519.c curve25519-donna-c64.a $(CFLAGS)
|
||||
|
||||
test-sc-curve25519-donna-c64: test-sc-curve25519.c curve25519-donna-c64.a
|
||||
gcc -o test-sc-curve25519-donna-c64 -O test-sc-curve25519.c curve25519-donna-c64.a test-sc-curve25519.s $(CFLAGS)
|
||||
|
||||
test-noncanon-donna: test-noncanon-curve25519-donna
|
||||
./test-noncanon-curve25519-donna
|
||||
|
||||
test-noncanon-donna-c64: test-noncanon-curve25519-donna-c64
|
||||
./test-noncanon-curve25519-donna-c64
|
||||
|
||||
test-noncanon-curve25519-donna: test-noncanon.c curve25519-donna.a
|
||||
gcc -o test-noncanon-curve25519-donna test-noncanon.c curve25519-donna.a $(CFLAGS) $(CFLAGS_32)
|
||||
|
||||
test-noncanon-curve25519-donna-c64: test-noncanon.c curve25519-donna-c64.a
|
||||
gcc -o test-noncanon-curve25519-donna-c64 test-noncanon.c curve25519-donna-c64.a $(CFLAGS)
|
40
lib/curve25519-donna/README
Normal file
40
lib/curve25519-donna/README
Normal file
|
@ -0,0 +1,40 @@
|
|||
See http://code.google.com/p/curve25519-donna/ for details.
|
||||
|
||||
BUILDING:
|
||||
|
||||
If you run `make`, two .a archives will be built, similar to djb's curve25519
|
||||
code. Alternatively, read on:
|
||||
|
||||
The C implementation is contained within curve25519-donna.c. It has no external
|
||||
dependancies and is BSD licenced. You can copy/include/link it directly in with
|
||||
your program. Recommended C flags: -O2
|
||||
|
||||
The x86-64 bit implementation is contained within curve25519-donna-x86-64.c and
|
||||
curve25519-donna-x86-64.s. Build like this:
|
||||
|
||||
% cpp curve25519-donna-x86-64.s > curve25519-donna-x86-64.s.pp
|
||||
% as -o curve25519-donna-x86-64.s.o curve25519-donna-x86-64.s.pp
|
||||
% gcc -O2 -c curve25519-donna-x86-64.c
|
||||
|
||||
Then the two .o files can be linked in
|
||||
|
||||
USAGE:
|
||||
|
||||
The usage is exactly the same as djb's code (as described at
|
||||
http://cr.yp.to/ecdh.html) expect that the function is called curve25519_donna.
|
||||
|
||||
In short,
|
||||
|
||||
To generate a private key just generate 32 random bytes.
|
||||
|
||||
To generate the public key, just do:
|
||||
|
||||
static const uint8_t basepoint[32] = {9};
|
||||
curve25519_donna(mypublic, mysecret, basepoint);
|
||||
|
||||
To generate an agreed key do:
|
||||
|
||||
uint8_t shared_key[32];
|
||||
curve25519_donna(shared_key, mysecret, theirpublic);
|
||||
|
||||
And hash the shared_key with a cryptographic hash function before using.
|
118
lib/curve25519-donna/contrib/Curve25519Donna.c
Normal file
118
lib/curve25519-donna/contrib/Curve25519Donna.c
Normal file
|
@ -0,0 +1,118 @@
|
|||
/*
|
||||
James Robson
|
||||
Public domain.
|
||||
*/
|
||||
|
||||
#include "Curve25519Donna.h"
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
extern void curve25519_donna(unsigned char *output, const unsigned char *a,
|
||||
const unsigned char *b);
|
||||
|
||||
unsigned char*
|
||||
as_unsigned_char_array(JNIEnv* env, jbyteArray array, int* len);
|
||||
|
||||
jbyteArray as_byte_array(JNIEnv* env, unsigned char* buf, int len);
|
||||
|
||||
|
||||
jbyteArray as_byte_array(JNIEnv* env, unsigned char* buf, int len) {
|
||||
jbyteArray array = (*env)->NewByteArray(env, len);
|
||||
(*env)->SetByteArrayRegion(env, array, 0, len, (jbyte*)buf);
|
||||
|
||||
//int i;
|
||||
//for (i = 0;i < len;++i) printf("%02x",(unsigned int) buf[i]); printf(" ");
|
||||
//printf("\n");
|
||||
|
||||
return array;
|
||||
}
|
||||
|
||||
unsigned char*
|
||||
as_unsigned_char_array(JNIEnv* env, jbyteArray array, int* len) {
|
||||
|
||||
*len = (*env)->GetArrayLength(env, array);
|
||||
unsigned char* buf = (unsigned char*)calloc(*len+1, sizeof(char));
|
||||
(*env)->GetByteArrayRegion (env, array, 0, *len, (jbyte*)buf);
|
||||
return buf;
|
||||
|
||||
}
|
||||
|
||||
JNIEXPORT jbyteArray JNICALL Java_Curve25519Donna_curve25519Donna
|
||||
(JNIEnv *env, jobject obj, jbyteArray a, jbyteArray b) {
|
||||
|
||||
unsigned char o[32] = {0};
|
||||
int l1, l2;
|
||||
unsigned char* a1 = as_unsigned_char_array(env, a, &l1);
|
||||
unsigned char* b1 = as_unsigned_char_array(env, b, &l2);
|
||||
|
||||
if ( !(l1 == 32 && l2 == 32) ) {
|
||||
fprintf(stderr, "Error, must be length 32");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
curve25519_donna(o, (const unsigned char*)a1, (const unsigned char*)b1);
|
||||
|
||||
free(a1);
|
||||
free(b1);
|
||||
|
||||
return as_byte_array(env, (unsigned char*)o, 32);
|
||||
}
|
||||
|
||||
JNIEXPORT jbyteArray JNICALL Java_Curve25519Donna_makePrivate
|
||||
(JNIEnv *env, jobject obj, jbyteArray secret) {
|
||||
|
||||
int len;
|
||||
unsigned char* k = as_unsigned_char_array(env, secret, &len);
|
||||
|
||||
if (len != 32) {
|
||||
fprintf(stderr, "Error, must be length 32");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
k[0] &= 248;
|
||||
k[31] &= 127;
|
||||
k[31] |= 64;
|
||||
return as_byte_array(env, k, 32);
|
||||
}
|
||||
|
||||
JNIEXPORT jbyteArray JNICALL Java_Curve25519Donna_getPublic
|
||||
(JNIEnv *env, jobject obj, jbyteArray privkey) {
|
||||
|
||||
int len;
|
||||
unsigned char* private = as_unsigned_char_array(env, privkey, &len);
|
||||
|
||||
if (len != 32) {
|
||||
fprintf(stderr, "Error, must be length 32");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
unsigned char pubkey[32];
|
||||
unsigned char basepoint[32] = {9};
|
||||
|
||||
curve25519_donna(pubkey, private, basepoint);
|
||||
return as_byte_array(env, (unsigned char*)pubkey, 32);
|
||||
}
|
||||
|
||||
JNIEXPORT jbyteArray JNICALL Java_Curve25519Donna_makeSharedSecret
|
||||
(JNIEnv *env, jobject obj, jbyteArray privkey, jbyteArray their_pubkey) {
|
||||
|
||||
unsigned char shared_secret[32];
|
||||
|
||||
int l1, l2;
|
||||
unsigned char* private = as_unsigned_char_array(env, privkey, &l1);
|
||||
unsigned char* pubkey = as_unsigned_char_array(env, their_pubkey, &l2);
|
||||
|
||||
if ( !(l1 == 32 && l2 == 32) ) {
|
||||
fprintf(stderr, "Error, must be length 32");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
curve25519_donna(shared_secret, private, pubkey);
|
||||
return as_byte_array(env, (unsigned char*)shared_secret, 32);
|
||||
}
|
||||
|
||||
JNIEXPORT void JNICALL Java_Curve25519Donna_helowrld
|
||||
(JNIEnv *env, jobject obj) {
|
||||
printf("helowrld\n");
|
||||
}
|
53
lib/curve25519-donna/contrib/Curve25519Donna.h
Normal file
53
lib/curve25519-donna/contrib/Curve25519Donna.h
Normal file
|
@ -0,0 +1,53 @@
|
|||
/* DO NOT EDIT THIS FILE - it is machine generated */
|
||||
#include <jni.h>
|
||||
/* Header for class Curve25519Donna */
|
||||
|
||||
#ifndef _Included_Curve25519Donna
|
||||
#define _Included_Curve25519Donna
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
/*
|
||||
* Class: Curve25519Donna
|
||||
* Method: curve25519Donna
|
||||
* Signature: ([B[B)[B
|
||||
*/
|
||||
JNIEXPORT jbyteArray JNICALL Java_Curve25519Donna_curve25519Donna
|
||||
(JNIEnv *, jobject, jbyteArray, jbyteArray);
|
||||
|
||||
/*
|
||||
* Class: Curve25519Donna
|
||||
* Method: makePrivate
|
||||
* Signature: ([B)[B
|
||||
*/
|
||||
JNIEXPORT jbyteArray JNICALL Java_Curve25519Donna_makePrivate
|
||||
(JNIEnv *, jobject, jbyteArray);
|
||||
|
||||
/*
|
||||
* Class: Curve25519Donna
|
||||
* Method: getPublic
|
||||
* Signature: ([B)[B
|
||||
*/
|
||||
JNIEXPORT jbyteArray JNICALL Java_Curve25519Donna_getPublic
|
||||
(JNIEnv *, jobject, jbyteArray);
|
||||
|
||||
/*
|
||||
* Class: Curve25519Donna
|
||||
* Method: makeSharedSecret
|
||||
* Signature: ([B[B)[B
|
||||
*/
|
||||
JNIEXPORT jbyteArray JNICALL Java_Curve25519Donna_makeSharedSecret
|
||||
(JNIEnv *, jobject, jbyteArray, jbyteArray);
|
||||
|
||||
/*
|
||||
* Class: Curve25519Donna
|
||||
* Method: helowrld
|
||||
* Signature: ()V
|
||||
*/
|
||||
JNIEXPORT void JNICALL Java_Curve25519Donna_helowrld
|
||||
(JNIEnv *, jobject);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
#endif
|
77
lib/curve25519-donna/contrib/Curve25519Donna.java
Normal file
77
lib/curve25519-donna/contrib/Curve25519Donna.java
Normal file
|
@ -0,0 +1,77 @@
|
|||
/*
|
||||
James Robson
|
||||
Public domain.
|
||||
*/
|
||||
|
||||
public class Curve25519Donna {
|
||||
|
||||
final protected static char[] hexArray = "0123456789ABCDEF".toCharArray();
|
||||
|
||||
public static String bytesToHex(byte[] bytes) {
|
||||
char[] hexChars = new char[bytes.length * 2];
|
||||
int v;
|
||||
for ( int j = 0; j < bytes.length; j++ ) {
|
||||
v = bytes[j] & 0xFF;
|
||||
hexChars[j * 2] = hexArray[v >>> 4];
|
||||
hexChars[j * 2 + 1] = hexArray[v & 0x0F];
|
||||
}
|
||||
return new String(hexChars);
|
||||
}
|
||||
|
||||
public native byte[] curve25519Donna(byte[] a, byte[] b);
|
||||
public native byte[] makePrivate(byte[] secret);
|
||||
public native byte[] getPublic(byte[] privkey);
|
||||
public native byte[] makeSharedSecret(byte[] privkey, byte[] theirPubKey);
|
||||
public native void helowrld();
|
||||
|
||||
// Uncomment if your Java is 32-bit:
|
||||
//static { System.loadLibrary("Curve25519Donna"); }
|
||||
|
||||
// Otherwise, load this 64-bit .jnilib:
|
||||
static { System.loadLibrary("Curve25519Donna_64"); }
|
||||
|
||||
/*
|
||||
To give the old tires a kick (OSX):
|
||||
java -cp `pwd` Curve25519Donna
|
||||
*/
|
||||
public static void main (String[] args) {
|
||||
|
||||
Curve25519Donna c = new Curve25519Donna();
|
||||
|
||||
// These should be 32 bytes long
|
||||
byte[] user1Secret = "abcdefghijklmnopqrstuvwxyz123456".getBytes();
|
||||
byte[] user2Secret = "654321zyxwvutsrqponmlkjihgfedcba".getBytes();
|
||||
|
||||
|
||||
// You can use the curve function directly...
|
||||
|
||||
//byte[] o = c.curve25519Donna(a, b);
|
||||
//System.out.println("o = " + bytesToHex(o));
|
||||
|
||||
|
||||
// ... but it's not really necessary. Just use the following
|
||||
// convenience methods:
|
||||
|
||||
byte[] privKey = c.makePrivate(user1Secret);
|
||||
byte[] pubKey = c.getPublic(privKey);
|
||||
|
||||
byte[] privKey2 = c.makePrivate(user2Secret);
|
||||
byte[] pubKey2 = c.getPublic(privKey2);
|
||||
|
||||
System.out.println("'user1' privKey = " + bytesToHex(privKey));
|
||||
System.out.println("'user1' pubKey = " + bytesToHex(pubKey));
|
||||
System.out.println("===================================================");
|
||||
|
||||
System.out.println("'user2' privKey = " + bytesToHex(privKey2));
|
||||
System.out.println("'user2' pubKey = " + bytesToHex(pubKey2));
|
||||
System.out.println("===================================================");
|
||||
|
||||
|
||||
byte[] ss1 = c.makeSharedSecret(privKey, pubKey2);
|
||||
System.out.println("'user1' computes shared secret: " + bytesToHex(ss1));
|
||||
|
||||
byte[] ss2 = c.makeSharedSecret(privKey2, pubKey);
|
||||
System.out.println("'user2' computes shared secret: " + bytesToHex(ss2));
|
||||
|
||||
}
|
||||
}
|
68
lib/curve25519-donna/contrib/make-snippets
Normal file
68
lib/curve25519-donna/contrib/make-snippets
Normal file
|
@ -0,0 +1,68 @@
|
|||
CFLAGS=-Wmissing-prototypes -Wdeclaration-after-statement -O2 -Wall
|
||||
CC=clang
|
||||
|
||||
|
||||
targets: curve25519-donna.a curve25519-donna-c64.a
|
||||
|
||||
test: test-donna test-donna-c64
|
||||
|
||||
|
||||
clean:
|
||||
rm -f java-src/*.class java-src/*.jnilib *.dylib *.o *.a *.pp test-curve25519-donna test-curve25519-donna-c64 speed-curve25519-donna speed-curve25519-donna-c64
|
||||
|
||||
curve25519-donna.a: curve25519-donna.o
|
||||
ar -rc curve25519-donna.a curve25519-donna.o
|
||||
ranlib curve25519-donna.a
|
||||
|
||||
|
||||
##### OSX dynamic library (32- & 64-bit)
|
||||
|
||||
curve25519donna.dylib: curve25519-donna.a curve25519-donna-c64.a
|
||||
$(CC) -m32 -fpic -shared -Wl,-all_load curve25519-donna.a -Wl,-all_load -o libcurve25519donna.dylib
|
||||
$(CC) -fpic -shared -Wl,-all_load curve25519-donna-c64.a -Wl,-all_load -o libcurve25519donna_64.dylib
|
||||
|
||||
##### OSX/Java section hence
|
||||
|
||||
# Java JNI - compiled for OSX (32- & 64-bit)
|
||||
Curve25519Donna.class:
|
||||
cd java-src; javah -jni Curve25519Donna; cd ..
|
||||
cd java-src; javac Curve25519Donna.java; cd ..
|
||||
|
||||
Curve25519Donna.jnilib: curve25519-donna.a curve25519-donna-c64.a Curve25519Donna.class
|
||||
@echo "Building 32-bit..."
|
||||
clang -o java-src/libCurve25519Donna.jnilib $(CFLAGS) -lc -shared -m32 -I /System/Library/Frameworks/JavaVM.framework/Headers curve25519-donna.o java-src/Curve25519Donna.c
|
||||
@echo "Building 64-bit..."
|
||||
clang -o java-src/libCurve25519Donna_64.jnilib $(CFLAGS) -lc -shared -I /System/Library/Frameworks/JavaVM.framework/Headers curve25519-donna-c64.o java-src/Curve25519Donna.c
|
||||
|
||||
##### OSX/Java section end
|
||||
|
||||
curve25519-donna.o: curve25519-donna.c
|
||||
$(CC) -c curve25519-donna.c $(CFLAGS) -m32
|
||||
|
||||
curve25519-donna-c64.a: curve25519-donna-c64.o
|
||||
ar -rc curve25519-donna-c64.a curve25519-donna-c64.o
|
||||
ranlib curve25519-donna-c64.a
|
||||
|
||||
curve25519-donna-c64.o: curve25519-donna-c64.c
|
||||
$(CC) -c curve25519-donna-c64.c $(CFLAGS)
|
||||
|
||||
test-donna: test-curve25519-donna
|
||||
./test-curve25519-donna | head -123456 | tail -1
|
||||
|
||||
test-donna-c64: test-curve25519-donna-c64
|
||||
./test-curve25519-donna-c64 | head -123456 | tail -1
|
||||
|
||||
test-curve25519-donna: test-curve25519.c curve25519-donna.a
|
||||
$(CC) -o test-curve25519-donna test-curve25519.c curve25519-donna.a $(CFLAGS) -m32
|
||||
|
||||
test-curve25519-donna-c64: test-curve25519.c curve25519-donna-c64.a
|
||||
$(CC) -o test-curve25519-donna-c64 test-curve25519.c curve25519-donna-c64.a $(CFLAGS)
|
||||
|
||||
speed-curve25519-donna: speed-curve25519.c curve25519-donna.a
|
||||
$(CC) -o speed-curve25519-donna speed-curve25519.c curve25519-donna.a $(CFLAGS) -m32
|
||||
|
||||
speed-curve25519-donna-c64: speed-curve25519.c curve25519-donna-c64.a
|
||||
$(CC) -o speed-curve25519-donna-c64 speed-curve25519.c curve25519-donna-c64.a $(CFLAGS)
|
||||
|
||||
test-sc-curve25519-donna-c64: test-sc-curve25519.c curve25519-donna-c64.a
|
||||
$(CC) -o test-sc-curve25519-donna-c64 -O test-sc-curve25519.c curve25519-donna-c64.a test-sc-curve25519.s $(CFLAGS)
|
449
lib/curve25519-donna/curve25519-donna-c64.c
Normal file
449
lib/curve25519-donna/curve25519-donna-c64.c
Normal file
|
@ -0,0 +1,449 @@
|
|||
/* Copyright 2008, Google Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Code released into the public domain.
|
||||
*
|
||||
* curve25519-donna: Curve25519 elliptic curve, public key function
|
||||
*
|
||||
* http://code.google.com/p/curve25519-donna/
|
||||
*
|
||||
* Adam Langley <agl@imperialviolet.org>
|
||||
*
|
||||
* Derived from public domain C code by Daniel J. Bernstein <djb@cr.yp.to>
|
||||
*
|
||||
* 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 <string.h>
|
||||
#include <stdint.h>
|
||||
|
||||
typedef uint8_t u8;
|
||||
typedef uint64_t limb;
|
||||
typedef limb felem[5];
|
||||
// This is a special gcc mode for 128-bit integers. It's implemented on 64-bit
|
||||
// platforms only as far as I know.
|
||||
typedef unsigned uint128_t __attribute__((mode(TI)));
|
||||
|
||||
#undef force_inline
|
||||
#define force_inline __attribute__((always_inline))
|
||||
|
||||
/* Sum two numbers: output += in */
|
||||
static inline void force_inline
|
||||
fsum(limb *output, const limb *in) {
|
||||
output[0] += in[0];
|
||||
output[1] += in[1];
|
||||
output[2] += in[2];
|
||||
output[3] += in[3];
|
||||
output[4] += in[4];
|
||||
}
|
||||
|
||||
/* Find the difference of two numbers: output = in - output
|
||||
* (note the order of the arguments!)
|
||||
*
|
||||
* Assumes that out[i] < 2**52
|
||||
* On return, out[i] < 2**55
|
||||
*/
|
||||
static inline void force_inline
|
||||
fdifference_backwards(felem out, const felem in) {
|
||||
/* 152 is 19 << 3 */
|
||||
static const limb two54m152 = (((limb)1) << 54) - 152;
|
||||
static const limb two54m8 = (((limb)1) << 54) - 8;
|
||||
|
||||
out[0] = in[0] + two54m152 - out[0];
|
||||
out[1] = in[1] + two54m8 - out[1];
|
||||
out[2] = in[2] + two54m8 - out[2];
|
||||
out[3] = in[3] + two54m8 - out[3];
|
||||
out[4] = in[4] + two54m8 - out[4];
|
||||
}
|
||||
|
||||
/* Multiply a number by a scalar: output = in * scalar */
|
||||
static inline void force_inline
|
||||
fscalar_product(felem output, const felem in, const limb scalar) {
|
||||
uint128_t a;
|
||||
|
||||
a = ((uint128_t) in[0]) * scalar;
|
||||
output[0] = ((limb)a) & 0x7ffffffffffff;
|
||||
|
||||
a = ((uint128_t) in[1]) * scalar + ((limb) (a >> 51));
|
||||
output[1] = ((limb)a) & 0x7ffffffffffff;
|
||||
|
||||
a = ((uint128_t) in[2]) * scalar + ((limb) (a >> 51));
|
||||
output[2] = ((limb)a) & 0x7ffffffffffff;
|
||||
|
||||
a = ((uint128_t) in[3]) * scalar + ((limb) (a >> 51));
|
||||
output[3] = ((limb)a) & 0x7ffffffffffff;
|
||||
|
||||
a = ((uint128_t) in[4]) * scalar + ((limb) (a >> 51));
|
||||
output[4] = ((limb)a) & 0x7ffffffffffff;
|
||||
|
||||
output[0] += (a >> 51) * 19;
|
||||
}
|
||||
|
||||
/* Multiply two numbers: output = in2 * in
|
||||
*
|
||||
* output must be distinct to both inputs. The inputs are reduced coefficient
|
||||
* form, the output is not.
|
||||
*
|
||||
* Assumes that in[i] < 2**55 and likewise for in2.
|
||||
* On return, output[i] < 2**52
|
||||
*/
|
||||
static inline void force_inline
|
||||
fmul(felem output, const felem in2, const felem in) {
|
||||
uint128_t t[5];
|
||||
limb r0,r1,r2,r3,r4,s0,s1,s2,s3,s4,c;
|
||||
|
||||
r0 = in[0];
|
||||
r1 = in[1];
|
||||
r2 = in[2];
|
||||
r3 = in[3];
|
||||
r4 = in[4];
|
||||
|
||||
s0 = in2[0];
|
||||
s1 = in2[1];
|
||||
s2 = in2[2];
|
||||
s3 = in2[3];
|
||||
s4 = in2[4];
|
||||
|
||||
t[0] = ((uint128_t) r0) * s0;
|
||||
t[1] = ((uint128_t) r0) * s1 + ((uint128_t) r1) * s0;
|
||||
t[2] = ((uint128_t) r0) * s2 + ((uint128_t) r2) * s0 + ((uint128_t) r1) * s1;
|
||||
t[3] = ((uint128_t) r0) * s3 + ((uint128_t) r3) * s0 + ((uint128_t) r1) * s2 + ((uint128_t) r2) * s1;
|
||||
t[4] = ((uint128_t) r0) * s4 + ((uint128_t) r4) * s0 + ((uint128_t) r3) * s1 + ((uint128_t) r1) * s3 + ((uint128_t) r2) * s2;
|
||||
|
||||
r4 *= 19;
|
||||
r1 *= 19;
|
||||
r2 *= 19;
|
||||
r3 *= 19;
|
||||
|
||||
t[0] += ((uint128_t) r4) * s1 + ((uint128_t) r1) * s4 + ((uint128_t) r2) * s3 + ((uint128_t) r3) * s2;
|
||||
t[1] += ((uint128_t) r4) * s2 + ((uint128_t) r2) * s4 + ((uint128_t) r3) * s3;
|
||||
t[2] += ((uint128_t) r4) * s3 + ((uint128_t) r3) * s4;
|
||||
t[3] += ((uint128_t) r4) * s4;
|
||||
|
||||
r0 = (limb)t[0] & 0x7ffffffffffff; c = (limb)(t[0] >> 51);
|
||||
t[1] += c; r1 = (limb)t[1] & 0x7ffffffffffff; c = (limb)(t[1] >> 51);
|
||||
t[2] += c; r2 = (limb)t[2] & 0x7ffffffffffff; c = (limb)(t[2] >> 51);
|
||||
t[3] += c; r3 = (limb)t[3] & 0x7ffffffffffff; c = (limb)(t[3] >> 51);
|
||||
t[4] += c; r4 = (limb)t[4] & 0x7ffffffffffff; c = (limb)(t[4] >> 51);
|
||||
r0 += c * 19; c = r0 >> 51; r0 = r0 & 0x7ffffffffffff;
|
||||
r1 += c; c = r1 >> 51; r1 = r1 & 0x7ffffffffffff;
|
||||
r2 += c;
|
||||
|
||||
output[0] = r0;
|
||||
output[1] = r1;
|
||||
output[2] = r2;
|
||||
output[3] = r3;
|
||||
output[4] = r4;
|
||||
}
|
||||
|
||||
static inline void force_inline
|
||||
fsquare_times(felem output, const felem in, limb count) {
|
||||
uint128_t t[5];
|
||||
limb r0,r1,r2,r3,r4,c;
|
||||
limb d0,d1,d2,d4,d419;
|
||||
|
||||
r0 = in[0];
|
||||
r1 = in[1];
|
||||
r2 = in[2];
|
||||
r3 = in[3];
|
||||
r4 = in[4];
|
||||
|
||||
do {
|
||||
d0 = r0 * 2;
|
||||
d1 = r1 * 2;
|
||||
d2 = r2 * 2 * 19;
|
||||
d419 = r4 * 19;
|
||||
d4 = d419 * 2;
|
||||
|
||||
t[0] = ((uint128_t) r0) * r0 + ((uint128_t) d4) * r1 + (((uint128_t) d2) * (r3 ));
|
||||
t[1] = ((uint128_t) d0) * r1 + ((uint128_t) d4) * r2 + (((uint128_t) r3) * (r3 * 19));
|
||||
t[2] = ((uint128_t) d0) * r2 + ((uint128_t) r1) * r1 + (((uint128_t) d4) * (r3 ));
|
||||
t[3] = ((uint128_t) d0) * r3 + ((uint128_t) d1) * r2 + (((uint128_t) r4) * (d419 ));
|
||||
t[4] = ((uint128_t) d0) * r4 + ((uint128_t) d1) * r3 + (((uint128_t) r2) * (r2 ));
|
||||
|
||||
r0 = (limb)t[0] & 0x7ffffffffffff; c = (limb)(t[0] >> 51);
|
||||
t[1] += c; r1 = (limb)t[1] & 0x7ffffffffffff; c = (limb)(t[1] >> 51);
|
||||
t[2] += c; r2 = (limb)t[2] & 0x7ffffffffffff; c = (limb)(t[2] >> 51);
|
||||
t[3] += c; r3 = (limb)t[3] & 0x7ffffffffffff; c = (limb)(t[3] >> 51);
|
||||
t[4] += c; r4 = (limb)t[4] & 0x7ffffffffffff; c = (limb)(t[4] >> 51);
|
||||
r0 += c * 19; c = r0 >> 51; r0 = r0 & 0x7ffffffffffff;
|
||||
r1 += c; c = r1 >> 51; r1 = r1 & 0x7ffffffffffff;
|
||||
r2 += c;
|
||||
} while(--count);
|
||||
|
||||
output[0] = r0;
|
||||
output[1] = r1;
|
||||
output[2] = r2;
|
||||
output[3] = r3;
|
||||
output[4] = r4;
|
||||
}
|
||||
|
||||
/* Load a little-endian 64-bit number */
|
||||
static limb
|
||||
load_limb(const u8 *in) {
|
||||
return
|
||||
((limb)in[0]) |
|
||||
(((limb)in[1]) << 8) |
|
||||
(((limb)in[2]) << 16) |
|
||||
(((limb)in[3]) << 24) |
|
||||
(((limb)in[4]) << 32) |
|
||||
(((limb)in[5]) << 40) |
|
||||
(((limb)in[6]) << 48) |
|
||||
(((limb)in[7]) << 56);
|
||||
}
|
||||
|
||||
static void
|
||||
store_limb(u8 *out, limb in) {
|
||||
out[0] = in & 0xff;
|
||||
out[1] = (in >> 8) & 0xff;
|
||||
out[2] = (in >> 16) & 0xff;
|
||||
out[3] = (in >> 24) & 0xff;
|
||||
out[4] = (in >> 32) & 0xff;
|
||||
out[5] = (in >> 40) & 0xff;
|
||||
out[6] = (in >> 48) & 0xff;
|
||||
out[7] = (in >> 56) & 0xff;
|
||||
}
|
||||
|
||||
/* Take a little-endian, 32-byte number and expand it into polynomial form */
|
||||
static void
|
||||
fexpand(limb *output, const u8 *in) {
|
||||
output[0] = load_limb(in) & 0x7ffffffffffff;
|
||||
output[1] = (load_limb(in+6) >> 3) & 0x7ffffffffffff;
|
||||
output[2] = (load_limb(in+12) >> 6) & 0x7ffffffffffff;
|
||||
output[3] = (load_limb(in+19) >> 1) & 0x7ffffffffffff;
|
||||
output[4] = (load_limb(in+24) >> 12) & 0x7ffffffffffff;
|
||||
}
|
||||
|
||||
/* Take a fully reduced polynomial form number and contract it into a
|
||||
* little-endian, 32-byte array
|
||||
*/
|
||||
static void
|
||||
fcontract(u8 *output, const felem input) {
|
||||
uint128_t t[5];
|
||||
|
||||
t[0] = input[0];
|
||||
t[1] = input[1];
|
||||
t[2] = input[2];
|
||||
t[3] = input[3];
|
||||
t[4] = input[4];
|
||||
|
||||
t[1] += t[0] >> 51; t[0] &= 0x7ffffffffffff;
|
||||
t[2] += t[1] >> 51; t[1] &= 0x7ffffffffffff;
|
||||
t[3] += t[2] >> 51; t[2] &= 0x7ffffffffffff;
|
||||
t[4] += t[3] >> 51; t[3] &= 0x7ffffffffffff;
|
||||
t[0] += 19 * (t[4] >> 51); t[4] &= 0x7ffffffffffff;
|
||||
|
||||
t[1] += t[0] >> 51; t[0] &= 0x7ffffffffffff;
|
||||
t[2] += t[1] >> 51; t[1] &= 0x7ffffffffffff;
|
||||
t[3] += t[2] >> 51; t[2] &= 0x7ffffffffffff;
|
||||
t[4] += t[3] >> 51; t[3] &= 0x7ffffffffffff;
|
||||
t[0] += 19 * (t[4] >> 51); t[4] &= 0x7ffffffffffff;
|
||||
|
||||
/* now t is between 0 and 2^255-1, properly carried. */
|
||||
/* case 1: between 0 and 2^255-20. case 2: between 2^255-19 and 2^255-1. */
|
||||
|
||||
t[0] += 19;
|
||||
|
||||
t[1] += t[0] >> 51; t[0] &= 0x7ffffffffffff;
|
||||
t[2] += t[1] >> 51; t[1] &= 0x7ffffffffffff;
|
||||
t[3] += t[2] >> 51; t[2] &= 0x7ffffffffffff;
|
||||
t[4] += t[3] >> 51; t[3] &= 0x7ffffffffffff;
|
||||
t[0] += 19 * (t[4] >> 51); t[4] &= 0x7ffffffffffff;
|
||||
|
||||
/* now between 19 and 2^255-1 in both cases, and offset by 19. */
|
||||
|
||||
t[0] += 0x8000000000000 - 19;
|
||||
t[1] += 0x8000000000000 - 1;
|
||||
t[2] += 0x8000000000000 - 1;
|
||||
t[3] += 0x8000000000000 - 1;
|
||||
t[4] += 0x8000000000000 - 1;
|
||||
|
||||
/* now between 2^255 and 2^256-20, and offset by 2^255. */
|
||||
|
||||
t[1] += t[0] >> 51; t[0] &= 0x7ffffffffffff;
|
||||
t[2] += t[1] >> 51; t[1] &= 0x7ffffffffffff;
|
||||
t[3] += t[2] >> 51; t[2] &= 0x7ffffffffffff;
|
||||
t[4] += t[3] >> 51; t[3] &= 0x7ffffffffffff;
|
||||
t[4] &= 0x7ffffffffffff;
|
||||
|
||||
store_limb(output, t[0] | (t[1] << 51));
|
||||
store_limb(output+8, (t[1] >> 13) | (t[2] << 38));
|
||||
store_limb(output+16, (t[2] >> 26) | (t[3] << 25));
|
||||
store_limb(output+24, (t[3] >> 39) | (t[4] << 12));
|
||||
}
|
||||
|
||||
/* Input: Q, Q', Q-Q'
|
||||
* Output: 2Q, Q+Q'
|
||||
*
|
||||
* x2 z3: long form
|
||||
* x3 z3: long form
|
||||
* x z: short form, destroyed
|
||||
* xprime zprime: short form, destroyed
|
||||
* qmqp: short form, preserved
|
||||
*/
|
||||
static void
|
||||
fmonty(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[5], origxprime[5], zzz[5], xx[5], zz[5], xxprime[5],
|
||||
zzprime[5], zzzprime[5];
|
||||
|
||||
memcpy(origx, x, 5 * sizeof(limb));
|
||||
fsum(x, z);
|
||||
fdifference_backwards(z, origx); // does x - z
|
||||
|
||||
memcpy(origxprime, xprime, sizeof(limb) * 5);
|
||||
fsum(xprime, zprime);
|
||||
fdifference_backwards(zprime, origxprime);
|
||||
fmul(xxprime, xprime, z);
|
||||
fmul(zzprime, x, zprime);
|
||||
memcpy(origxprime, xxprime, sizeof(limb) * 5);
|
||||
fsum(xxprime, zzprime);
|
||||
fdifference_backwards(zzprime, origxprime);
|
||||
fsquare_times(x3, xxprime, 1);
|
||||
fsquare_times(zzzprime, zzprime, 1);
|
||||
fmul(z3, zzzprime, qmqp);
|
||||
|
||||
fsquare_times(xx, x, 1);
|
||||
fsquare_times(zz, z, 1);
|
||||
fmul(x2, xx, zz);
|
||||
fdifference_backwards(zz, xx); // does zz = xx - zz
|
||||
fscalar_product(zzz, zz, 121665);
|
||||
fsum(zzz, xx);
|
||||
fmul(z2, zz, zzz);
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// Maybe swap the contents of two limb arrays (@a and @b), each @len elements
|
||||
// long. Perform the swap iff @swap is non-zero.
|
||||
//
|
||||
// This function performs the swap without leaking any side-channel
|
||||
// information.
|
||||
// -----------------------------------------------------------------------------
|
||||
static void
|
||||
swap_conditional(limb a[5], limb b[5], limb iswap) {
|
||||
unsigned i;
|
||||
const limb swap = -iswap;
|
||||
|
||||
for (i = 0; i < 5; ++i) {
|
||||
const limb x = swap & (a[i] ^ b[i]);
|
||||
a[i] ^= x;
|
||||
b[i] ^= x;
|
||||
}
|
||||
}
|
||||
|
||||
/* Calculates nQ where Q is the x-coordinate of a point on the curve
|
||||
*
|
||||
* resultx/resultz: the x coordinate of the resulting curve point (short form)
|
||||
* n: a 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[5] = {0}, b[5] = {1}, c[5] = {1}, d[5] = {0};
|
||||
limb *nqpqx = a, *nqpqz = b, *nqx = c, *nqz = d, *t;
|
||||
limb e[5] = {0}, f[5] = {1}, g[5] = {0}, h[5] = {1};
|
||||
limb *nqpqx2 = e, *nqpqz2 = f, *nqx2 = g, *nqz2 = h;
|
||||
|
||||
unsigned i, j;
|
||||
|
||||
memcpy(nqpqx, q, sizeof(limb) * 5);
|
||||
|
||||
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) * 5);
|
||||
memcpy(resultz, nqz, sizeof(limb) * 5);
|
||||
}
|
||||
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// Shamelessly copied from djb's code, tightened a little
|
||||
// -----------------------------------------------------------------------------
|
||||
static void
|
||||
crecip(felem out, const felem z) {
|
||||
felem a,t0,b,c;
|
||||
|
||||
/* 2 */ fsquare_times(a, z, 1); // a = 2
|
||||
/* 8 */ fsquare_times(t0, a, 2);
|
||||
/* 9 */ fmul(b, t0, z); // b = 9
|
||||
/* 11 */ fmul(a, b, a); // a = 11
|
||||
/* 22 */ fsquare_times(t0, a, 1);
|
||||
/* 2^5 - 2^0 = 31 */ fmul(b, t0, b);
|
||||
/* 2^10 - 2^5 */ fsquare_times(t0, b, 5);
|
||||
/* 2^10 - 2^0 */ fmul(b, t0, b);
|
||||
/* 2^20 - 2^10 */ fsquare_times(t0, b, 10);
|
||||
/* 2^20 - 2^0 */ fmul(c, t0, b);
|
||||
/* 2^40 - 2^20 */ fsquare_times(t0, c, 20);
|
||||
/* 2^40 - 2^0 */ fmul(t0, t0, c);
|
||||
/* 2^50 - 2^10 */ fsquare_times(t0, t0, 10);
|
||||
/* 2^50 - 2^0 */ fmul(b, t0, b);
|
||||
/* 2^100 - 2^50 */ fsquare_times(t0, b, 50);
|
||||
/* 2^100 - 2^0 */ fmul(c, t0, b);
|
||||
/* 2^200 - 2^100 */ fsquare_times(t0, c, 100);
|
||||
/* 2^200 - 2^0 */ fmul(t0, t0, c);
|
||||
/* 2^250 - 2^50 */ fsquare_times(t0, t0, 50);
|
||||
/* 2^250 - 2^0 */ fmul(t0, t0, b);
|
||||
/* 2^255 - 2^5 */ fsquare_times(t0, t0, 5);
|
||||
/* 2^255 - 21 */ fmul(out, t0, a);
|
||||
}
|
||||
|
||||
int curve25519_donna(u8 *, const u8 *, const u8 *);
|
||||
|
||||
int
|
||||
curve25519_donna(u8 *mypublic, const u8 *secret, const u8 *basepoint) {
|
||||
limb bp[5], x[5], z[5], zmone[5];
|
||||
uint8_t e[32];
|
||||
int i;
|
||||
|
||||
for (i = 0;i < 32;++i) e[i] = secret[i];
|
||||
e[0] &= 248;
|
||||
e[31] &= 127;
|
||||
e[31] |= 64;
|
||||
|
||||
fexpand(bp, basepoint);
|
||||
cmult(x, z, e, bp);
|
||||
crecip(zmone, z);
|
||||
fmul(z, x, zmone);
|
||||
fcontract(mypublic, z);
|
||||
return 0;
|
||||
}
|
860
lib/curve25519-donna/curve25519-donna.c
Normal file
860
lib/curve25519-donna/curve25519-donna.c
Normal file
|
@ -0,0 +1,860 @@
|
|||
/* 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 <agl@imperialviolet.org>
|
||||
*
|
||||
* Derived from public domain C code by Daniel J. Bernstein <djb@cr.yp.to>
|
||||
*
|
||||
* 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 <string.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#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;
|
||||
}
|
||||
|
||||
/* 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;
|
||||
}
|
13
lib/curve25519-donna/curve25519-donna.podspec
Normal file
13
lib/curve25519-donna/curve25519-donna.podspec
Normal file
|
@ -0,0 +1,13 @@
|
|||
Pod::Spec.new do |s|
|
||||
s.name = "curve25519-donna"
|
||||
s.version = "1.2.1"
|
||||
s.summary = "Implementations of a fast elliptic-curve, Diffie-Hellman primitive"
|
||||
s.description = <<-DESC
|
||||
Curve25519 is a state-of-the-art Diffie-Hellman function suitable for a wide variety of applications.
|
||||
DESC
|
||||
s.homepage = "http://code.google.com/p/curve25519-donna"
|
||||
s.license = 'BSD 3-Clause'
|
||||
s.author = 'Dan Bernstein'
|
||||
s.source = { :git => "https://github.com/agl/curve25519-donna.git", :tag => "1.2.1" }
|
||||
s.source_files = 'curve25519-donna.c'
|
||||
end
|
4
lib/curve25519-donna/python-src/curve25519/__init__.py
Normal file
4
lib/curve25519-donna/python-src/curve25519/__init__.py
Normal file
|
@ -0,0 +1,4 @@
|
|||
|
||||
from .keys import Private, Public
|
||||
|
||||
hush_pyflakes = [Private, Public]; del hush_pyflakes
|
105
lib/curve25519-donna/python-src/curve25519/curve25519module.c
Normal file
105
lib/curve25519-donna/python-src/curve25519/curve25519module.c
Normal file
|
@ -0,0 +1,105 @@
|
|||
/* tell python that PyArg_ParseTuple(t#) means Py_ssize_t, not int */
|
||||
#define PY_SSIZE_T_CLEAN
|
||||
#include <Python.h>
|
||||
#if (PY_VERSION_HEX < 0x02050000)
|
||||
typedef int Py_ssize_t;
|
||||
#endif
|
||||
|
||||
/* This is required for compatibility with Python 2. */
|
||||
#if PY_MAJOR_VERSION >= 3
|
||||
#include <bytesobject.h>
|
||||
#define y "y"
|
||||
#else
|
||||
#define PyBytes_FromStringAndSize PyString_FromStringAndSize
|
||||
#define y "t"
|
||||
#endif
|
||||
|
||||
int curve25519_donna(char *mypublic,
|
||||
const char *secret, const char *basepoint);
|
||||
|
||||
static PyObject *
|
||||
pycurve25519_makeprivate(PyObject *self, PyObject *args)
|
||||
{
|
||||
char *in1;
|
||||
Py_ssize_t in1len;
|
||||
if (!PyArg_ParseTuple(args, y"#:clamp", &in1, &in1len))
|
||||
return NULL;
|
||||
if (in1len != 32) {
|
||||
PyErr_SetString(PyExc_ValueError, "input must be 32-byte string");
|
||||
return NULL;
|
||||
}
|
||||
in1[0] &= 248;
|
||||
in1[31] &= 127;
|
||||
in1[31] |= 64;
|
||||
return PyBytes_FromStringAndSize((char *)in1, 32);
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
pycurve25519_makepublic(PyObject *self, PyObject *args)
|
||||
{
|
||||
const char *private;
|
||||
char mypublic[32];
|
||||
char basepoint[32] = {9};
|
||||
Py_ssize_t privatelen;
|
||||
if (!PyArg_ParseTuple(args, y"#:makepublic", &private, &privatelen))
|
||||
return NULL;
|
||||
if (privatelen != 32) {
|
||||
PyErr_SetString(PyExc_ValueError, "input must be 32-byte string");
|
||||
return NULL;
|
||||
}
|
||||
curve25519_donna(mypublic, private, basepoint);
|
||||
return PyBytes_FromStringAndSize((char *)mypublic, 32);
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
pycurve25519_makeshared(PyObject *self, PyObject *args)
|
||||
{
|
||||
const char *myprivate, *theirpublic;
|
||||
char shared_key[32];
|
||||
Py_ssize_t myprivatelen, theirpubliclen;
|
||||
if (!PyArg_ParseTuple(args, y"#"y"#:generate",
|
||||
&myprivate, &myprivatelen, &theirpublic, &theirpubliclen))
|
||||
return NULL;
|
||||
if (myprivatelen != 32) {
|
||||
PyErr_SetString(PyExc_ValueError, "input must be 32-byte string");
|
||||
return NULL;
|
||||
}
|
||||
if (theirpubliclen != 32) {
|
||||
PyErr_SetString(PyExc_ValueError, "input must be 32-byte string");
|
||||
return NULL;
|
||||
}
|
||||
curve25519_donna(shared_key, myprivate, theirpublic);
|
||||
return PyBytes_FromStringAndSize((char *)shared_key, 32);
|
||||
}
|
||||
|
||||
|
||||
static PyMethodDef
|
||||
curve25519_functions[] = {
|
||||
{"make_private", pycurve25519_makeprivate, METH_VARARGS, "data->private"},
|
||||
{"make_public", pycurve25519_makepublic, METH_VARARGS, "private->public"},
|
||||
{"make_shared", pycurve25519_makeshared, METH_VARARGS, "private+public->shared"},
|
||||
{NULL, NULL, 0, NULL},
|
||||
};
|
||||
|
||||
#if PY_MAJOR_VERSION >= 3
|
||||
static struct PyModuleDef
|
||||
curve25519_module = {
|
||||
PyModuleDef_HEAD_INIT,
|
||||
"_curve25519",
|
||||
NULL,
|
||||
NULL,
|
||||
curve25519_functions,
|
||||
};
|
||||
|
||||
PyObject *
|
||||
PyInit__curve25519(void)
|
||||
{
|
||||
return PyModule_Create(&curve25519_module);
|
||||
}
|
||||
#else
|
||||
PyMODINIT_FUNC
|
||||
init_curve25519(void)
|
||||
{
|
||||
(void)Py_InitModule("_curve25519", curve25519_functions);
|
||||
}
|
||||
#endif
|
46
lib/curve25519-donna/python-src/curve25519/keys.py
Normal file
46
lib/curve25519-donna/python-src/curve25519/keys.py
Normal file
|
@ -0,0 +1,46 @@
|
|||
from . import _curve25519
|
||||
from hashlib import sha256
|
||||
import os
|
||||
|
||||
# the curve25519 functions are really simple, and could be used without an
|
||||
# OOP layer, but it's a bit too easy to accidentally swap the private and
|
||||
# public keys that way.
|
||||
|
||||
def _hash_shared(shared):
|
||||
return sha256(b"curve25519-shared:"+shared).digest()
|
||||
|
||||
class Private:
|
||||
def __init__(self, secret=None, seed=None):
|
||||
if secret is None:
|
||||
if seed is None:
|
||||
secret = os.urandom(32)
|
||||
else:
|
||||
secret = sha256(b"curve25519-private:"+seed).digest()
|
||||
else:
|
||||
assert seed is None, "provide secret, seed, or neither, not both"
|
||||
if not isinstance(secret, bytes) or len(secret) != 32:
|
||||
raise TypeError("secret= must be 32-byte string")
|
||||
self.private = _curve25519.make_private(secret)
|
||||
|
||||
def serialize(self):
|
||||
return self.private
|
||||
|
||||
def get_public(self):
|
||||
return Public(_curve25519.make_public(self.private))
|
||||
|
||||
def get_shared_key(self, public, hashfunc=None):
|
||||
if not isinstance(public, Public):
|
||||
raise ValueError("'public' must be an instance of Public")
|
||||
if hashfunc is None:
|
||||
hashfunc = _hash_shared
|
||||
shared = _curve25519.make_shared(self.private, public.public)
|
||||
return hashfunc(shared)
|
||||
|
||||
class Public:
|
||||
def __init__(self, public):
|
||||
assert isinstance(public, bytes)
|
||||
assert len(public) == 32
|
||||
self.public = public
|
||||
|
||||
def serialize(self):
|
||||
return self.public
|
99
lib/curve25519-donna/python-src/curve25519/test/test_curve25519.py
Executable file
99
lib/curve25519-donna/python-src/curve25519/test/test_curve25519.py
Executable file
|
@ -0,0 +1,99 @@
|
|||
#! /usr/bin/env python
|
||||
|
||||
import unittest
|
||||
|
||||
from curve25519 import Private, Public
|
||||
from hashlib import sha1, sha256
|
||||
from binascii import hexlify
|
||||
|
||||
class Basic(unittest.TestCase):
|
||||
def test_basic(self):
|
||||
secret1 = b"abcdefghijklmnopqrstuvwxyz123456"
|
||||
self.assertEqual(len(secret1), 32)
|
||||
|
||||
secret2 = b"654321zyxwvutsrqponmlkjihgfedcba"
|
||||
self.assertEqual(len(secret2), 32)
|
||||
priv1 = Private(secret=secret1)
|
||||
pub1 = priv1.get_public()
|
||||
priv2 = Private(secret=secret2)
|
||||
pub2 = priv2.get_public()
|
||||
shared12 = priv1.get_shared_key(pub2)
|
||||
e = b"b0818125eab42a8ac1af5e8b9b9c15ed2605c2bbe9675de89e5e6e7f442b9598"
|
||||
self.assertEqual(hexlify(shared12), e)
|
||||
shared21 = priv2.get_shared_key(pub1)
|
||||
self.assertEqual(shared12, shared21)
|
||||
|
||||
pub2a = Public(pub2.serialize())
|
||||
shared12a = priv1.get_shared_key(pub2a)
|
||||
self.assertEqual(hexlify(shared12a), e)
|
||||
|
||||
def test_errors(self):
|
||||
priv1 = Private()
|
||||
self.assertRaises(ValueError, priv1.get_shared_key, priv1)
|
||||
|
||||
def test_seed(self):
|
||||
# use 32-byte secret
|
||||
self.assertRaises(TypeError, Private, secret=123)
|
||||
self.assertRaises(TypeError, Private, secret=b"too short")
|
||||
secret1 = b"abcdefghijklmnopqrstuvwxyz123456"
|
||||
assert len(secret1) == 32
|
||||
priv1 = Private(secret=secret1)
|
||||
priv1a = Private(secret=secret1)
|
||||
priv1b = Private(priv1.serialize())
|
||||
self.assertEqual(priv1.serialize(), priv1a.serialize())
|
||||
self.assertEqual(priv1.serialize(), priv1b.serialize())
|
||||
e = b"6062636465666768696a6b6c6d6e6f707172737475767778797a313233343576"
|
||||
self.assertEqual(hexlify(priv1.serialize()), e)
|
||||
|
||||
# the private key is a clamped form of the secret, so they won't
|
||||
# quite be the same
|
||||
p = Private(secret=b"\x00"*32)
|
||||
self.assertEqual(hexlify(p.serialize()), b"00"*31+b"40")
|
||||
p = Private(secret=b"\xff"*32)
|
||||
self.assertEqual(hexlify(p.serialize()), b"f8"+b"ff"*30+b"7f")
|
||||
|
||||
# use arbitrary-length seed
|
||||
self.assertRaises(TypeError, Private, seed=123)
|
||||
priv1 = Private(seed=b"abc")
|
||||
priv1a = Private(seed=b"abc")
|
||||
priv1b = Private(priv1.serialize())
|
||||
self.assertEqual(priv1.serialize(), priv1a.serialize())
|
||||
self.assertEqual(priv1.serialize(), priv1b.serialize())
|
||||
self.assertRaises(AssertionError, Private, seed=b"abc", secret=b"no")
|
||||
|
||||
priv1 = Private(seed=b"abc")
|
||||
priv1a = Private(priv1.serialize())
|
||||
self.assertEqual(priv1.serialize(), priv1a.serialize())
|
||||
self.assertRaises(AssertionError, Private, seed=b"abc", secret=b"no")
|
||||
|
||||
# use built-in os.urandom
|
||||
priv2 = Private()
|
||||
priv2a = Private(priv2.private)
|
||||
self.assertEqual(priv2.serialize(), priv2a.serialize())
|
||||
|
||||
# attempt to use both secret= and seed=, not allowed
|
||||
self.assertRaises(AssertionError, Private, seed=b"abc", secret=b"no")
|
||||
|
||||
def test_hashfunc(self):
|
||||
priv1 = Private(seed=b"abc")
|
||||
priv2 = Private(seed=b"def")
|
||||
shared_sha256 = priv1.get_shared_key(priv2.get_public())
|
||||
e = b"da959ffe77ebeb4757fe5ba310e28ede425ae0d0ff5ec9c884e2d08f311cf5e5"
|
||||
self.assertEqual(hexlify(shared_sha256), e)
|
||||
|
||||
# confirm the hash function remains what we think it is
|
||||
def myhash(shared_key):
|
||||
return sha256(b"curve25519-shared:"+shared_key).digest()
|
||||
shared_myhash = priv1.get_shared_key(priv2.get_public(), myhash)
|
||||
self.assertEqual(hexlify(shared_myhash), e)
|
||||
|
||||
def hexhash(shared_key):
|
||||
return sha1(shared_key).hexdigest().encode()
|
||||
shared_hexhash = priv1.get_shared_key(priv2.get_public(), hexhash)
|
||||
self.assertEqual(shared_hexhash,
|
||||
b"80eec98222c8edc4324fb9477a3c775ce7c6c93a")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
|
46
lib/curve25519-donna/python-src/curve25519/test/test_speed.py
Executable file
46
lib/curve25519-donna/python-src/curve25519/test/test_speed.py
Executable file
|
@ -0,0 +1,46 @@
|
|||
#! /usr/bin/env python
|
||||
|
||||
from time import time
|
||||
from curve25519 import Private
|
||||
|
||||
count = 10000
|
||||
elapsed_get_public = 0.0
|
||||
elapsed_get_shared = 0.0
|
||||
|
||||
def abbreviate_time(data):
|
||||
# 1.23s, 790ms, 132us
|
||||
if data is None:
|
||||
return ""
|
||||
s = float(data)
|
||||
if s >= 10:
|
||||
#return abbreviate.abbreviate_time(data)
|
||||
return "%d" % s
|
||||
if s >= 1.0:
|
||||
return "%.2fs" % s
|
||||
if s >= 0.01:
|
||||
return "%dms" % (1000*s)
|
||||
if s >= 0.001:
|
||||
return "%.1fms" % (1000*s)
|
||||
if s >= 0.000001:
|
||||
return "%.1fus" % (1000000*s)
|
||||
return "%dns" % (1000000000*s)
|
||||
|
||||
def nohash(key): return key
|
||||
|
||||
for i in range(count):
|
||||
p = Private()
|
||||
start = time()
|
||||
pub = p.get_public()
|
||||
elapsed_get_public += time() - start
|
||||
pub2 = Private().get_public()
|
||||
start = time()
|
||||
shared = p.get_shared_key(pub2) #, hashfunc=nohash)
|
||||
elapsed_get_shared += time() - start
|
||||
|
||||
print("get_public: %s" % abbreviate_time(elapsed_get_public / count))
|
||||
print("get_shared: %s" % abbreviate_time(elapsed_get_shared / count))
|
||||
|
||||
# these take about 560us-570us each (with the default compiler settings, -Os)
|
||||
# on my laptop, same with -O2
|
||||
# of which the python overhead is about 5us
|
||||
# and the get_shared_key() hash step adds about 5us
|
38
lib/curve25519-donna/setup.py
Executable file
38
lib/curve25519-donna/setup.py
Executable file
|
@ -0,0 +1,38 @@
|
|||
#! /usr/bin/env python
|
||||
|
||||
from subprocess import Popen, PIPE
|
||||
from distutils.core import setup, Extension
|
||||
|
||||
version = Popen(["git", "describe", "--tags"], stdout=PIPE).communicate()[0]\
|
||||
.strip().decode("utf8")
|
||||
|
||||
ext_modules = [Extension("curve25519._curve25519",
|
||||
["python-src/curve25519/curve25519module.c",
|
||||
"curve25519-donna.c"],
|
||||
)]
|
||||
|
||||
short_description="Python wrapper for the Curve25519 cryptographic library"
|
||||
long_description="""\
|
||||
Curve25519 is a fast elliptic-curve key-agreement protocol, in which two
|
||||
parties Alice and Bob each generate a (public,private) keypair, exchange
|
||||
public keys, and can then compute the same shared key. Specifically, Alice
|
||||
computes F(Aprivate, Bpublic), Bob computes F(Bprivate, Apublic), and both
|
||||
get the same value (and nobody else can guess that shared value, even if they
|
||||
know Apublic and Bpublic).
|
||||
|
||||
This is a Python wrapper for the portable 'curve25519-donna' implementation
|
||||
of this algorithm, written by Adam Langley, hosted at
|
||||
http://code.google.com/p/curve25519-donna/
|
||||
"""
|
||||
|
||||
setup(name="curve25519-donna",
|
||||
version=version,
|
||||
description=short_description,
|
||||
long_description=long_description,
|
||||
author="Brian Warner",
|
||||
author_email="warner-pycurve25519-donna@lothar.com",
|
||||
license="BSD",
|
||||
packages=["curve25519", "curve25519.test"],
|
||||
package_dir={"curve25519": "python-src/curve25519"},
|
||||
ext_modules=ext_modules,
|
||||
)
|
50
lib/curve25519-donna/speed-curve25519.c
Normal file
50
lib/curve25519-donna/speed-curve25519.c
Normal file
|
@ -0,0 +1,50 @@
|
|||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <sys/time.h>
|
||||
#include <time.h>
|
||||
#include <stdint.h>
|
||||
|
||||
typedef uint8_t u8;
|
||||
|
||||
extern void curve25519_donna(u8 *output, const u8 *secret, const u8 *bp);
|
||||
|
||||
static uint64_t
|
||||
time_now() {
|
||||
struct timeval tv;
|
||||
uint64_t ret;
|
||||
|
||||
gettimeofday(&tv, NULL);
|
||||
ret = tv.tv_sec;
|
||||
ret *= 1000000;
|
||||
ret += tv.tv_usec;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int
|
||||
main() {
|
||||
static const unsigned char basepoint[32] = {9};
|
||||
unsigned char mysecret[32], mypublic[32];
|
||||
unsigned i;
|
||||
uint64_t start, end;
|
||||
|
||||
memset(mysecret, 42, 32);
|
||||
mysecret[0] &= 248;
|
||||
mysecret[31] &= 127;
|
||||
mysecret[31] |= 64;
|
||||
|
||||
// Load the caches
|
||||
for (i = 0; i < 1000; ++i) {
|
||||
curve25519_donna(mypublic, mysecret, basepoint);
|
||||
}
|
||||
|
||||
start = time_now();
|
||||
for (i = 0; i < 30000; ++i) {
|
||||
curve25519_donna(mypublic, mysecret, basepoint);
|
||||
}
|
||||
end = time_now();
|
||||
|
||||
printf("%luus\n", (unsigned long) ((end - start) / 30000));
|
||||
|
||||
return 0;
|
||||
}
|
54
lib/curve25519-donna/test-curve25519.c
Normal file
54
lib/curve25519-donna/test-curve25519.c
Normal file
|
@ -0,0 +1,54 @@
|
|||
/*
|
||||
test-curve25519 version 20050915
|
||||
D. J. Bernstein
|
||||
Public domain.
|
||||
|
||||
Tiny modifications by agl
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
extern void curve25519_donna(unsigned char *output, const unsigned char *a,
|
||||
const unsigned char *b);
|
||||
void doit(unsigned char *ek,unsigned char *e,unsigned char *k);
|
||||
|
||||
void doit(unsigned char *ek,unsigned char *e,unsigned char *k)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0;i < 32;++i) printf("%02x",(unsigned int) e[i]); printf(" ");
|
||||
for (i = 0;i < 32;++i) printf("%02x",(unsigned int) k[i]); printf(" ");
|
||||
curve25519_donna(ek,e,k);
|
||||
for (i = 0;i < 32;++i) printf("%02x",(unsigned int) ek[i]); printf("\n");
|
||||
}
|
||||
|
||||
unsigned char e1k[32];
|
||||
unsigned char e2k[32];
|
||||
unsigned char e1e2k[32];
|
||||
unsigned char e2e1k[32];
|
||||
unsigned char e1[32] = {3};
|
||||
unsigned char e2[32] = {5};
|
||||
unsigned char k[32] = {9};
|
||||
|
||||
int
|
||||
main()
|
||||
{
|
||||
int loop;
|
||||
int i;
|
||||
|
||||
for (loop = 0;loop < 10000;++loop) {
|
||||
doit(e1k,e1,k);
|
||||
doit(e2e1k,e2,e1k);
|
||||
doit(e2k,e2,k);
|
||||
doit(e1e2k,e1,e2k);
|
||||
for (i = 0;i < 32;++i) if (e1e2k[i] != e2e1k[i]) {
|
||||
printf("fail\n");
|
||||
return 1;
|
||||
}
|
||||
for (i = 0;i < 32;++i) e1[i] ^= e2k[i];
|
||||
for (i = 0;i < 32;++i) e2[i] ^= e1k[i];
|
||||
for (i = 0;i < 32;++i) k[i] ^= e1e2k[i];
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
39
lib/curve25519-donna/test-noncanon.c
Normal file
39
lib/curve25519-donna/test-noncanon.c
Normal file
|
@ -0,0 +1,39 @@
|
|||
/* This file can be used to test whether the code handles non-canonical curve
|
||||
* points (i.e. points with the 256th bit set) in the same way as the reference
|
||||
* implementation. */
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
extern void curve25519_donna(unsigned char *output, const unsigned char *a,
|
||||
const unsigned char *b);
|
||||
int
|
||||
main()
|
||||
{
|
||||
static const uint8_t point1[32] = {
|
||||
0x25,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
};
|
||||
static const uint8_t point2[32] = {
|
||||
0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
|
||||
0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
|
||||
0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
|
||||
0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
|
||||
};
|
||||
static const uint8_t scalar[32] = { 1 };
|
||||
uint8_t out1[32], out2[32];
|
||||
|
||||
curve25519_donna(out1, scalar, point1);
|
||||
curve25519_donna(out2, scalar, point2);
|
||||
|
||||
if (0 == memcmp(out1, out2, sizeof(out1))) {
|
||||
fprintf(stderr, "Top bit not ignored.\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
fprintf(stderr, "Top bit correctly ignored.\n");
|
||||
return 0;
|
||||
}
|
72
lib/curve25519-donna/test-sc-curve25519.c
Normal file
72
lib/curve25519-donna/test-sc-curve25519.c
Normal file
|
@ -0,0 +1,72 @@
|
|||
#define _GNU_SOURCE
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <stdint.h>
|
||||
#include <math.h>
|
||||
|
||||
extern void curve25519_donna(uint8_t *, const uint8_t *, const uint8_t *);
|
||||
extern uint64_t tsc_read();
|
||||
|
||||
int
|
||||
main(int argc, char **argv) {
|
||||
uint8_t private_key[32], public[32], peer1[32], peer2[32], output[32];
|
||||
static const uint8_t basepoint[32] = {9};
|
||||
unsigned i;
|
||||
uint64_t sum = 0, sum_squares = 0, skipped = 0, mean;
|
||||
static const unsigned count = 200000;
|
||||
|
||||
memset(private_key, 42, sizeof(private_key));
|
||||
|
||||
private_key[0] &= 248;
|
||||
private_key[31] &= 127;
|
||||
private_key[31] |= 64;
|
||||
|
||||
curve25519_donna(public, private_key, basepoint);
|
||||
memset(peer1, 0, sizeof(peer1));
|
||||
memset(peer2, 255, sizeof(peer2));
|
||||
|
||||
for (i = 0; i < count; ++i) {
|
||||
const uint64_t start = tsc_read();
|
||||
curve25519_donna(output, peer1, public);
|
||||
const uint64_t end = tsc_read();
|
||||
const uint64_t delta = end - start;
|
||||
if (delta > 650000) {
|
||||
// something terrible happened (task switch etc)
|
||||
skipped++;
|
||||
continue;
|
||||
}
|
||||
sum += delta;
|
||||
sum_squares += (delta * delta);
|
||||
}
|
||||
|
||||
mean = sum / ((uint64_t) count);
|
||||
printf("all 0: mean:%lu sd:%f skipped:%lu\n",
|
||||
mean,
|
||||
sqrt((double)(sum_squares/((uint64_t) count) - mean*mean)),
|
||||
skipped);
|
||||
|
||||
sum = sum_squares = skipped = 0;
|
||||
|
||||
for (i = 0; i < count; ++i) {
|
||||
const uint64_t start = tsc_read();
|
||||
curve25519_donna(output, peer2, public);
|
||||
const uint64_t end = tsc_read();
|
||||
const uint64_t delta = end - start;
|
||||
if (delta > 650000) {
|
||||
// something terrible happened (task switch etc)
|
||||
skipped++;
|
||||
continue;
|
||||
}
|
||||
sum += delta;
|
||||
sum_squares += (delta * delta);
|
||||
}
|
||||
|
||||
mean = sum / ((uint64_t) count);
|
||||
printf("all 1: mean:%lu sd:%f skipped:%lu\n",
|
||||
mean,
|
||||
sqrt((double)(sum_squares/((uint64_t) count) - mean*mean)),
|
||||
skipped);
|
||||
|
||||
return 0;
|
||||
}
|
8
lib/curve25519-donna/test-sc-curve25519.s
Normal file
8
lib/curve25519-donna/test-sc-curve25519.s
Normal file
|
@ -0,0 +1,8 @@
|
|||
.text
|
||||
.globl tsc_read
|
||||
|
||||
tsc_read:
|
||||
rdtsc
|
||||
shl $32,%rdx
|
||||
or %rdx,%rax
|
||||
ret
|
82
lib/doctest/.clang-format
Normal file
82
lib/doctest/.clang-format
Normal file
|
@ -0,0 +1,82 @@
|
|||
# https://clang.llvm.org/docs/ClangFormatStyleOptions.html
|
||||
|
||||
DisableFormat: false
|
||||
Language: Cpp
|
||||
Standard: Cpp11
|
||||
IndentWidth: 4
|
||||
TabWidth: 4
|
||||
UseTab: Never
|
||||
ColumnLimit: 100
|
||||
ReflowComments: false
|
||||
SortIncludes: false
|
||||
|
||||
AlignConsecutiveAssignments: true
|
||||
AlignConsecutiveDeclarations: true
|
||||
AlignEscapedNewlinesLeft: false
|
||||
AlignOperands: true
|
||||
AlignTrailingComments: true
|
||||
AlignAfterOpenBracket: true
|
||||
DerivePointerAlignment: false
|
||||
PointerAlignment: Left
|
||||
IndentCaseLabels: true
|
||||
ContinuationIndentWidth: 8
|
||||
NamespaceIndentation: Inner
|
||||
CompactNamespaces: true
|
||||
FixNamespaceComments: true
|
||||
AccessModifierOffset: -4
|
||||
|
||||
SpaceAfterControlStatementKeyword: false
|
||||
SpaceAfterCStyleCast: false
|
||||
SpaceBeforeAssignmentOperators: true
|
||||
SpaceBeforeParens: Never
|
||||
SpaceInEmptyParentheses: false
|
||||
SpacesBeforeTrailingComments: 1
|
||||
SpacesInAngles: false
|
||||
SpacesInCStyleCastParentheses: false
|
||||
SpacesInContainerLiterals: false
|
||||
SpacesInParentheses: false
|
||||
SpacesInSquareBrackets: false
|
||||
Cpp11BracedListStyle: true
|
||||
|
||||
KeepEmptyLinesAtTheStartOfBlocks: false
|
||||
MaxEmptyLinesToKeep: 1
|
||||
BinPackArguments: true
|
||||
BinPackParameters: true
|
||||
AlwaysBreakAfterReturnType: None
|
||||
AlwaysBreakAfterDefinitionReturnType: None
|
||||
AlwaysBreakTemplateDeclarations: true
|
||||
BreakConstructorInitializersBeforeComma: true
|
||||
ConstructorInitializerAllOnOneLineOrOnePerLine: false
|
||||
ConstructorInitializerIndentWidth: 8
|
||||
|
||||
AllowShortIfStatementsOnASingleLine: false
|
||||
AllowShortLoopsOnASingleLine: false
|
||||
AllowShortBlocksOnASingleLine: true
|
||||
AllowShortCaseLabelsOnASingleLine: true
|
||||
AllowAllParametersOfDeclarationOnNextLine: true
|
||||
AllowShortFunctionsOnASingleLine: All
|
||||
|
||||
BreakBeforeBinaryOperators: false
|
||||
BreakBeforeTernaryOperators: false
|
||||
BreakStringLiterals: true
|
||||
BreakBeforeBraces: Custom
|
||||
BraceWrapping:
|
||||
AfterClass: true
|
||||
AfterEnum: true
|
||||
AfterNamespace: false
|
||||
AfterStruct: true
|
||||
AfterUnion: true
|
||||
|
||||
BeforeCatch: false
|
||||
BeforeElse: false
|
||||
IndentBraces: false
|
||||
AfterFunction: false
|
||||
AfterControlStatement: false
|
||||
|
||||
# penalties not thought of yet
|
||||
PenaltyBreakBeforeFirstCallParameter: 19
|
||||
PenaltyBreakComment: 60
|
||||
PenaltyBreakString: 1000
|
||||
PenaltyBreakFirstLessLess: 120
|
||||
PenaltyExcessCharacter: 1000000
|
||||
PenaltyReturnTypeOnItsOwnLine: 1000
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue