From bde5a8dcb62ae3ce43b9324007396f3f64313c60 Mon Sep 17 00:00:00 2001 From: Luke Kenneth Casson Leighton Date: Thu, 29 Dec 2022 12:53:45 +0000 Subject: [PATCH] add bryan hawkins chacha20 source from https://github.com/spcnvdr/xchacha20 --- crypto/chacha20/LICENSE | 28 +++ crypto/chacha20/Makefile | 30 +++ crypto/chacha20/NOTICE | 33 +++ crypto/chacha20/README.md | 119 +++++++++++ crypto/chacha20/changelog | 33 +++ crypto/chacha20/src/test.c | 348 ++++++++++++++++++++++++++++++++ crypto/chacha20/src/xchacha20.c | 289 ++++++++++++++++++++++++++ crypto/chacha20/src/xchacha20.h | 212 +++++++++++++++++++ 8 files changed, 1092 insertions(+) create mode 100644 crypto/chacha20/LICENSE create mode 100644 crypto/chacha20/Makefile create mode 100644 crypto/chacha20/NOTICE create mode 100644 crypto/chacha20/README.md create mode 100644 crypto/chacha20/changelog create mode 100644 crypto/chacha20/src/test.c create mode 100644 crypto/chacha20/src/xchacha20.c create mode 100644 crypto/chacha20/src/xchacha20.h diff --git a/crypto/chacha20/LICENSE b/crypto/chacha20/LICENSE new file mode 100644 index 00000000..f27c5138 --- /dev/null +++ b/crypto/chacha20/LICENSE @@ -0,0 +1,28 @@ +Copyright 2019 Bryan Hawkins + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: + +1. Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. + +2. 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. + +3. Neither the name of the copyright holder 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 +HOLDER 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. diff --git a/crypto/chacha20/Makefile b/crypto/chacha20/Makefile new file mode 100644 index 00000000..ef18a75a --- /dev/null +++ b/crypto/chacha20/Makefile @@ -0,0 +1,30 @@ +# A simple Makefile, to build run: make all +TARGET = test + +CC = gcc +#compiler flags here +CFLAGS = -O3 -Wall -Wextra + +#linker flags here +LFLAGS = -Wall + +SRCDIR = src + +SOURCES := $(wildcard $(SRCDIR)/*.c) +INCLUDES := $(wildcard $(SRCDIR)/*.h)) +OBJECTS := $(SOURCES:$(SRCDIR)/%.c=$(SRCDIR)/%.o) + +.PHONY: all clean remove +all: ${TARGET} + +$(TARGET): $(OBJECTS) + @$(CC) -o $@ $(LFLAGS) $(OBJECTS) + +$(OBJECTS): $(SRCDIR)/%.o : $(SRCDIR)/%.c + @$(CC) $(CFLAGS) -c $< -o $@ + +clean: + @$ rm -f $(OBJECTS) + +remove: clean + @$ rm -f $(TARGET) diff --git a/crypto/chacha20/NOTICE b/crypto/chacha20/NOTICE new file mode 100644 index 00000000..5c3049bf --- /dev/null +++ b/crypto/chacha20/NOTICE @@ -0,0 +1,33 @@ +This project contains code developed by Daniel J. Bernstein which was +released into the public domain. This code is based on Bernstein's +"chacha-merged.c version 20080118". Daniel J. Bernstein's original code +can be found at the following here: http://cr.yp.to/chacha.html + +This project also contains code based on part of the libsodium cryptographic +library. The xchacha_hchacha and xchacha_set_counter functions were borrowed +from libsodium and modified. +More information about libsodium can be found at the following +websites: +https://github.com/jedisct1/libsodium +https://download.libsodium.org/doc/ + +The code based on libsodium is used under the following license: + +/* + * ISC License + * + * Copyright (c) 2013-2019 + * Frank Denis + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ diff --git a/crypto/chacha20/README.md b/crypto/chacha20/README.md new file mode 100644 index 00000000..6c75ea05 --- /dev/null +++ b/crypto/chacha20/README.md @@ -0,0 +1,119 @@ +# XChaCha20 - Extended Nonce Version of ChaCha20 + +XChaCha20 is a stream cipher based on ChaCha20. XChaCha20 uses a 256-bit +key and a 192-bit nonce. According to an [IETF draft:](https://tools.ietf.org/html/draft-arciszewski-xchacha-02), "The eXtended-nonce ChaCha cipher construction (XChaCha) allows for +ChaCha-based ciphersuites to accept a 192-bit nonce with similar guarantees +to the original construction, except with a much lower probability of +nonce misuse occurring. This enables XChaCha constructions to be stateless, +while retaining the same security assumptions as ChaCha." +Also, XChaCha20 does not use any look up tables and is immune to +timing attacks. This library is based on Daniel J. Bernstein's reference +implementation of the ChaCha stream cipher. + +I decided to make this small C library for XChaCha20 because I could not +find one. Unlike some other libraries, it only allows using XChaCha20 with +a 256-bit key and a 192-bit nonce. No other key sizes or nonce sizes are +allowed. A large benefit of using XChaCha20 over the regular ChaCha20 is that +the larger nonce (192 bits v.s. 64 bits) allows the use of random nonces and +is more resistant to nonce misuse. + +**More Information** + +[IETF XChaCha20 Draft](https://tools.ietf.org/html/draft-arciszewski-xchacha-03) + +[Bernstein's ChaCha Web page](http://cr.yp.to/chacha.html) + +[Libsodium Documentation](https://libsodium.gitbook.io/doc/advanced/stream_ciphers/xchacha20) + +[Crypto++ Documentation](https://www.cryptopp.com/wiki/XChaCha20) + +[Wikipedia](https://en.wikipedia.org/wiki/Salsa20) + +**WARNING** + +I am not a cryptographer so use this library at your own risk. + + +**Getting Started** + +Import the library into your project + +```C + #include "xchacha20.h" +``` + +Create a XChaCha context + +```C + XChaCha_ctx ctx; +``` + +Set up the 256-bit encryption key and the 192-bit nonce to be used. + +```C + xchacha_keysetup(&ctx, key, nonce); +``` + +Optionally, set the counter to a different starting value other than zero. + +```C + xchacha_set_counter(&ctx, 0x1); +``` + +Then use xchacha_encrypt_bytes or xchacha_encrypt_blocks to encrypt data + +```C + xchacha_encrypt_bytes(&ctx, plaintext, ciphertext, sizeof(plaintext)); +``` + + +**Test Vectors** + +In the src folder is a program named test.c It calculates and compares +XChaCha20 test vectors obtained from two different sources. The test vectors +were borrowed from the IETF draft regarding XChaCha20 and an example from +Crypto++ wikipedia. It will compare the output of this XChaCha20 library with +known good test vectors to ensure this library is working correctly. + +To make the test program simply run make + + make + +Then run the test program + + ./test + +The program will produce the following output if successful: + + Cryptographic tests passed + +If this library failed to generate the correct ciphertexts, then something +is wrong with the library and you will see this output: + + Cryptographic tests failed! + + +**To Do** + +- [x] Add a program to calculate and compare test vectors +- [ ] Find and add more test vectors for XChaCha20 + + +**Contributing** + +Pull requests, new feature suggestions, and bug reports/issues are +welcome. + + +**Versioning** + +This project uses semantic versioning 2.0. Version numbers follow the +MAJOR.MINOR.PATCH format. + + +**License** + +This project is licensed under the 3-Clause BSD License also known as the +*"New BSD License"* or the *"Modified BSD License"*. A copy of the license +can be found in the LICENSE file. A copy can also be found at the +[Open Source Institute](https://opensource.org/licenses/BSD-3-Clause) diff --git a/crypto/chacha20/changelog b/crypto/chacha20/changelog new file mode 100644 index 00000000..0a819b82 --- /dev/null +++ b/crypto/chacha20/changelog @@ -0,0 +1,33 @@ +xchacha20 (0.0.5) urgency=low; + * Corrected confusing comments in the source code. + + -- Bryan Hawkins Wed, 17 Jul 2019 06:34:18 -0500 + +xchacha20 (0.0.4) urgency=low; + * Added a new test vector from the latest version of the IETF draft. + Found here: https://tools.ietf.org/html/draft-arciszewski-xchacha-03 + * Updated the README.md file. + + -- Bryan Hawkins Mon, 17 Jun 2019 12:22:44 -0500 + +xchacha20 (0.0.3) urgency=low; + * Fixed minor typos and errors throughout the project + * Corrected inconsistent use of tabs v.s. spaces + * Fixed a minor warning issued while compiling the library + + -- Bryan Hawkins Mon, 03 Jun 2019 11:36:49 -0500 + +xchacha20 (0.0.2) urgency=low; + * Added a program to calculate and compare this library's output with + known good test vectors. + * Fixed minor errors in the README.md file and xchacha.c + + -- Bryan Hawkins Fri, 31 May 2019 12:49:28 -0500 + +xchacha20 (0.0.1) urgency=low; + * Initial commit and now managing project with Git. + + -- Bryan Hawkins Tue, 28 May 2019 18:11:11 -0500 + + +use the 'date -R' command to make the date string. diff --git a/crypto/chacha20/src/test.c b/crypto/chacha20/src/test.c new file mode 100644 index 00000000..38a56a56 --- /dev/null +++ b/crypto/chacha20/src/test.c @@ -0,0 +1,348 @@ +/************************************************************************* + * This is a simple program to calculate test vectors and compare them * + * to known good values for XChaCha20. + *************************************************************************/ +#include +#include +#include +#include +#include +#include "xchacha20.h" + + +/** Calculate and compare the newest test vectors from the IETF + * Draft for XchaCha20. The test vectors were taken from + * version 03 of the draft: + * https://tools.ietf.org/html/draft-arciszewski-xchacha-03 + * This version was published on: October 11, 2018 and + * expired on: June 21, 2019 + * The biggest difference between this IETF test vector and the + * other one is that this version initializes the XChaCha20 internal + * counter to 1 instead of 0. + * @returns 0 on success, -1 on failure or error + * + */ +int check_second_ietf(void){ + XChaCha_ctx ctx; + uint8_t *buffer; + uint8_t counter[8] = {0x1}; + + /* Test vectors from IETF XChaCha20 draft 03 */ + uint8_t plaintext[] = { + 0x54, 0x68, 0x65, 0x20, 0x64, 0x68, 0x6f, 0x6c, + 0x65, 0x20, 0x28, 0x70, 0x72, 0x6f, 0x6e, 0x6f, + 0x75, 0x6e, 0x63, 0x65, 0x64, 0x20, 0x22, 0x64, + 0x6f, 0x6c, 0x65, 0x22, 0x29, 0x20, 0x69, 0x73, + 0x20, 0x61, 0x6c, 0x73, 0x6f, 0x20, 0x6b, 0x6e, + 0x6f, 0x77, 0x6e, 0x20, 0x61, 0x73, 0x20, 0x74, + 0x68, 0x65, 0x20, 0x41, 0x73, 0x69, 0x61, 0x74, + 0x69, 0x63, 0x20, 0x77, 0x69, 0x6c, 0x64, 0x20, + 0x64, 0x6f, 0x67, 0x2c, 0x20, 0x72, 0x65, 0x64, + 0x20, 0x64, 0x6f, 0x67, 0x2c, 0x20, 0x61, 0x6e, + 0x64, 0x20, 0x77, 0x68, 0x69, 0x73, 0x74, 0x6c, + 0x69, 0x6e, 0x67, 0x20, 0x64, 0x6f, 0x67, 0x2e, + 0x20, 0x49, 0x74, 0x20, 0x69, 0x73, 0x20, 0x61, + 0x62, 0x6f, 0x75, 0x74, 0x20, 0x74, 0x68, 0x65, + 0x20, 0x73, 0x69, 0x7a, 0x65, 0x20, 0x6f, 0x66, + 0x20, 0x61, 0x20, 0x47, 0x65, 0x72, 0x6d, 0x61, + 0x6e, 0x20, 0x73, 0x68, 0x65, 0x70, 0x68, 0x65, + 0x72, 0x64, 0x20, 0x62, 0x75, 0x74, 0x20, 0x6c, + 0x6f, 0x6f, 0x6b, 0x73, 0x20, 0x6d, 0x6f, 0x72, + 0x65, 0x20, 0x6c, 0x69, 0x6b, 0x65, 0x20, 0x61, + 0x20, 0x6c, 0x6f, 0x6e, 0x67, 0x2d, 0x6c, 0x65, + 0x67, 0x67, 0x65, 0x64, 0x20, 0x66, 0x6f, 0x78, + 0x2e, 0x20, 0x54, 0x68, 0x69, 0x73, 0x20, 0x68, + 0x69, 0x67, 0x68, 0x6c, 0x79, 0x20, 0x65, 0x6c, + 0x75, 0x73, 0x69, 0x76, 0x65, 0x20, 0x61, 0x6e, + 0x64, 0x20, 0x73, 0x6b, 0x69, 0x6c, 0x6c, 0x65, + 0x64, 0x20, 0x6a, 0x75, 0x6d, 0x70, 0x65, 0x72, + 0x20, 0x69, 0x73, 0x20, 0x63, 0x6c, 0x61, 0x73, + 0x73, 0x69, 0x66, 0x69, 0x65, 0x64, 0x20, 0x77, + 0x69, 0x74, 0x68, 0x20, 0x77, 0x6f, 0x6c, 0x76, + 0x65, 0x73, 0x2c, 0x20, 0x63, 0x6f, 0x79, 0x6f, + 0x74, 0x65, 0x73, 0x2c, 0x20, 0x6a, 0x61, 0x63, + 0x6b, 0x61, 0x6c, 0x73, 0x2c, 0x20, 0x61, 0x6e, + 0x64, 0x20, 0x66, 0x6f, 0x78, 0x65, 0x73, 0x20, + 0x69, 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, 0x74, + 0x61, 0x78, 0x6f, 0x6e, 0x6f, 0x6d, 0x69, 0x63, + 0x20, 0x66, 0x61, 0x6d, 0x69, 0x6c, 0x79, 0x20, + 0x43, 0x61, 0x6e, 0x69, 0x64, 0x61, 0x65, 0x2e + }; + + uint8_t key[] = { + 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, + 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f, + 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, + 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f + }; + + uint8_t iv[] = { + 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, + 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, + 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x58 + }; + + uint8_t correct_ciphertext[] = { + 0x7d, 0x0a, 0x2e, 0x6b, 0x7f, 0x7c, 0x65, 0xa2, + 0x36, 0x54, 0x26, 0x30, 0x29, 0x4e, 0x06, 0x3b, + 0x7a, 0xb9, 0xb5, 0x55, 0xa5, 0xd5, 0x14, 0x9a, + 0xa2, 0x1e, 0x4a, 0xe1, 0xe4, 0xfb, 0xce, 0x87, + 0xec, 0xc8, 0xe0, 0x8a, 0x8b, 0x5e, 0x35, 0x0a, + 0xbe, 0x62, 0x2b, 0x2f, 0xfa, 0x61, 0x7b, 0x20, + 0x2c, 0xfa, 0xd7, 0x20, 0x32, 0xa3, 0x03, 0x7e, + 0x76, 0xff, 0xdc, 0xdc, 0x43, 0x76, 0xee, 0x05, + 0x3a, 0x19, 0x0d, 0x7e, 0x46, 0xca, 0x1d, 0xe0, + 0x41, 0x44, 0x85, 0x03, 0x81, 0xb9, 0xcb, 0x29, + 0xf0, 0x51, 0x91, 0x53, 0x86, 0xb8, 0xa7, 0x10, + 0xb8, 0xac, 0x4d, 0x02, 0x7b, 0x8b, 0x05, 0x0f, + 0x7c, 0xba, 0x58, 0x54, 0xe0, 0x28, 0xd5, 0x64, + 0xe4, 0x53, 0xb8, 0xa9, 0x68, 0x82, 0x41, 0x73, + 0xfc, 0x16, 0x48, 0x8b, 0x89, 0x70, 0xca, 0xc8, + 0x28, 0xf1, 0x1a, 0xe5, 0x3c, 0xab, 0xd2, 0x01, + 0x12, 0xf8, 0x71, 0x07, 0xdf, 0x24, 0xee, 0x61, + 0x83, 0xd2, 0x27, 0x4f, 0xe4, 0xc8, 0xb1, 0x48, + 0x55, 0x34, 0xef, 0x2c, 0x5f, 0xbc, 0x1e, 0xc2, + 0x4b, 0xfc, 0x36, 0x63, 0xef, 0xaa, 0x08, 0xbc, + 0x04, 0x7d, 0x29, 0xd2, 0x50, 0x43, 0x53, 0x2d, + 0xb8, 0x39, 0x1a, 0x8a, 0x3d, 0x77, 0x6b, 0xf4, + 0x37, 0x2a, 0x69, 0x55, 0x82, 0x7c, 0xcb, 0x0c, + 0xdd, 0x4a, 0xf4, 0x03, 0xa7, 0xce, 0x4c, 0x63, + 0xd5, 0x95, 0xc7, 0x5a, 0x43, 0xe0, 0x45, 0xf0, + 0xcc, 0xe1, 0xf2, 0x9c, 0x8b, 0x93, 0xbd, 0x65, + 0xaf, 0xc5, 0x97, 0x49, 0x22, 0xf2, 0x14, 0xa4, + 0x0b, 0x7c, 0x40, 0x2c, 0xdb, 0x91, 0xae, 0x73, + 0xc0, 0xb6, 0x36, 0x15, 0xcd, 0xad, 0x04, 0x80, + 0x68, 0x0f, 0x16, 0x51, 0x5a, 0x7a, 0xce, 0x9d, + 0x39, 0x23, 0x64, 0x64, 0x32, 0x8a, 0x37, 0x74, + 0x3f, 0xfc, 0x28, 0xf4, 0xdd, 0xb3, 0x24, 0xf4, + 0xd0, 0xf5, 0xbb, 0xdc, 0x27, 0x0c, 0x65, 0xb1, + 0x74, 0x9a, 0x6e, 0xff, 0xf1, 0xfb, 0xaa, 0x09, + 0x53, 0x61, 0x75, 0xcc, 0xd2, 0x9f, 0xb9, 0xe6, + 0x05, 0x7b, 0x30, 0x73, 0x20, 0xd3, 0x16, 0x83, + 0x8a, 0x9c, 0x71, 0xf7, 0x0b, 0x5b, 0x59, 0x07, + 0xa6, 0x6f, 0x7e, 0xa4, 0x9a, 0xad, 0xc4, 0x09 + }; + + /* Allocate a buffer to hold our calculated ciphertext */ + if((buffer = malloc(1024 * sizeof(uint8_t))) == NULL){ + perror("malloc() error"); + return(-1); + } + + xchacha_keysetup(&ctx, key, iv); + + /*This version of the IETF draft initializes their counter to 1 + * instead of 0 */ + xchacha_set_counter(&ctx, counter); + xchacha_encrypt_bytes(&ctx, plaintext, buffer, 304); + + /* Make sure our ciphertext matches */ + if(memcmp(buffer, correct_ciphertext, 304) != 0){ + free(buffer); + return(-1); + } + + free(buffer); + + return(0); +} + +/** Calculate and compare the test vectors from the IETF + * Draft for XchaCha20. The test vectors were taken from + * this version of the draft: + * https://tools.ietf.org/html/draft-arciszewski-xchacha-02 + * This version was published on: October 11, 2018 and + * expired on: April 14, 2019 + * @returns 0 on success, -1 on failure or error + * + */ +int check_ietf(void){ + XChaCha_ctx ctx; + uint8_t *buffer; + + /* Test vectors from IETF XChaCha20 draft */ + uint8_t plaintext[] = { + 0x54, 0x68, 0x65, 0x20, 0x64, 0x68, 0x6f, 0x6c, + 0x65, 0x20, 0x28, 0x70, 0x72, 0x6f, 0x6e, 0x6f, + 0x75, 0x6e, 0x63, 0x65, 0x64, 0x20, 0x22, 0x64, + 0x6f, 0x6c, 0x65, 0x22, 0x29, 0x20, 0x69, 0x73, + 0x20, 0x61, 0x6c, 0x73, 0x6f, 0x20, 0x6b, 0x6e, + 0x6f, 0x77, 0x6e, 0x20, 0x61, 0x73, 0x20, 0x74, + 0x68, 0x65, 0x20, 0x41, 0x73, 0x69, 0x61, 0x74, + 0x69, 0x63, 0x20, 0x77, 0x69, 0x6c, 0x64, 0x20, + 0x64, 0x6f, 0x67, 0x2c, 0x20, 0x72, 0x65, 0x64, + 0x20, 0x64, 0x6f, 0x67, 0x2c, 0x20, 0x61, 0x6e, + 0x64, 0x20, 0x77, 0x68, 0x69, 0x73, 0x74, 0x6c, + 0x69, 0x6e, 0x67, 0x20, 0x64, 0x6f, 0x67, 0x2e, + 0x20, 0x49, 0x74, 0x20, 0x69, 0x73, 0x20, 0x61, + 0x62, 0x6f, 0x75, 0x74, 0x20, 0x74, 0x68, 0x65, + 0x20, 0x73, 0x69, 0x7a, 0x65, 0x20, 0x6f, 0x66, + 0x20, 0x61, 0x20, 0x47, 0x65, 0x72, 0x6d, 0x61, + 0x6e, 0x20, 0x73, 0x68, 0x65, 0x70, 0x68, 0x65, + 0x72, 0x64, 0x20, 0x62, 0x75, 0x74, 0x20, 0x6c, + 0x6f, 0x6f, 0x6b, 0x73, 0x20, 0x6d, 0x6f, 0x72, + 0x65, 0x20, 0x6c, 0x69, 0x6b, 0x65, 0x20, 0x61, + 0x20, 0x6c, 0x6f, 0x6e, 0x67, 0x2d, 0x6c, 0x65, + 0x67, 0x67, 0x65, 0x64, 0x20, 0x66, 0x6f, 0x78, + 0x2e, 0x20, 0x54, 0x68, 0x69, 0x73, 0x20, 0x68, + 0x69, 0x67, 0x68, 0x6c, 0x79, 0x20, 0x65, 0x6c, + 0x75, 0x73, 0x69, 0x76, 0x65, 0x20, 0x61, 0x6e, + 0x64, 0x20, 0x73, 0x6b, 0x69, 0x6c, 0x6c, 0x65, + 0x64, 0x20, 0x6a, 0x75, 0x6d, 0x70, 0x65, 0x72, + 0x20, 0x69, 0x73, 0x20, 0x63, 0x6c, 0x61, 0x73, + 0x73, 0x69, 0x66, 0x69, 0x65, 0x64, 0x20, 0x77, + 0x69, 0x74, 0x68, 0x20, 0x77, 0x6f, 0x6c, 0x76, + 0x65, 0x73, 0x2c, 0x20, 0x63, 0x6f, 0x79, 0x6f, + 0x74, 0x65, 0x73, 0x2c, 0x20, 0x6a, 0x61, 0x63, + 0x6b, 0x61, 0x6c, 0x73, 0x2c, 0x20, 0x61, 0x6e, + 0x64, 0x20, 0x66, 0x6f, 0x78, 0x65, 0x73, 0x20, + 0x69, 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, 0x74, + 0x61, 0x78, 0x6f, 0x6e, 0x6f, 0x6d, 0x69, 0x63, + 0x20, 0x66, 0x61, 0x6d, 0x69, 0x6c, 0x79, 0x20, + 0x43, 0x61, 0x6e, 0x69, 0x64, 0x61, 0x65, 0x2e + }; + + uint8_t key[] = { + 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, + 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f, + 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, + 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f + }; + + uint8_t iv[] = { + 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, + 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, + 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x58 + }; + + uint8_t correct_ciphertext[] = { + 0x45, 0x59, 0xab, 0xba, 0x4e, 0x48, 0xc1, 0x61, + 0x02, 0xe8, 0xbb, 0x2c, 0x05, 0xe6, 0x94, 0x7f, + 0x50, 0xa7, 0x86, 0xde, 0x16, 0x2f, 0x9b, 0x0b, + 0x7e, 0x59, 0x2a, 0x9b, 0x53, 0xd0, 0xd4, 0xe9, + 0x8d, 0x8d, 0x64, 0x10, 0xd5, 0x40, 0xa1, 0xa6, + 0x37, 0x5b, 0x26, 0xd8, 0x0d, 0xac, 0xe4, 0xfa, + 0xb5, 0x23, 0x84, 0xc7, 0x31, 0xac, 0xbf, 0x16, + 0xa5, 0x92, 0x3c, 0x0c, 0x48, 0xd3, 0x57, 0x5d, + 0x4d, 0x0d, 0x2c, 0x67, 0x3b, 0x66, 0x6f, 0xaa, + 0x73, 0x10, 0x61, 0x27, 0x77, 0x01, 0x09, 0x3a, + 0x6b, 0xf7, 0xa1, 0x58, 0xa8, 0x86, 0x42, 0x92, + 0xa4, 0x1c, 0x48, 0xe3, 0xa9, 0xb4, 0xc0, 0xda, + 0xec, 0xe0, 0xf8, 0xd9, 0x8d, 0x0d, 0x7e, 0x05, + 0xb3, 0x7a, 0x30, 0x7b, 0xbb, 0x66, 0x33, 0x31, + 0x64, 0xec, 0x9e, 0x1b, 0x24, 0xea, 0x0d, 0x6c, + 0x3f, 0xfd, 0xdc, 0xec, 0x4f, 0x68, 0xe7, 0x44, + 0x30, 0x56, 0x19, 0x3a, 0x03, 0xc8, 0x10, 0xe1, + 0x13, 0x44, 0xca, 0x06, 0xd8, 0xed, 0x8a, 0x2b, + 0xfb, 0x1e, 0x8d, 0x48, 0xcf, 0xa6, 0xbc, 0x0e, + 0xb4, 0xe2, 0x46, 0x4b, 0x74, 0x81, 0x42, 0x40, + 0x7c, 0x9f, 0x43, 0x1a, 0xee, 0x76, 0x99, 0x60, + 0xe1, 0x5b, 0xa8, 0xb9, 0x68, 0x90, 0x46, 0x6e, + 0xf2, 0x45, 0x75, 0x99, 0x85, 0x23, 0x85, 0xc6, + 0x61, 0xf7, 0x52, 0xce, 0x20, 0xf9, 0xda, 0x0c, + 0x09, 0xab, 0x6b, 0x19, 0xdf, 0x74, 0xe7, 0x6a, + 0x95, 0x96, 0x74, 0x46, 0xf8, 0xd0, 0xfd, 0x41, + 0x5e, 0x7b, 0xee, 0x2a, 0x12, 0xa1, 0x14, 0xc2, + 0x0e, 0xb5, 0x29, 0x2a, 0xe7, 0xa3, 0x49, 0xae, + 0x57, 0x78, 0x20, 0xd5, 0x52, 0x0a, 0x1f, 0x3f, + 0xb6, 0x2a, 0x17, 0xce, 0x6a, 0x7e, 0x68, 0xfa, + 0x7c, 0x79, 0x11, 0x1d, 0x88, 0x60, 0x92, 0x0b, + 0xc0, 0x48, 0xef, 0x43, 0xfe, 0x84, 0x48, 0x6c, + 0xcb, 0x87, 0xc2, 0x5f, 0x0a, 0xe0, 0x45, 0xf0, + 0xcc, 0xe1, 0xe7, 0x98, 0x9a, 0x9a, 0xa2, 0x20, + 0xa2, 0x8b, 0xdd, 0x48, 0x27, 0xe7, 0x51, 0xa2, + 0x4a, 0x6d, 0x5c, 0x62, 0xd7, 0x90, 0xa6, 0x63, + 0x93, 0xb9, 0x31, 0x11, 0xc1, 0xa5, 0x5d, 0xd7, + 0x42, 0x1a, 0x10, 0x18, 0x49, 0x74, 0xc7, 0xc5 + }; + + /* Allocate a buffer to hold our calculated ciphertext */ + if((buffer = malloc(1024 * sizeof(uint8_t))) == NULL){ + perror("malloc() error"); + return(-1); + } + + xchacha_keysetup(&ctx, key, iv); + xchacha_encrypt_bytes(&ctx, plaintext, buffer, 304); + + /* Make sure our ciphertext matches */ + if(memcmp(buffer, correct_ciphertext, 304) != 0){ + free(buffer); + return(-1); + } + + free(buffer); + + return(0); +} + + +/** Compare our output to the output of a known good XChaCha20 library. + * The test vectors used here are from examples given of the Crypto++ + * cryptographic library's XChaCha20 examples. These values can be + * found here: + * https://www.cryptopp.com/wiki/XChaCha20 + * @returns 0 on success, -1 on failure or error + * + */ +int check_cpp(void){ + XChaCha_ctx ctx; + uint8_t *buffer; + uint8_t counter[8] = {0x1}; + + /* Test values from Crypto++ documentation */ + uint8_t key[] = { + 0x5E, 0xC5, 0x8B, 0x6D, 0x51, 0x4F, 0xE0, 0xA5, + 0x6F, 0x1E, 0x0D, 0xEA, 0x7B, 0xDC, 0x09, 0x5A, + 0x10, 0xF5, 0xB6, 0x18, 0xBD, 0xB6, 0xF2, 0x26, + 0x2F, 0xCC, 0x59, 0x7B, 0xB2, 0x30, 0xB3, 0xEF + }; + + uint8_t iv[] = { + 0xA3, 0x45, 0xF5, 0xCF, 0x80, 0x23, 0x51, 0x7C, + 0xC0, 0xFC, 0xF0, 0x75, 0x74, 0x8C, 0x86, 0x5F, + 0x7D, 0xE8, 0xCA, 0x0C, 0x72, 0x36, 0xAB, 0xDA + }; + + uint8_t correct_ciphertext[] = { + 0xEE, 0xA7, 0xC2, 0x71, 0x19, 0x10, 0x65, 0x69, + 0x92, 0xE1, 0xCE, 0xD8, 0x16, 0xE2, 0x0E, 0x62, + 0x1B, 0x25, 0x17, 0x82, 0x36, 0x71, 0x6A, 0xE4, + 0x99, 0xF2, 0x97, 0x37, 0xA7, 0x2A, 0xFC, 0xF8, + 0x6C, 0x72 + }; + + uint8_t plaintext[] = "My Plaintext!! My Dear plaintext!!"; + uint32_t msglen = strlen((char *)plaintext); + + /* Allocate a buffer to hold our calculated ciphertext */ + if((buffer = malloc(50 * sizeof(uint8_t))) == NULL){ + perror("malloc() error"); + return(-1); + } + + xchacha_keysetup(&ctx, key, iv); + + /* Crypto++ initializes their counter to 1 instead of 0 */ + xchacha_set_counter(&ctx, counter); + xchacha_encrypt_bytes(&ctx, plaintext, buffer, msglen); + + /* Compare our ciphertext to the correct ciphertext */ + if(memcmp(buffer, correct_ciphertext, msglen) != 0){ + free(buffer); + return(-1); + } + + free(buffer); + return(0); +} + +int main(void){ + if((check_ietf()) == 0 && (check_cpp()) == 0 && (check_second_ietf() == 0)){ + printf("Cryptographic tests passed\n"); + } else { + printf("Cryptographic tests failed!\n"); + } + + return(0); +} diff --git a/crypto/chacha20/src/xchacha20.c b/crypto/chacha20/src/xchacha20.c new file mode 100644 index 00000000..2b29f60b --- /dev/null +++ b/crypto/chacha20/src/xchacha20.c @@ -0,0 +1,289 @@ +/************************************************************************* + * This is a small cryptographic library that implements the XChaCha20 * + * stream cipher. It is based on "chacha-merged.c version 20080118" * + * created by D. J. Bernstein and released in to the Public domain. * + * Check out his website at: http://cr.yp.to/chacha.html * + * The xchacha_hchacha() and xchacha_set_counter() functions are based * + * on code found in libsodium. To find the associated license and more * + * info., look in the NOTICE file. * + *************************************************************************/ +#include +#include +#include "xchacha20.h" + + +/** hchacha an intermediary step towards XChaCha20 based on the + * construction and security proof used to create XSalsa20. + * @param out Holds output of hchacha + * @param in The input to process with hchacha + * @param k The key to use with hchacha + * + */ +void xchacha_hchacha20(uint8_t *out, const uint8_t *in, const uint8_t *k){ + int i; + uint32_t x0, x1, x2, x3, x4, x5, x6, x7; + uint32_t x8, x9, x10, x11, x12, x13, x14, x15; + + /* XChaCha Constant */ + x0 = 0x61707865; + x1 = 0x3320646e; + x2 = 0x79622d32; + x3 = 0x6b206574; + + x4 = U8TO32_LITTLE(k + 0); + x5 = U8TO32_LITTLE(k + 4); + x6 = U8TO32_LITTLE(k + 8); + x7 = U8TO32_LITTLE(k + 12); + x8 = U8TO32_LITTLE(k + 16); + x9 = U8TO32_LITTLE(k + 20); + x10 = U8TO32_LITTLE(k + 24); + x11 = U8TO32_LITTLE(k + 28); + x12 = U8TO32_LITTLE(in + 0); + x13 = U8TO32_LITTLE(in + 4); + x14 = U8TO32_LITTLE(in + 8); + x15 = U8TO32_LITTLE(in + 12); + + for (i = 0; i < 10; i++){ + QUARTERROUND(x0, x4, x8, x12); + QUARTERROUND(x1, x5, x9, x13); + QUARTERROUND(x2, x6, x10, x14); + QUARTERROUND(x3, x7, x11, x15); + QUARTERROUND(x0, x5, x10, x15); + QUARTERROUND(x1, x6, x11, x12); + QUARTERROUND(x2, x7, x8, x13); + QUARTERROUND(x3, x4, x9, x14); + } + + U32TO8_LITTLE(out + 0, x0); + U32TO8_LITTLE(out + 4, x1); + U32TO8_LITTLE(out + 8, x2); + U32TO8_LITTLE(out + 12, x3); + U32TO8_LITTLE(out + 16, x12); + U32TO8_LITTLE(out + 20, x13); + U32TO8_LITTLE(out + 24, x14); + U32TO8_LITTLE(out + 28, x15); +} + + +/** Setup the XChaCha20 encryption key + * @param x The XChaCha20 Context to use + * @param k A buffer holding the encryption key to use + * @note Valid key sizes are 256 bits, and the only valid IV size + * is 192 bits. + * + */ +void xchacha_keysetup(XChaCha_ctx *ctx, const uint8_t *k, uint8_t *iv){ + /* The sub-key to use */ + uint8_t k2[32]; + + /* Generate the sub-key to use from the 256-bit key and 192-bit iv + * We then use this sub-key and the last 8 bytes of the iv + * as normal. + */ + xchacha_hchacha20(k2, iv, k); + + + ctx->input[0] = 0x61707865; + ctx->input[1] = 0x3320646e; + ctx->input[2] = 0x79622d32; + ctx->input[3] = 0x6b206574; + ctx->input[4] = U8TO32_LITTLE(k2 + 0); + ctx->input[5] = U8TO32_LITTLE(k2 + 4); + ctx->input[6] = U8TO32_LITTLE(k2 + 8); + ctx->input[7] = U8TO32_LITTLE(k2 + 12); + ctx->input[8] = U8TO32_LITTLE(k2 + 16); + ctx->input[9] = U8TO32_LITTLE(k2 + 20); + ctx->input[10] = U8TO32_LITTLE(k2 + 24); + ctx->input[11] = U8TO32_LITTLE(k2 + 28); + ctx->input[12] = 0; /* Internal counter */ + ctx->input[13] = 0; /* Internal counter */ + ctx->input[14] = U8TO32_LITTLE(iv + 16); + ctx->input[15] = U8TO32_LITTLE(iv + 20); +} + + +/** Set the internal counter to a specific number. Depending + * on the specification, sometimes the counter is started at 1. + * @param ctx The XChaCha context to modify + * @param counter The number to set the counter to + * + */ +void xchacha_set_counter(XChaCha_ctx *ctx, uint8_t *counter){ + ctx->input[12] = U8TO32_LITTLE(counter + 0); + ctx->input[13] = U8TO32_LITTLE(counter + 4); +} + + +/** Encrypt data with the XChaCha20 stream cipher + * @param x The XChaCha20 context with the cipher's state to use + * @param m The plaintext to encrypt + * @param c A buffer to hold the ciphertext created from the plaintext + * @param bytes The length of the plaintext to encrypt + * @note length of c must be >= the length of m otherwise a buffer + * overflow will occur. + * + */ +void xchacha_encrypt_bytes(XChaCha_ctx *ctx, const uint8_t *m, uint8_t *c, uint32_t bytes){ + uint32_t x0, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12, x13, x14, x15; + uint32_t j0, j1, j2, j3, j4, j5, j6, j7, j8, j9, j10, j11, j12, j13, j14, j15; + uint8_t *ctarget = NULL; + uint8_t tmp[64]; + uint32_t i; + + if (!bytes) return; + + j0 = ctx->input[0]; + j1 = ctx->input[1]; + j2 = ctx->input[2]; + j3 = ctx->input[3]; + j4 = ctx->input[4]; + j5 = ctx->input[5]; + j6 = ctx->input[6]; + j7 = ctx->input[7]; + j8 = ctx->input[8]; + j9 = ctx->input[9]; + j10 = ctx->input[10]; + j11 = ctx->input[11]; + j12 = ctx->input[12]; + j13 = ctx->input[13]; + j14 = ctx->input[14]; + j15 = ctx->input[15]; + + for (;;) { + if (bytes < 64) { + for (i = 0;i < bytes;++i) + tmp[i] = m[i]; + m = tmp; + ctarget = c; + c = tmp; + } + x0 = j0; + x1 = j1; + x2 = j2; + x3 = j3; + x4 = j4; + x5 = j5; + x6 = j6; + x7 = j7; + x8 = j8; + x9 = j9; + x10 = j10; + x11 = j11; + x12 = j12; + x13 = j13; + x14 = j14; + x15 = j15; + + /* Do 20 rounds instead of 8 */ + for (i = 20;i > 0;i -= 2) { + QUARTERROUND( x0, x4, x8,x12) + QUARTERROUND( x1, x5, x9,x13) + QUARTERROUND( x2, x6,x10,x14) + QUARTERROUND( x3, x7,x11,x15) + QUARTERROUND( x0, x5,x10,x15) + QUARTERROUND( x1, x6,x11,x12) + QUARTERROUND( x2, x7, x8,x13) + QUARTERROUND( x3, x4, x9,x14) + } + x0 = PLUS(x0,j0); + x1 = PLUS(x1,j1); + x2 = PLUS(x2,j2); + x3 = PLUS(x3,j3); + x4 = PLUS(x4,j4); + x5 = PLUS(x5,j5); + x6 = PLUS(x6,j6); + x7 = PLUS(x7,j7); + x8 = PLUS(x8,j8); + x9 = PLUS(x9,j9); + x10 = PLUS(x10,j10); + x11 = PLUS(x11,j11); + x12 = PLUS(x12,j12); + x13 = PLUS(x13,j13); + x14 = PLUS(x14,j14); + x15 = PLUS(x15,j15); + + x0 = XOR(x0,U8TO32_LITTLE(m + 0)); + x1 = XOR(x1,U8TO32_LITTLE(m + 4)); + x2 = XOR(x2,U8TO32_LITTLE(m + 8)); + x3 = XOR(x3,U8TO32_LITTLE(m + 12)); + x4 = XOR(x4,U8TO32_LITTLE(m + 16)); + x5 = XOR(x5,U8TO32_LITTLE(m + 20)); + x6 = XOR(x6,U8TO32_LITTLE(m + 24)); + x7 = XOR(x7,U8TO32_LITTLE(m + 28)); + x8 = XOR(x8,U8TO32_LITTLE(m + 32)); + x9 = XOR(x9,U8TO32_LITTLE(m + 36)); + x10 = XOR(x10,U8TO32_LITTLE(m + 40)); + x11 = XOR(x11,U8TO32_LITTLE(m + 44)); + x12 = XOR(x12,U8TO32_LITTLE(m + 48)); + x13 = XOR(x13,U8TO32_LITTLE(m + 52)); + x14 = XOR(x14,U8TO32_LITTLE(m + 56)); + x15 = XOR(x15,U8TO32_LITTLE(m + 60)); + + j12 = PLUSONE(j12); + if (!j12) { + j13 = PLUSONE(j13); + } + + U32TO8_LITTLE(c + 0,x0); + U32TO8_LITTLE(c + 4,x1); + U32TO8_LITTLE(c + 8,x2); + U32TO8_LITTLE(c + 12,x3); + U32TO8_LITTLE(c + 16,x4); + U32TO8_LITTLE(c + 20,x5); + U32TO8_LITTLE(c + 24,x6); + U32TO8_LITTLE(c + 28,x7); + U32TO8_LITTLE(c + 32,x8); + U32TO8_LITTLE(c + 36,x9); + U32TO8_LITTLE(c + 40,x10); + U32TO8_LITTLE(c + 44,x11); + U32TO8_LITTLE(c + 48,x12); + U32TO8_LITTLE(c + 52,x13); + U32TO8_LITTLE(c + 56,x14); + U32TO8_LITTLE(c + 60,x15); + + if (bytes <= 64) { + if (bytes < 64) { + for (i = 0;i < bytes;++i) + ctarget[i] = c[i]; + } + ctx->input[12] = j12; + ctx->input[13] = j13; + return; + } + bytes -= 64; + c += 64; + m += 64; + } +} + + +/** Decrypt data with the XChaCha20 stream cipher + * @param x The XChaCha20 context with the cipher's state to use + * @param c The ciphertext to decrypt + * @param m A buffer to hold the plaintext + * @param bytes The number of bytes of ciphertext to decrypt + * @note length of m must be >= the length of c otherwise a buffer + * overflow will occur. + * + */ +void xchacha_decrypt_bytes(XChaCha_ctx *ctx, const uint8_t *c, uint8_t *m, uint32_t bytes){ + xchacha_encrypt_bytes(ctx,c,m,bytes); +} + + +/** Generate a keystream from encrypting a zero byte plaintext + * @param x The XChaCha context to use + * @param stream A buffer to store the generated keystream + * @param bytes The number of bytes of keystream to generate + * @note Mostly for testing purposes + * + */ +void xchacha_keystream_bytes(XChaCha_ctx *ctx, uint8_t *stream, uint32_t bytes){ + uint32_t i; + + for (i = 0;i < bytes;++i){ + stream[i] = 0; + } + + xchacha_encrypt_bytes(ctx,stream,stream,bytes); +} diff --git a/crypto/chacha20/src/xchacha20.h b/crypto/chacha20/src/xchacha20.h new file mode 100644 index 00000000..84ac3f40 --- /dev/null +++ b/crypto/chacha20/src/xchacha20.h @@ -0,0 +1,212 @@ +/************************************************************************* + * This is a small library for the XChaCha20 encryption algorithm. This * + * library is based on Daniel J. Bernstein's ChaCha reference * + * implementation, which can be found here: http://cr.yp.to/chacha.html * + * The xchacha_hchacha() and xchacha_set_counter functions are based on * + * code found in libsodium. To find the associated license and more * + * info., look in the NOTICE file. * + *************************************************************************/ +#include + +#ifndef XCHACHA20_H_ +#define XCHACHA20_H_ + + +/** Key and IV sizes that are supported by XChaCha20. + * All sizes are in bits. + */ +#define NAME "XChaCha20" +#define KEYSIZE 256 /* 256-bits, 32 bytes */ +#define BLOCKSIZE 512 /* 512-bits, 64 bytes */ +#define IVSIZE 192 /* 192-bits, 24 bytes */ + + +/* XChaCha20 block size in bytes */ +#define XCHACHA_BLOCKLENGTH 64 + + +/* The following macros are used to obtain exact-width results. */ +#define U8V(v) ((uint8_t)(v) & (0xFF)) +#define U16V(v) ((uint16_t)(v) & (0xFFFF)) +#define U32V(v) ((uint32_t)(v) & (0xFFFFFFFF)) +#define U64V(v) ((uint64_t)(v) & (0xFFFFFFFFFFFFFFFF)) + + +/** The following macros return words with their bits rotated over n + * positions to the left/right. + */ +#define ROTL32(v, n) \ + (U32V((v) << (n)) | ((v) >> (32 - (n)))) + + +/** The following macros load words from an array of bytes with + * different types of endianness, and vice versa. + */ +#define U8TO32_LITTLE(p) \ + (((uint32_t)((p)[0]) ) | \ + ((uint32_t)((p)[1]) << 8) | \ + ((uint32_t)((p)[2]) << 16) | \ + ((uint32_t)((p)[3]) << 24)) + +#define U32TO8_LITTLE(p, v) \ + do { \ + (p)[0] = U8V((v) ); \ + (p)[1] = U8V((v) >> 8); \ + (p)[2] = U8V((v) >> 16); \ + (p)[3] = U8V((v) >> 24); \ + } while (0) + + +#define ROTATE(v,c) (ROTL32(v,c)) +#define XOR(v,w) ((v) ^ (w)) +#define PLUS(v,w) (U32V((v) + (w))) +#define PLUSONE(v) (PLUS((v),1)) + + +/* The ChaCha quarter round */ +#define QUARTERROUND(a,b,c,d) \ + a = PLUS(a,b); d = ROTATE(XOR(d,a),16); \ + c = PLUS(c,d); b = ROTATE(XOR(b,c),12); \ + a = PLUS(a,b); d = ROTATE(XOR(d,a), 8); \ + c = PLUS(c,d); b = ROTATE(XOR(b,c), 7); + + +/** ChaCha_ctx is the structure containing the representation of the + * internal state of the XChaCha20 cipher. + * + */ +typedef struct +{ + uint32_t input[16]; +} XChaCha_ctx; + + +/* ------------------------------------------------------------------------- */ + + +/** hchacha an intermediary step towards XChaCha20 based on the + * construction and security proof used to create XSalsa20. + * @param out Holds output of hchacha + * @param in The input to process with hchacha + * @param k The key to use with hchacha + * + */ +void xchacha_hchacha20(uint8_t *out, const uint8_t *in, const uint8_t *k); + + +/** Set the encryption key and iv to be used with XChaCha + * @param ctx The XChaCha context to use + * @param k The 256-bit/32-byte key to use for encryption + * @param iv The 192-bit/24-byte iv or nonce to use + * @note It is the user's responsibility to ensure that the key + * and the iv are of the correct lengths! + */ +void xchacha_keysetup(XChaCha_ctx *ctx, const uint8_t *k, uint8_t *iv); + + +/** Set the internal counter to a specific number. Depending + * on the specification, sometimes the counter is started at 1. + * @param ctx The XChaCha context to modify + * @param counter The number to set the counter to + * + */ +void xchacha_set_counter(XChaCha_ctx *ctx, uint8_t *counter); + + +/** Encryption/decryption of arbitrary length messages. + * + * For efficiency reasons, the API provides two types of + * encrypt/decrypt functions. The xchacha_encrypt_bytes() function + * (declared here) encrypts byte strings of arbitrary length, while + * the xchacha_encrypt_blocks() function (defined later) only accepts + * lengths which are multiples of CHACHA_BLOCKLENGTH. + * + * The user is allowed to make multiple calls to + * xchacha_encrypt_blocks() to incrementally encrypt a long message, + * but he is NOT allowed to make additional encryption calls once he + * has called xchacha_encrypt_bytes() (unless he starts a new message + * of course). For example, this sequence of calls is acceptable: + * + * xchacha_keysetup(); + * + * xchacha_ivsetup(); + * xchacha_encrypt_blocks(); + * xchacha_encrypt_blocks(); + * xchacha_encrypt_bytes(); + * + * xchacha_ivsetup(); + * xchacha_encrypt_blocks(); + * xchacha_encrypt_blocks(); + * + * xchacha_ivsetup(); + * xchacha_encrypt_bytes(); + * + * The following sequence is not: + * + * xchacha_keysetup(); + * xchacha_ivsetup(); + * xchacha_encrypt_blocks(); + * xchacha_encrypt_bytes(); + * xchacha_encrypt_blocks(); + * + */ + + +/** Encrypt a set of bytes with XChaCha20 + * @param ctx The XChaCha20 context to use + * @param plaintext The data to be encrypted + * @param ciphertext A buffer to hold the encrypted data + * @param msglen Message length in bytes + * + */ +void xchacha_encrypt_bytes(XChaCha_ctx* ctx, const uint8_t* plaintext, + uint8_t* ciphertext, + uint32_t msglen); + + +/** Dencrypt a set of bytes with XChaCha20 + * @param ctx The XChaCha20 context to use + * @param ciphertext The encrypted data to decrypt + * @param plaintext A buffer to hold the decrypted data + * @param msglen Message length in bytes + * + */ +void xchacha_decrypt_bytes(XChaCha_ctx* ctx, const uint8_t* ciphertext, + uint8_t* plaintext, + uint32_t msglen); + + +/** For testing purposes it can sometimes be useful to have a function + * which immediately generates keystream without having to provide it + * with a zero plaintext. + * @param ctx The XChaCha context to use + * @param keystream A buffer to hold the keystream + * @param length Length of keystream in bytes + * + */ +void xchacha_keystream_bytes(XChaCha_ctx* ctx, uint8_t* keystream, uint32_t length); + + +/** Encrypt/decrypt of blocks. + * @param ctx The XChaCha context to use + * @param plaintext A buffer which holds unencrypted data + * @param ciphertext A buffer which holds encrypted data + * @param blocks The number of 512 blocks to process with XChaCha20 + * + */ +#define xchacha_encrypt_blocks(ctx, plaintext, ciphertext, blocks) \ + xchacha_encrypt_bytes(ctx, plaintext, ciphertext, \ + (blocks) * XCHACHA_BLOCKLENGTH) + + +#define xchacha_decrypt_blocks(ctx, ciphertext, plaintext, blocks) \ + xchacha_decrypt_bytes(ctx, ciphertext, plaintext, \ + (blocks) * XCHACHA_BLOCKLENGTH) + + +#define xchacha_keystream_blocks(ctx, keystream, blocks) \ + xchacha_keystream_bytes(ctx, keystream, \ + (blocks) * XCHACHA_BLOCKLENGTH) + + +#endif -- 2.30.2