├── Makefile ├── changelog ├── LICENSE ├── NOTICE ├── README.md └── src ├── xchacha20.h ├── xchacha20.c └── test.c /Makefile: -------------------------------------------------------------------------------- 1 | # A simple Makefile, to build run: make all 2 | TARGET = test 3 | 4 | CC = gcc 5 | #compiler flags here 6 | CFLAGS = -O3 -Wall -Wextra 7 | 8 | #linker flags here 9 | LFLAGS = -Wall 10 | 11 | SRCDIR = src 12 | 13 | SOURCES := $(wildcard $(SRCDIR)/*.c) 14 | INCLUDES := $(wildcard $(SRCDIR)/*.h)) 15 | OBJECTS := $(SOURCES:$(SRCDIR)/%.c=$(SRCDIR)/%.o) 16 | 17 | .PHONY: all clean remove 18 | all: ${TARGET} 19 | 20 | $(TARGET): $(OBJECTS) 21 | @$(CC) -o $@ $(LFLAGS) $(OBJECTS) 22 | 23 | $(OBJECTS): $(SRCDIR)/%.o : $(SRCDIR)/%.c 24 | @$(CC) $(CFLAGS) -c $< -o $@ 25 | 26 | clean: 27 | @$ rm -f $(OBJECTS) 28 | 29 | remove: clean 30 | @$ rm -f $(TARGET) 31 | -------------------------------------------------------------------------------- /changelog: -------------------------------------------------------------------------------- 1 | xchacha20 (0.0.5) urgency=low; 2 | * Corrected confusing comments in the source code. 3 | 4 | -- Bryan Hawkins Wed, 17 Jul 2019 06:34:18 -0500 5 | 6 | xchacha20 (0.0.4) urgency=low; 7 | * Added a new test vector from the latest version of the IETF draft. 8 | Found here: https://tools.ietf.org/html/draft-arciszewski-xchacha-03 9 | * Updated the README.md file. 10 | 11 | -- Bryan Hawkins Mon, 17 Jun 2019 12:22:44 -0500 12 | 13 | xchacha20 (0.0.3) urgency=low; 14 | * Fixed minor typos and errors throughout the project 15 | * Corrected inconsistent use of tabs v.s. spaces 16 | * Fixed a minor warning issued while compiling the library 17 | 18 | -- Bryan Hawkins Mon, 03 Jun 2019 11:36:49 -0500 19 | 20 | xchacha20 (0.0.2) urgency=low; 21 | * Added a program to calculate and compare this library's output with 22 | known good test vectors. 23 | * Fixed minor errors in the README.md file and xchacha.c 24 | 25 | -- Bryan Hawkins Fri, 31 May 2019 12:49:28 -0500 26 | 27 | xchacha20 (0.0.1) urgency=low; 28 | * Initial commit and now managing project with Git. 29 | 30 | -- Bryan Hawkins Tue, 28 May 2019 18:11:11 -0500 31 | 32 | 33 | use the 'date -R' command to make the date string. 34 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright 2019 Bryan Hawkins 2 | 3 | Redistribution and use in source and binary forms, with or without 4 | modification, are permitted provided that the following conditions 5 | are met: 6 | 7 | 1. Redistributions of source code must retain the above copyright notice, 8 | this list of conditions and the following disclaimer. 9 | 10 | 2. Redistributions in binary form must reproduce the above copyright 11 | notice, this list of conditions and the following disclaimer in the 12 | documentation and/or other materials provided with the distribution. 13 | 14 | 3. Neither the name of the copyright holder nor the names of its 15 | contributors may be used to endorse or promote products derived from 16 | this software without specific prior written permission. 17 | 18 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 19 | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 20 | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 21 | A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 22 | HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 23 | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED 24 | TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 25 | PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 26 | LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 27 | NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 28 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 | -------------------------------------------------------------------------------- /NOTICE: -------------------------------------------------------------------------------- 1 | This project contains code developed by Daniel J. Bernstein which was 2 | released into the public domain. This code is based on Bernstein's 3 | "chacha-merged.c version 20080118". Daniel J. Bernstein's original code 4 | can be found at the following here: http://cr.yp.to/chacha.html 5 | 6 | This project also contains code based on part of the libsodium cryptographic 7 | library. The xchacha_hchacha and xchacha_set_counter functions were borrowed 8 | from libsodium and modified. 9 | More information about libsodium can be found at the following 10 | websites: 11 | https://github.com/jedisct1/libsodium 12 | https://download.libsodium.org/doc/ 13 | 14 | The code based on libsodium is used under the following license: 15 | 16 | /* 17 | * ISC License 18 | * 19 | * Copyright (c) 2013-2019 20 | * Frank Denis 21 | * 22 | * Permission to use, copy, modify, and/or distribute this software for any 23 | * purpose with or without fee is hereby granted, provided that the above 24 | * copyright notice and this permission notice appear in all copies. 25 | * 26 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 27 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 28 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 29 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 30 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 31 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 32 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 33 | */ 34 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # XChaCha20 - Extended Nonce Version of ChaCha20 2 | 3 | XChaCha20 is a stream cipher based on ChaCha20. XChaCha20 uses a 256-bit 4 | 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 5 | ChaCha-based ciphersuites to accept a 192-bit nonce with similar guarantees 6 | to the original construction, except with a much lower probability of 7 | nonce misuse occurring. This enables XChaCha constructions to be stateless, 8 | while retaining the same security assumptions as ChaCha." 9 | Also, XChaCha20 does not use any look up tables and is immune to 10 | timing attacks. This library is based on Daniel J. Bernstein's reference 11 | implementation of the ChaCha stream cipher. 12 | 13 | I decided to make this small C library for XChaCha20 because I could not 14 | find one. Unlike some other libraries, it only allows using XChaCha20 with 15 | a 256-bit key and a 192-bit nonce. No other key sizes or nonce sizes are 16 | allowed. A large benefit of using XChaCha20 over the regular ChaCha20 is that 17 | the larger nonce (192 bits v.s. 64 bits) allows the use of random nonces and 18 | is more resistant to nonce misuse. 19 | 20 | **More Information** 21 | 22 | [IETF XChaCha20 Draft](https://tools.ietf.org/html/draft-arciszewski-xchacha-03) 23 | 24 | [Bernstein's ChaCha Web page](http://cr.yp.to/chacha.html) 25 | 26 | [Libsodium Documentation](https://libsodium.gitbook.io/doc/advanced/stream_ciphers/xchacha20) 27 | 28 | [Crypto++ Documentation](https://www.cryptopp.com/wiki/XChaCha20) 29 | 30 | [Wikipedia](https://en.wikipedia.org/wiki/Salsa20) 31 | 32 | **WARNING** 33 | 34 | I am not a cryptographer so use this library at your own risk. 35 | 36 | 37 | **Getting Started** 38 | 39 | Import the library into your project 40 | 41 | ```C 42 | #include "xchacha20.h" 43 | ``` 44 | 45 | Create a XChaCha context 46 | 47 | ```C 48 | XChaCha_ctx ctx; 49 | ``` 50 | 51 | Set up the 256-bit encryption key and the 192-bit nonce to be used. 52 | 53 | ```C 54 | xchacha_keysetup(&ctx, key, nonce); 55 | ``` 56 | 57 | Optionally, set the counter to a different starting value other than zero. 58 | 59 | ```C 60 | xchacha_set_counter(&ctx, 0x1); 61 | ``` 62 | 63 | Then use xchacha_encrypt_bytes or xchacha_encrypt_blocks to encrypt data 64 | 65 | ```C 66 | xchacha_encrypt_bytes(&ctx, plaintext, ciphertext, sizeof(plaintext)); 67 | ``` 68 | 69 | 70 | **Test Vectors** 71 | 72 | In the src folder is a program named test.c It calculates and compares 73 | XChaCha20 test vectors obtained from two different sources. The test vectors 74 | were borrowed from the IETF draft regarding XChaCha20 and an example from 75 | Crypto++ wikipedia. It will compare the output of this XChaCha20 library with 76 | known good test vectors to ensure this library is working correctly. 77 | 78 | To make the test program simply run make 79 | 80 | make 81 | 82 | Then run the test program 83 | 84 | ./test 85 | 86 | The program will produce the following output if successful: 87 | 88 | Cryptographic tests passed 89 | 90 | If this library failed to generate the correct ciphertexts, then something 91 | is wrong with the library and you will see this output: 92 | 93 | Cryptographic tests failed! 94 | 95 | 96 | **To Do** 97 | 98 | - [x] Add a program to calculate and compare test vectors 99 | - [ ] Find and add more test vectors for XChaCha20 100 | 101 | 102 | **Contributing** 103 | 104 | Pull requests, new feature suggestions, and bug reports/issues are 105 | welcome. 106 | 107 | 108 | **Versioning** 109 | 110 | This project uses semantic versioning 2.0. Version numbers follow the 111 | MAJOR.MINOR.PATCH format. 112 | 113 | 114 | **License** 115 | 116 | This project is licensed under the 3-Clause BSD License also known as the 117 | *"New BSD License"* or the *"Modified BSD License"*. A copy of the license 118 | can be found in the LICENSE file. A copy can also be found at the 119 | [Open Source Institute](https://opensource.org/licenses/BSD-3-Clause) 120 | -------------------------------------------------------------------------------- /src/xchacha20.h: -------------------------------------------------------------------------------- 1 | /************************************************************************* 2 | * This is a small library for the XChaCha20 encryption algorithm. This * 3 | * library is based on Daniel J. Bernstein's ChaCha reference * 4 | * implementation, which can be found here: http://cr.yp.to/chacha.html * 5 | * The xchacha_hchacha() and xchacha_set_counter functions are based on * 6 | * code found in libsodium. To find the associated license and more * 7 | * info., look in the NOTICE file. * 8 | *************************************************************************/ 9 | #include 10 | 11 | #ifndef XCHACHA20_H_ 12 | #define XCHACHA20_H_ 13 | 14 | 15 | /** Key and IV sizes that are supported by XChaCha20. 16 | * All sizes are in bits. 17 | */ 18 | #define NAME "XChaCha20" 19 | #define KEYSIZE 256 /* 256-bits, 32 bytes */ 20 | #define BLOCKSIZE 512 /* 512-bits, 64 bytes */ 21 | #define IVSIZE 192 /* 192-bits, 24 bytes */ 22 | 23 | 24 | /* XChaCha20 block size in bytes */ 25 | #define XCHACHA_BLOCKLENGTH 64 26 | 27 | 28 | /* The following macros are used to obtain exact-width results. */ 29 | #define U8V(v) ((uint8_t)(v) & (0xFF)) 30 | #define U16V(v) ((uint16_t)(v) & (0xFFFF)) 31 | #define U32V(v) ((uint32_t)(v) & (0xFFFFFFFF)) 32 | #define U64V(v) ((uint64_t)(v) & (0xFFFFFFFFFFFFFFFF)) 33 | 34 | 35 | /** The following macros return words with their bits rotated over n 36 | * positions to the left/right. 37 | */ 38 | #define ROTL32(v, n) \ 39 | (U32V((v) << (n)) | ((v) >> (32 - (n)))) 40 | 41 | 42 | /** The following macros load words from an array of bytes with 43 | * different types of endianness, and vice versa. 44 | */ 45 | #define U8TO32_LITTLE(p) \ 46 | (((uint32_t)((p)[0]) ) | \ 47 | ((uint32_t)((p)[1]) << 8) | \ 48 | ((uint32_t)((p)[2]) << 16) | \ 49 | ((uint32_t)((p)[3]) << 24)) 50 | 51 | #define U32TO8_LITTLE(p, v) \ 52 | do { \ 53 | (p)[0] = U8V((v) ); \ 54 | (p)[1] = U8V((v) >> 8); \ 55 | (p)[2] = U8V((v) >> 16); \ 56 | (p)[3] = U8V((v) >> 24); \ 57 | } while (0) 58 | 59 | 60 | #define ROTATE(v,c) (ROTL32(v,c)) 61 | #define XOR(v,w) ((v) ^ (w)) 62 | #define PLUS(v,w) (U32V((v) + (w))) 63 | #define PLUSONE(v) (PLUS((v),1)) 64 | 65 | 66 | /* The ChaCha quarter round */ 67 | #define QUARTERROUND(a,b,c,d) \ 68 | a = PLUS(a,b); d = ROTATE(XOR(d,a),16); \ 69 | c = PLUS(c,d); b = ROTATE(XOR(b,c),12); \ 70 | a = PLUS(a,b); d = ROTATE(XOR(d,a), 8); \ 71 | c = PLUS(c,d); b = ROTATE(XOR(b,c), 7); 72 | 73 | 74 | /** ChaCha_ctx is the structure containing the representation of the 75 | * internal state of the XChaCha20 cipher. 76 | * 77 | */ 78 | typedef struct 79 | { 80 | uint32_t input[16]; 81 | } XChaCha_ctx; 82 | 83 | 84 | /* ------------------------------------------------------------------------- */ 85 | 86 | 87 | /** hchacha an intermediary step towards XChaCha20 based on the 88 | * construction and security proof used to create XSalsa20. 89 | * @param out Holds output of hchacha 90 | * @param in The input to process with hchacha 91 | * @param k The key to use with hchacha 92 | * 93 | */ 94 | void xchacha_hchacha20(uint8_t *out, const uint8_t *in, const uint8_t *k); 95 | 96 | 97 | /** Set the encryption key and iv to be used with XChaCha 98 | * @param ctx The XChaCha context to use 99 | * @param k The 256-bit/32-byte key to use for encryption 100 | * @param iv The 192-bit/24-byte iv or nonce to use 101 | * @note It is the user's responsibility to ensure that the key 102 | * and the iv are of the correct lengths! 103 | */ 104 | void xchacha_keysetup(XChaCha_ctx *ctx, const uint8_t *k, uint8_t *iv); 105 | 106 | 107 | /** Set the internal counter to a specific number. Depending 108 | * on the specification, sometimes the counter is started at 1. 109 | * @param ctx The XChaCha context to modify 110 | * @param counter The number to set the counter to 111 | * 112 | */ 113 | void xchacha_set_counter(XChaCha_ctx *ctx, uint8_t *counter); 114 | 115 | 116 | /** Encryption/decryption of arbitrary length messages. 117 | * 118 | * For efficiency reasons, the API provides two types of 119 | * encrypt/decrypt functions. The xchacha_encrypt_bytes() function 120 | * (declared here) encrypts byte strings of arbitrary length, while 121 | * the xchacha_encrypt_blocks() function (defined later) only accepts 122 | * lengths which are multiples of CHACHA_BLOCKLENGTH. 123 | * 124 | * The user is allowed to make multiple calls to 125 | * xchacha_encrypt_blocks() to incrementally encrypt a long message, 126 | * but he is NOT allowed to make additional encryption calls once he 127 | * has called xchacha_encrypt_bytes() (unless he starts a new message 128 | * of course). For example, this sequence of calls is acceptable: 129 | * 130 | * xchacha_keysetup(); 131 | * 132 | * xchacha_ivsetup(); 133 | * xchacha_encrypt_blocks(); 134 | * xchacha_encrypt_blocks(); 135 | * xchacha_encrypt_bytes(); 136 | * 137 | * xchacha_ivsetup(); 138 | * xchacha_encrypt_blocks(); 139 | * xchacha_encrypt_blocks(); 140 | * 141 | * xchacha_ivsetup(); 142 | * xchacha_encrypt_bytes(); 143 | * 144 | * The following sequence is not: 145 | * 146 | * xchacha_keysetup(); 147 | * xchacha_ivsetup(); 148 | * xchacha_encrypt_blocks(); 149 | * xchacha_encrypt_bytes(); 150 | * xchacha_encrypt_blocks(); 151 | * 152 | */ 153 | 154 | 155 | /** Encrypt a set of bytes with XChaCha20 156 | * @param ctx The XChaCha20 context to use 157 | * @param plaintext The data to be encrypted 158 | * @param ciphertext A buffer to hold the encrypted data 159 | * @param msglen Message length in bytes 160 | * 161 | */ 162 | void xchacha_encrypt_bytes(XChaCha_ctx* ctx, const uint8_t* plaintext, 163 | uint8_t* ciphertext, 164 | uint32_t msglen); 165 | 166 | 167 | /** Dencrypt a set of bytes with XChaCha20 168 | * @param ctx The XChaCha20 context to use 169 | * @param ciphertext The encrypted data to decrypt 170 | * @param plaintext A buffer to hold the decrypted data 171 | * @param msglen Message length in bytes 172 | * 173 | */ 174 | void xchacha_decrypt_bytes(XChaCha_ctx* ctx, const uint8_t* ciphertext, 175 | uint8_t* plaintext, 176 | uint32_t msglen); 177 | 178 | 179 | /** For testing purposes it can sometimes be useful to have a function 180 | * which immediately generates keystream without having to provide it 181 | * with a zero plaintext. 182 | * @param ctx The XChaCha context to use 183 | * @param keystream A buffer to hold the keystream 184 | * @param length Length of keystream in bytes 185 | * 186 | */ 187 | void xchacha_keystream_bytes(XChaCha_ctx* ctx, uint8_t* keystream, uint32_t length); 188 | 189 | 190 | /** Encrypt/decrypt of blocks. 191 | * @param ctx The XChaCha context to use 192 | * @param plaintext A buffer which holds unencrypted data 193 | * @param ciphertext A buffer which holds encrypted data 194 | * @param blocks The number of 512 blocks to process with XChaCha20 195 | * 196 | */ 197 | #define xchacha_encrypt_blocks(ctx, plaintext, ciphertext, blocks) \ 198 | xchacha_encrypt_bytes(ctx, plaintext, ciphertext, \ 199 | (blocks) * XCHACHA_BLOCKLENGTH) 200 | 201 | 202 | #define xchacha_decrypt_blocks(ctx, ciphertext, plaintext, blocks) \ 203 | xchacha_decrypt_bytes(ctx, ciphertext, plaintext, \ 204 | (blocks) * XCHACHA_BLOCKLENGTH) 205 | 206 | 207 | #define xchacha_keystream_blocks(ctx, keystream, blocks) \ 208 | xchacha_keystream_bytes(ctx, keystream, \ 209 | (blocks) * XCHACHA_BLOCKLENGTH) 210 | 211 | 212 | #endif 213 | -------------------------------------------------------------------------------- /src/xchacha20.c: -------------------------------------------------------------------------------- 1 | /************************************************************************* 2 | * This is a small cryptographic library that implements the XChaCha20 * 3 | * stream cipher. It is based on "chacha-merged.c version 20080118" * 4 | * created by D. J. Bernstein and released in to the Public domain. * 5 | * Check out his website at: http://cr.yp.to/chacha.html * 6 | * The xchacha_hchacha() and xchacha_set_counter() functions are based * 7 | * on code found in libsodium. To find the associated license and more * 8 | * info., look in the NOTICE file. * 9 | *************************************************************************/ 10 | #include 11 | #include 12 | #include "xchacha20.h" 13 | 14 | 15 | /** hchacha an intermediary step towards XChaCha20 based on the 16 | * construction and security proof used to create XSalsa20. 17 | * @param out Holds output of hchacha 18 | * @param in The input to process with hchacha 19 | * @param k The key to use with hchacha 20 | * 21 | */ 22 | void xchacha_hchacha20(uint8_t *out, const uint8_t *in, const uint8_t *k){ 23 | int i; 24 | uint32_t x0, x1, x2, x3, x4, x5, x6, x7; 25 | uint32_t x8, x9, x10, x11, x12, x13, x14, x15; 26 | 27 | /* XChaCha Constant */ 28 | x0 = 0x61707865; 29 | x1 = 0x3320646e; 30 | x2 = 0x79622d32; 31 | x3 = 0x6b206574; 32 | 33 | x4 = U8TO32_LITTLE(k + 0); 34 | x5 = U8TO32_LITTLE(k + 4); 35 | x6 = U8TO32_LITTLE(k + 8); 36 | x7 = U8TO32_LITTLE(k + 12); 37 | x8 = U8TO32_LITTLE(k + 16); 38 | x9 = U8TO32_LITTLE(k + 20); 39 | x10 = U8TO32_LITTLE(k + 24); 40 | x11 = U8TO32_LITTLE(k + 28); 41 | x12 = U8TO32_LITTLE(in + 0); 42 | x13 = U8TO32_LITTLE(in + 4); 43 | x14 = U8TO32_LITTLE(in + 8); 44 | x15 = U8TO32_LITTLE(in + 12); 45 | 46 | for (i = 0; i < 10; i++){ 47 | QUARTERROUND(x0, x4, x8, x12); 48 | QUARTERROUND(x1, x5, x9, x13); 49 | QUARTERROUND(x2, x6, x10, x14); 50 | QUARTERROUND(x3, x7, x11, x15); 51 | QUARTERROUND(x0, x5, x10, x15); 52 | QUARTERROUND(x1, x6, x11, x12); 53 | QUARTERROUND(x2, x7, x8, x13); 54 | QUARTERROUND(x3, x4, x9, x14); 55 | } 56 | 57 | U32TO8_LITTLE(out + 0, x0); 58 | U32TO8_LITTLE(out + 4, x1); 59 | U32TO8_LITTLE(out + 8, x2); 60 | U32TO8_LITTLE(out + 12, x3); 61 | U32TO8_LITTLE(out + 16, x12); 62 | U32TO8_LITTLE(out + 20, x13); 63 | U32TO8_LITTLE(out + 24, x14); 64 | U32TO8_LITTLE(out + 28, x15); 65 | } 66 | 67 | 68 | /** Setup the XChaCha20 encryption key 69 | * @param x The XChaCha20 Context to use 70 | * @param k A buffer holding the encryption key to use 71 | * @note Valid key sizes are 256 bits, and the only valid IV size 72 | * is 192 bits. 73 | * 74 | */ 75 | void xchacha_keysetup(XChaCha_ctx *ctx, const uint8_t *k, uint8_t *iv){ 76 | /* The sub-key to use */ 77 | uint8_t k2[32]; 78 | 79 | /* Generate the sub-key to use from the 256-bit key and 192-bit iv 80 | * We then use this sub-key and the last 8 bytes of the iv 81 | * as normal. 82 | */ 83 | xchacha_hchacha20(k2, iv, k); 84 | 85 | 86 | ctx->input[0] = 0x61707865; 87 | ctx->input[1] = 0x3320646e; 88 | ctx->input[2] = 0x79622d32; 89 | ctx->input[3] = 0x6b206574; 90 | ctx->input[4] = U8TO32_LITTLE(k2 + 0); 91 | ctx->input[5] = U8TO32_LITTLE(k2 + 4); 92 | ctx->input[6] = U8TO32_LITTLE(k2 + 8); 93 | ctx->input[7] = U8TO32_LITTLE(k2 + 12); 94 | ctx->input[8] = U8TO32_LITTLE(k2 + 16); 95 | ctx->input[9] = U8TO32_LITTLE(k2 + 20); 96 | ctx->input[10] = U8TO32_LITTLE(k2 + 24); 97 | ctx->input[11] = U8TO32_LITTLE(k2 + 28); 98 | ctx->input[12] = 0; /* Internal counter */ 99 | ctx->input[13] = 0; /* Internal counter */ 100 | ctx->input[14] = U8TO32_LITTLE(iv + 16); 101 | ctx->input[15] = U8TO32_LITTLE(iv + 20); 102 | } 103 | 104 | 105 | /** Set the internal counter to a specific number. Depending 106 | * on the specification, sometimes the counter is started at 1. 107 | * @param ctx The XChaCha context to modify 108 | * @param counter The number to set the counter to 109 | * 110 | */ 111 | void xchacha_set_counter(XChaCha_ctx *ctx, uint8_t *counter){ 112 | ctx->input[12] = U8TO32_LITTLE(counter + 0); 113 | ctx->input[13] = U8TO32_LITTLE(counter + 4); 114 | } 115 | 116 | 117 | /** Encrypt data with the XChaCha20 stream cipher 118 | * @param x The XChaCha20 context with the cipher's state to use 119 | * @param m The plaintext to encrypt 120 | * @param c A buffer to hold the ciphertext created from the plaintext 121 | * @param bytes The length of the plaintext to encrypt 122 | * @note length of c must be >= the length of m otherwise a buffer 123 | * overflow will occur. 124 | * 125 | */ 126 | void xchacha_encrypt_bytes(XChaCha_ctx *ctx, const uint8_t *m, uint8_t *c, uint32_t bytes){ 127 | uint32_t x0, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12, x13, x14, x15; 128 | uint32_t j0, j1, j2, j3, j4, j5, j6, j7, j8, j9, j10, j11, j12, j13, j14, j15; 129 | uint8_t *ctarget = NULL; 130 | uint8_t tmp[64]; 131 | uint32_t i; 132 | 133 | if (!bytes) return; 134 | 135 | j0 = ctx->input[0]; 136 | j1 = ctx->input[1]; 137 | j2 = ctx->input[2]; 138 | j3 = ctx->input[3]; 139 | j4 = ctx->input[4]; 140 | j5 = ctx->input[5]; 141 | j6 = ctx->input[6]; 142 | j7 = ctx->input[7]; 143 | j8 = ctx->input[8]; 144 | j9 = ctx->input[9]; 145 | j10 = ctx->input[10]; 146 | j11 = ctx->input[11]; 147 | j12 = ctx->input[12]; 148 | j13 = ctx->input[13]; 149 | j14 = ctx->input[14]; 150 | j15 = ctx->input[15]; 151 | 152 | for (;;) { 153 | if (bytes < 64) { 154 | for (i = 0;i < bytes;++i) 155 | tmp[i] = m[i]; 156 | m = tmp; 157 | ctarget = c; 158 | c = tmp; 159 | } 160 | x0 = j0; 161 | x1 = j1; 162 | x2 = j2; 163 | x3 = j3; 164 | x4 = j4; 165 | x5 = j5; 166 | x6 = j6; 167 | x7 = j7; 168 | x8 = j8; 169 | x9 = j9; 170 | x10 = j10; 171 | x11 = j11; 172 | x12 = j12; 173 | x13 = j13; 174 | x14 = j14; 175 | x15 = j15; 176 | 177 | /* Do 20 rounds instead of 8 */ 178 | for (i = 20;i > 0;i -= 2) { 179 | QUARTERROUND( x0, x4, x8,x12) 180 | QUARTERROUND( x1, x5, x9,x13) 181 | QUARTERROUND( x2, x6,x10,x14) 182 | QUARTERROUND( x3, x7,x11,x15) 183 | QUARTERROUND( x0, x5,x10,x15) 184 | QUARTERROUND( x1, x6,x11,x12) 185 | QUARTERROUND( x2, x7, x8,x13) 186 | QUARTERROUND( x3, x4, x9,x14) 187 | } 188 | x0 = PLUS(x0,j0); 189 | x1 = PLUS(x1,j1); 190 | x2 = PLUS(x2,j2); 191 | x3 = PLUS(x3,j3); 192 | x4 = PLUS(x4,j4); 193 | x5 = PLUS(x5,j5); 194 | x6 = PLUS(x6,j6); 195 | x7 = PLUS(x7,j7); 196 | x8 = PLUS(x8,j8); 197 | x9 = PLUS(x9,j9); 198 | x10 = PLUS(x10,j10); 199 | x11 = PLUS(x11,j11); 200 | x12 = PLUS(x12,j12); 201 | x13 = PLUS(x13,j13); 202 | x14 = PLUS(x14,j14); 203 | x15 = PLUS(x15,j15); 204 | 205 | x0 = XOR(x0,U8TO32_LITTLE(m + 0)); 206 | x1 = XOR(x1,U8TO32_LITTLE(m + 4)); 207 | x2 = XOR(x2,U8TO32_LITTLE(m + 8)); 208 | x3 = XOR(x3,U8TO32_LITTLE(m + 12)); 209 | x4 = XOR(x4,U8TO32_LITTLE(m + 16)); 210 | x5 = XOR(x5,U8TO32_LITTLE(m + 20)); 211 | x6 = XOR(x6,U8TO32_LITTLE(m + 24)); 212 | x7 = XOR(x7,U8TO32_LITTLE(m + 28)); 213 | x8 = XOR(x8,U8TO32_LITTLE(m + 32)); 214 | x9 = XOR(x9,U8TO32_LITTLE(m + 36)); 215 | x10 = XOR(x10,U8TO32_LITTLE(m + 40)); 216 | x11 = XOR(x11,U8TO32_LITTLE(m + 44)); 217 | x12 = XOR(x12,U8TO32_LITTLE(m + 48)); 218 | x13 = XOR(x13,U8TO32_LITTLE(m + 52)); 219 | x14 = XOR(x14,U8TO32_LITTLE(m + 56)); 220 | x15 = XOR(x15,U8TO32_LITTLE(m + 60)); 221 | 222 | j12 = PLUSONE(j12); 223 | if (!j12) { 224 | j13 = PLUSONE(j13); 225 | } 226 | 227 | U32TO8_LITTLE(c + 0,x0); 228 | U32TO8_LITTLE(c + 4,x1); 229 | U32TO8_LITTLE(c + 8,x2); 230 | U32TO8_LITTLE(c + 12,x3); 231 | U32TO8_LITTLE(c + 16,x4); 232 | U32TO8_LITTLE(c + 20,x5); 233 | U32TO8_LITTLE(c + 24,x6); 234 | U32TO8_LITTLE(c + 28,x7); 235 | U32TO8_LITTLE(c + 32,x8); 236 | U32TO8_LITTLE(c + 36,x9); 237 | U32TO8_LITTLE(c + 40,x10); 238 | U32TO8_LITTLE(c + 44,x11); 239 | U32TO8_LITTLE(c + 48,x12); 240 | U32TO8_LITTLE(c + 52,x13); 241 | U32TO8_LITTLE(c + 56,x14); 242 | U32TO8_LITTLE(c + 60,x15); 243 | 244 | if (bytes <= 64) { 245 | if (bytes < 64) { 246 | for (i = 0;i < bytes;++i) 247 | ctarget[i] = c[i]; 248 | } 249 | ctx->input[12] = j12; 250 | ctx->input[13] = j13; 251 | return; 252 | } 253 | bytes -= 64; 254 | c += 64; 255 | m += 64; 256 | } 257 | } 258 | 259 | 260 | /** Decrypt data with the XChaCha20 stream cipher 261 | * @param x The XChaCha20 context with the cipher's state to use 262 | * @param c The ciphertext to decrypt 263 | * @param m A buffer to hold the plaintext 264 | * @param bytes The number of bytes of ciphertext to decrypt 265 | * @note length of m must be >= the length of c otherwise a buffer 266 | * overflow will occur. 267 | * 268 | */ 269 | void xchacha_decrypt_bytes(XChaCha_ctx *ctx, const uint8_t *c, uint8_t *m, uint32_t bytes){ 270 | xchacha_encrypt_bytes(ctx,c,m,bytes); 271 | } 272 | 273 | 274 | /** Generate a keystream from encrypting a zero byte plaintext 275 | * @param x The XChaCha context to use 276 | * @param stream A buffer to store the generated keystream 277 | * @param bytes The number of bytes of keystream to generate 278 | * @note Mostly for testing purposes 279 | * 280 | */ 281 | void xchacha_keystream_bytes(XChaCha_ctx *ctx, uint8_t *stream, uint32_t bytes){ 282 | uint32_t i; 283 | 284 | for (i = 0;i < bytes;++i){ 285 | stream[i] = 0; 286 | } 287 | 288 | xchacha_encrypt_bytes(ctx,stream,stream,bytes); 289 | } 290 | -------------------------------------------------------------------------------- /src/test.c: -------------------------------------------------------------------------------- 1 | /************************************************************************* 2 | * This is a simple program to calculate test vectors and compare them * 3 | * to known good values for XChaCha20. 4 | *************************************************************************/ 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include "xchacha20.h" 11 | 12 | 13 | /** Calculate and compare the newest test vectors from the IETF 14 | * Draft for XchaCha20. The test vectors were taken from 15 | * version 03 of the draft: 16 | * https://tools.ietf.org/html/draft-arciszewski-xchacha-03 17 | * This version was published on: October 11, 2018 and 18 | * expired on: June 21, 2019 19 | * The biggest difference between this IETF test vector and the 20 | * other one is that this version initializes the XChaCha20 internal 21 | * counter to 1 instead of 0. 22 | * @returns 0 on success, -1 on failure or error 23 | * 24 | */ 25 | int check_second_ietf(void){ 26 | XChaCha_ctx ctx; 27 | uint8_t *buffer; 28 | uint8_t counter[8] = {0x1}; 29 | 30 | /* Test vectors from IETF XChaCha20 draft 03 */ 31 | uint8_t plaintext[] = { 32 | 0x54, 0x68, 0x65, 0x20, 0x64, 0x68, 0x6f, 0x6c, 33 | 0x65, 0x20, 0x28, 0x70, 0x72, 0x6f, 0x6e, 0x6f, 34 | 0x75, 0x6e, 0x63, 0x65, 0x64, 0x20, 0x22, 0x64, 35 | 0x6f, 0x6c, 0x65, 0x22, 0x29, 0x20, 0x69, 0x73, 36 | 0x20, 0x61, 0x6c, 0x73, 0x6f, 0x20, 0x6b, 0x6e, 37 | 0x6f, 0x77, 0x6e, 0x20, 0x61, 0x73, 0x20, 0x74, 38 | 0x68, 0x65, 0x20, 0x41, 0x73, 0x69, 0x61, 0x74, 39 | 0x69, 0x63, 0x20, 0x77, 0x69, 0x6c, 0x64, 0x20, 40 | 0x64, 0x6f, 0x67, 0x2c, 0x20, 0x72, 0x65, 0x64, 41 | 0x20, 0x64, 0x6f, 0x67, 0x2c, 0x20, 0x61, 0x6e, 42 | 0x64, 0x20, 0x77, 0x68, 0x69, 0x73, 0x74, 0x6c, 43 | 0x69, 0x6e, 0x67, 0x20, 0x64, 0x6f, 0x67, 0x2e, 44 | 0x20, 0x49, 0x74, 0x20, 0x69, 0x73, 0x20, 0x61, 45 | 0x62, 0x6f, 0x75, 0x74, 0x20, 0x74, 0x68, 0x65, 46 | 0x20, 0x73, 0x69, 0x7a, 0x65, 0x20, 0x6f, 0x66, 47 | 0x20, 0x61, 0x20, 0x47, 0x65, 0x72, 0x6d, 0x61, 48 | 0x6e, 0x20, 0x73, 0x68, 0x65, 0x70, 0x68, 0x65, 49 | 0x72, 0x64, 0x20, 0x62, 0x75, 0x74, 0x20, 0x6c, 50 | 0x6f, 0x6f, 0x6b, 0x73, 0x20, 0x6d, 0x6f, 0x72, 51 | 0x65, 0x20, 0x6c, 0x69, 0x6b, 0x65, 0x20, 0x61, 52 | 0x20, 0x6c, 0x6f, 0x6e, 0x67, 0x2d, 0x6c, 0x65, 53 | 0x67, 0x67, 0x65, 0x64, 0x20, 0x66, 0x6f, 0x78, 54 | 0x2e, 0x20, 0x54, 0x68, 0x69, 0x73, 0x20, 0x68, 55 | 0x69, 0x67, 0x68, 0x6c, 0x79, 0x20, 0x65, 0x6c, 56 | 0x75, 0x73, 0x69, 0x76, 0x65, 0x20, 0x61, 0x6e, 57 | 0x64, 0x20, 0x73, 0x6b, 0x69, 0x6c, 0x6c, 0x65, 58 | 0x64, 0x20, 0x6a, 0x75, 0x6d, 0x70, 0x65, 0x72, 59 | 0x20, 0x69, 0x73, 0x20, 0x63, 0x6c, 0x61, 0x73, 60 | 0x73, 0x69, 0x66, 0x69, 0x65, 0x64, 0x20, 0x77, 61 | 0x69, 0x74, 0x68, 0x20, 0x77, 0x6f, 0x6c, 0x76, 62 | 0x65, 0x73, 0x2c, 0x20, 0x63, 0x6f, 0x79, 0x6f, 63 | 0x74, 0x65, 0x73, 0x2c, 0x20, 0x6a, 0x61, 0x63, 64 | 0x6b, 0x61, 0x6c, 0x73, 0x2c, 0x20, 0x61, 0x6e, 65 | 0x64, 0x20, 0x66, 0x6f, 0x78, 0x65, 0x73, 0x20, 66 | 0x69, 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, 0x74, 67 | 0x61, 0x78, 0x6f, 0x6e, 0x6f, 0x6d, 0x69, 0x63, 68 | 0x20, 0x66, 0x61, 0x6d, 0x69, 0x6c, 0x79, 0x20, 69 | 0x43, 0x61, 0x6e, 0x69, 0x64, 0x61, 0x65, 0x2e 70 | }; 71 | 72 | uint8_t key[] = { 73 | 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 74 | 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f, 75 | 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 76 | 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f 77 | }; 78 | 79 | uint8_t iv[] = { 80 | 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 81 | 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, 82 | 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x58 83 | }; 84 | 85 | uint8_t correct_ciphertext[] = { 86 | 0x7d, 0x0a, 0x2e, 0x6b, 0x7f, 0x7c, 0x65, 0xa2, 87 | 0x36, 0x54, 0x26, 0x30, 0x29, 0x4e, 0x06, 0x3b, 88 | 0x7a, 0xb9, 0xb5, 0x55, 0xa5, 0xd5, 0x14, 0x9a, 89 | 0xa2, 0x1e, 0x4a, 0xe1, 0xe4, 0xfb, 0xce, 0x87, 90 | 0xec, 0xc8, 0xe0, 0x8a, 0x8b, 0x5e, 0x35, 0x0a, 91 | 0xbe, 0x62, 0x2b, 0x2f, 0xfa, 0x61, 0x7b, 0x20, 92 | 0x2c, 0xfa, 0xd7, 0x20, 0x32, 0xa3, 0x03, 0x7e, 93 | 0x76, 0xff, 0xdc, 0xdc, 0x43, 0x76, 0xee, 0x05, 94 | 0x3a, 0x19, 0x0d, 0x7e, 0x46, 0xca, 0x1d, 0xe0, 95 | 0x41, 0x44, 0x85, 0x03, 0x81, 0xb9, 0xcb, 0x29, 96 | 0xf0, 0x51, 0x91, 0x53, 0x86, 0xb8, 0xa7, 0x10, 97 | 0xb8, 0xac, 0x4d, 0x02, 0x7b, 0x8b, 0x05, 0x0f, 98 | 0x7c, 0xba, 0x58, 0x54, 0xe0, 0x28, 0xd5, 0x64, 99 | 0xe4, 0x53, 0xb8, 0xa9, 0x68, 0x82, 0x41, 0x73, 100 | 0xfc, 0x16, 0x48, 0x8b, 0x89, 0x70, 0xca, 0xc8, 101 | 0x28, 0xf1, 0x1a, 0xe5, 0x3c, 0xab, 0xd2, 0x01, 102 | 0x12, 0xf8, 0x71, 0x07, 0xdf, 0x24, 0xee, 0x61, 103 | 0x83, 0xd2, 0x27, 0x4f, 0xe4, 0xc8, 0xb1, 0x48, 104 | 0x55, 0x34, 0xef, 0x2c, 0x5f, 0xbc, 0x1e, 0xc2, 105 | 0x4b, 0xfc, 0x36, 0x63, 0xef, 0xaa, 0x08, 0xbc, 106 | 0x04, 0x7d, 0x29, 0xd2, 0x50, 0x43, 0x53, 0x2d, 107 | 0xb8, 0x39, 0x1a, 0x8a, 0x3d, 0x77, 0x6b, 0xf4, 108 | 0x37, 0x2a, 0x69, 0x55, 0x82, 0x7c, 0xcb, 0x0c, 109 | 0xdd, 0x4a, 0xf4, 0x03, 0xa7, 0xce, 0x4c, 0x63, 110 | 0xd5, 0x95, 0xc7, 0x5a, 0x43, 0xe0, 0x45, 0xf0, 111 | 0xcc, 0xe1, 0xf2, 0x9c, 0x8b, 0x93, 0xbd, 0x65, 112 | 0xaf, 0xc5, 0x97, 0x49, 0x22, 0xf2, 0x14, 0xa4, 113 | 0x0b, 0x7c, 0x40, 0x2c, 0xdb, 0x91, 0xae, 0x73, 114 | 0xc0, 0xb6, 0x36, 0x15, 0xcd, 0xad, 0x04, 0x80, 115 | 0x68, 0x0f, 0x16, 0x51, 0x5a, 0x7a, 0xce, 0x9d, 116 | 0x39, 0x23, 0x64, 0x64, 0x32, 0x8a, 0x37, 0x74, 117 | 0x3f, 0xfc, 0x28, 0xf4, 0xdd, 0xb3, 0x24, 0xf4, 118 | 0xd0, 0xf5, 0xbb, 0xdc, 0x27, 0x0c, 0x65, 0xb1, 119 | 0x74, 0x9a, 0x6e, 0xff, 0xf1, 0xfb, 0xaa, 0x09, 120 | 0x53, 0x61, 0x75, 0xcc, 0xd2, 0x9f, 0xb9, 0xe6, 121 | 0x05, 0x7b, 0x30, 0x73, 0x20, 0xd3, 0x16, 0x83, 122 | 0x8a, 0x9c, 0x71, 0xf7, 0x0b, 0x5b, 0x59, 0x07, 123 | 0xa6, 0x6f, 0x7e, 0xa4, 0x9a, 0xad, 0xc4, 0x09 124 | }; 125 | 126 | /* Allocate a buffer to hold our calculated ciphertext */ 127 | if((buffer = malloc(1024 * sizeof(uint8_t))) == NULL){ 128 | perror("malloc() error"); 129 | return(-1); 130 | } 131 | 132 | xchacha_keysetup(&ctx, key, iv); 133 | 134 | /*This version of the IETF draft initializes their counter to 1 135 | * instead of 0 */ 136 | xchacha_set_counter(&ctx, counter); 137 | xchacha_encrypt_bytes(&ctx, plaintext, buffer, 304); 138 | 139 | /* Make sure our ciphertext matches */ 140 | if(memcmp(buffer, correct_ciphertext, 304) != 0){ 141 | free(buffer); 142 | return(-1); 143 | } 144 | 145 | free(buffer); 146 | 147 | return(0); 148 | } 149 | 150 | /** Calculate and compare the test vectors from the IETF 151 | * Draft for XchaCha20. The test vectors were taken from 152 | * this version of the draft: 153 | * https://tools.ietf.org/html/draft-arciszewski-xchacha-02 154 | * This version was published on: October 11, 2018 and 155 | * expired on: April 14, 2019 156 | * @returns 0 on success, -1 on failure or error 157 | * 158 | */ 159 | int check_ietf(void){ 160 | XChaCha_ctx ctx; 161 | uint8_t *buffer; 162 | 163 | /* Test vectors from IETF XChaCha20 draft */ 164 | uint8_t plaintext[] = { 165 | 0x54, 0x68, 0x65, 0x20, 0x64, 0x68, 0x6f, 0x6c, 166 | 0x65, 0x20, 0x28, 0x70, 0x72, 0x6f, 0x6e, 0x6f, 167 | 0x75, 0x6e, 0x63, 0x65, 0x64, 0x20, 0x22, 0x64, 168 | 0x6f, 0x6c, 0x65, 0x22, 0x29, 0x20, 0x69, 0x73, 169 | 0x20, 0x61, 0x6c, 0x73, 0x6f, 0x20, 0x6b, 0x6e, 170 | 0x6f, 0x77, 0x6e, 0x20, 0x61, 0x73, 0x20, 0x74, 171 | 0x68, 0x65, 0x20, 0x41, 0x73, 0x69, 0x61, 0x74, 172 | 0x69, 0x63, 0x20, 0x77, 0x69, 0x6c, 0x64, 0x20, 173 | 0x64, 0x6f, 0x67, 0x2c, 0x20, 0x72, 0x65, 0x64, 174 | 0x20, 0x64, 0x6f, 0x67, 0x2c, 0x20, 0x61, 0x6e, 175 | 0x64, 0x20, 0x77, 0x68, 0x69, 0x73, 0x74, 0x6c, 176 | 0x69, 0x6e, 0x67, 0x20, 0x64, 0x6f, 0x67, 0x2e, 177 | 0x20, 0x49, 0x74, 0x20, 0x69, 0x73, 0x20, 0x61, 178 | 0x62, 0x6f, 0x75, 0x74, 0x20, 0x74, 0x68, 0x65, 179 | 0x20, 0x73, 0x69, 0x7a, 0x65, 0x20, 0x6f, 0x66, 180 | 0x20, 0x61, 0x20, 0x47, 0x65, 0x72, 0x6d, 0x61, 181 | 0x6e, 0x20, 0x73, 0x68, 0x65, 0x70, 0x68, 0x65, 182 | 0x72, 0x64, 0x20, 0x62, 0x75, 0x74, 0x20, 0x6c, 183 | 0x6f, 0x6f, 0x6b, 0x73, 0x20, 0x6d, 0x6f, 0x72, 184 | 0x65, 0x20, 0x6c, 0x69, 0x6b, 0x65, 0x20, 0x61, 185 | 0x20, 0x6c, 0x6f, 0x6e, 0x67, 0x2d, 0x6c, 0x65, 186 | 0x67, 0x67, 0x65, 0x64, 0x20, 0x66, 0x6f, 0x78, 187 | 0x2e, 0x20, 0x54, 0x68, 0x69, 0x73, 0x20, 0x68, 188 | 0x69, 0x67, 0x68, 0x6c, 0x79, 0x20, 0x65, 0x6c, 189 | 0x75, 0x73, 0x69, 0x76, 0x65, 0x20, 0x61, 0x6e, 190 | 0x64, 0x20, 0x73, 0x6b, 0x69, 0x6c, 0x6c, 0x65, 191 | 0x64, 0x20, 0x6a, 0x75, 0x6d, 0x70, 0x65, 0x72, 192 | 0x20, 0x69, 0x73, 0x20, 0x63, 0x6c, 0x61, 0x73, 193 | 0x73, 0x69, 0x66, 0x69, 0x65, 0x64, 0x20, 0x77, 194 | 0x69, 0x74, 0x68, 0x20, 0x77, 0x6f, 0x6c, 0x76, 195 | 0x65, 0x73, 0x2c, 0x20, 0x63, 0x6f, 0x79, 0x6f, 196 | 0x74, 0x65, 0x73, 0x2c, 0x20, 0x6a, 0x61, 0x63, 197 | 0x6b, 0x61, 0x6c, 0x73, 0x2c, 0x20, 0x61, 0x6e, 198 | 0x64, 0x20, 0x66, 0x6f, 0x78, 0x65, 0x73, 0x20, 199 | 0x69, 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, 0x74, 200 | 0x61, 0x78, 0x6f, 0x6e, 0x6f, 0x6d, 0x69, 0x63, 201 | 0x20, 0x66, 0x61, 0x6d, 0x69, 0x6c, 0x79, 0x20, 202 | 0x43, 0x61, 0x6e, 0x69, 0x64, 0x61, 0x65, 0x2e 203 | }; 204 | 205 | uint8_t key[] = { 206 | 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 207 | 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f, 208 | 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 209 | 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f 210 | }; 211 | 212 | uint8_t iv[] = { 213 | 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 214 | 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, 215 | 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x58 216 | }; 217 | 218 | uint8_t correct_ciphertext[] = { 219 | 0x45, 0x59, 0xab, 0xba, 0x4e, 0x48, 0xc1, 0x61, 220 | 0x02, 0xe8, 0xbb, 0x2c, 0x05, 0xe6, 0x94, 0x7f, 221 | 0x50, 0xa7, 0x86, 0xde, 0x16, 0x2f, 0x9b, 0x0b, 222 | 0x7e, 0x59, 0x2a, 0x9b, 0x53, 0xd0, 0xd4, 0xe9, 223 | 0x8d, 0x8d, 0x64, 0x10, 0xd5, 0x40, 0xa1, 0xa6, 224 | 0x37, 0x5b, 0x26, 0xd8, 0x0d, 0xac, 0xe4, 0xfa, 225 | 0xb5, 0x23, 0x84, 0xc7, 0x31, 0xac, 0xbf, 0x16, 226 | 0xa5, 0x92, 0x3c, 0x0c, 0x48, 0xd3, 0x57, 0x5d, 227 | 0x4d, 0x0d, 0x2c, 0x67, 0x3b, 0x66, 0x6f, 0xaa, 228 | 0x73, 0x10, 0x61, 0x27, 0x77, 0x01, 0x09, 0x3a, 229 | 0x6b, 0xf7, 0xa1, 0x58, 0xa8, 0x86, 0x42, 0x92, 230 | 0xa4, 0x1c, 0x48, 0xe3, 0xa9, 0xb4, 0xc0, 0xda, 231 | 0xec, 0xe0, 0xf8, 0xd9, 0x8d, 0x0d, 0x7e, 0x05, 232 | 0xb3, 0x7a, 0x30, 0x7b, 0xbb, 0x66, 0x33, 0x31, 233 | 0x64, 0xec, 0x9e, 0x1b, 0x24, 0xea, 0x0d, 0x6c, 234 | 0x3f, 0xfd, 0xdc, 0xec, 0x4f, 0x68, 0xe7, 0x44, 235 | 0x30, 0x56, 0x19, 0x3a, 0x03, 0xc8, 0x10, 0xe1, 236 | 0x13, 0x44, 0xca, 0x06, 0xd8, 0xed, 0x8a, 0x2b, 237 | 0xfb, 0x1e, 0x8d, 0x48, 0xcf, 0xa6, 0xbc, 0x0e, 238 | 0xb4, 0xe2, 0x46, 0x4b, 0x74, 0x81, 0x42, 0x40, 239 | 0x7c, 0x9f, 0x43, 0x1a, 0xee, 0x76, 0x99, 0x60, 240 | 0xe1, 0x5b, 0xa8, 0xb9, 0x68, 0x90, 0x46, 0x6e, 241 | 0xf2, 0x45, 0x75, 0x99, 0x85, 0x23, 0x85, 0xc6, 242 | 0x61, 0xf7, 0x52, 0xce, 0x20, 0xf9, 0xda, 0x0c, 243 | 0x09, 0xab, 0x6b, 0x19, 0xdf, 0x74, 0xe7, 0x6a, 244 | 0x95, 0x96, 0x74, 0x46, 0xf8, 0xd0, 0xfd, 0x41, 245 | 0x5e, 0x7b, 0xee, 0x2a, 0x12, 0xa1, 0x14, 0xc2, 246 | 0x0e, 0xb5, 0x29, 0x2a, 0xe7, 0xa3, 0x49, 0xae, 247 | 0x57, 0x78, 0x20, 0xd5, 0x52, 0x0a, 0x1f, 0x3f, 248 | 0xb6, 0x2a, 0x17, 0xce, 0x6a, 0x7e, 0x68, 0xfa, 249 | 0x7c, 0x79, 0x11, 0x1d, 0x88, 0x60, 0x92, 0x0b, 250 | 0xc0, 0x48, 0xef, 0x43, 0xfe, 0x84, 0x48, 0x6c, 251 | 0xcb, 0x87, 0xc2, 0x5f, 0x0a, 0xe0, 0x45, 0xf0, 252 | 0xcc, 0xe1, 0xe7, 0x98, 0x9a, 0x9a, 0xa2, 0x20, 253 | 0xa2, 0x8b, 0xdd, 0x48, 0x27, 0xe7, 0x51, 0xa2, 254 | 0x4a, 0x6d, 0x5c, 0x62, 0xd7, 0x90, 0xa6, 0x63, 255 | 0x93, 0xb9, 0x31, 0x11, 0xc1, 0xa5, 0x5d, 0xd7, 256 | 0x42, 0x1a, 0x10, 0x18, 0x49, 0x74, 0xc7, 0xc5 257 | }; 258 | 259 | /* Allocate a buffer to hold our calculated ciphertext */ 260 | if((buffer = malloc(1024 * sizeof(uint8_t))) == NULL){ 261 | perror("malloc() error"); 262 | return(-1); 263 | } 264 | 265 | xchacha_keysetup(&ctx, key, iv); 266 | xchacha_encrypt_bytes(&ctx, plaintext, buffer, 304); 267 | 268 | /* Make sure our ciphertext matches */ 269 | if(memcmp(buffer, correct_ciphertext, 304) != 0){ 270 | free(buffer); 271 | return(-1); 272 | } 273 | 274 | free(buffer); 275 | 276 | return(0); 277 | } 278 | 279 | 280 | /** Compare our output to the output of a known good XChaCha20 library. 281 | * The test vectors used here are from examples given of the Crypto++ 282 | * cryptographic library's XChaCha20 examples. These values can be 283 | * found here: 284 | * https://www.cryptopp.com/wiki/XChaCha20 285 | * @returns 0 on success, -1 on failure or error 286 | * 287 | */ 288 | int check_cpp(void){ 289 | XChaCha_ctx ctx; 290 | uint8_t *buffer; 291 | uint8_t counter[8] = {0x1}; 292 | 293 | /* Test values from Crypto++ documentation */ 294 | uint8_t key[] = { 295 | 0x5E, 0xC5, 0x8B, 0x6D, 0x51, 0x4F, 0xE0, 0xA5, 296 | 0x6F, 0x1E, 0x0D, 0xEA, 0x7B, 0xDC, 0x09, 0x5A, 297 | 0x10, 0xF5, 0xB6, 0x18, 0xBD, 0xB6, 0xF2, 0x26, 298 | 0x2F, 0xCC, 0x59, 0x7B, 0xB2, 0x30, 0xB3, 0xEF 299 | }; 300 | 301 | uint8_t iv[] = { 302 | 0xA3, 0x45, 0xF5, 0xCF, 0x80, 0x23, 0x51, 0x7C, 303 | 0xC0, 0xFC, 0xF0, 0x75, 0x74, 0x8C, 0x86, 0x5F, 304 | 0x7D, 0xE8, 0xCA, 0x0C, 0x72, 0x36, 0xAB, 0xDA 305 | }; 306 | 307 | uint8_t correct_ciphertext[] = { 308 | 0xEE, 0xA7, 0xC2, 0x71, 0x19, 0x10, 0x65, 0x69, 309 | 0x92, 0xE1, 0xCE, 0xD8, 0x16, 0xE2, 0x0E, 0x62, 310 | 0x1B, 0x25, 0x17, 0x82, 0x36, 0x71, 0x6A, 0xE4, 311 | 0x99, 0xF2, 0x97, 0x37, 0xA7, 0x2A, 0xFC, 0xF8, 312 | 0x6C, 0x72 313 | }; 314 | 315 | uint8_t plaintext[] = "My Plaintext!! My Dear plaintext!!"; 316 | uint32_t msglen = strlen((char *)plaintext); 317 | 318 | /* Allocate a buffer to hold our calculated ciphertext */ 319 | if((buffer = malloc(50 * sizeof(uint8_t))) == NULL){ 320 | perror("malloc() error"); 321 | return(-1); 322 | } 323 | 324 | xchacha_keysetup(&ctx, key, iv); 325 | 326 | /* Crypto++ initializes their counter to 1 instead of 0 */ 327 | xchacha_set_counter(&ctx, counter); 328 | xchacha_encrypt_bytes(&ctx, plaintext, buffer, msglen); 329 | 330 | /* Compare our ciphertext to the correct ciphertext */ 331 | if(memcmp(buffer, correct_ciphertext, msglen) != 0){ 332 | free(buffer); 333 | return(-1); 334 | } 335 | 336 | free(buffer); 337 | return(0); 338 | } 339 | 340 | int main(void){ 341 | if((check_ietf()) == 0 && (check_cpp()) == 0 && (check_second_ietf() == 0)){ 342 | printf("Cryptographic tests passed\n"); 343 | } else { 344 | printf("Cryptographic tests failed!\n"); 345 | } 346 | 347 | return(0); 348 | } 349 | --------------------------------------------------------------------------------