diff options
author | Stephane Glondu <steph@glondu.net> | 2020-11-07 12:00:10 +0100 |
---|---|---|
committer | Stephane Glondu <steph@glondu.net> | 2020-11-07 12:00:10 +0100 |
commit | c3a5c21db26e9634999edbb6bbfe9d2400cccfe7 (patch) | |
tree | 2e3ade5a9cfae0d405021c02e6bf6530ac7bf242 | |
parent | 1cb150352152fe253d871467e50f942069b29141 (diff) | |
parent | c5a87c30c742c1142b8bc6a2163f116707e0efdc (diff) |
Update upstream source from tag 'upstream/1.16.1'
Update to upstream version '1.16.1'
with Debian dir 4c91978f927d379dcec861b888db4cf17b232f95
-rw-r--r-- | .gitignore | 3 | ||||
-rw-r--r-- | Changes | 8 | ||||
-rw-r--r-- | Makefile | 41 | ||||
-rw-r--r-- | README.md | 40 | ||||
-rw-r--r-- | _oasis | 145 | ||||
-rw-r--r-- | _tags | 122 | ||||
-rwxr-xr-x | configure | 67 | ||||
-rw-r--r-- | cryptokit.opam | 35 | ||||
-rw-r--r-- | dune-project | 24 | ||||
-rw-r--r-- | setup.ml | 39 | ||||
-rw-r--r-- | src/META | 12 | ||||
-rw-r--r-- | src/api-cryptokit.odocl | 5 | ||||
-rw-r--r-- | src/blake2.c | 314 | ||||
-rw-r--r-- | src/blake2.h | 47 | ||||
-rw-r--r-- | src/config/config_vars.ml.default | 7 | ||||
-rw-r--r-- | src/config/dune | 7 | ||||
-rw-r--r-- | src/config/flags.ml | 45 | ||||
-rw-r--r-- | src/cryptokit.ml | 63 | ||||
-rw-r--r-- | src/cryptokit.mldylib | 5 | ||||
-rw-r--r-- | src/cryptokit.mli | 58 | ||||
-rw-r--r-- | src/cryptokit.mllib | 5 | ||||
-rw-r--r-- | src/dune | 41 | ||||
-rw-r--r-- | src/libcryptokit_stubs.clib | 28 | ||||
-rw-r--r-- | src/stubs-blake2.c | 75 | ||||
-rw-r--r-- | src/stubs-zlib.c | 6 | ||||
-rw-r--r-- | test/dune | 16 | ||||
-rw-r--r-- | test/speedtest.ml | 6 | ||||
-rw-r--r-- | test/test.ml | 86 |
28 files changed, 889 insertions, 461 deletions
@@ -3,3 +3,6 @@ setup.data setup.log *.native *~ +.merlin +# This file is generated by the configure script +src/config/config_vars.ml @@ -1,3 +1,11 @@ +Release 1.16.1: +- Make the tests faster and more robust +- Update dependencies and documentation. + +Release 1.16: +- Use dune as the build system (contributed by Andrey Mokhov, PR #24) +- Add BLAKE2b and BLAKE2s hash and MAC functions. + Release 1.15: - Added constant-time `string_equal` and `bytes_equal` comparison functions (execution time depends on the lengths of the strings but not on their diff --git a/Makefile b/Makefile deleted file mode 100644 index 3639f14..0000000 --- a/Makefile +++ /dev/null @@ -1,41 +0,0 @@ -# OASIS_START -# DO NOT EDIT (digest: a3c674b4239234cbbe53afe090018954) - -SETUP = ocaml setup.ml - -build: setup.data - $(SETUP) -build $(BUILDFLAGS) - -doc: setup.data build - $(SETUP) -doc $(DOCFLAGS) - -test: setup.data build - $(SETUP) -test $(TESTFLAGS) - -all: - $(SETUP) -all $(ALLFLAGS) - -install: setup.data - $(SETUP) -install $(INSTALLFLAGS) - -uninstall: setup.data - $(SETUP) -uninstall $(UNINSTALLFLAGS) - -reinstall: setup.data - $(SETUP) -reinstall $(REINSTALLFLAGS) - -clean: - $(SETUP) -clean $(CLEANFLAGS) - -distclean: - $(SETUP) -distclean $(DISTCLEANFLAGS) - -setup.data: - $(SETUP) -configure $(CONFIGUREFLAGS) - -configure: - $(SETUP) -configure $(CONFIGUREFLAGS) - -.PHONY: build doc test all install uninstall reinstall clean distclean configure - -# OASIS_STOP @@ -6,7 +6,7 @@ The Cryptokit library for OCaml provides a variety of cryptographic primitives t * Symmetric-key ciphers: AES, Chacha20, DES, Triple-DES, Blowfish, ARCfour, in ECB, CBC, CFB, OFB and counter modes. * Public-key cryptography: RSA encryption and signature, Diffie-Hellman key agreement. -* Hash functions and MACs: SHA-3, SHA-1, SHA-2, RIPEMD-160, MD5, and MACs based on AES and DES. +* Hash functions and MACs: SHA-3, SHA-2, BLAKE2b, RIPEMD-160, and MACs based on AES and DES. (SHA-1 and MD5, despite being broken, are also provided for historical value.) * Random number generation. * Encodings and compression: base 64, hexadecimal, Zlib compression. @@ -17,28 +17,38 @@ This library is distributed under the conditions of the GNU Library General Publ ## Requirements * OCaml 4.02 or more recent. -* The findlib/ocamlfind tool. -* The OASIS tool. +* The Dune build system, version 2.0 or more recent. * The Zarith library, version 1.4 or more recent. * The Zlib C library, version 1.1.3 or up is recommended. If it is not installed on your system (look for libz.a or libz.so), get it from http://www.gzip.org/, or indicate in the Makefile that you do not have it. If you are running Linux or BSD or MacOS, your distribution provides precompiled binaries for this library. * If the operating system does not provide the `/dev/random` device for random number generation, consider installing the [EGD](http://egd.sourceforge.net/) entropy gathering daemon. Without `/dev/random` nor EGD, this library cannot generate cryptographically-strong random data nor RSA keys. The remainder of the library still works, though. -## Installation +## Build, test and install +* To configure, run `./configure`. There are options to disable or enable some features (run `./configure --help` for a list), but the default configuration is fine most of the time. + +* To build, run `dune build`. + +* To execute a test, run `dune exec test/<name>.exe` where `<name>` can be `test`, + `prngtest` or `speedtest`, supplying additional command line arguments if needed. + The main test file `test/test.ml` is also included into the `runtest` alias, so it + can be executed simply by `dune test`. + +* To install, run `dune install`. + +## Using the library + +The package name is `cryptokit`. With Dune, use `(library cryptokit)`. With ocamlfind, do ``` -./configure --enable-tests -make -make test -make install + ocamlfind ocamlopt -package cryptokit ... # for compilation + ocamlfind ocamlopt -package cryptokit -linkpkg ... # for linking ``` ## Documentation -See the extensive documentation comments in file src/cryptokit.mli. - -Compilation options: `ocamlfind ocamlopt -package cryptokit`... +See the extensive documentation comments in file `src/cryptokit.mli`. -Linking options: `ocamlfind ocamlopt -linkpkg -package cryptokit`... +To build HTML documentation, run `dune build @doc`. The resulting index file is +located at `_build/default/_doc/_html/cryptokit/Cryptokit/index.html`. ## Warnings and disclaimers @@ -68,6 +78,8 @@ SHA-2 is implemented from scratch based on FIPS publication 180-2. It passes th SHA-3 is based on the "readable" implementation of Keccak written by Markku-Juhani O. Saarinen <mjos@iki.fi>. +BLAKE2b is implemented from scratch based on RFC 7693. The test vectors are taken from https://github.com/BLAKE2/BLAKE2/tree/master/testvectors; others were obtained with the b2sum program. + RIPEMD-160 is based on the reference implementation by A.Bosselaers. It passes the test vectors listed at http://www.esat.kuleuven.ac.be/~bosselae/ripemd160.html MD5 uses the public-domain implementation by Colin Plumb that is also used in the OCaml runtime system for module Digest. @@ -76,10 +88,10 @@ RSA encryption and decryption was implemented from scratch, using the Zarith OCa RSA key generation uses GMP's `nextprime` function for probabilistic primality testing. -The hardware RNG uses the RDRAND instruction of recent x86 processors, if supported. It is not available on other platforms. +The hardware RNG uses the RDRAND instruction of recent x86 processors, if supported. It is not available on other platforms. A check is included to reject the broken RDRAND on AMD Ryzen 3000 processors (https://arstechnica.com/gadgets/2019/10/how-a-months-old-amd-microcode-bug-destroyed-my-weekend/). The seeded PRNG is just the Chacha20 stream cipher encrypting the all-zeroes message. The seed is used as the Chacha20 key. An alternate seeded PRNG is provided, based on AES encryption of a 128-bit counter. Both PRNGs pass the Dieharder statistical tests. Still, better use the system RNG or the hardware RNG if high-quality random numbers are needed. ## Performance -If you configure with the options `--enable-tests --enable-bench`, then do `make test`, a simple benchmark is performed and shows the speed of various operations from this library. +If you run `dune exec test/speedtest.exe`, a simple benchmark is performed and shows the speed of various operations from this library. @@ -1,145 +0,0 @@ -OASISFormat: 0.4 -Name: cryptokit -Version: 1.15 -Authors: Xavier Leroy -License: LGPL-2 with OCaml linking exception -BuildTools: ocamlbuild, ocamldoc -Plugins: META (0.4), DevFiles (0.4) - -Synopsis: Cryptographic primitives -Description: - This library provides a variety of cryptographic primitives that can be used - to implement cryptographic protocols in security-sensitive applications. The - primitives provided include: - . - - Symmetric-key ciphers: AES, Chacha20, Blowfish, DES, Triple-DES, ARCfour, - in ECB, CBC, CFB, OFB and counter modes. - - Public-key cryptography: RSA encryption, Diffie-Hellman key agreement. - - Hash functions and MACs: SHA-1, SHA-2, SHA-3, RIPEMD160, MD5, - and MACs based on AES and DES. - - Random number generation. - - Encodings and compression: base 64, hexadecimal, Zlib compression. - . - Additional ciphers and hashes can easily be used in conjunction with - the library. In particular, basic mechanisms such as chaining modes, - output buffering, and padding are provided by generic classes that can - easily be composed with user-provided ciphers. More generally, the library - promotes a "Lego"-like style of constructing and composing - transformations over character streams. - -Flag zlib - Description: Enable ZLib - Default$: !os_type(Win32) - -Flag hardwaresupport - Description: Enable hardware support for AES and GCM (needs GCC or Clang) - Default$: (architecture(amd64) || architecture(i386)) && !os_type(Win32) - -Library cryptokit - Path: src - Modules: CryptokitBignum, Cryptokit - CSources: aesni.c, - aesni.h, - arcfour.c, - arcfour.h, - stubs-arcfour.c, - blowfish.c, - blowfish.h, - stubs-blowfish.c, - d3des.c, - d3des.h, - stubs-des.c, - rijndael-alg-fst.c, - rijndael-alg-fst.h, - ripemd160.c, - ripemd160.h, - stubs-ripemd160.c, - sha1.c, - sha1.h, - stubs-sha1.c, - sha256.c, - sha256.h, - stubs-sha256.c, - sha512.c, - sha512.h, - stubs-sha512.c, - stubs-aes.c, - stubs-md5.c, - stubs-misc.c, - stubs-rng.c, - stubs-zlib.c, - keccak.h, - keccak.c, - stubs-sha3.c, - chacha20.h, - chacha20.c, - stubs-chacha20.c - BuildDepends: unix, zarith - CCOpt: -DCAML_NAME_SPACE - if flag(zlib) - CCOpt+: -DHAVE_ZLIB - if system(win32) || system(win64) - CCLib: zlib.lib - else - CCLib: -lz - if system(win32) || system(win64) - CCLib+: advapi32.lib - else if system(mingw) || system(mingw64) - CCLib+: -ladvapi32 - if flag(hardwaresupport) - CCOpt+: -maes - -Executable test - Path: test - MainIs: test.ml - CompiledObject: native - BuildDepends: cryptokit - Build$: flag(tests) - Install: false - -Executable prngtest - Path: test - MainIs: prngtest.ml - CompiledObject: native - BuildDepends: cryptokit - Build$: flag(tests) - Install: false - -Test main - Command: $test - TestTools: test - -Flag bench - Description: Build and run benchmark - Default: false - -Executable speedtest - Path: test - MainIs: speedtest.ml - CompiledObject: native - BuildDepends: cryptokit - Install: false - Build$: flag(bench) - -Test bench - Command: $speedtest - Run$: flag(bench) - TestTools: speedtest - -Document "api-cryptokit" - Title: API reference for Cryptokit - Type: ocamlbuild (0.3) - InstallDir: $htmldir/cryptokit - BuildTools+: ocamldoc - XOCamlBuildPath: src/ - XOCamlbuildLibraries: cryptokit - -SourceRepository head - Type: git - Location: https://github.com/xavierleroy/cryptokit - Browser: https://github.com/xavierleroy/cryptokit - -SourceRepository this - Type: git - Location: https://github.com/xavierleroy/cryptokit/releases/tag/release113 - Browser: https://github.com/xavierleroy/cryptokit/releases/tag/release113 @@ -1,122 +0,0 @@ -# OASIS_START -# DO NOT EDIT (digest: 62ba61e1d8ad56a1e96795f7c6fb78e2) -# Ignore VCS directories, you can use the same kind of rule outside -# OASIS_START/STOP if you want to exclude directories that contains -# useless stuff for the build process -true: annot, bin_annot -<**/.svn>: -traverse -<**/.svn>: not_hygienic -".bzr": -traverse -".bzr": not_hygienic -".hg": -traverse -".hg": not_hygienic -".git": -traverse -".git": not_hygienic -"_darcs": -traverse -"_darcs": not_hygienic -# Library cryptokit -"src/cryptokit.cmxs": use_cryptokit -<src/*.ml{,i,y}>: oasis_library_cryptokit_ccopt -"src/aesni.c": oasis_library_cryptokit_ccopt -"src/arcfour.c": oasis_library_cryptokit_ccopt -"src/stubs-arcfour.c": oasis_library_cryptokit_ccopt -"src/blowfish.c": oasis_library_cryptokit_ccopt -"src/stubs-blowfish.c": oasis_library_cryptokit_ccopt -"src/d3des.c": oasis_library_cryptokit_ccopt -"src/stubs-des.c": oasis_library_cryptokit_ccopt -"src/rijndael-alg-fst.c": oasis_library_cryptokit_ccopt -"src/ripemd160.c": oasis_library_cryptokit_ccopt -"src/stubs-ripemd160.c": oasis_library_cryptokit_ccopt -"src/sha1.c": oasis_library_cryptokit_ccopt -"src/stubs-sha1.c": oasis_library_cryptokit_ccopt -"src/sha256.c": oasis_library_cryptokit_ccopt -"src/stubs-sha256.c": oasis_library_cryptokit_ccopt -"src/sha512.c": oasis_library_cryptokit_ccopt -"src/stubs-sha512.c": oasis_library_cryptokit_ccopt -"src/stubs-aes.c": oasis_library_cryptokit_ccopt -"src/stubs-md5.c": oasis_library_cryptokit_ccopt -"src/stubs-misc.c": oasis_library_cryptokit_ccopt -"src/stubs-rng.c": oasis_library_cryptokit_ccopt -"src/stubs-zlib.c": oasis_library_cryptokit_ccopt -"src/keccak.c": oasis_library_cryptokit_ccopt -"src/stubs-sha3.c": oasis_library_cryptokit_ccopt -"src/chacha20.c": oasis_library_cryptokit_ccopt -"src/stubs-chacha20.c": oasis_library_cryptokit_ccopt -<src/cryptokit.{cma,cmxa}>: oasis_library_cryptokit_cclib -"src/libcryptokit_stubs.lib": oasis_library_cryptokit_cclib -"src/dllcryptokit_stubs.dll": oasis_library_cryptokit_cclib -"src/libcryptokit_stubs.a": oasis_library_cryptokit_cclib -"src/dllcryptokit_stubs.so": oasis_library_cryptokit_cclib -<src/cryptokit.{cma,cmxa}>: use_libcryptokit_stubs -<src/*.ml{,i,y}>: pkg_unix -<src/*.ml{,i,y}>: pkg_zarith -"src/aesni.c": pkg_unix -"src/aesni.c": pkg_zarith -"src/arcfour.c": pkg_unix -"src/arcfour.c": pkg_zarith -"src/stubs-arcfour.c": pkg_unix -"src/stubs-arcfour.c": pkg_zarith -"src/blowfish.c": pkg_unix -"src/blowfish.c": pkg_zarith -"src/stubs-blowfish.c": pkg_unix -"src/stubs-blowfish.c": pkg_zarith -"src/d3des.c": pkg_unix -"src/d3des.c": pkg_zarith -"src/stubs-des.c": pkg_unix -"src/stubs-des.c": pkg_zarith -"src/rijndael-alg-fst.c": pkg_unix -"src/rijndael-alg-fst.c": pkg_zarith -"src/ripemd160.c": pkg_unix -"src/ripemd160.c": pkg_zarith -"src/stubs-ripemd160.c": pkg_unix -"src/stubs-ripemd160.c": pkg_zarith -"src/sha1.c": pkg_unix -"src/sha1.c": pkg_zarith -"src/stubs-sha1.c": pkg_unix -"src/stubs-sha1.c": pkg_zarith -"src/sha256.c": pkg_unix -"src/sha256.c": pkg_zarith -"src/stubs-sha256.c": pkg_unix -"src/stubs-sha256.c": pkg_zarith -"src/sha512.c": pkg_unix -"src/sha512.c": pkg_zarith -"src/stubs-sha512.c": pkg_unix -"src/stubs-sha512.c": pkg_zarith -"src/stubs-aes.c": pkg_unix -"src/stubs-aes.c": pkg_zarith -"src/stubs-md5.c": pkg_unix -"src/stubs-md5.c": pkg_zarith -"src/stubs-misc.c": pkg_unix -"src/stubs-misc.c": pkg_zarith -"src/stubs-rng.c": pkg_unix -"src/stubs-rng.c": pkg_zarith -"src/stubs-zlib.c": pkg_unix -"src/stubs-zlib.c": pkg_zarith -"src/keccak.c": pkg_unix -"src/keccak.c": pkg_zarith -"src/stubs-sha3.c": pkg_unix -"src/stubs-sha3.c": pkg_zarith -"src/chacha20.c": pkg_unix -"src/chacha20.c": pkg_zarith -"src/stubs-chacha20.c": pkg_unix -"src/stubs-chacha20.c": pkg_zarith -# Executable test -"test/test.native": pkg_unix -"test/test.native": pkg_zarith -"test/test.native": use_cryptokit -# Executable prngtest -"test/prngtest.native": pkg_unix -"test/prngtest.native": pkg_zarith -"test/prngtest.native": use_cryptokit -# Executable speedtest -"test/speedtest.native": pkg_unix -"test/speedtest.native": pkg_zarith -"test/speedtest.native": use_cryptokit -<test/*.ml{,i,y}>: pkg_unix -<test/*.ml{,i,y}>: pkg_zarith -<test/*.ml{,i,y}>: use_cryptokit -# OASIS_STOP -"build": not_hygienic -"build": -traverse -"src/cryptokit.cmxs": use_libcryptokit_stubs -<*/*.cm{o,x}>: safe_string @@ -1,27 +1,48 @@ -#!/bin/sh +#!/usr/bin/env ocaml +(* -*- tuareg -*- *) -# OASIS_START -# DO NOT EDIT (digest: dc86c2ad450f91ca10c931b6045d0499) -set -e +type 'a value = + | This of 'a + | Auto -FST=true -for i in "$@"; do - if $FST; then - set -- - FST=false - fi +let string_of_value to_string = function + | This a -> "This (" ^ to_string a ^ ")" + | Auto -> "Auto" - case $i in - --*=*) - ARG=${i%%=*} - VAL=${i##*=} - set -- "$@" "$ARG" "$VAL" - ;; - *) - set -- "$@" "$i" - ;; - esac -done +let () = + let declare_flag arg description = + let reference = ref Auto in + let args = + [ "--enable-" ^ arg, Arg.Unit (fun () -> reference := This true), + " Enable " ^ description + ; "--disable-" ^ arg, Arg.Unit (fun () -> reference := This false), + " Disable " ^ description + ] + in args, reference + in + let args_zlib, ref_zlib = declare_flag "zlib" "ZLib" in + let args_hardware_support, ref_hardware_support = + declare_flag "hardwaresupport" + "hardware support for AES and GCM (needs GCC or Clang)" in + Arg.parse + (Arg.align (args_zlib @ args_hardware_support)) + (fun s -> raise (Arg.Bad (Printf.sprintf "don't know what to do with %S" s))) + "Usage: ./configure [OPTIONS]"; + let oc = open_out_bin "src/config/config_vars.ml" in + Printf.fprintf oc {| +type 'a value = + | This of 'a + | Auto -ocaml setup.ml -configure "$@" -# OASIS_STOP +let enable_zlib = %s +let enable_hardware_support = %s +|} + (string_of_value string_of_bool !ref_zlib) + (string_of_value string_of_bool !ref_hardware_support); + close_out oc; + (* Below is a temporary workaround to make sure the configuration happens + every time this script is run. *) + (try + Sys.remove "_build/default/src/flags.sexp"; + with _ -> ()); + exit (Sys.command "dune build @configure --release") diff --git a/cryptokit.opam b/cryptokit.opam new file mode 100644 index 0000000..a5e6c09 --- /dev/null +++ b/cryptokit.opam @@ -0,0 +1,35 @@ +# This file is generated by dune, edit dune-project instead +opam-version: "2.0" +synopsis: "A library of cryptographic primitives" +description: """ +Cryptokit includes block ciphers (AES, DES, 3DES), stream ciphers +(ARCfour), public-key crypto (RSA, DH), hashes (SHA-1, SHA-256, +SHA-3), MACs, compression, random number generation -- all presented +with a compositional, extensible interface.""" +maintainer: ["Xavier Leroy <xavier.leroy@college-de-france.fr>"] +authors: ["Xavier Leroy"] +homepage: "https://github.com/xavierleroy/cryptokit" +bug-reports: "https://github.com/xavierleroy/cryptokit/issues" +depends: [ + "ocaml" {>= "4.03.0"} + "dune" {>= "2.0"} + "dune-configurator" + "zarith" {>= "1.4"} + "conf-zlib" + "conf-gmp-powm-sec" +] +build: [ + ["dune" "subst"] {pinned} + [ + "dune" + "build" + "-p" + name + "-j" + jobs + "@install" + "@runtest" {with-test} + "@doc" {with-doc} + ] +] +dev-repo: "git+https://github.com/xavierleroy/cryptokit.git" diff --git a/dune-project b/dune-project new file mode 100644 index 0000000..65441b0 --- /dev/null +++ b/dune-project @@ -0,0 +1,24 @@ +(lang dune 2.0) +(generate_opam_files true) + +(name cryptokit) +(source (github xavierleroy/cryptokit)) +(authors "Xavier Leroy") +(maintainers "Xavier Leroy <xavier.leroy@college-de-france.fr>") + +(package + (name cryptokit) + (synopsis "A library of cryptographic primitives") + + (description "Cryptokit includes block ciphers (AES, DES, 3DES), stream ciphers +(ARCfour), public-key crypto (RSA, DH), hashes (SHA-1, SHA-256, +SHA-3), MACs, compression, random number generation -- all presented +with a compositional, extensible interface.") + + (depends + (ocaml (>= 4.03.0)) + (dune (>= 2.0)) + dune-configurator + (zarith (>= 1.4)) + conf-zlib + conf-gmp-powm-sec)) diff --git a/setup.ml b/setup.ml deleted file mode 100644 index a07ec9f..0000000 --- a/setup.ml +++ /dev/null @@ -1,39 +0,0 @@ -(* setup.ml generated for the first time by OASIS v0.4.6 *) - -(* OASIS_START *) -(* DO NOT EDIT (digest: a426e2d026defb34183b787d31fbdcff) *) -(******************************************************************************) -(* OASIS: architecture for building OCaml libraries and applications *) -(* *) -(* Copyright (C) 2011-2016, Sylvain Le Gall *) -(* Copyright (C) 2008-2011, OCamlCore SARL *) -(* *) -(* This library is free software; you can redistribute it and/or modify it *) -(* under the terms of the GNU Lesser General Public License as published by *) -(* the Free Software Foundation; either version 2.1 of the License, or (at *) -(* your option) any later version, with the OCaml static compilation *) -(* exception. *) -(* *) -(* This library is distributed in the hope that it will be useful, but *) -(* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY *) -(* or FITNESS FOR A PARTICULAR PURPOSE. See the file COPYING for more *) -(* details. *) -(* *) -(* You should have received a copy of the GNU Lesser General Public License *) -(* along with this library; if not, write to the Free Software Foundation, *) -(* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA *) -(******************************************************************************) - -let () = - try - Topdirs.dir_directory (Sys.getenv "OCAML_TOPLEVEL_PATH") - with Not_found -> () -;; -#use "topfind";; -#require "oasis.dynrun";; -open OASISDynRun;; - -let setup_t = BaseCompat.Compat_0_4.adapt_setup_t setup_t -open BaseCompat.Compat_0_4 -(* OASIS_STOP *) -let () = setup ();; diff --git a/src/META b/src/META deleted file mode 100644 index 98a8e7d..0000000 --- a/src/META +++ /dev/null @@ -1,12 +0,0 @@ -# OASIS_START -# DO NOT EDIT (digest: 0b7c5c15af8df30a424bef17dc87d1b1) -version = "1.15" -description = "Cryptographic primitives" -requires = "unix zarith" -archive(byte) = "cryptokit.cma" -archive(byte, plugin) = "cryptokit.cma" -archive(native) = "cryptokit.cmxa" -archive(native, plugin) = "cryptokit.cmxs" -exists_if = "cryptokit.cma" -# OASIS_STOP - diff --git a/src/api-cryptokit.odocl b/src/api-cryptokit.odocl deleted file mode 100644 index c8577fb..0000000 --- a/src/api-cryptokit.odocl +++ /dev/null @@ -1,5 +0,0 @@ -# OASIS_START -# DO NOT EDIT (digest: f65b9dc92e3f638af8533b26ac90c400) -CryptokitBignum -Cryptokit -# OASIS_STOP diff --git a/src/blake2.c b/src/blake2.c new file mode 100644 index 0000000..cdd0384 --- /dev/null +++ b/src/blake2.c @@ -0,0 +1,314 @@ +/***********************************************************************/ +/* */ +/* The Cryptokit library */ +/* */ +/* Xavier Leroy, Collège de France and Inria */ +/* */ +/* Copyright 2020 Institut National de Recherche en Informatique et */ +/* en Automatique. All rights reserved. This file is distributed */ +/* under the terms of the GNU Library General Public License, with */ +/* the special exception on linking described in file LICENSE. */ +/* */ +/***********************************************************************/ + +/* BLAKE2 hashing */ + +#include <assert.h> +#include <stdint.h> +#include <string.h> +#include "blake2.h" + +static const uint8_t BLAKE2_sigma[12][16] = { + { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 }, + { 14, 10, 4, 8, 9, 15, 13, 6, 1, 12, 0, 2, 11, 7, 5, 3 }, + { 11, 8, 12, 0, 5, 2, 15, 13, 10, 14, 3, 6, 7, 1, 9, 4 }, + { 7, 9, 3, 1, 13, 12, 11, 14, 2, 6, 5, 10, 4, 0, 15, 8 }, + { 9, 0, 5, 7, 2, 4, 10, 15, 14, 1, 11, 12, 6, 8, 3, 13 }, + { 2, 12, 6, 10, 0, 11, 8, 3, 4, 13, 7, 5, 15, 14, 1, 9 }, + { 12, 5, 1, 15, 14, 13, 4, 10, 0, 7, 6, 3, 9, 2, 8, 11 }, + { 13, 11, 7, 14, 12, 1, 3, 9, 5, 0, 15, 4, 8, 6, 2, 10 }, + { 6, 15, 14, 9, 11, 3, 0, 8, 12, 2, 13, 7, 1, 4, 10, 5 }, + { 10, 2, 8, 4, 7, 6, 1, 5, 15, 11, 9, 14, 3, 12, 13, 0 }, + { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 }, + { 14, 10, 4, 8, 9, 15, 13, 6, 1, 12, 0, 2, 11, 7, 5, 3 } +}; + +/* BLAKE2b */ + +static inline uint64_t U8TO64LE(unsigned char * src) +{ + return (uint64_t) src[0] | ((uint64_t) src[1] << 8) + | ((uint64_t) src[2] << 16) | ((uint64_t) src[3] << 24) + | ((uint64_t) src[4] << 32) | ((uint64_t) src[5] << 40) + | ((uint64_t) src[6] << 48) | ((uint64_t) src[7] << 56); +} + +static inline uint64_t ROTR64(uint64_t x, int amount) +{ + return (x >> amount) | (x << (64 - amount)); +} + +static const uint64_t blake2b_iv[8] = { + UINT64_C(0x6a09e667f3bcc908), + UINT64_C(0xbb67ae8584caa73b), + UINT64_C(0x3c6ef372fe94f82b), + UINT64_C(0xa54ff53a5f1d36f1), + UINT64_C(0x510e527fade682d1), + UINT64_C(0x9b05688c2b3e6c1f), + UINT64_C(0x1f83d9abfb41bd6b), + UINT64_C(0x5be0cd19137e2179) +}; + +#define MIX2B(a,b,c,d,x,y) \ + do { \ + a += b + x; \ + d = ROTR64(d ^ a, 32); \ + c += d; \ + b = ROTR64(b ^ c, 24); \ + a += b + y; \ + d = ROTR64(d ^ a, 16); \ + c += d; \ + b = ROTR64(b ^ c, 63); \ + } while(0) \ + +static void blake2b_compress(struct blake2b * s, unsigned char * data, + unsigned int numbytes, int is_last_block) +{ + uint64_t v0, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15; + uint64_t m[16]; + int i; + const uint8_t * sigma; + + /* Update the length */ + s->len[0] += numbytes; + if (s->len[0] < numbytes) s->len[1]++; /* carry */ + /* Initialize work space */ + v0 = s->h[0]; v1 = s->h[1]; + v2 = s->h[2]; v3 = s->h[3]; + v4 = s->h[4]; v5 = s->h[5]; + v6 = s->h[6]; v7 = s->h[7]; + v8 = blake2b_iv[0]; v9 = blake2b_iv[1]; + v10 = blake2b_iv[2]; v11 = blake2b_iv[3]; + v12 = blake2b_iv[4] ^ s->len[0]; + v13 = blake2b_iv[5] ^ s->len[1]; + v14 = is_last_block ? ~ blake2b_iv[6] : blake2b_iv[6]; + v15 = blake2b_iv[7]; + /* Convert data to 16 64-bit words */ + for (i = 0; i < 16; i++) { + m[i] = U8TO64LE(data + i * 8); + } + /* Twelve rounds of mixing */ + for (i = 0; i < 12; i++) { + sigma = BLAKE2_sigma[i]; + MIX2B(v0, v4, v8, v12, m[sigma[0]], m[sigma[1]]); + MIX2B(v1, v5, v9, v13, m[sigma[2]], m[sigma[3]]); + MIX2B(v2, v6, v10, v14, m[sigma[4]], m[sigma[5]]); + MIX2B(v3, v7, v11, v15, m[sigma[6]], m[sigma[7]]); + MIX2B(v0, v5, v10, v15, m[sigma[8]], m[sigma[9]]); + MIX2B(v1, v6, v11, v12, m[sigma[10]], m[sigma[11]]); + MIX2B(v2, v7, v8, v13, m[sigma[12]], m[sigma[13]]); + MIX2B(v3, v4, v9, v14, m[sigma[14]], m[sigma[15]]); + } + /* Update state */ + s->h[0] ^= v0 ^ v8; s->h[1] ^= v1 ^ v9; + s->h[2] ^= v2 ^ v10; s->h[3] ^= v3 ^ v11; + s->h[4] ^= v4 ^ v12; s->h[5] ^= v5 ^ v13; + s->h[6] ^= v6 ^ v14; s->h[7] ^= v7 ^ v15; +} + +void blake2b_init(struct blake2b * s, + int hashlen, int keylen, unsigned char * key) +{ + int i; + assert (0 < hashlen && hashlen <= 64); + assert (0 <= keylen && keylen <= 64); + for (i = 0; i < 8; i++) s->h[i] = blake2b_iv[i]; + s->h[0] ^= 0x01010000 | (keylen << 8) | hashlen; + s->len[0] = s->len[1] = 0; + s->numbytes = 0; + /* If key was supplied, pad to 128 bytes and prepend to message */ + if (keylen > 0) { + memset(s->buffer, 0, BLAKE2b_BLOCKSIZE); + memcpy(s->buffer, key, keylen); + s->numbytes = BLAKE2b_BLOCKSIZE; + } +} + +void blake2b_add_data(struct blake2b * s, + unsigned char * data, size_t len) +{ + int n; + /* If data was left in buffer, pad it with fresh data and compress */ + if (s->numbytes > 0) { + n = BLAKE2b_BLOCKSIZE - s->numbytes; + if (len <= n) { + /* Not enough fresh data to compress. Buffer the data. */ + memcpy(s->buffer + s->numbytes, data, len); + s->numbytes += len; + return; + } + memcpy(s->buffer + s->numbytes, data, n); + blake2b_compress(s, s->buffer, BLAKE2b_BLOCKSIZE, 0); + data += n; len -= n; + } + /* Process data by blocks of BLAKE2b_BLOCKSIZE */ + while (len > BLAKE2b_BLOCKSIZE) { + blake2b_compress(s, data, BLAKE2b_BLOCKSIZE, 0); + data += BLAKE2b_BLOCKSIZE; len -= BLAKE2b_BLOCKSIZE; + } + /* Save remaining data */ + memcpy(s->buffer, data, len); + s->numbytes = len; +} + +void blake2b_final(struct blake2b * s, int hashlen, unsigned char * hash) +{ + unsigned int i; + assert (0 < hashlen && hashlen <= 64); + /* The final block is composed of the remaining data padded with zeros. */ + memset(s->buffer + s->numbytes, 0, BLAKE2b_BLOCKSIZE - s->numbytes); + blake2b_compress(s, s->buffer, s->numbytes, 1); + /* Extract the hash */ + for (i = 0; i < hashlen; i++) { + hash[i] = s->h[i / 8] >> (8 * (i % 8)); + } +} + +/* BLAKE2s */ + +static inline uint32_t U8TO32LE(unsigned char * src) +{ + return (uint32_t) src[0] | ((uint32_t) src[1] << 8) + | ((uint32_t) src[2] << 16) | ((uint32_t) src[3] << 24); +} + +static inline uint32_t ROTR32(uint32_t x, int amount) +{ + return (x >> amount) | (x << (32 - amount)); +} + +static const uint32_t blake2s_iv[8] = { + UINT32_C(0x6A09E667), + UINT32_C(0xBB67AE85), + UINT32_C(0x3C6EF372), + UINT32_C(0xA54FF53A), + UINT32_C(0x510E527F), + UINT32_C(0x9B05688C), + UINT32_C(0x1F83D9AB), + UINT32_C(0x5BE0CD19) +}; + +#define MIX2S(a,b,c,d,x,y) \ + do { \ + a += b + x; \ + d = ROTR32(d ^ a, 16); \ + c += d; \ + b = ROTR32(b ^ c, 12); \ + a += b + y; \ + d = ROTR32(d ^ a, 8); \ + c += d; \ + b = ROTR32(b ^ c, 7); \ + } while(0) \ + +static void blake2s_compress(struct blake2s * s, unsigned char * data, + unsigned int numbytes, int is_last_block) +{ + uint32_t v0, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15; + uint32_t m[16]; + int i; + const uint8_t * sigma; + + /* Update the length */ + s->len[0] += numbytes; + if (s->len[0] < numbytes) s->len[1]++; /* carry */ + /* Initialize work space */ + v0 = s->h[0]; v1 = s->h[1]; + v2 = s->h[2]; v3 = s->h[3]; + v4 = s->h[4]; v5 = s->h[5]; + v6 = s->h[6]; v7 = s->h[7]; + v8 = blake2s_iv[0]; v9 = blake2s_iv[1]; + v10 = blake2s_iv[2]; v11 = blake2s_iv[3]; + v12 = blake2s_iv[4] ^ s->len[0]; + v13 = blake2s_iv[5] ^ s->len[1]; + v14 = is_last_block ? ~ blake2s_iv[6] : blake2s_iv[6]; + v15 = blake2s_iv[7]; + /* Convert data to 16 32-bit words */ + for (i = 0; i < 16; i++) { + m[i] = U8TO32LE(data + i * 4); + } + /* Ten rounds of mixing */ + for (i = 0; i < 10; i++) { + sigma = BLAKE2_sigma[i]; + MIX2S(v0, v4, v8, v12, m[sigma[0]], m[sigma[1]]); + MIX2S(v1, v5, v9, v13, m[sigma[2]], m[sigma[3]]); + MIX2S(v2, v6, v10, v14, m[sigma[4]], m[sigma[5]]); + MIX2S(v3, v7, v11, v15, m[sigma[6]], m[sigma[7]]); + MIX2S(v0, v5, v10, v15, m[sigma[8]], m[sigma[9]]); + MIX2S(v1, v6, v11, v12, m[sigma[10]], m[sigma[11]]); + MIX2S(v2, v7, v8, v13, m[sigma[12]], m[sigma[13]]); + MIX2S(v3, v4, v9, v14, m[sigma[14]], m[sigma[15]]); + } + /* Update state */ + s->h[0] ^= v0 ^ v8; s->h[1] ^= v1 ^ v9; + s->h[2] ^= v2 ^ v10; s->h[3] ^= v3 ^ v11; + s->h[4] ^= v4 ^ v12; s->h[5] ^= v5 ^ v13; + s->h[6] ^= v6 ^ v14; s->h[7] ^= v7 ^ v15; +} + +void blake2s_init(struct blake2s * s, + int hashlen, int keylen, unsigned char * key) +{ + int i; + assert (0 < hashlen && hashlen <= 32); + assert (0 <= keylen && keylen <= 32); + for (i = 0; i < 8; i++) s->h[i] = blake2s_iv[i]; + s->h[0] ^= 0x01010000 | (keylen << 8) | hashlen; + s->len[0] = s->len[1] = 0; + s->numbytes = 0; + /* If key was supplied, pad to 64 bytes and prepend to message */ + if (keylen > 0) { + memset(s->buffer, 0, BLAKE2s_BLOCKSIZE); + memcpy(s->buffer, key, keylen); + s->numbytes = BLAKE2s_BLOCKSIZE; + } +} + +void blake2s_add_data(struct blake2s * s, + unsigned char * data, size_t len) +{ + int n; + /* If data was left in buffer, pad it with fresh data and compress */ + if (s->numbytes > 0) { + n = BLAKE2s_BLOCKSIZE - s->numbytes; + if (len <= n) { + /* Not enough fresh data to compress. Buffer the data. */ + memcpy(s->buffer + s->numbytes, data, len); + s->numbytes += len; + return; + } + memcpy(s->buffer + s->numbytes, data, n); + blake2s_compress(s, s->buffer, BLAKE2s_BLOCKSIZE, 0); + data += n; len -= n; + } + /* Process data by blocks of BLAKE2s_BLOCKSIZE */ + while (len > BLAKE2s_BLOCKSIZE) { + blake2s_compress(s, data, BLAKE2s_BLOCKSIZE, 0); + data += BLAKE2s_BLOCKSIZE; len -= BLAKE2s_BLOCKSIZE; + } + /* Save remaining data */ + memcpy(s->buffer, data, len); + s->numbytes = len; +} + +void blake2s_final(struct blake2s * s, int hashlen, unsigned char * hash) +{ + unsigned int i; + assert (0 < hashlen && hashlen <= 32); + /* The final block is composed of the remaining data padded with zeros. */ + memset(s->buffer + s->numbytes, 0, BLAKE2s_BLOCKSIZE - s->numbytes); + blake2s_compress(s, s->buffer, s->numbytes, 1); + /* Extract the hash */ + for (i = 0; i < hashlen; i++) { + hash[i] = s->h[i / 4] >> (8 * (i % 4)); + } +} diff --git a/src/blake2.h b/src/blake2.h new file mode 100644 index 0000000..1693b33 --- /dev/null +++ b/src/blake2.h @@ -0,0 +1,47 @@ +/***********************************************************************/ +/* */ +/* The Cryptokit library */ +/* */ +/* Xavier Leroy, Collège de France and Inria */ +/* */ +/* Copyright 2020 Institut National de Recherche en Informatique et */ +/* en Automatique. All rights reserved. This file is distributed */ +/* under the terms of the GNU Library General Public License, with */ +/* the special exception on linking described in file LICENSE. */ +/* */ +/***********************************************************************/ + +/* BLAKE2b hashing */ + +#define BLAKE2b_BLOCKSIZE 128 + +struct blake2b { + uint64_t h[8]; + uint64_t len[2]; + int numbytes; + unsigned char buffer[BLAKE2b_BLOCKSIZE]; +}; + +extern void blake2b_init(struct blake2b * s, + int hashlen, int keylen, unsigned char * key); +extern void blake2b_add_data(struct blake2b * s, + unsigned char * data, size_t len); +extern void blake2b_final(struct blake2b * s, + int hashlen, unsigned char * hash); + +#define BLAKE2s_BLOCKSIZE 64 + +struct blake2s { + uint32_t h[8]; + uint32_t len[2]; + int numbytes; + unsigned char buffer[BLAKE2s_BLOCKSIZE]; +}; + +extern void blake2s_init(struct blake2s * s, + int hashlen, int keylen, unsigned char * key); +extern void blake2s_add_data(struct blake2s * s, + unsigned char * data, size_t len); +extern void blake2s_final(struct blake2s * s, + int hashlen, unsigned char * hash); + diff --git a/src/config/config_vars.ml.default b/src/config/config_vars.ml.default new file mode 100644 index 0000000..1b56c41 --- /dev/null +++ b/src/config/config_vars.ml.default @@ -0,0 +1,7 @@ +type 'a value = + | This of 'a + | Auto + +let enable_zlib = Auto + +let enable_hardware_support = Auto diff --git a/src/config/dune b/src/config/dune new file mode 100644 index 0000000..ece93d5 --- /dev/null +++ b/src/config/dune @@ -0,0 +1,7 @@ +(executable + (name flags) + (libraries dune-configurator)) + +(rule + (mode fallback) + (action (copy config_vars.ml.default config_vars.ml))) diff --git a/src/config/flags.ml b/src/config/flags.ml new file mode 100644 index 0000000..f8f2157 --- /dev/null +++ b/src/config/flags.ml @@ -0,0 +1,45 @@ +(* Compute compilation and linking flags *) + +open Config_vars + +module Configurator = Configurator.V1 + +(* Compile and link a dummy C program with the given flags. *) +let test ~cfg ~c_flags ~link_flags = + let test_program = "int main() { return 0; }" in + Configurator.c_test cfg test_program ~c_flags ~link_flags + +let () = Configurator.main ~name:"cryptokit" (fun cfg -> + let os_type = Configurator.ocaml_config_var_exn cfg "os_type" in + let system = Configurator.ocaml_config_var_exn cfg "system" in + let architecture = Configurator.ocaml_config_var_exn cfg "architecture" in + let zlib = match enable_zlib with + | This bool -> bool + | Auto -> os_type <> "Win32" + in + let hardware_support = match enable_hardware_support with + | This bool -> bool + | Auto -> (architecture = "amd64" || architecture = "i386") + && test ~cfg ~c_flags:[ "-maes" ] ~link_flags:[] + in + let append_if c y x = if c then x @ [ y ] else x in + let flags = + [] + |> append_if zlib "-DHAVE_ZLIB" + |> append_if hardware_support "-maes" + in + let library_flags = + [] + |> append_if (zlib && (system = "win32" || system = "win64")) "zlib.lib" + |> append_if (zlib && system <> "win32" && system <> "win64") "-lz" + |> append_if (system = "win32" || system = "win64") "advapi32.lib" + |> append_if (system = "mingw" || system = "mingw64") "-ladvapi32" + in + Configurator.Flags.write_sexp "flags.sexp" flags; + Configurator.Flags.write_sexp "library_flags.sexp" library_flags; + let describe_bool = function + | true -> "enabled" + | false -> "disabled" + in + Printf.printf "ZLib: ............................... %s\n" (describe_bool zlib); + Printf.printf "Hardware support for AES and GCM: ... %s\n" (describe_bool hardware_support)) diff --git a/src/cryptokit.ml b/src/cryptokit.ml index d2fd91e..dcb2629 100644 --- a/src/cryptokit.ml +++ b/src/cryptokit.ml @@ -90,6 +90,12 @@ external ripemd160_final: bytes -> string = "caml_ripemd160_final" external md5_init: unit -> bytes = "caml_md5_init" external md5_update: bytes -> bytes -> int -> int -> unit = "caml_md5_update" external md5_final: bytes -> string = "caml_md5_final" +external blake2b_init: int -> string -> bytes = "caml_blake2b_init" +external blake2b_update: bytes -> bytes -> int -> int -> unit = "caml_blake2b_update" +external blake2b_final: bytes -> int -> string = "caml_blake2b_final" +external blake2s_init: int -> string -> bytes = "caml_blake2s_init" +external blake2s_update: bytes -> bytes -> int -> int -> unit = "caml_blake2s_update" +external blake2s_final: bytes -> int -> string = "caml_blake2s_final" (* Abstract transform type *) @@ -1092,6 +1098,56 @@ class md5 = let md5 () = new md5 +class blake2b sz key = + object(self) + val context = + if sz >= 8 && sz <= 512 && sz mod 8 = 0 && String.length key <= 64 + then blake2b_init (sz / 8) key + else raise (Error Wrong_key_size) + method hash_size = sz / 8 + method add_substring src ofs len = + if ofs < 0 || len < 0 || ofs > Bytes.length src - len + then invalid_arg "blake2b#add_substring"; + blake2b_update context src ofs len + method add_string src = + blake2b_update context (Bytes.unsafe_of_string src) 0 (String.length src) + method add_char c = + self#add_string (String.make 1 c) + method add_byte b = + self#add_char (Char.unsafe_chr b) + method result = blake2b_final context (sz / 8) + method wipe = + wipe_bytes context + end + +let blake2b sz = new blake2b sz "" +let blake2b512 () = new blake2b 512 "" + +class blake2s sz key = + object(self) + val context = + if sz >= 8 && sz <= 256 && sz mod 8 = 0 && String.length key <= 32 + then blake2s_init (sz / 8) key + else raise (Error Wrong_key_size) + method hash_size = sz / 8 + method add_substring src ofs len = + if ofs < 0 || len < 0 || ofs > Bytes.length src - len + then invalid_arg "blake2s#add_substring"; + blake2s_update context src ofs len + method add_string src = + blake2s_update context (Bytes.unsafe_of_string src) 0 (String.length src) + method add_char c = + self#add_string (String.make 1 c) + method add_byte b = + self#add_char (Char.unsafe_chr b) + method result = blake2s_final context (sz / 8) + method wipe = + wipe_bytes context + end + +let blake2s sz = new blake2s sz "" +let blake2s256 () = new blake2s 256 "" + end (* High-level entry points for ciphers *) @@ -1114,6 +1170,7 @@ let make_block_cipher ?(mode = CBC) ?pad ?iv dir block_cipher = (ECB, _) -> block_cipher | (CBC, Encrypt) -> new Block.cbc_encrypt ?iv block_cipher | (CBC, Decrypt) -> new Block.cbc_decrypt ?iv block_cipher + | (CFB n, Encrypt) -> new Block.cfb_encrypt ?iv n block_cipher | (CFB n, Decrypt) -> new Block.cfb_decrypt ?iv n block_cipher | (OFB n, _) -> new Block.ofb ?iv n block_cipher @@ -1212,6 +1269,12 @@ let hmac_sha512 key = new HMAC_SHA512.hmac key let hmac_ripemd160 key = new HMAC_RIPEMD160.hmac key let hmac_md5 key = new HMAC_MD5.hmac key +let blake2b sz key = new Hash.blake2b sz key +let blake2b512 key = new Hash.blake2b 512 key + +let blake2s sz key = new Hash.blake2s sz key +let blake2s256 key = new Hash.blake2s 256 key + let aes ?iv ?pad key = new Block.mac ?iv ?pad (new Block.aes_encrypt key) let des ?iv ?pad key = diff --git a/src/cryptokit.mldylib b/src/cryptokit.mldylib deleted file mode 100644 index c8577fb..0000000 --- a/src/cryptokit.mldylib +++ /dev/null @@ -1,5 +0,0 @@ -# OASIS_START -# DO NOT EDIT (digest: f65b9dc92e3f638af8533b26ac90c400) -CryptokitBignum -Cryptokit -# OASIS_STOP diff --git a/src/cryptokit.mli b/src/cryptokit.mli index 3cb58ed..0392eca 100644 --- a/src/cryptokit.mli +++ b/src/cryptokit.mli @@ -11,8 +11,6 @@ (* *) (***********************************************************************) -(* $Id$ *) - (** The Cryptokit library provides a variety of cryptographic primitives that can be used to implement cryptographic protocols in security-sensitive applications. The primitives provided include: @@ -23,11 +21,6 @@ and MACs based on AES and DES. - Random number generation. - Encodings and compression: base 64, hexadecimal, Zlib compression. - - To use this library, link with - [ocamlc unix.cma nums.cma cryptokit.cma] - or - [ocamlopt unix.cmxa nums.cmxa cryptokit.cmxa]. *) (** {1 General-purpose abstract interfaces} *) @@ -603,6 +596,22 @@ module Hash : sig val sha512: unit -> hash (** SHA-512 is SHA-2 specialized to 512 bit hashes (64 bytes). *) + val blake2b: int -> hash + (** The BLAKE2b hash function produces hashes of length 1 to 64 bytes. + The parameter is the desired size of the hash, in bits. + It must be between 8 and 512, and a multiple of 8. *) + + val blake2b512: unit -> hash + (** BLAKE2b512 is BLAKE2b specialized to 512 bit hashes (64 bytes). *) + + val blake2s: int -> hash + (** The BLAKE2s hash function produces hashes of length 1 to 32 bytes. + The parameter is the desired size of the hash, in bits. + It must be between 8 and 256, and a multiple of 8. *) + + val blake2s256: unit -> hash + (** BLAKE2s256 is BLAKE2s specialized to 256 bit hashes (32 bytes). *) + val ripemd160: unit -> hash (** RIPEMD-160 produces 160-bit hashes (20 bytes). *) @@ -631,9 +640,10 @@ end and if it matches the transmitted MAC, be reasonably certain that the text was authentified by someone who possesses the secret key. - The module [MAC] provides five MAC functions based on the hashes - SHA-1, SHA256, SHA512, RIPEMD160 and MD5, and five MAC functions based on - the block ciphers AES, DES, and Triple-DES. *) + The module [MAC] provides six MAC functions based on the hashes + BLAKE2b, SHA-1, SHA256, SHA512, RIPEMD160 and MD5, + and five MAC functions based on the block ciphers AES, DES, and Triple-DES. +*) module MAC: sig val hmac_sha1: string -> hash @@ -669,6 +679,34 @@ module MAC: sig long. The [key] argument is the MAC key; it can have any length, but a minimal length of 16 bytes is recommended. *) + val blake2b: int -> string -> hash + (** [blake2b sz key] is the BLAKE2b keyed hash function. + The returned hash values have length 1 to 64 bytes. + The [sz] is the desired size of the hash, in bits. + It must be between 8 and 512, and a multiple of 8. + The [key] argument is the MAC key. It must have length 64 at most. + A length of 64 bytes is recommended. *) + + val blake2b512: string -> hash + (** [blake2b512 key] is the BLAKE2b keyed hash function specialized + to 512 byte hashes (64 bytes). + The [key] argument is the MAC key. It must have length 64 at most. + A length of 64 bytes is recommended. *) + + val blake2s: int -> string -> hash + (** [blake2s sz key] is the BLAKE2s keyed hash function. + The returned hash values have length 1 to 32 bytes. + The [sz] is the desired size of the hash, in bits. + It must be between 8 and 256, and a multiple of 8. + The [key] argument is the MAC key. It must have length 32 at most. + A length of 32 bytes is recommended. *) + + val blake2s256: string -> hash + (** [blake2s256 key] is the BLAKE2s keyed hash function specialized + to 256 byte hashes (32 bytes). + The [key] argument is the MAC key. It must have length 32 at most. + A length of 32 bytes is recommended. *) + val aes_cmac: ?iv:string -> string -> hash (** [aes_cmac key] returns a MAC based on AES encryption in CMAC mode, also known as OMAC1 mode. The input data is encrypted using diff --git a/src/cryptokit.mllib b/src/cryptokit.mllib deleted file mode 100644 index c8577fb..0000000 --- a/src/cryptokit.mllib +++ /dev/null @@ -1,5 +0,0 @@ -# OASIS_START -# DO NOT EDIT (digest: f65b9dc92e3f638af8533b26ac90c400) -CryptokitBignum -Cryptokit -# OASIS_STOP diff --git a/src/dune b/src/dune new file mode 100644 index 0000000..a6642bc --- /dev/null +++ b/src/dune @@ -0,0 +1,41 @@ +(library (name cryptokit) (public_name cryptokit) + (libraries unix zarith) + (modules CryptokitBignum Cryptokit) + (foreign_stubs + (language c) + (flags -DCAML_NAME_SPACE (:include flags.sexp)) + (names aesni + arcfour + stubs-arcfour + blowfish + stubs-blowfish + d3des + stubs-des + rijndael-alg-fst + ripemd160 + stubs-ripemd160 + sha1 + stubs-sha1 + sha256 + stubs-sha256 + sha512 + stubs-sha512 + stubs-aes + stubs-md5 + stubs-misc + stubs-rng + stubs-zlib + keccak + stubs-sha3 + chacha20 + stubs-chacha20 + blake2 + stubs-blake2)) + (c_library_flags (:include library_flags.sexp)) + (flags :standard -safe-string -w -7 -w -27 -w -37)) + +; compute flags +(rule + (alias configure) + (targets flags.sexp library_flags.sexp) + (action (run config/flags.exe))) diff --git a/src/libcryptokit_stubs.clib b/src/libcryptokit_stubs.clib deleted file mode 100644 index 94cc08d..0000000 --- a/src/libcryptokit_stubs.clib +++ /dev/null @@ -1,28 +0,0 @@ -# OASIS_START -# DO NOT EDIT (digest: c7ac7a160eaa5e93a581a4efbe9317de) -aesni.o -arcfour.o -stubs-arcfour.o -blowfish.o -stubs-blowfish.o -d3des.o -stubs-des.o -rijndael-alg-fst.o -ripemd160.o -stubs-ripemd160.o -sha1.o -stubs-sha1.o -sha256.o -stubs-sha256.o -sha512.o -stubs-sha512.o -stubs-aes.o -stubs-md5.o -stubs-misc.o -stubs-rng.o -stubs-zlib.o -keccak.o -stubs-sha3.o -chacha20.o -stubs-chacha20.o -# OASIS_STOP diff --git a/src/stubs-blake2.c b/src/stubs-blake2.c new file mode 100644 index 0000000..2ccd1d3 --- /dev/null +++ b/src/stubs-blake2.c @@ -0,0 +1,75 @@ +/***********************************************************************/ +/* */ +/* The Cryptokit library */ +/* */ +/* Xavier Leroy, Collège de France and Inria */ +/* */ +/* Copyright 2020 Institut National de Recherche en Informatique et */ +/* en Automatique. All rights reserved. This file is distributed */ +/* under the terms of the GNU Library General Public License, with */ +/* the special exception on linking described in file LICENSE. */ +/* */ +/***********************************************************************/ + +#include <stdint.h> +#include <string.h> +#include <caml/mlvalues.h> +#include <caml/memory.h> +#include <caml/alloc.h> +#include "blake2.h" + +#define blake2b_val(v) ((struct blake2b *) String_val(v)) + +CAMLprim value caml_blake2b_init(value hashlen, value key) +{ + value ctx = caml_alloc_string(sizeof(struct blake2b)); + blake2b_init(blake2b_val(ctx), + Int_val(hashlen), + caml_string_length(key), &Byte_u(key, 0)); + return ctx; +} + +CAMLprim value caml_blake2b_update(value ctx, value src, value ofs, value len) +{ + blake2b_add_data(blake2b_val(ctx), + &Byte_u(src, Long_val(ofs)), Long_val(len)); + return Val_unit; +} + +CAMLprim value caml_blake2b_final(value ctx, value hashlen) +{ + CAMLparam1(ctx); + CAMLlocal1(res); + int len = Int_val(hashlen); + res = caml_alloc_string(len); + blake2b_final(blake2b_val(ctx), len, &Byte_u(res, 0)); + CAMLreturn(res); +} + +#define blake2s_val(v) ((struct blake2s *) String_val(v)) + +CAMLprim value caml_blake2s_init(value hashlen, value key) +{ + value ctx = caml_alloc_string(sizeof(struct blake2s)); + blake2s_init(blake2s_val(ctx), + Int_val(hashlen), + caml_string_length(key), &Byte_u(key, 0)); + return ctx; +} + +CAMLprim value caml_blake2s_update(value ctx, value src, value ofs, value len) +{ + blake2s_add_data(blake2s_val(ctx), + &Byte_u(src, Long_val(ofs)), Long_val(len)); + return Val_unit; +} + +CAMLprim value caml_blake2s_final(value ctx, value hashlen) +{ + CAMLparam1(ctx); + CAMLlocal1(res); + int len = Int_val(hashlen); + res = caml_alloc_string(len); + blake2s_final(blake2s_val(ctx), len, &Byte_u(res, 0)); + CAMLreturn(res); +} diff --git a/src/stubs-zlib.c b/src/stubs-zlib.c index 1d9af34..dd84dba 100644 --- a/src/stubs-zlib.c +++ b/src/stubs-zlib.c @@ -186,12 +186,12 @@ static void caml_zlib_not_supported(void) if (caml_zlib_error_exn == NULL) { caml_zlib_error_exn = caml_named_value("Cryptokit.Error"); if (caml_zlib_error_exn == NULL) - invalid_argument("Exception Cryptokit.Error not initialized"); + caml_invalid_argument("Exception Cryptokit.Error not initialized"); } - bucket = alloc_small(2, 0); + bucket = caml_alloc_small(2, 0); Field(bucket, 0) = *caml_zlib_error_exn; Field(bucket, 1) = Val_int(12); /* Compression_not_supported */ - mlraise(bucket); + caml_raise(bucket); } CAMLprim diff --git a/test/dune b/test/dune new file mode 100644 index 0000000..3e89187 --- /dev/null +++ b/test/dune @@ -0,0 +1,16 @@ +(test + (name test) + (modules test) + (libraries cryptokit) + (flags :standard -w -35)) + +(executable + (name prngtest) + (modules prngtest) + (libraries cryptokit)) + +(executable + (name speedtest) + (modules speedtest) + (libraries cryptokit) + (flags :standard -w -35)) diff --git a/test/speedtest.ml b/test/speedtest.ml index 0552d90..8a3ea59 100644 --- a/test/speedtest.ml +++ b/test/speedtest.ml @@ -108,8 +108,12 @@ let _ = (hash (Hash.sha3 384) 4000000 16); time_fn "SHA-3 512, 64_000_000 bytes, 16-byte chunks" (hash (Hash.sha3 512) 4000000 16); + time_fn "BLAKE2b 512, 64_000_000 bytes, 16-byte chunks" + (hash (Hash.blake2b 512) 4000000 16); + time_fn "BLAKE2s 256, 64_000_000 bytes, 16-byte chunks" + (hash (Hash.blake2s 256) 4000000 16); time_fn "RIPEMD-160, 64_000_000 bytes, 16-byte chunks" - (hash (Hash.sha256()) 4000000 16); + (hash (Hash.ripemd160()) 4000000 16); time_fn "MD5, 64_000_000 bytes, 16-byte chunks" (hash (Hash.md5()) 4000000 16); time_fn "AES CMAC, 64_000_000 bytes, 16-byte chunks" diff --git a/test/test.ml b/test/test.ml index d5b7690..8ebfaff 100644 --- a/test/test.ml +++ b/test/test.ml @@ -41,6 +41,10 @@ let test test_number answer correct_answer = printf " %d..." test_number end +(* Whether to run the most expensive tests or not *) + +let long_tests = ref false + (* Useful auxiliaries *) let hex s = transform_string (Hexa.decode()) s @@ -318,6 +322,7 @@ let _ = (hex "84983E441C3BD26EBAAE4AA1F95129E5E54670F1"); test 6 (hash_million_a (Hash.sha1())) (hex "34AA973CD4C4DAA4F61EEB2BDBAD27316534016F"); + if !long_tests then test 99 (hash_extremely_long (Hash.sha1())) (hex "7789f0c9 ef7bfc40 d9331114 3dfbe69e 2017f592") @@ -346,6 +351,7 @@ let _ = (hex "248d6a61d20638b8e5c026930c3e6039a33ce45964ff2167f6ecedd419db06c1"); test 4 (hash_million_a (Hash.sha2 256)) (hex "cdc76e5c9914fb9281a1c7e284d73e67f1809a48a497200e046d39ccc7112cd0"); + if !long_tests then test 99 (hash_extremely_long (Hash.sha256())) (hex "50e72a0e 26442fe2 552dc393 8ac58658 228c0cbf b1d2ca87 2ae43526 6fcd055e") @@ -376,6 +382,7 @@ let _ = (hex "8e959b75dae313da 8cf4f72814fc143f 8f7779c6eb9f7fa1 7299aeadb6889018 501d289e4900f7e4 331b99dec4b5433a c7d329eeb6dd2654 5e96e55b874be909"); test 5 (hash_million_a (Hash.sha2 512)) (hex "e718483d0ce76964 4e2e42c7bc15b463 8e1f98b13b204428 5632a803afa973eb de0ff244877ea60a 4cb0432ce577c31b eb009c5c2c49aa2e 4eadb217ad8cc09b"); + if !long_tests then test 99 (hash_extremely_long (Hash.sha2 512)) (hex "b47c933421ea2db1 49ad6e10fce6c7f9 3d0752380180ffd7 f4629a712134831d 77be6091b819ed35 2c2967a2e2d4fa50 50723c9630691f1a 05a7281dbe6c1086") @@ -427,6 +434,7 @@ let _ = (hex "eee9e24d78c18553 37983451df97c8ad 9eedf256c6334f8e 948d252d5e0e7684 7aa0774ddb90a842 190d2c558b4b8340"); test 20 (hash_million_a (Hash.sha3 512)) (hex "3c3a876da14034ab 60627c077bb98f7e 120a2a5370212dff b3385a18d4f38859 ed311d0a9d5141ce 9cc5c66ee689b266 a8aa18ace8282a0e 0db596c90b0a7b87"); + if !long_tests then test 99 (hash_extremely_long (Hash.sha3 512)) (hex "235ffd53504ef836 a1342b488f483b39 6eabbfe642cf78ee 0d31feec788b23d0 d18d5c339550dd59 58a500d4b95363da 1b5fa18affc1bab2 292dc63b7d85097c") @@ -479,11 +487,67 @@ let _ = (hex "2c23146a63a29acf 99e73b88f8c24eaa 7dc60aa771780ccc 006afbfa8fe2479b 2dd2b21362337441 ac12b515911957ff"); test 20 (hash 512 s) (hex "0eab42de4c3ceb92 35fc91acffe746b2 9c29a8c366b7c60e 4e67c466f36a4304 c00fa9caf9d87976 ba469bcbe06713b4 35f091ef2769fb16 0cdab33d3670680e"); + if !long_tests then test 98 (hash_extremely_long (Hash.keccak 256)) (hex "5f313c39963dcf79 2b5470d4ade9f3a3 56a3e4021748690a 958372e2b06f82a4"); + if !long_tests then test 99 (hash_extremely_long (Hash.keccak 512)) (hex "3e122edaf3739823 1cfaca4c7c216c9d 66d5b899ec1d7ac6 17c40c7261906a45 fc01617a021e5da3 bd8d4182695b5cb7 85a28237cbb16759 0e34718e56d8aab8") +(* BLAKE2b *) + +let _ = + testing_function "BLAKE2b-512"; + let hash s = hash_string (Hash.blake2b512 ()) s in + test 1 (hash "") + (hex "786a02f742015903c6c6fd852552d272912f4740e15847618a86e217f71f5419d25e1031afee585313896444934eb04b903a685b1448b755d56f701afe9be2ce"); + test 2 (hash "abc") + (hex "ba80a53f981c4d0d6a2797b69f12f6e94c212f14685ac4b74b12bb6fdbffa2d17d87c5392aab792dc252d5de4533cc9518d38aa8dbf1925ab92386edd4009923"); + test 3 (hash "abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmnhijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu") + (hex "ce741ac5930fe346811175c5227bb7bfcd47f42612fae46c0809514f9e0e3a11ee1773287147cdeaeedff50709aa716341fe65240f4ad6777d6bfaf9726e5e52") + +let _ = + testing_function "BLAKE2b-512 (keyed)"; + let mkstring n = String.init n (fun i -> Char.chr i) in + let key = mkstring 0x40 in + let hash s = hash_string (MAC.blake2b512 key) s in + List.iter + (fun (len, result) -> test len (hash (mkstring len)) (hex result)) + [ +0, "10ebb67700b1868efb4417987acf4690ae9d972fb7a590c2f02871799aaa4786b5e996e8f0f4eb981fc214b005f42d2ff4233499391653df7aefcbc13fc51568"; +1, "961f6dd1e4dd30f63901690c512e78e4b45e4742ed197c3c5e45c549fd25f2e4187b0bc9fe30492b16b0d0bc4ef9b0f34c7003fac09a5ef1532e69430234cebd"; +2, "da2cfbe2d8409a0f38026113884f84b50156371ae304c4430173d08a99d9fb1b983164a3770706d537f49e0c916d9f32b95cc37a95b99d857436f0232c88a965"; +3, "33d0825dddf7ada99b0e7e307104ad07ca9cfd9692214f1561356315e784f3e5a17e364ae9dbb14cb2036df932b77f4b292761365fb328de7afdc6d8998f5fc1"; +4, "beaa5a3d08f3807143cf621d95cd690514d0b49efff9c91d24b59241ec0eefa5f60196d407048bba8d2146828ebcb0488d8842fd56bb4f6df8e19c4b4daab8ac"; +5, "098084b51fd13deae5f4320de94a688ee07baea2800486689a8636117b46c1f4c1f6af7f74ae7c857600456a58a3af251dc4723a64cc7c0a5ab6d9cac91c20bb"; +6, "6044540d560853eb1c57df0077dd381094781cdb9073e5b1b3d3f6c7829e12066bbaca96d989a690de72ca3133a83652ba284a6d62942b271ffa2620c9e75b1f"; +7, "7a8cfe9b90f75f7ecb3acc053aaed6193112b6f6a4aeeb3f65d3de541942deb9e2228152a3c4bbbe72fc3b12629528cfbb09fe630f0474339f54abf453e2ed52"; +128, "72065ee4dd91c2d8509fa1fc28a37c7fc9fa7d5b3f8ad3d0d7a25626b57b1b44788d4caf806290425f9890a3a2a35a905ab4b37acfd0da6e4517b2525c9651e4"; +192, "8d6cf87c08380d2d1506eee46fd4222d21d8c04e585fbfd08269c98f702833a156326a0724656400ee09351d57b440175e2a5de93cc5f80db6daf83576cf75fa"; +255, "142709d62e28fcccd0af97fad0f8465b971e82201dc51070faa0372aa43e92484be1c1e73ba10906d5d1853db6a4106e0a7bf9800d373d6dee2d46d62ef2a461" + ] + +let _ = + testing_function "BLAKE2s-256 (keyed)"; + let mkstring n = String.init n (fun i -> Char.chr i) in + let key = mkstring 0x20 in + let hash s = hash_string (MAC.blake2s256 key) s in + List.iter + (fun (len, result) -> test len (hash (mkstring len)) (hex result)) + [ +0, "48a8997da407876b3d79c0d92325ad3b89cbb754d86ab71aee047ad345fd2c49"; +1, "40d15fee7c328830166ac3f918650f807e7e01e177258cdc0a39b11f598066f1"; +2, "6bb71300644cd3991b26ccd4d274acd1adeab8b1d7914546c1198bbe9fc9d803"; +3, "1d220dbe2ee134661fdf6d9e74b41704710556f2f6e5a091b227697445dbea6b"; +4, "f6c3fbadb4cc687a0064a5be6e791bec63b868ad62fba61b3757ef9ca52e05b2"; +5, "49c1f21188dfd769aea0e911dd6b41f14dab109d2b85977aa3088b5c707e8598"; +6, "fdd8993dcd43f696d44f3cea0ff35345234ec8ee083eb3cada017c7f78c17143"; +7, "e6c8125637438d0905b749f46560ac89fd471cf8692e28fab982f73f019b83a9"; +128, "0c311f38c35a4fb90d651c289d486856cd1413df9b0677f53ece2cd9e477c60a"; +192, "5950d39a23e1545f301270aa1a12f2e6c453776e4d6355de425cc153f9818867"; +255, "3fb735061abc519dfe979e54c1ee5bfad0a9d858b3315bad34bde999efd724dd" + ] + (* RIPEMD-160 *) let _ = testing_function "RIPEMD-160"; @@ -904,14 +968,20 @@ let chisquare b = let t = Char.code (Bytes.get b i) in freq.(t) <- freq.(t) + 1 done; - let t = Array.fold_left (fun s x -> let x = float x in s +. x *. x) 0.0 freq - and r = float r - and n = float n in - let sr = 2.0 *. sqrt r in - abs_float ((r *. t /. n) -. n -. r) <= sr - -let test_rng ?(len = 100000) (r: Random.rng) = - let b = Bytes.create len in + let expected = float n /. float r in + let t = + Array.fold_left + (fun s x -> let d = float x -. expected in d *. d +. s) + 0.0 freq in + let chi2 = t /. expected in + let degfree = float r -. 1.0 in + (* The degree of freedom is high, so we approximate as a normal + distribution with mean equal to degfree and variance 2 * degfree. + Four sigmas correspond to a 99.9936% confidence interval. *) + chi2 <= degfree +. 4.0 *. sqrt (2.0 *. degfree) + +let test_rng ?(len = 10000) (r: Random.rng) = + let b = Bytes.make len '\000' in r#random_bytes b 0 len; r#wipe; printf "chi^2 %s\n" |