├── .gitignore ├── .vscode └── c_cpp_properties.json ├── LICENSE ├── README.md ├── content ├── api │ ├── hash.mdz │ ├── index.mdz │ ├── kdf.mdz │ ├── kx.mdz │ ├── pwhash.mdz │ ├── random.mdz │ ├── secretbox.mdz │ ├── sign.mdz │ └── util.mdz └── index.mdz ├── hydrogen.c ├── hydrogen.h ├── impl ├── common.h ├── core.h ├── gimli-core.h ├── gimli-core │ ├── portable.h │ └── sse2.h ├── hash.h ├── hydrogen_p.h ├── kdf.h ├── kx.h ├── pwhash.h ├── random.h ├── random │ ├── avr.h │ ├── ch32.h │ ├── chibios.h │ ├── esp32.h │ ├── linux_kernel.h │ ├── mbed.h │ ├── nrf52832.h │ ├── particle.h │ ├── riot.h │ ├── rtthread.h │ ├── stm32.h │ ├── unix.h │ ├── wasi.h │ └── windows.h ├── secretbox.h ├── sign.h └── x25519.h ├── jhydro.c ├── project.janet └── test ├── suite1.janet ├── suite2.janet └── suite3.janet /.gitignore: -------------------------------------------------------------------------------- 1 | build 2 | site 3 | jpm_tree 4 | -------------------------------------------------------------------------------- /.vscode/c_cpp_properties.json: -------------------------------------------------------------------------------- 1 | { 2 | "configurations": [ 3 | { 4 | "name": "Linux", 5 | "includePath": [ 6 | "${workspaceFolder}/**", 7 | "libhydrogen", 8 | "/usr/local/include/janet" 9 | ], 10 | "defines": [], 11 | "compilerPath": "/usr/bin/gcc", 12 | "cStandard": "c99", 13 | "cppStandard": "c++17", 14 | "intelliSenseMode": "gcc-x64", 15 | "compilerArgs": [ 16 | "-O2", 17 | "-fPIC" 18 | ] 19 | } 20 | ], 21 | "version": 4 22 | } -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2019 Calvin Rose 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy of 4 | this software and associated documentation files (the "Software"), to deal in 5 | the Software without restriction, including without limitation the rights to 6 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies 7 | of the Software, and to permit persons to whom the Software is furnished to do 8 | so, subject to the following conditions: 9 | 10 | The above copyright notice and this permission notice shall be included in all 11 | copies or substantial portions of the Software. 12 | 13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 | SOFTWARE. 20 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # jhydro 2 | 3 | Lightweight cryptographic and random number generation utils for Janet. Based on [libhydrogen](https://github.com/jedisct1/libhydrogen/). 4 | 5 | Bindings for most of the libhydrogen API are available so far, with the exception of the key sharing API. 6 | 7 | ```clojure 8 | (use jhydro) 9 | 10 | (print (random/u32)) 11 | 12 | (pp (random/buf 1024)) 13 | 14 | (def buf @"") 15 | (for i 0 10 16 | (random/buf buf 64)) 17 | ``` 18 | 19 | ## Documentation 20 | 21 | Documentation can be built with [Mendoza](https://github.com/bakpakin/mendoza). 22 | First, install the latest verion of mendoza, and then run `mdz && mdz serve` 23 | from the jhydro repository directory. You can then navigate to 24 | `http://localhost:8000` to see the documentation. 25 | 26 | ## Building 27 | 28 | ``` 29 | jpm build 30 | ``` 31 | 32 | To build the library. 33 | 34 | ## Testing 35 | 36 | ``` 37 | jpm test 38 | ``` 39 | 40 | ## License 41 | 42 | This module is licensed under the MIT/X11 License. 43 | -------------------------------------------------------------------------------- /content/api/hash.mdz: -------------------------------------------------------------------------------- 1 | {:title "General Purpose Hashing" 2 | :author "Calvin Rose" 3 | :license "MIT" 4 | :template "mdzdoc/main.html"} 5 | --- 6 | 7 | ## Index 8 | 9 | @api-index[build/jhydro][hash/] 10 | 11 | ## Reference 12 | 13 | @api-docs[build/jhydro][hash/] 14 | -------------------------------------------------------------------------------- /content/api/index.mdz: -------------------------------------------------------------------------------- 1 | {:title "API" 2 | :author "Calvin Rose" 3 | :license "MIT" 4 | :template "mdzdoc/main.html" 5 | :order 1} 6 | --- 7 | 8 | ## Index 9 | 10 | @api-index[build/jhydro] 11 | 12 | ## Reference 13 | 14 | @api-docs[build/jhydro] 15 | -------------------------------------------------------------------------------- /content/api/kdf.mdz: -------------------------------------------------------------------------------- 1 | {:title "Key Derivation" 2 | :author "Calvin Rose" 3 | :license "MIT" 4 | :template "mdzdoc/main.html"} 5 | --- 6 | 7 | ## Index 8 | 9 | @api-index[build/jhydro][kdf/] 10 | 11 | ## Reference 12 | 13 | @api-docs[build/jhydro][kdf/] 14 | 15 | -------------------------------------------------------------------------------- /content/api/kx.mdz: -------------------------------------------------------------------------------- 1 | {:title "Key Exchange" 2 | :author "Calvin Rose" 3 | :license "MIT" 4 | :template "mdzdoc/main.html"} 5 | --- 6 | 7 | Jhydro comes with three variants of key exchanges. The N variant, the KK variant, and 8 | the XX variant. For more information on their use in libhydrogen, see 9 | @link[https://github.com/jedisct1/libhydrogen/wiki/Key-exchange]{the wiki}. All variants 10 | exchange a pair of symmetric keys, so that client A can send encrypted messages to client B, and 11 | B can send encrypted messages to A. 12 | 13 | ### Usage Examples 14 | 15 | #### N variant 16 | 17 | @codeblock[janet]``` 18 | (use jhydro) 19 | 20 | (def {:public-key pk :secret-key sk} (kx/keygen)) 21 | (def packet @"") 22 | (def psk (random/buf kx/psk-bytes)) 23 | (def {:tx client-tx :rx client-rx} (kx/n1 packet psk pk)) 24 | (def {:tx server-tx :rx server-rx} (kx/n2 packet psk pk sk)) 25 | # (test "client tx = server rx" (util/= client-tx server-rx)) 26 | # (test "client rx = server tx" (util/= client-rx server-tx)) 27 | ``` 28 | 29 | #### KK variant 30 | 31 | @codeblock[janet]``` 32 | (use jhydro) 33 | 34 | (def {:public-key pk1 :secret-key sk1} (kx/keygen)) 35 | (def {:public-key pk2 :secret-key sk2} (kx/keygen)) 36 | (def packet1 @"") 37 | (def packet2 @"") 38 | (def a-state (kx/kk1 packet1 pk2 pk1 sk1)) 39 | (def {:tx b-tx :rx b-rx} (kx/kk2 packet2 packet1 pk1 pk2 sk2)) 40 | (def {:tx a-tx :rx a-rx} (kx/kk3 a-state packet2 pk1 sk1)) 41 | # (test "a tx = b rx" (util/= a-tx b-rx)) 42 | # (test "a rx = b tx" (util/= a-rx b-tx)) 43 | ``` 44 | 45 | #### XX variant 46 | 47 | @codeblock[janet]``` 48 | (use jhydro) 49 | 50 | (def {:public-key pk1 :secret-key sk1} (kx/keygen)) 51 | (def {:public-key pk2 :secret-key sk2} (kx/keygen)) 52 | (def packet1 @"") 53 | (def packet2 @"") 54 | (def packet3 @"") 55 | (def psk (random/buf kx/psk-bytes)) 56 | (def a-state (kx/xx1 packet1 psk)) 57 | (def b-state (kx/xx2 packet2 packet1 psk pk2 sk2)) 58 | (def {:tx b-tx :rx b-rx} (kx/xx3 a-state packet3 packet2 psk pk1 sk1)) 59 | (def {:tx a-tx :rx a-rx} (kx/xx4 b-state packet3 psk)) 60 | # (test "a tx = b rx" (util/= a-tx b-rx)) 61 | # (test "a rx = b tx" (util/= a-rx b-tx)) 62 | ``` 63 | 64 | 65 | ## Index 66 | 67 | @api-index[build/jhydro][kx/] 68 | 69 | ## Reference 70 | 71 | @api-docs[build/jhydro][kx/] -------------------------------------------------------------------------------- /content/api/pwhash.mdz: -------------------------------------------------------------------------------- 1 | {:title "Password Hashing" 2 | :author "Calvin Rose" 3 | :license "MIT" 4 | :template "mdzdoc/main.html"} 5 | --- 6 | 7 | ## Index 8 | 9 | @api-index[build/jhydro][pwhash/] 10 | 11 | ## Reference 12 | 13 | @api-docs[build/jhydro][pwhash/] 14 | 15 | -------------------------------------------------------------------------------- /content/api/random.mdz: -------------------------------------------------------------------------------- 1 | {:title "Random Number Generation" 2 | :author "Calvin Rose" 3 | :license "MIT" 4 | :template "mdzdoc/main.html"} 5 | --- 6 | 7 | ## Index 8 | 9 | @api-index[build/jhydro][random/] 10 | 11 | ## Reference 12 | 13 | @api-docs[build/jhydro][random/] 14 | 15 | -------------------------------------------------------------------------------- /content/api/secretbox.mdz: -------------------------------------------------------------------------------- 1 | {:title "Symmetric Encryption" 2 | :author "Calvin Rose" 3 | :license "MIT" 4 | :template "mdzdoc/main.html"} 5 | --- 6 | 7 | ## Index 8 | 9 | @api-index[build/jhydro][secretbox/] 10 | 11 | ## Reference 12 | 13 | @api-docs[build/jhydro][secretbox/] 14 | 15 | -------------------------------------------------------------------------------- /content/api/sign.mdz: -------------------------------------------------------------------------------- 1 | {:title "Public Key Signing" 2 | :author "Calvin Rose" 3 | :license "MIT" 4 | :template "mdzdoc/main.html"} 5 | --- 6 | 7 | ## Index 8 | 9 | @api-index[build/jhydro][sign/] 10 | 11 | ## Reference 12 | 13 | @api-docs[build/jhydro][sign/] 14 | 15 | -------------------------------------------------------------------------------- /content/api/util.mdz: -------------------------------------------------------------------------------- 1 | {:title "Utilities" 2 | :author "Calvin Rose" 3 | :license "MIT" 4 | :template "mdzdoc/main.html"} 5 | --- 6 | 7 | ## Index 8 | 9 | @api-index[build/jhydro][util/] 10 | 11 | ## Reference 12 | 13 | @api-docs[build/jhydro][util/] 14 | 15 | -------------------------------------------------------------------------------- /content/index.mdz: -------------------------------------------------------------------------------- 1 | {:title "Jhydro" 2 | :author "Calvin Rose" 3 | :license "MIT" 4 | :template "mdzdoc/main.html" 5 | :order 0} 6 | --- 7 | 8 | Jhydro is a lightweight cryptographic library for Janet. It is a binding to 9 | libhydrogen, which can be found at @link[https://github.com/jedisct1/libhydrogen]. 10 | Jhydro is a direct binding to libhydrogen that supports cryptographic random 11 | number generation, hashing, symmetric key encryption, password hashing, key 12 | derivation functions, and public key signatures. These are all built using only 13 | a few built in primitives, which means that jhydro will not let you interact 14 | with other standard cryptographic formats such as SHA-256, AES, RSA, etc. Do 15 | not use jhydro if you want to implement SSL, for example. Jhydro will help you 16 | implement your own secure protocol over an insecure network, however. 17 | 18 | ## Source code 19 | 20 | @p{@link[https://github.com/janet-lang/jhydro]} 21 | 22 | ## Install 23 | 24 | @codeblock``` 25 | [sudo] jpm install https://github.com/janet-lang/jhydro.git 26 | ``` 27 | -------------------------------------------------------------------------------- /hydrogen.c: -------------------------------------------------------------------------------- 1 | #include "hydrogen.h" 2 | 3 | #include "impl/common.h" 4 | #include "impl/hydrogen_p.h" 5 | 6 | #include "impl/random.h" 7 | 8 | #include "impl/core.h" 9 | #include "impl/gimli-core.h" 10 | 11 | #include "impl/hash.h" 12 | #include "impl/kdf.h" 13 | #include "impl/secretbox.h" 14 | 15 | #include "impl/x25519.h" 16 | 17 | #include "impl/kx.h" 18 | #include "impl/pwhash.h" 19 | #include "impl/sign.h" 20 | -------------------------------------------------------------------------------- /hydrogen.h: -------------------------------------------------------------------------------- 1 | #ifndef hydrogen_H 2 | #define hydrogen_H 3 | 4 | #if !(defined(__linux__) && defined(__KERNEL__)) 5 | #include 6 | #include 7 | #include 8 | #endif 9 | 10 | #ifdef __GNUC__ 11 | #pragma GCC diagnostic ignored "-Wdeclaration-after-statement" 12 | #endif 13 | 14 | #ifdef __cplusplus 15 | #ifdef __GNUC__ 16 | #pragma GCC diagnostic ignored "-Wlong-long" 17 | #endif 18 | extern "C" { 19 | #endif 20 | 21 | #if defined(__clang__) || defined(__GNUC__) 22 | #define _hydro_attr_(X) __attribute__(X) 23 | #else 24 | #define _hydro_attr_(X) 25 | #endif 26 | #define _hydro_attr_deprecated_ _hydro_attr_((deprecated)) 27 | #define _hydro_attr_malloc_ _hydro_attr_((malloc)) 28 | #define _hydro_attr_noinline_ _hydro_attr_((noinline)) 29 | #define _hydro_attr_noreturn_ _hydro_attr_((noreturn)) 30 | #define _hydro_attr_warn_unused_result_ _hydro_attr_((warn_unused_result)) 31 | #define _hydro_attr_weak_ _hydro_attr_((weak)) 32 | 33 | #if defined(__INTEL_COMPILER) || defined(_MSC_VER) 34 | #define _hydro_attr_aligned_(X) __declspec(align(X)) 35 | #elif defined(__clang__) || defined(__GNUC__) 36 | #define _hydro_attr_aligned_(X) _hydro_attr_((aligned(X))) 37 | #else 38 | #define _hydro_attr_aligned_(X) 39 | #endif 40 | 41 | #define HYDRO_VERSION_MAJOR 1 42 | #define HYDRO_VERSION_MINOR 0 43 | 44 | int hydro_init(void); 45 | 46 | /* ---------------- */ 47 | 48 | #define hydro_random_SEEDBYTES 32 49 | 50 | uint32_t hydro_random_u32(void); 51 | 52 | uint32_t hydro_random_uniform(const uint32_t upper_bound); 53 | 54 | void hydro_random_buf(void *out, size_t out_len); 55 | 56 | void hydro_random_buf_deterministic(void *out, size_t out_len, 57 | const uint8_t seed[hydro_random_SEEDBYTES]); 58 | 59 | void hydro_random_ratchet(void); 60 | 61 | void hydro_random_reseed(void); 62 | 63 | /* ---------------- */ 64 | 65 | #define hydro_hash_BYTES 32 66 | #define hydro_hash_BYTES_MAX 65535 67 | #define hydro_hash_BYTES_MIN 16 68 | #define hydro_hash_CONTEXTBYTES 8 69 | #define hydro_hash_KEYBYTES 32 70 | 71 | typedef struct hydro_hash_state { 72 | uint32_t state[12]; 73 | uint8_t buf_off; 74 | uint8_t align[3]; 75 | } hydro_hash_state; 76 | 77 | void hydro_hash_keygen(uint8_t key[hydro_hash_KEYBYTES]); 78 | 79 | int hydro_hash_init(hydro_hash_state *state, const char ctx[hydro_hash_CONTEXTBYTES], 80 | const uint8_t key[hydro_hash_KEYBYTES]); 81 | 82 | int hydro_hash_update(hydro_hash_state *state, const void *in_, size_t in_len); 83 | 84 | int hydro_hash_final(hydro_hash_state *state, uint8_t *out, size_t out_len); 85 | 86 | int hydro_hash_hash(uint8_t *out, size_t out_len, const void *in_, size_t in_len, 87 | const char ctx[hydro_hash_CONTEXTBYTES], 88 | const uint8_t key[hydro_hash_KEYBYTES]); 89 | 90 | /* ---------------- */ 91 | 92 | #define hydro_secretbox_CONTEXTBYTES 8 93 | #define hydro_secretbox_HEADERBYTES (20 + 16) 94 | #define hydro_secretbox_KEYBYTES 32 95 | #define hydro_secretbox_PROBEBYTES 16 96 | 97 | void hydro_secretbox_keygen(uint8_t key[hydro_secretbox_KEYBYTES]); 98 | 99 | int hydro_secretbox_encrypt(uint8_t *c, const void *m_, size_t mlen, uint64_t msg_id, 100 | const char ctx[hydro_secretbox_CONTEXTBYTES], 101 | const uint8_t key[hydro_secretbox_KEYBYTES]); 102 | 103 | int hydro_secretbox_decrypt(void *m_, const uint8_t *c, size_t clen, uint64_t msg_id, 104 | const char ctx[hydro_secretbox_CONTEXTBYTES], 105 | const uint8_t key[hydro_secretbox_KEYBYTES]) 106 | _hydro_attr_warn_unused_result_; 107 | 108 | void hydro_secretbox_probe_create(uint8_t probe[hydro_secretbox_PROBEBYTES], const uint8_t *c, 109 | size_t c_len, const char ctx[hydro_secretbox_CONTEXTBYTES], 110 | const uint8_t key[hydro_secretbox_KEYBYTES]); 111 | 112 | int hydro_secretbox_probe_verify(const uint8_t probe[hydro_secretbox_PROBEBYTES], const uint8_t *c, 113 | size_t c_len, const char ctx[hydro_secretbox_CONTEXTBYTES], 114 | const uint8_t key[hydro_secretbox_KEYBYTES]) 115 | _hydro_attr_warn_unused_result_; 116 | 117 | /* ---------------- */ 118 | 119 | #define hydro_kdf_CONTEXTBYTES 8 120 | #define hydro_kdf_KEYBYTES 32 121 | #define hydro_kdf_BYTES_MAX 65535 122 | #define hydro_kdf_BYTES_MIN 16 123 | 124 | void hydro_kdf_keygen(uint8_t key[hydro_kdf_KEYBYTES]); 125 | 126 | int hydro_kdf_derive_from_key(uint8_t *subkey, size_t subkey_len, uint64_t subkey_id, 127 | const char ctx[hydro_kdf_CONTEXTBYTES], 128 | const uint8_t key[hydro_kdf_KEYBYTES]); 129 | 130 | /* ---------------- */ 131 | 132 | #define hydro_sign_BYTES 64 133 | #define hydro_sign_CONTEXTBYTES 8 134 | #define hydro_sign_PUBLICKEYBYTES 32 135 | #define hydro_sign_SECRETKEYBYTES 64 136 | #define hydro_sign_SEEDBYTES 32 137 | 138 | typedef struct hydro_sign_state { 139 | hydro_hash_state hash_st; 140 | } hydro_sign_state; 141 | 142 | typedef struct hydro_sign_keypair { 143 | uint8_t pk[hydro_sign_PUBLICKEYBYTES]; 144 | uint8_t sk[hydro_sign_SECRETKEYBYTES]; 145 | } hydro_sign_keypair; 146 | 147 | void hydro_sign_keygen(hydro_sign_keypair *kp); 148 | 149 | void hydro_sign_keygen_deterministic(hydro_sign_keypair *kp, 150 | const uint8_t seed[hydro_sign_SEEDBYTES]); 151 | 152 | int hydro_sign_init(hydro_sign_state *state, const char ctx[hydro_sign_CONTEXTBYTES]); 153 | 154 | int hydro_sign_update(hydro_sign_state *state, const void *m_, size_t mlen); 155 | 156 | int hydro_sign_final_create(hydro_sign_state *state, uint8_t csig[hydro_sign_BYTES], 157 | const uint8_t sk[hydro_sign_SECRETKEYBYTES]); 158 | 159 | int hydro_sign_final_verify(hydro_sign_state *state, const uint8_t csig[hydro_sign_BYTES], 160 | const uint8_t pk[hydro_sign_PUBLICKEYBYTES]) 161 | _hydro_attr_warn_unused_result_; 162 | 163 | int hydro_sign_create(uint8_t csig[hydro_sign_BYTES], const void *m_, size_t mlen, 164 | const char ctx[hydro_sign_CONTEXTBYTES], 165 | const uint8_t sk[hydro_sign_SECRETKEYBYTES]); 166 | 167 | int hydro_sign_verify(const uint8_t csig[hydro_sign_BYTES], const void *m_, size_t mlen, 168 | const char ctx[hydro_sign_CONTEXTBYTES], 169 | const uint8_t pk[hydro_sign_PUBLICKEYBYTES]) _hydro_attr_warn_unused_result_; 170 | 171 | /* ---------------- */ 172 | 173 | #define hydro_kx_SESSIONKEYBYTES 32 174 | #define hydro_kx_PUBLICKEYBYTES 32 175 | #define hydro_kx_SECRETKEYBYTES 32 176 | #define hydro_kx_PSKBYTES 32 177 | #define hydro_kx_SEEDBYTES 32 178 | 179 | typedef struct hydro_kx_keypair { 180 | uint8_t pk[hydro_kx_PUBLICKEYBYTES]; 181 | uint8_t sk[hydro_kx_SECRETKEYBYTES]; 182 | } hydro_kx_keypair; 183 | 184 | typedef struct hydro_kx_session_keypair { 185 | uint8_t rx[hydro_kx_SESSIONKEYBYTES]; 186 | uint8_t tx[hydro_kx_SESSIONKEYBYTES]; 187 | } hydro_kx_session_keypair; 188 | 189 | typedef struct hydro_kx_state { 190 | hydro_kx_keypair eph_kp; 191 | hydro_hash_state h_st; 192 | } hydro_kx_state; 193 | 194 | void hydro_kx_keygen(hydro_kx_keypair *static_kp); 195 | 196 | void hydro_kx_keygen_deterministic(hydro_kx_keypair *static_kp, 197 | const uint8_t seed[hydro_kx_SEEDBYTES]); 198 | 199 | /* NOISE_N */ 200 | 201 | #define hydro_kx_N_PACKET1BYTES (32 + 16) 202 | 203 | int hydro_kx_n_1(hydro_kx_session_keypair *kp, uint8_t packet1[hydro_kx_N_PACKET1BYTES], 204 | const uint8_t psk[hydro_kx_PSKBYTES], 205 | const uint8_t peer_static_pk[hydro_kx_PUBLICKEYBYTES]); 206 | 207 | int hydro_kx_n_2(hydro_kx_session_keypair *kp, const uint8_t packet1[hydro_kx_N_PACKET1BYTES], 208 | const uint8_t psk[hydro_kx_PSKBYTES], const hydro_kx_keypair *static_kp); 209 | 210 | /* NOISE_KK */ 211 | 212 | #define hydro_kx_KK_PACKET1BYTES (32 + 16) 213 | #define hydro_kx_KK_PACKET2BYTES (32 + 16) 214 | 215 | int hydro_kx_kk_1(hydro_kx_state *state, uint8_t packet1[hydro_kx_KK_PACKET1BYTES], 216 | const uint8_t peer_static_pk[hydro_kx_PUBLICKEYBYTES], 217 | const hydro_kx_keypair *static_kp); 218 | 219 | int hydro_kx_kk_2(hydro_kx_session_keypair *kp, uint8_t packet2[hydro_kx_KK_PACKET2BYTES], 220 | const uint8_t packet1[hydro_kx_KK_PACKET1BYTES], 221 | const uint8_t peer_static_pk[hydro_kx_PUBLICKEYBYTES], 222 | const hydro_kx_keypair *static_kp); 223 | 224 | int hydro_kx_kk_3(hydro_kx_state *state, hydro_kx_session_keypair *kp, 225 | const uint8_t packet2[hydro_kx_KK_PACKET2BYTES], 226 | const hydro_kx_keypair *static_kp); 227 | 228 | /* NOISE_XX */ 229 | 230 | #define hydro_kx_XX_PACKET1BYTES (32 + 16) 231 | #define hydro_kx_XX_PACKET2BYTES (32 + 32 + 16 + 16) 232 | #define hydro_kx_XX_PACKET3BYTES (32 + 16 + 16) 233 | 234 | int hydro_kx_xx_1(hydro_kx_state *state, uint8_t packet1[hydro_kx_XX_PACKET1BYTES], 235 | const uint8_t psk[hydro_kx_PSKBYTES]); 236 | 237 | int hydro_kx_xx_2(hydro_kx_state *state, uint8_t packet2[hydro_kx_XX_PACKET2BYTES], 238 | const uint8_t packet1[hydro_kx_XX_PACKET1BYTES], 239 | const uint8_t psk[hydro_kx_PSKBYTES], const hydro_kx_keypair *static_kp); 240 | 241 | int hydro_kx_xx_3(hydro_kx_state *state, hydro_kx_session_keypair *kp, 242 | uint8_t packet3[hydro_kx_XX_PACKET3BYTES], 243 | uint8_t peer_static_pk[hydro_kx_PUBLICKEYBYTES], 244 | const uint8_t packet2[hydro_kx_XX_PACKET2BYTES], 245 | const uint8_t psk[hydro_kx_PSKBYTES], const hydro_kx_keypair *static_kp); 246 | 247 | int hydro_kx_xx_4(hydro_kx_state *state, hydro_kx_session_keypair *kp, 248 | uint8_t peer_static_pk[hydro_kx_PUBLICKEYBYTES], 249 | const uint8_t packet3[hydro_kx_XX_PACKET3BYTES], 250 | const uint8_t psk[hydro_kx_PSKBYTES]); 251 | 252 | /* NOISE_NK */ 253 | 254 | #define hydro_kx_NK_PACKET1BYTES (32 + 16) 255 | #define hydro_kx_NK_PACKET2BYTES (32 + 16) 256 | 257 | int hydro_kx_nk_1(hydro_kx_state *state, uint8_t packet1[hydro_kx_NK_PACKET1BYTES], 258 | const uint8_t psk[hydro_kx_PSKBYTES], 259 | const uint8_t peer_static_pk[hydro_kx_PUBLICKEYBYTES]); 260 | 261 | int hydro_kx_nk_2(hydro_kx_session_keypair *kp, uint8_t packet2[hydro_kx_NK_PACKET2BYTES], 262 | const uint8_t packet1[hydro_kx_NK_PACKET1BYTES], 263 | const uint8_t psk[hydro_kx_PSKBYTES], const hydro_kx_keypair *static_kp); 264 | 265 | int hydro_kx_nk_3(hydro_kx_state *state, hydro_kx_session_keypair *kp, 266 | const uint8_t packet2[hydro_kx_NK_PACKET2BYTES]); 267 | 268 | /* ---------------- */ 269 | 270 | #define hydro_pwhash_CONTEXTBYTES 8 271 | #define hydro_pwhash_MASTERKEYBYTES 32 272 | #define hydro_pwhash_STOREDBYTES 128 273 | 274 | void hydro_pwhash_keygen(uint8_t master_key[hydro_pwhash_MASTERKEYBYTES]); 275 | 276 | int hydro_pwhash_deterministic(uint8_t *h, size_t h_len, const char *passwd, size_t passwd_len, 277 | const char ctx[hydro_pwhash_CONTEXTBYTES], 278 | const uint8_t master_key[hydro_pwhash_MASTERKEYBYTES], 279 | uint64_t opslimit, size_t memlimit, uint8_t threads); 280 | 281 | int hydro_pwhash_create(uint8_t stored[hydro_pwhash_STOREDBYTES], const char *passwd, 282 | size_t passwd_len, const uint8_t master_key[hydro_pwhash_MASTERKEYBYTES], 283 | uint64_t opslimit, size_t memlimit, uint8_t threads); 284 | 285 | int hydro_pwhash_verify(const uint8_t stored[hydro_pwhash_STOREDBYTES], const char *passwd, 286 | size_t passwd_len, const uint8_t master_key[hydro_pwhash_MASTERKEYBYTES], 287 | uint64_t opslimit_max, size_t memlimit_max, uint8_t threads_max); 288 | 289 | int hydro_pwhash_derive_static_key(uint8_t *static_key, size_t static_key_len, 290 | const uint8_t stored[hydro_pwhash_STOREDBYTES], 291 | const char *passwd, size_t passwd_len, 292 | const char ctx[hydro_pwhash_CONTEXTBYTES], 293 | const uint8_t master_key[hydro_pwhash_MASTERKEYBYTES], 294 | uint64_t opslimit_max, size_t memlimit_max, uint8_t threads_max); 295 | 296 | int hydro_pwhash_reencrypt(uint8_t stored[hydro_pwhash_STOREDBYTES], 297 | const uint8_t master_key[hydro_pwhash_MASTERKEYBYTES], 298 | const uint8_t new_master_key[hydro_pwhash_MASTERKEYBYTES]); 299 | 300 | int hydro_pwhash_upgrade(uint8_t stored[hydro_pwhash_STOREDBYTES], 301 | const uint8_t master_key[hydro_pwhash_MASTERKEYBYTES], uint64_t opslimit, 302 | size_t memlimit, uint8_t threads); 303 | 304 | /* ---------------- */ 305 | 306 | void hydro_memzero(void *pnt, size_t len); 307 | 308 | void hydro_increment(uint8_t *n, size_t len); 309 | 310 | bool hydro_equal(const void *b1_, const void *b2_, size_t len); 311 | 312 | int hydro_compare(const uint8_t *b1_, const uint8_t *b2_, size_t len); 313 | 314 | char *hydro_bin2hex(char *hex, size_t hex_maxlen, const uint8_t *bin, size_t bin_len); 315 | 316 | int hydro_hex2bin(uint8_t *bin, size_t bin_maxlen, const char *hex, size_t hex_len, 317 | const char *ignore, const char **hex_end_p); 318 | 319 | int hydro_pad(unsigned char *buf, size_t unpadded_buflen, size_t blocksize, size_t max_buflen); 320 | 321 | int hydro_unpad(const unsigned char *buf, size_t padded_buflen, size_t blocksize); 322 | 323 | /* ---------------- */ 324 | 325 | #define HYDRO_HWTYPE_ATMEGA328 1 326 | 327 | #ifndef HYDRO_HWTYPE 328 | #ifdef __AVR__ 329 | #define HYDRO_HWTYPE HYDRO_HWTYPE_ATMEGA328 330 | #endif 331 | #endif 332 | 333 | #ifdef __cplusplus 334 | } 335 | #endif 336 | 337 | #endif 338 | -------------------------------------------------------------------------------- /impl/common.h: -------------------------------------------------------------------------------- 1 | #if defined(__linux__) && defined(__KERNEL__) 2 | #define TLS /* Danger: at most one call into hydro_*() at a time */ 3 | #define CHAR_BIT 8 4 | #define abort BUG 5 | #define uint_fast16_t uint16_t 6 | #define errno hydro_errno 7 | static int errno; 8 | #else 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #endif 16 | 17 | #if !defined(__unix__) && (defined(__APPLE__) || defined(__linux__)) 18 | #define __unix__ 1 19 | #endif 20 | #ifndef __GNUC__ 21 | #define __restrict__ 22 | #endif 23 | 24 | #if defined(__BYTE_ORDER__) && defined(__ORDER_BIG_ENDIAN__) && \ 25 | __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ 26 | #define NATIVE_BIG_ENDIAN 27 | #endif 28 | #ifndef NATIVE_BIG_ENDIAN 29 | #ifndef NATIVE_LITTLE_ENDIAN 30 | #define NATIVE_LITTLE_ENDIAN 31 | #endif 32 | #endif 33 | 34 | #ifndef TLS 35 | #if defined(_WIN32) && !defined(__GNUC__) 36 | #define TLS __declspec(thread) 37 | #elif (defined(__clang__) || defined(__GNUC__)) && defined(__unix__) && !defined(__TINYC__) 38 | #define TLS __thread 39 | #else 40 | #define TLS 41 | #endif 42 | #endif 43 | 44 | #ifndef SIZE_MAX 45 | #define SIZE_MAX ((size_t) -1) 46 | #endif 47 | 48 | #ifdef __OpenBSD__ 49 | #define HAVE_EXPLICIT_BZERO 1 50 | #elif defined(__GLIBC__) && defined(__GLIBC_PREREQ) && defined(_GNU_SOURCE) 51 | #if __GLIBC_PREREQ(2, 25) 52 | #define HAVE_EXPLICIT_BZERO 1 53 | #endif 54 | #endif 55 | 56 | #define COMPILER_ASSERT(X) (void) sizeof(char[(X) ? 1 : -1]) 57 | 58 | #define ROTL32(x, b) (uint32_t)(((x) << (b)) | ((x) >> (32 - (b)))) 59 | #define ROTL64(x, b) (uint64_t)(((x) << (b)) | ((x) >> (64 - (b)))) 60 | #define ROTR32(x, b) (uint32_t)(((x) >> (b)) | ((x) << (32 - (b)))) 61 | #define ROTR64(x, b) (uint64_t)(((x) >> (b)) | ((x) << (64 - (b)))) 62 | 63 | #define LOAD64_LE(SRC) load64_le(SRC) 64 | static inline uint64_t 65 | load64_le(const uint8_t src[8]) 66 | { 67 | #ifdef NATIVE_LITTLE_ENDIAN 68 | uint64_t w; 69 | memcpy(&w, src, sizeof w); 70 | return w; 71 | #else 72 | uint64_t w = (uint64_t) src[0]; 73 | w |= (uint64_t) src[1] << 8; 74 | w |= (uint64_t) src[2] << 16; 75 | w |= (uint64_t) src[3] << 24; 76 | w |= (uint64_t) src[4] << 32; 77 | w |= (uint64_t) src[5] << 40; 78 | w |= (uint64_t) src[6] << 48; 79 | w |= (uint64_t) src[7] << 56; 80 | return w; 81 | #endif 82 | } 83 | 84 | #define STORE64_LE(DST, W) store64_le((DST), (W)) 85 | static inline void 86 | store64_le(uint8_t dst[8], uint64_t w) 87 | { 88 | #ifdef NATIVE_LITTLE_ENDIAN 89 | memcpy(dst, &w, sizeof w); 90 | #else 91 | dst[0] = (uint8_t) w; 92 | w >>= 8; 93 | dst[1] = (uint8_t) w; 94 | w >>= 8; 95 | dst[2] = (uint8_t) w; 96 | w >>= 8; 97 | dst[3] = (uint8_t) w; 98 | w >>= 8; 99 | dst[4] = (uint8_t) w; 100 | w >>= 8; 101 | dst[5] = (uint8_t) w; 102 | w >>= 8; 103 | dst[6] = (uint8_t) w; 104 | w >>= 8; 105 | dst[7] = (uint8_t) w; 106 | #endif 107 | } 108 | 109 | #define LOAD32_LE(SRC) load32_le(SRC) 110 | static inline uint32_t 111 | load32_le(const uint8_t src[4]) 112 | { 113 | #ifdef NATIVE_LITTLE_ENDIAN 114 | uint32_t w; 115 | memcpy(&w, src, sizeof w); 116 | return w; 117 | #else 118 | uint32_t w = (uint32_t) src[0]; 119 | w |= (uint32_t) src[1] << 8; 120 | w |= (uint32_t) src[2] << 16; 121 | w |= (uint32_t) src[3] << 24; 122 | return w; 123 | #endif 124 | } 125 | 126 | #define STORE32_LE(DST, W) store32_le((DST), (W)) 127 | static inline void 128 | store32_le(uint8_t dst[4], uint32_t w) 129 | { 130 | #ifdef NATIVE_LITTLE_ENDIAN 131 | memcpy(dst, &w, sizeof w); 132 | #else 133 | dst[0] = (uint8_t) w; 134 | w >>= 8; 135 | dst[1] = (uint8_t) w; 136 | w >>= 8; 137 | dst[2] = (uint8_t) w; 138 | w >>= 8; 139 | dst[3] = (uint8_t) w; 140 | #endif 141 | } 142 | 143 | #define LOAD16_LE(SRC) load16_le(SRC) 144 | static inline uint16_t 145 | load16_le(const uint8_t src[2]) 146 | { 147 | #ifdef NATIVE_LITTLE_ENDIAN 148 | uint16_t w; 149 | memcpy(&w, src, sizeof w); 150 | return w; 151 | #else 152 | uint16_t w = (uint16_t) src[0]; 153 | w |= (uint16_t) src[1] << 8; 154 | return w; 155 | #endif 156 | } 157 | 158 | #define STORE16_LE(DST, W) store16_le((DST), (W)) 159 | static inline void 160 | store16_le(uint8_t dst[2], uint16_t w) 161 | { 162 | #ifdef NATIVE_LITTLE_ENDIAN 163 | memcpy(dst, &w, sizeof w); 164 | #else 165 | dst[0] = (uint8_t) w; 166 | w >>= 8; 167 | dst[1] = (uint8_t) w; 168 | #endif 169 | } 170 | 171 | /* ----- */ 172 | 173 | #define LOAD64_BE(SRC) load64_be(SRC) 174 | static inline uint64_t 175 | load64_be(const uint8_t src[8]) 176 | { 177 | #ifdef NATIVE_BIG_ENDIAN 178 | uint64_t w; 179 | memcpy(&w, src, sizeof w); 180 | return w; 181 | #else 182 | uint64_t w = (uint64_t) src[7]; 183 | w |= (uint64_t) src[6] << 8; 184 | w |= (uint64_t) src[5] << 16; 185 | w |= (uint64_t) src[4] << 24; 186 | w |= (uint64_t) src[3] << 32; 187 | w |= (uint64_t) src[2] << 40; 188 | w |= (uint64_t) src[1] << 48; 189 | w |= (uint64_t) src[0] << 56; 190 | return w; 191 | #endif 192 | } 193 | 194 | #define STORE64_BE(DST, W) store64_be((DST), (W)) 195 | static inline void 196 | store64_be(uint8_t dst[8], uint64_t w) 197 | { 198 | #ifdef NATIVE_BIG_ENDIAN 199 | memcpy(dst, &w, sizeof w); 200 | #else 201 | dst[7] = (uint8_t) w; 202 | w >>= 8; 203 | dst[6] = (uint8_t) w; 204 | w >>= 8; 205 | dst[5] = (uint8_t) w; 206 | w >>= 8; 207 | dst[4] = (uint8_t) w; 208 | w >>= 8; 209 | dst[3] = (uint8_t) w; 210 | w >>= 8; 211 | dst[2] = (uint8_t) w; 212 | w >>= 8; 213 | dst[1] = (uint8_t) w; 214 | w >>= 8; 215 | dst[0] = (uint8_t) w; 216 | #endif 217 | } 218 | 219 | #define LOAD32_BE(SRC) load32_be(SRC) 220 | static inline uint32_t 221 | load32_be(const uint8_t src[4]) 222 | { 223 | #ifdef NATIVE_BIG_ENDIAN 224 | uint32_t w; 225 | memcpy(&w, src, sizeof w); 226 | return w; 227 | #else 228 | uint32_t w = (uint32_t) src[3]; 229 | w |= (uint32_t) src[2] << 8; 230 | w |= (uint32_t) src[1] << 16; 231 | w |= (uint32_t) src[0] << 24; 232 | return w; 233 | #endif 234 | } 235 | 236 | #define STORE32_BE(DST, W) store32_be((DST), (W)) 237 | static inline void 238 | store32_be(uint8_t dst[4], uint32_t w) 239 | { 240 | #ifdef NATIVE_BIG_ENDIAN 241 | memcpy(dst, &w, sizeof w); 242 | #else 243 | dst[3] = (uint8_t) w; 244 | w >>= 8; 245 | dst[2] = (uint8_t) w; 246 | w >>= 8; 247 | dst[1] = (uint8_t) w; 248 | w >>= 8; 249 | dst[0] = (uint8_t) w; 250 | #endif 251 | } 252 | 253 | #define LOAD16_BE(SRC) load16_be(SRC) 254 | static inline uint16_t 255 | load16_be(const uint8_t src[2]) 256 | { 257 | #ifdef NATIVE_BIG_ENDIAN 258 | uint16_t w; 259 | memcpy(&w, src, sizeof w); 260 | return w; 261 | #else 262 | uint16_t w = (uint16_t) src[1]; 263 | w |= (uint16_t) src[0] << 8; 264 | return w; 265 | #endif 266 | } 267 | 268 | #define STORE16_BE(DST, W) store16_be((DST), (W)) 269 | static inline void 270 | store16_be(uint8_t dst[2], uint16_t w) 271 | { 272 | #ifdef NATIVE_BIG_ENDIAN 273 | memcpy(dst, &w, sizeof w); 274 | #else 275 | dst[1] = (uint8_t) w; 276 | w >>= 8; 277 | dst[0] = (uint8_t) w; 278 | #endif 279 | } 280 | 281 | static inline void 282 | mem_cpy(void *__restrict__ dst_, const void *__restrict__ src_, size_t n) 283 | { 284 | unsigned char * dst = (unsigned char *) dst_; 285 | const unsigned char *src = (const unsigned char *) src_; 286 | size_t i; 287 | 288 | for (i = 0; i < n; i++) { 289 | dst[i] = src[i]; 290 | } 291 | } 292 | 293 | static inline void 294 | mem_zero(void *dst_, size_t n) 295 | { 296 | unsigned char *dst = (unsigned char *) dst_; 297 | size_t i; 298 | 299 | for (i = 0; i < n; i++) { 300 | dst[i] = 0; 301 | } 302 | } 303 | 304 | static inline void 305 | mem_xor(void *__restrict__ dst_, const void *__restrict__ src_, size_t n) 306 | { 307 | unsigned char * dst = (unsigned char *) dst_; 308 | const unsigned char *src = (const unsigned char *) src_; 309 | size_t i; 310 | 311 | for (i = 0; i < n; i++) { 312 | dst[i] ^= src[i]; 313 | } 314 | } 315 | 316 | static inline void 317 | mem_xor2(void *__restrict__ dst_, const void *__restrict__ src1_, const void *__restrict__ src2_, 318 | size_t n) 319 | { 320 | unsigned char * dst = (unsigned char *) dst_; 321 | const unsigned char *src1 = (const unsigned char *) src1_; 322 | const unsigned char *src2 = (const unsigned char *) src2_; 323 | size_t i; 324 | 325 | for (i = 0; i < n; i++) { 326 | dst[i] = src1[i] ^ src2[i]; 327 | } 328 | } 329 | 330 | static const uint8_t zero[64] = { 0 }; 331 | -------------------------------------------------------------------------------- /impl/core.h: -------------------------------------------------------------------------------- 1 | int 2 | hydro_init(void) 3 | { 4 | hydro_random_ensure_initialized(); 5 | return 0; 6 | } 7 | 8 | void 9 | hydro_memzero(void *pnt, size_t len) 10 | { 11 | #ifdef HAVE_EXPLICIT_BZERO 12 | explicit_bzero(pnt, len); 13 | #else 14 | volatile unsigned char *volatile pnt_ = (volatile unsigned char *volatile) pnt; 15 | size_t i = (size_t) 0U; 16 | 17 | while (i < len) { 18 | pnt_[i++] = 0U; 19 | } 20 | #endif 21 | } 22 | 23 | void 24 | hydro_increment(uint8_t *n, size_t len) 25 | { 26 | size_t i; 27 | uint_fast16_t c = 1U; 28 | 29 | for (i = 0; i < len; i++) { 30 | c += (uint_fast16_t) n[i]; 31 | n[i] = (uint8_t) c; 32 | c >>= 8; 33 | } 34 | } 35 | 36 | char * 37 | hydro_bin2hex(char *hex, size_t hex_maxlen, const uint8_t *bin, size_t bin_len) 38 | { 39 | size_t i = (size_t) 0U; 40 | unsigned int x; 41 | int b; 42 | int c; 43 | 44 | if (bin_len >= SIZE_MAX / 2 || hex_maxlen <= bin_len * 2U) { 45 | abort(); 46 | } 47 | while (i < bin_len) { 48 | c = bin[i] & 0xf; 49 | b = bin[i] >> 4; 50 | x = (unsigned char) (87U + c + (((c - 10U) >> 8) & ~38U)) << 8 | 51 | (unsigned char) (87U + b + (((b - 10U) >> 8) & ~38U)); 52 | hex[i * 2U] = (char) x; 53 | x >>= 8; 54 | hex[i * 2U + 1U] = (char) x; 55 | i++; 56 | } 57 | hex[i * 2U] = 0U; 58 | 59 | return hex; 60 | } 61 | 62 | int 63 | hydro_hex2bin(uint8_t *bin, size_t bin_maxlen, const char *hex, size_t hex_len, const char *ignore, 64 | const char **hex_end_p) 65 | { 66 | size_t bin_pos = (size_t) 0U; 67 | size_t hex_pos = (size_t) 0U; 68 | int ret = 0; 69 | unsigned char c; 70 | unsigned char c_alpha0, c_alpha; 71 | unsigned char c_num0, c_num; 72 | uint8_t c_acc = 0U; 73 | uint8_t c_val; 74 | unsigned char state = 0U; 75 | 76 | while (hex_pos < hex_len) { 77 | c = (unsigned char) hex[hex_pos]; 78 | c_num = c ^ 48U; 79 | c_num0 = (c_num - 10U) >> 8; 80 | c_alpha = (c & ~32U) - 55U; 81 | c_alpha0 = ((c_alpha - 10U) ^ (c_alpha - 16U)) >> 8; 82 | if ((c_num0 | c_alpha0) == 0U) { 83 | if (ignore != NULL && state == 0U && strchr(ignore, c) != NULL) { 84 | hex_pos++; 85 | continue; 86 | } 87 | break; 88 | } 89 | c_val = (uint8_t) ((c_num0 & c_num) | (c_alpha0 & c_alpha)); 90 | if (bin_pos >= bin_maxlen) { 91 | ret = -1; 92 | errno = ERANGE; 93 | break; 94 | } 95 | if (state == 0U) { 96 | c_acc = c_val * 16U; 97 | } else { 98 | bin[bin_pos++] = c_acc | c_val; 99 | } 100 | state = ~state; 101 | hex_pos++; 102 | } 103 | if (state != 0U) { 104 | hex_pos--; 105 | errno = EINVAL; 106 | ret = -1; 107 | } 108 | if (ret != 0) { 109 | bin_pos = (size_t) 0U; 110 | } 111 | if (hex_end_p != NULL) { 112 | *hex_end_p = &hex[hex_pos]; 113 | } else if (hex_pos != hex_len) { 114 | errno = EINVAL; 115 | ret = -1; 116 | } 117 | if (ret != 0) { 118 | return ret; 119 | } 120 | return (int) bin_pos; 121 | } 122 | 123 | bool 124 | hydro_equal(const void *b1_, const void *b2_, size_t len) 125 | { 126 | const volatile uint8_t *volatile b1 = (const volatile uint8_t *volatile) b1_; 127 | const uint8_t *b2 = (const uint8_t *) b2_; 128 | size_t i; 129 | uint8_t d = (uint8_t) 0U; 130 | 131 | if (b1 == b2) { 132 | d = ~d; 133 | } 134 | for (i = 0U; i < len; i++) { 135 | d |= b1[i] ^ b2[i]; 136 | } 137 | return (bool) (1 & ((d - 1) >> 8)); 138 | } 139 | 140 | int 141 | hydro_compare(const uint8_t *b1_, const uint8_t *b2_, size_t len) 142 | { 143 | const volatile uint8_t *volatile b1 = (const volatile uint8_t *volatile) b1_; 144 | const uint8_t *b2 = (const uint8_t *) b2_; 145 | uint8_t gt = 0U; 146 | uint8_t eq = 1U; 147 | size_t i; 148 | 149 | i = len; 150 | while (i != 0U) { 151 | i--; 152 | gt |= ((b2[i] - b1[i]) >> 8) & eq; 153 | eq &= ((b2[i] ^ b1[i]) - 1) >> 8; 154 | } 155 | return (int) (gt + gt + eq) - 1; 156 | } 157 | 158 | int 159 | hydro_pad(unsigned char *buf, size_t unpadded_buflen, size_t blocksize, size_t max_buflen) 160 | { 161 | unsigned char *tail; 162 | size_t i; 163 | size_t xpadlen; 164 | size_t xpadded_len; 165 | volatile unsigned char mask; 166 | unsigned char barrier_mask; 167 | 168 | if (blocksize <= 0U || max_buflen > INT_MAX) { 169 | return -1; 170 | } 171 | xpadlen = blocksize - 1U; 172 | if ((blocksize & (blocksize - 1U)) == 0U) { 173 | xpadlen -= unpadded_buflen & (blocksize - 1U); 174 | } else { 175 | xpadlen -= unpadded_buflen % blocksize; 176 | } 177 | if ((size_t) SIZE_MAX - unpadded_buflen <= xpadlen) { 178 | return -1; 179 | } 180 | xpadded_len = unpadded_buflen + xpadlen; 181 | if (xpadded_len >= max_buflen) { 182 | return -1; 183 | } 184 | tail = &buf[xpadded_len]; 185 | mask = 0U; 186 | for (i = 0; i < blocksize; i++) { 187 | barrier_mask = (unsigned char) (((i ^ xpadlen) - 1U) >> ((sizeof(size_t) - 1U) * CHAR_BIT)); 188 | *(tail - i) = ((*(tail - i)) & mask) | (0x80 & barrier_mask); 189 | mask |= barrier_mask; 190 | } 191 | return (int) (xpadded_len + 1); 192 | } 193 | 194 | int 195 | hydro_unpad(const unsigned char *buf, size_t padded_buflen, size_t blocksize) 196 | { 197 | const unsigned char *tail; 198 | unsigned char acc = 0U; 199 | unsigned char c; 200 | unsigned char valid = 0U; 201 | volatile size_t pad_len = 0U; 202 | size_t i; 203 | size_t is_barrier; 204 | 205 | if (padded_buflen < blocksize || blocksize <= 0U) { 206 | return -1; 207 | } 208 | tail = &buf[padded_buflen - 1U]; 209 | 210 | for (i = 0U; i < blocksize; i++) { 211 | c = *(tail - i); 212 | is_barrier = (((acc - 1U) & (pad_len - 1U) & ((c ^ 0x80) - 1U)) >> 8) & 1U; 213 | acc |= c; 214 | pad_len |= i & (1U + ~is_barrier); 215 | valid |= (unsigned char) is_barrier; 216 | } 217 | if (valid == 0) { 218 | return -1; 219 | } 220 | return (int) (padded_buflen - 1 - pad_len); 221 | } 222 | -------------------------------------------------------------------------------- /impl/gimli-core.h: -------------------------------------------------------------------------------- 1 | #ifdef __SSE2__ 2 | #include "gimli-core/sse2.h" 3 | #else 4 | #include "gimli-core/portable.h" 5 | #endif 6 | 7 | static void 8 | gimli_core_u8(uint8_t state_u8[gimli_BLOCKBYTES], uint8_t tag) 9 | { 10 | state_u8[gimli_BLOCKBYTES - 1] ^= tag; 11 | #ifndef NATIVE_LITTLE_ENDIAN 12 | uint32_t state_u32[12]; 13 | int i; 14 | 15 | for (i = 0; i < 12; i++) { 16 | state_u32[i] = LOAD32_LE(&state_u8[i * 4]); 17 | } 18 | gimli_core(state_u32); 19 | for (i = 0; i < 12; i++) { 20 | STORE32_LE(&state_u8[i * 4], state_u32[i]); 21 | } 22 | #else 23 | gimli_core((uint32_t *) (void *) state_u8); /* state_u8 must be properly aligned */ 24 | #endif 25 | } 26 | -------------------------------------------------------------------------------- /impl/gimli-core/portable.h: -------------------------------------------------------------------------------- 1 | static void 2 | gimli_core(uint32_t state[gimli_BLOCKBYTES / 4]) 3 | { 4 | unsigned int round; 5 | unsigned int column; 6 | uint32_t x; 7 | uint32_t y; 8 | uint32_t z; 9 | 10 | for (round = 24; round > 0; round--) { 11 | for (column = 0; column < 4; column++) { 12 | x = ROTL32(state[column], 24); 13 | y = ROTL32(state[4 + column], 9); 14 | z = state[8 + column]; 15 | 16 | state[8 + column] = x ^ (z << 1) ^ ((y & z) << 2); 17 | state[4 + column] = y ^ x ^ ((x | z) << 1); 18 | state[column] = z ^ y ^ ((x & y) << 3); 19 | } 20 | switch (round & 3) { 21 | case 0: 22 | x = state[0]; 23 | state[0] = state[1]; 24 | state[1] = x; 25 | x = state[2]; 26 | state[2] = state[3]; 27 | state[3] = x; 28 | state[0] ^= ((uint32_t) 0x9e377900 | round); 29 | break; 30 | case 2: 31 | x = state[0]; 32 | state[0] = state[2]; 33 | state[2] = x; 34 | x = state[1]; 35 | state[1] = state[3]; 36 | state[3] = x; 37 | } 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /impl/gimli-core/sse2.h: -------------------------------------------------------------------------------- 1 | #include 2 | #ifdef __SSSE3__ 3 | # include 4 | #endif 5 | 6 | #define S 9 7 | 8 | static inline __m128i 9 | shift(__m128i x, int bits) 10 | { 11 | return _mm_slli_epi32(x, bits); 12 | } 13 | 14 | static inline __m128i 15 | rotate(__m128i x, int bits) 16 | { 17 | return _mm_slli_epi32(x, bits) | _mm_srli_epi32(x, 32 - bits); 18 | } 19 | 20 | #ifdef __SSSE3__ 21 | static inline __m128i 22 | rotate24(__m128i x) 23 | { 24 | return _mm_shuffle_epi8(x, _mm_set_epi8(12, 15, 14, 13, 8, 11, 10, 9, 4, 7, 6, 5, 0, 3, 2, 1)); 25 | } 26 | #else 27 | static inline __m128i 28 | rotate24(__m128i x) 29 | { 30 | uint8_t _hydro_attr_aligned_(16) x8[16], y8[16]; 31 | 32 | _mm_storeu_si128((__m128i *) (void *) x8, x); 33 | 34 | y8[ 0] = x8[ 1]; y8[ 1] = x8[ 2]; y8[ 2] = x8[ 3]; y8[ 3] = x8[ 0]; 35 | y8[ 4] = x8[ 5]; y8[ 5] = x8[ 6]; y8[ 6] = x8[ 7]; y8[ 7] = x8[ 4]; 36 | y8[ 8] = x8[ 9]; y8[ 9] = x8[10]; y8[10] = x8[11]; y8[11] = x8[ 8]; 37 | y8[12] = x8[13]; y8[13] = x8[14]; y8[14] = x8[15]; y8[15] = x8[12]; 38 | 39 | return _mm_loadu_si128((const __m128i *) (const void *) y8); 40 | } 41 | #endif 42 | 43 | static const uint32_t _hydro_attr_aligned_(16) coeffs[24] = { 44 | 0x9e377904, 0, 0, 0, 0x9e377908, 0, 0, 0, 0x9e37790c, 0, 0, 0, 45 | 0x9e377910, 0, 0, 0, 0x9e377914, 0, 0, 0, 0x9e377918, 0, 0, 0, 46 | }; 47 | 48 | static void 49 | gimli_core(uint32_t state[gimli_BLOCKBYTES / 4]) 50 | { 51 | __m128i x = _mm_loadu_si128((const __m128i *) (const void *) &state[0]); 52 | __m128i y = _mm_loadu_si128((const __m128i *) (const void *) &state[4]); 53 | __m128i z = _mm_loadu_si128((const __m128i *) (const void *) &state[8]); 54 | __m128i newy; 55 | __m128i newz; 56 | int round; 57 | 58 | for (round = 5; round >= 0; round--) { 59 | x = rotate24(x); 60 | y = rotate(y, S); 61 | newz = x ^ shift(z, 1) ^ shift(y & z, 2); 62 | newy = y ^ x ^ shift(x | z, 1); 63 | x = z ^ y ^ shift(x & y, 3); 64 | y = newy; 65 | z = newz; 66 | 67 | x = _mm_shuffle_epi32(x, _MM_SHUFFLE(2, 3, 0, 1)); 68 | x ^= ((const __m128i *) (const void *) coeffs)[round]; 69 | 70 | x = rotate24(x); 71 | y = rotate(y, S); 72 | newz = x ^ shift(z, 1) ^ shift(y & z, 2); 73 | newy = y ^ x ^ shift(x | z, 1); 74 | x = z ^ y ^ shift(x & y, 3); 75 | y = newy; 76 | z = newz; 77 | 78 | x = rotate24(x); 79 | y = rotate(y, S); 80 | newz = x ^ shift(z, 1) ^ shift(y & z, 2); 81 | newy = y ^ x ^ shift(x | z, 1); 82 | x = z ^ y ^ shift(x & y, 3); 83 | y = newy; 84 | z = newz; 85 | 86 | x = _mm_shuffle_epi32(x, _MM_SHUFFLE(1, 0, 3, 2)); 87 | 88 | x = rotate24(x); 89 | y = rotate(y, S); 90 | newz = x ^ shift(z, 1) ^ shift(y & z, 2); 91 | newy = y ^ x ^ shift(x | z, 1); 92 | x = z ^ y ^ shift(x & y, 3); 93 | y = newy; 94 | z = newz; 95 | } 96 | 97 | _mm_storeu_si128((__m128i *) (void *) &state[0], x); 98 | _mm_storeu_si128((__m128i *) (void *) &state[4], y); 99 | _mm_storeu_si128((__m128i *) (void *) &state[8], z); 100 | } 101 | -------------------------------------------------------------------------------- /impl/hash.h: -------------------------------------------------------------------------------- 1 | int 2 | hydro_hash_update(hydro_hash_state *state, const void *in_, size_t in_len) 3 | { 4 | const uint8_t *in = (const uint8_t *) in_; 5 | uint8_t * buf = (uint8_t *) (void *) state->state; 6 | size_t left; 7 | size_t ps; 8 | size_t i; 9 | 10 | while (in_len > 0) { 11 | left = gimli_RATE - state->buf_off; 12 | if ((ps = in_len) > left) { 13 | ps = left; 14 | } 15 | for (i = 0; i < ps; i++) { 16 | buf[state->buf_off + i] ^= in[i]; 17 | } 18 | in += ps; 19 | in_len -= ps; 20 | state->buf_off += (uint8_t) ps; 21 | if (state->buf_off == gimli_RATE) { 22 | gimli_core_u8(buf, 0); 23 | state->buf_off = 0; 24 | } 25 | } 26 | return 0; 27 | } 28 | 29 | /* pad(str_enc("kmac") || str_enc(context)) || pad(str_enc(k)) || 30 | msg || right_enc(msg_len) || 0x00 */ 31 | 32 | int 33 | hydro_hash_init(hydro_hash_state *state, const char ctx[hydro_hash_CONTEXTBYTES], 34 | const uint8_t key[hydro_hash_KEYBYTES]) 35 | { 36 | uint8_t block[64] = { 4, 'k', 'm', 'a', 'c', 8 }; 37 | size_t p; 38 | 39 | COMPILER_ASSERT(hydro_hash_KEYBYTES <= sizeof block - gimli_RATE - 1); 40 | COMPILER_ASSERT(hydro_hash_CONTEXTBYTES == 8); 41 | mem_zero(block + 14, sizeof block - 14); 42 | memcpy(block + 6, ctx, 8); 43 | if (key != NULL) { 44 | block[gimli_RATE] = (uint8_t) hydro_hash_KEYBYTES; 45 | memcpy(block + gimli_RATE + 1, key, hydro_hash_KEYBYTES); 46 | p = (gimli_RATE + 1 + hydro_hash_KEYBYTES + (gimli_RATE - 1)) & ~(size_t) (gimli_RATE - 1); 47 | } else { 48 | block[gimli_RATE] = (uint8_t) 0; 49 | p = (gimli_RATE + 1 + 0 + (gimli_RATE - 1)) & ~(size_t) (gimli_RATE - 1); 50 | } 51 | mem_zero(state, sizeof *state); 52 | hydro_hash_update(state, block, p); 53 | 54 | return 0; 55 | } 56 | 57 | /* pad(str_enc("tmac") || str_enc(context)) || pad(str_enc(k)) || 58 | pad(right_enc(tweak)) || msg || right_enc(msg_len) || 0x00 */ 59 | 60 | static int 61 | hydro_hash_init_with_tweak(hydro_hash_state *state, const char ctx[hydro_hash_CONTEXTBYTES], 62 | uint64_t tweak, const uint8_t key[hydro_hash_KEYBYTES]) 63 | { 64 | uint8_t block[80] = { 4, 't', 'm', 'a', 'c', 8 }; 65 | size_t p; 66 | 67 | COMPILER_ASSERT(hydro_hash_KEYBYTES <= sizeof block - 2 * gimli_RATE - 1); 68 | COMPILER_ASSERT(hydro_hash_CONTEXTBYTES == 8); 69 | mem_zero(block + 14, sizeof block - 14); 70 | memcpy(block + 6, ctx, 8); 71 | if (key != NULL) { 72 | block[gimli_RATE] = (uint8_t) hydro_hash_KEYBYTES; 73 | memcpy(block + gimli_RATE + 1, key, hydro_hash_KEYBYTES); 74 | p = (gimli_RATE + 1 + hydro_hash_KEYBYTES + (gimli_RATE - 1)) & ~(size_t) (gimli_RATE - 1); 75 | } else { 76 | block[gimli_RATE] = (uint8_t) 0; 77 | p = (gimli_RATE + 1 + 0 + (gimli_RATE - 1)) & ~(size_t) (gimli_RATE - 1); 78 | } 79 | block[p] = (uint8_t) sizeof tweak; 80 | STORE64_LE(&block[p + 1], tweak); 81 | p += gimli_RATE; 82 | mem_zero(state, sizeof *state); 83 | hydro_hash_update(state, block, p); 84 | 85 | return 0; 86 | } 87 | 88 | int 89 | hydro_hash_final(hydro_hash_state *state, uint8_t *out, size_t out_len) 90 | { 91 | uint8_t lc[4]; 92 | uint8_t *buf = (uint8_t *) (void *) state->state; 93 | size_t i; 94 | size_t lc_len; 95 | size_t leftover; 96 | 97 | if (out_len < hydro_hash_BYTES_MIN || out_len > hydro_hash_BYTES_MAX) { 98 | return -1; 99 | } 100 | COMPILER_ASSERT(hydro_hash_BYTES_MAX <= 0xffff); 101 | lc[1] = (uint8_t) out_len; 102 | lc[2] = (uint8_t) (out_len >> 8); 103 | lc[3] = 0; 104 | lc_len = (size_t) (1 + (lc[2] != 0)); 105 | lc[0] = (uint8_t) lc_len; 106 | hydro_hash_update(state, lc, 1 + lc_len + 1); 107 | gimli_pad_u8(buf, state->buf_off, gimli_DOMAIN_XOF); 108 | for (i = 0; i < out_len / gimli_RATE; i++) { 109 | gimli_core_u8(buf, 0); 110 | memcpy(out + i * gimli_RATE, buf, gimli_RATE); 111 | } 112 | leftover = out_len % gimli_RATE; 113 | if (leftover != 0) { 114 | gimli_core_u8(buf, 0); 115 | mem_cpy(out + i * gimli_RATE, buf, leftover); 116 | } 117 | state->buf_off = gimli_RATE; 118 | 119 | return 0; 120 | } 121 | 122 | int 123 | hydro_hash_hash(uint8_t *out, size_t out_len, const void *in_, size_t in_len, 124 | const char ctx[hydro_hash_CONTEXTBYTES], const uint8_t key[hydro_hash_KEYBYTES]) 125 | { 126 | hydro_hash_state st; 127 | const uint8_t * in = (const uint8_t *) in_; 128 | 129 | if (hydro_hash_init(&st, ctx, key) != 0 || hydro_hash_update(&st, in, in_len) != 0 || 130 | hydro_hash_final(&st, out, out_len) != 0) { 131 | return -1; 132 | } 133 | return 0; 134 | } 135 | 136 | void 137 | hydro_hash_keygen(uint8_t key[hydro_hash_KEYBYTES]) 138 | { 139 | hydro_random_buf(key, hydro_hash_KEYBYTES); 140 | } 141 | -------------------------------------------------------------------------------- /impl/hydrogen_p.h: -------------------------------------------------------------------------------- 1 | static int hydro_random_init(void); 2 | 3 | /* ---------------- */ 4 | 5 | #define gimli_BLOCKBYTES 48 6 | #define gimli_CAPACITY 32 7 | #define gimli_RATE 16 8 | 9 | #define gimli_TAG_HEADER 0x01 10 | #define gimli_TAG_PAYLOAD 0x02 11 | #define gimli_TAG_FINAL 0x08 12 | #define gimli_TAG_FINAL0 0xf8 13 | #define gimli_TAG_KEY0 0xfe 14 | #define gimli_TAG_KEY 0xff 15 | 16 | #define gimli_DOMAIN_AEAD 0x0 17 | #define gimli_DOMAIN_XOF 0xf 18 | 19 | static void gimli_core_u8(uint8_t state_u8[gimli_BLOCKBYTES], uint8_t tag); 20 | 21 | static inline void 22 | gimli_pad_u8(uint8_t buf[gimli_BLOCKBYTES], size_t pos, uint8_t domain) 23 | { 24 | buf[pos] ^= (domain << 1) | 1; 25 | buf[gimli_RATE - 1] ^= 0x80; 26 | } 27 | 28 | static inline void 29 | hydro_mem_ct_zero_u32(uint32_t *dst_, size_t n) 30 | { 31 | volatile uint32_t *volatile dst = (volatile uint32_t *volatile) (void *) dst_; 32 | size_t i; 33 | 34 | for (i = 0; i < n; i++) { 35 | dst[i] = 0; 36 | } 37 | } 38 | 39 | static inline uint32_t hydro_mem_ct_cmp_u32(const uint32_t *b1_, const uint32_t *b2, 40 | size_t n) _hydro_attr_warn_unused_result_; 41 | 42 | static inline uint32_t 43 | hydro_mem_ct_cmp_u32(const uint32_t *b1_, const uint32_t *b2, size_t n) 44 | { 45 | const volatile uint32_t *volatile b1 = (const volatile uint32_t *volatile) (const void *) b1_; 46 | size_t i; 47 | uint32_t cv = 0; 48 | 49 | for (i = 0; i < n; i++) { 50 | cv |= b1[i] ^ b2[i]; 51 | } 52 | return cv; 53 | } 54 | 55 | /* ---------------- */ 56 | 57 | static int hydro_hash_init_with_tweak(hydro_hash_state *state, 58 | const char ctx[hydro_hash_CONTEXTBYTES], uint64_t tweak, 59 | const uint8_t key[hydro_hash_KEYBYTES]); 60 | 61 | /* ---------------- */ 62 | 63 | #define hydro_secretbox_NONCEBYTES 20 64 | #define hydro_secretbox_MACBYTES 16 65 | 66 | /* ---------------- */ 67 | 68 | #define hydro_x25519_BYTES 32 69 | #define hydro_x25519_PUBLICKEYBYTES 32 70 | #define hydro_x25519_SECRETKEYBYTES 32 71 | 72 | static int hydro_x25519_scalarmult(uint8_t out[hydro_x25519_BYTES], 73 | const uint8_t scalar[hydro_x25519_SECRETKEYBYTES], 74 | const uint8_t x1[hydro_x25519_PUBLICKEYBYTES], 75 | bool clamp) _hydro_attr_warn_unused_result_; 76 | 77 | static inline int hydro_x25519_scalarmult_base(uint8_t pk[hydro_x25519_PUBLICKEYBYTES], 78 | const uint8_t sk[hydro_x25519_SECRETKEYBYTES]) 79 | _hydro_attr_warn_unused_result_; 80 | 81 | static inline void 82 | hydro_x25519_scalarmult_base_uniform(uint8_t pk[hydro_x25519_PUBLICKEYBYTES], 83 | const uint8_t sk[hydro_x25519_SECRETKEYBYTES]); 84 | -------------------------------------------------------------------------------- /impl/kdf.h: -------------------------------------------------------------------------------- 1 | int 2 | hydro_kdf_derive_from_key(uint8_t *subkey, size_t subkey_len, uint64_t subkey_id, 3 | const char ctx[hydro_kdf_CONTEXTBYTES], 4 | const uint8_t key[hydro_kdf_KEYBYTES]) 5 | { 6 | hydro_hash_state st; 7 | 8 | COMPILER_ASSERT(hydro_kdf_CONTEXTBYTES >= hydro_hash_CONTEXTBYTES); 9 | COMPILER_ASSERT(hydro_kdf_KEYBYTES >= hydro_hash_KEYBYTES); 10 | if (hydro_hash_init_with_tweak(&st, ctx, subkey_id, key) != 0) { 11 | return -1; 12 | } 13 | return hydro_hash_final(&st, subkey, subkey_len); 14 | } 15 | 16 | void 17 | hydro_kdf_keygen(uint8_t key[hydro_kdf_KEYBYTES]) 18 | { 19 | hydro_random_buf(key, hydro_kdf_KEYBYTES); 20 | } 21 | -------------------------------------------------------------------------------- /impl/kx.h: -------------------------------------------------------------------------------- 1 | #define hydro_kx_AEAD_KEYBYTES hydro_hash_KEYBYTES 2 | #define hydro_kx_AEAD_MACBYTES 16 3 | 4 | #define hydro_kx_CONTEXT "hydro_kx" 5 | 6 | static void 7 | hydro_kx_aead_init(uint8_t aead_state[gimli_BLOCKBYTES], uint8_t k[hydro_kx_AEAD_KEYBYTES], 8 | hydro_kx_state *state) 9 | { 10 | static const uint8_t prefix[] = { 6, 'k', 'x', 'x', '2', '5', '6', 0 }; 11 | 12 | hydro_hash_final(&state->h_st, k, hydro_kx_AEAD_KEYBYTES); 13 | 14 | mem_zero(aead_state + sizeof prefix, gimli_BLOCKBYTES - sizeof prefix); 15 | memcpy(aead_state, prefix, sizeof prefix); 16 | gimli_core_u8(aead_state, gimli_TAG_HEADER); 17 | 18 | COMPILER_ASSERT(hydro_kx_AEAD_KEYBYTES == 2 * gimli_RATE); 19 | mem_xor(aead_state, k, gimli_RATE); 20 | gimli_core_u8(aead_state, gimli_TAG_KEY); 21 | mem_xor(aead_state, k + gimli_RATE, gimli_RATE); 22 | gimli_core_u8(aead_state, gimli_TAG_KEY); 23 | } 24 | 25 | static void 26 | hydro_kx_aead_final(uint8_t *aead_state, const uint8_t key[hydro_kx_AEAD_KEYBYTES]) 27 | { 28 | COMPILER_ASSERT(hydro_kx_AEAD_KEYBYTES == gimli_CAPACITY); 29 | mem_xor(aead_state + gimli_RATE, key, hydro_kx_AEAD_KEYBYTES); 30 | gimli_core_u8(aead_state, gimli_TAG_FINAL); 31 | mem_xor(aead_state + gimli_RATE, key, hydro_kx_AEAD_KEYBYTES); 32 | gimli_core_u8(aead_state, gimli_TAG_FINAL); 33 | } 34 | 35 | static void 36 | hydro_kx_aead_xor_enc(uint8_t aead_state[gimli_BLOCKBYTES], uint8_t *out, const uint8_t *in, 37 | size_t inlen) 38 | { 39 | size_t i; 40 | size_t leftover; 41 | 42 | for (i = 0; i < inlen / gimli_RATE; i++) { 43 | mem_xor2(&out[i * gimli_RATE], &in[i * gimli_RATE], aead_state, gimli_RATE); 44 | memcpy(aead_state, &out[i * gimli_RATE], gimli_RATE); 45 | gimli_core_u8(aead_state, gimli_TAG_PAYLOAD); 46 | } 47 | leftover = inlen % gimli_RATE; 48 | if (leftover != 0) { 49 | mem_xor2(&out[i * gimli_RATE], &in[i * gimli_RATE], aead_state, leftover); 50 | mem_cpy(aead_state, &out[i * gimli_RATE], leftover); 51 | } 52 | gimli_pad_u8(aead_state, leftover, gimli_DOMAIN_AEAD); 53 | gimli_core_u8(aead_state, gimli_TAG_PAYLOAD); 54 | } 55 | 56 | static void 57 | hydro_kx_aead_xor_dec(uint8_t aead_state[gimli_BLOCKBYTES], uint8_t *out, const uint8_t *in, 58 | size_t inlen) 59 | { 60 | size_t i; 61 | size_t leftover; 62 | 63 | for (i = 0; i < inlen / gimli_RATE; i++) { 64 | mem_xor2(&out[i * gimli_RATE], &in[i * gimli_RATE], aead_state, gimli_RATE); 65 | memcpy(aead_state, &in[i * gimli_RATE], gimli_RATE); 66 | gimli_core_u8(aead_state, gimli_TAG_PAYLOAD); 67 | } 68 | leftover = inlen % gimli_RATE; 69 | if (leftover != 0) { 70 | mem_xor2(&out[i * gimli_RATE], &in[i * gimli_RATE], aead_state, leftover); 71 | mem_cpy(aead_state, &in[i * gimli_RATE], leftover); 72 | } 73 | gimli_pad_u8(aead_state, leftover, gimli_DOMAIN_AEAD); 74 | gimli_core_u8(aead_state, gimli_TAG_PAYLOAD); 75 | } 76 | 77 | static void 78 | hydro_kx_aead_encrypt(hydro_kx_state *state, uint8_t *c, const uint8_t *m, size_t mlen) 79 | { 80 | _hydro_attr_aligned_(16) uint8_t aead_state[gimli_BLOCKBYTES]; 81 | uint8_t k[hydro_kx_AEAD_KEYBYTES]; 82 | uint8_t * mac = &c[0]; 83 | uint8_t * ct = &c[hydro_kx_AEAD_MACBYTES]; 84 | 85 | hydro_kx_aead_init(aead_state, k, state); 86 | hydro_kx_aead_xor_enc(aead_state, ct, m, mlen); 87 | hydro_kx_aead_final(aead_state, k); 88 | COMPILER_ASSERT(hydro_kx_AEAD_MACBYTES <= gimli_CAPACITY); 89 | memcpy(mac, aead_state + gimli_RATE, hydro_kx_AEAD_MACBYTES); 90 | hydro_hash_update(&state->h_st, c, mlen + hydro_kx_AEAD_MACBYTES); 91 | } 92 | 93 | static int hydro_kx_aead_decrypt(hydro_kx_state *state, uint8_t *m, const uint8_t *c, 94 | size_t clen) _hydro_attr_warn_unused_result_; 95 | 96 | static int 97 | hydro_kx_aead_decrypt(hydro_kx_state *state, uint8_t *m, const uint8_t *c, size_t clen) 98 | { 99 | _hydro_attr_aligned_(16) uint32_t int_state[gimli_BLOCKBYTES / 4]; 100 | uint32_t pub_mac[hydro_kx_AEAD_MACBYTES / 4]; 101 | uint8_t k[hydro_kx_AEAD_KEYBYTES]; 102 | uint8_t * aead_state = (uint8_t *) (void *) int_state; 103 | const uint8_t * mac; 104 | const uint8_t * ct; 105 | size_t mlen; 106 | uint32_t cv; 107 | 108 | if (clen < hydro_kx_AEAD_MACBYTES) { 109 | return -1; 110 | } 111 | mac = &c[0]; 112 | ct = &c[hydro_kx_AEAD_MACBYTES]; 113 | mlen = clen - hydro_kx_AEAD_MACBYTES; 114 | memcpy(pub_mac, mac, sizeof pub_mac); 115 | hydro_kx_aead_init(aead_state, k, state); 116 | hydro_hash_update(&state->h_st, c, clen); 117 | hydro_kx_aead_xor_dec(aead_state, m, ct, mlen); 118 | hydro_kx_aead_final(aead_state, k); 119 | COMPILER_ASSERT(hydro_kx_AEAD_MACBYTES <= gimli_CAPACITY); 120 | COMPILER_ASSERT(gimli_RATE % 4 == 0); 121 | cv = hydro_mem_ct_cmp_u32(int_state + gimli_RATE / 4, pub_mac, hydro_kx_AEAD_MACBYTES / 4); 122 | hydro_mem_ct_zero_u32(int_state, gimli_BLOCKBYTES / 4); 123 | if (cv != 0) { 124 | mem_zero(m, mlen); 125 | return -1; 126 | } 127 | return 0; 128 | } 129 | 130 | /* -- */ 131 | 132 | void 133 | hydro_kx_keygen(hydro_kx_keypair *static_kp) 134 | { 135 | hydro_random_buf(static_kp->sk, hydro_kx_SECRETKEYBYTES); 136 | if (hydro_x25519_scalarmult_base(static_kp->pk, static_kp->sk) != 0) { 137 | abort(); 138 | } 139 | } 140 | 141 | void 142 | hydro_kx_keygen_deterministic(hydro_kx_keypair *static_kp, const uint8_t seed[hydro_kx_SEEDBYTES]) 143 | { 144 | COMPILER_ASSERT(hydro_kx_SEEDBYTES >= hydro_random_SEEDBYTES); 145 | hydro_random_buf_deterministic(static_kp->sk, hydro_kx_SECRETKEYBYTES, seed); 146 | if (hydro_x25519_scalarmult_base(static_kp->pk, static_kp->sk) != 0) { 147 | abort(); 148 | } 149 | } 150 | 151 | static void 152 | hydro_kx_init_state(hydro_kx_state *state, const char *name) 153 | { 154 | mem_zero(state, sizeof *state); 155 | hydro_hash_init(&state->h_st, hydro_kx_CONTEXT, NULL); 156 | hydro_hash_update(&state->h_st, name, strlen(name)); 157 | hydro_hash_final(&state->h_st, NULL, 0); 158 | } 159 | 160 | static void 161 | hydro_kx_final(hydro_kx_state *state, uint8_t session_k1[hydro_kx_SESSIONKEYBYTES], 162 | uint8_t session_k2[hydro_kx_SESSIONKEYBYTES]) 163 | { 164 | uint8_t kdf_key[hydro_kdf_KEYBYTES]; 165 | 166 | hydro_hash_final(&state->h_st, kdf_key, sizeof kdf_key); 167 | hydro_kdf_derive_from_key(session_k1, hydro_kx_SESSIONKEYBYTES, 0, hydro_kx_CONTEXT, kdf_key); 168 | hydro_kdf_derive_from_key(session_k2, hydro_kx_SESSIONKEYBYTES, 1, hydro_kx_CONTEXT, kdf_key); 169 | } 170 | 171 | static int 172 | hydro_kx_dh(hydro_kx_state *state, const uint8_t sk[hydro_x25519_SECRETKEYBYTES], 173 | const uint8_t pk[hydro_x25519_PUBLICKEYBYTES]) 174 | { 175 | uint8_t dh_result[hydro_x25519_BYTES]; 176 | 177 | if (hydro_x25519_scalarmult(dh_result, sk, pk, 1) != 0) { 178 | return -1; 179 | } 180 | hydro_hash_update(&state->h_st, dh_result, hydro_x25519_BYTES); 181 | 182 | return 0; 183 | } 184 | 185 | static void 186 | hydro_kx_eph_keygen(hydro_kx_state *state, hydro_kx_keypair *kp) 187 | { 188 | hydro_kx_keygen(kp); 189 | hydro_hash_update(&state->h_st, kp->pk, sizeof kp->pk); 190 | } 191 | 192 | /* NOISE_N */ 193 | 194 | int 195 | hydro_kx_n_1(hydro_kx_session_keypair *kp, uint8_t packet1[hydro_kx_N_PACKET1BYTES], 196 | const uint8_t psk[hydro_kx_PSKBYTES], 197 | const uint8_t peer_static_pk[hydro_kx_PUBLICKEYBYTES]) 198 | { 199 | hydro_kx_state state; 200 | uint8_t * packet1_eph_pk = &packet1[0]; 201 | uint8_t * packet1_mac = &packet1[hydro_kx_PUBLICKEYBYTES]; 202 | 203 | if (psk == NULL) { 204 | psk = zero; 205 | } 206 | hydro_kx_init_state(&state, "Noise_Npsk0_hydro1"); 207 | hydro_hash_update(&state.h_st, peer_static_pk, hydro_x25519_PUBLICKEYBYTES); 208 | 209 | hydro_hash_update(&state.h_st, psk, hydro_kx_PSKBYTES); 210 | hydro_kx_eph_keygen(&state, &state.eph_kp); 211 | if (hydro_kx_dh(&state, state.eph_kp.sk, peer_static_pk) != 0) { 212 | return -1; 213 | } 214 | hydro_kx_aead_encrypt(&state, packet1_mac, NULL, 0); 215 | memcpy(packet1_eph_pk, state.eph_kp.pk, sizeof state.eph_kp.pk); 216 | 217 | hydro_kx_final(&state, kp->rx, kp->tx); 218 | 219 | return 0; 220 | } 221 | 222 | int 223 | hydro_kx_n_2(hydro_kx_session_keypair *kp, const uint8_t packet1[hydro_kx_N_PACKET1BYTES], 224 | const uint8_t psk[hydro_kx_PSKBYTES], const hydro_kx_keypair *static_kp) 225 | { 226 | hydro_kx_state state; 227 | const uint8_t *peer_eph_pk = &packet1[0]; 228 | const uint8_t *packet1_mac = &packet1[hydro_kx_PUBLICKEYBYTES]; 229 | 230 | if (psk == NULL) { 231 | psk = zero; 232 | } 233 | hydro_kx_init_state(&state, "Noise_Npsk0_hydro1"); 234 | hydro_hash_update(&state.h_st, static_kp->pk, hydro_kx_PUBLICKEYBYTES); 235 | 236 | hydro_hash_update(&state.h_st, psk, hydro_kx_PSKBYTES); 237 | hydro_hash_update(&state.h_st, peer_eph_pk, hydro_x25519_PUBLICKEYBYTES); 238 | if (hydro_kx_dh(&state, static_kp->sk, peer_eph_pk) != 0 || 239 | hydro_kx_aead_decrypt(&state, NULL, packet1_mac, hydro_kx_AEAD_MACBYTES) != 0) { 240 | return -1; 241 | } 242 | hydro_kx_final(&state, kp->tx, kp->rx); 243 | 244 | return 0; 245 | } 246 | 247 | /* NOISE_KK */ 248 | 249 | int 250 | hydro_kx_kk_1(hydro_kx_state *state, uint8_t packet1[hydro_kx_KK_PACKET1BYTES], 251 | const uint8_t peer_static_pk[hydro_kx_PUBLICKEYBYTES], 252 | const hydro_kx_keypair *static_kp) 253 | { 254 | uint8_t *packet1_eph_pk = &packet1[0]; 255 | uint8_t *packet1_mac = &packet1[hydro_kx_PUBLICKEYBYTES]; 256 | 257 | hydro_kx_init_state(state, "Noise_KK_hydro1"); 258 | hydro_hash_update(&state->h_st, static_kp->pk, hydro_kx_PUBLICKEYBYTES); 259 | hydro_hash_update(&state->h_st, peer_static_pk, hydro_kx_PUBLICKEYBYTES); 260 | 261 | hydro_kx_eph_keygen(state, &state->eph_kp); 262 | if (hydro_kx_dh(state, state->eph_kp.sk, peer_static_pk) != 0 || 263 | hydro_kx_dh(state, static_kp->sk, peer_static_pk) != 0) { 264 | return -1; 265 | } 266 | hydro_kx_aead_encrypt(state, packet1_mac, NULL, 0); 267 | memcpy(packet1_eph_pk, state->eph_kp.pk, sizeof state->eph_kp.pk); 268 | 269 | return 0; 270 | } 271 | 272 | int 273 | hydro_kx_kk_2(hydro_kx_session_keypair *kp, uint8_t packet2[hydro_kx_KK_PACKET2BYTES], 274 | const uint8_t packet1[hydro_kx_KK_PACKET1BYTES], 275 | const uint8_t peer_static_pk[hydro_kx_PUBLICKEYBYTES], 276 | const hydro_kx_keypair *static_kp) 277 | { 278 | hydro_kx_state state; 279 | const uint8_t *peer_eph_pk = &packet1[0]; 280 | const uint8_t *packet1_mac = &packet1[hydro_kx_PUBLICKEYBYTES]; 281 | uint8_t * packet2_eph_pk = &packet2[0]; 282 | uint8_t * packet2_mac = &packet2[hydro_kx_PUBLICKEYBYTES]; 283 | 284 | hydro_kx_init_state(&state, "Noise_KK_hydro1"); 285 | hydro_hash_update(&state.h_st, peer_static_pk, hydro_kx_PUBLICKEYBYTES); 286 | hydro_hash_update(&state.h_st, static_kp->pk, hydro_kx_PUBLICKEYBYTES); 287 | 288 | hydro_hash_update(&state.h_st, peer_eph_pk, hydro_kx_PUBLICKEYBYTES); 289 | if (hydro_kx_dh(&state, static_kp->sk, peer_eph_pk) != 0 || 290 | hydro_kx_dh(&state, static_kp->sk, peer_static_pk) != 0 || 291 | hydro_kx_aead_decrypt(&state, NULL, packet1_mac, hydro_kx_AEAD_MACBYTES) != 0) { 292 | return -1; 293 | } 294 | 295 | hydro_kx_eph_keygen(&state, &state.eph_kp); 296 | if (hydro_kx_dh(&state, state.eph_kp.sk, peer_eph_pk) != 0 || 297 | hydro_kx_dh(&state, state.eph_kp.sk, peer_static_pk) != 0) { 298 | return -1; 299 | } 300 | hydro_kx_aead_encrypt(&state, packet2_mac, NULL, 0); 301 | hydro_kx_final(&state, kp->tx, kp->rx); 302 | memcpy(packet2_eph_pk, state.eph_kp.pk, sizeof state.eph_kp.pk); 303 | 304 | return 0; 305 | } 306 | 307 | int 308 | hydro_kx_kk_3(hydro_kx_state *state, hydro_kx_session_keypair *kp, 309 | const uint8_t packet2[hydro_kx_KK_PACKET2BYTES], const hydro_kx_keypair *static_kp) 310 | { 311 | const uint8_t *peer_eph_pk = packet2; 312 | const uint8_t *packet2_mac = &packet2[hydro_kx_PUBLICKEYBYTES]; 313 | 314 | hydro_hash_update(&state->h_st, peer_eph_pk, hydro_kx_PUBLICKEYBYTES); 315 | if (hydro_kx_dh(state, state->eph_kp.sk, peer_eph_pk) != 0 || 316 | hydro_kx_dh(state, static_kp->sk, peer_eph_pk) != 0) { 317 | return -1; 318 | } 319 | 320 | if (hydro_kx_aead_decrypt(state, NULL, packet2_mac, hydro_kx_AEAD_MACBYTES) != 0) { 321 | return -1; 322 | } 323 | hydro_kx_final(state, kp->rx, kp->tx); 324 | 325 | return 0; 326 | } 327 | 328 | /* NOISE_XX */ 329 | 330 | int 331 | hydro_kx_xx_1(hydro_kx_state *state, uint8_t packet1[hydro_kx_XX_PACKET1BYTES], 332 | const uint8_t psk[hydro_kx_PSKBYTES]) 333 | { 334 | uint8_t *packet1_eph_pk = &packet1[0]; 335 | uint8_t *packet1_mac = &packet1[hydro_kx_PUBLICKEYBYTES]; 336 | 337 | if (psk == NULL) { 338 | psk = zero; 339 | } 340 | hydro_kx_init_state(state, "Noise_XXpsk0+psk3_hydro1"); 341 | 342 | hydro_kx_eph_keygen(state, &state->eph_kp); 343 | hydro_hash_update(&state->h_st, psk, hydro_kx_PSKBYTES); 344 | memcpy(packet1_eph_pk, state->eph_kp.pk, sizeof state->eph_kp.pk); 345 | hydro_kx_aead_encrypt(state, packet1_mac, NULL, 0); 346 | 347 | return 0; 348 | } 349 | 350 | int 351 | hydro_kx_xx_2(hydro_kx_state *state, uint8_t packet2[hydro_kx_XX_PACKET2BYTES], 352 | const uint8_t packet1[hydro_kx_XX_PACKET1BYTES], const uint8_t psk[hydro_kx_PSKBYTES], 353 | const hydro_kx_keypair *static_kp) 354 | { 355 | const uint8_t *peer_eph_pk = &packet1[0]; 356 | const uint8_t *packet1_mac = &packet1[hydro_kx_PUBLICKEYBYTES]; 357 | uint8_t * packet2_eph_pk = &packet2[0]; 358 | uint8_t * packet2_enc_static_pk = &packet2[hydro_kx_PUBLICKEYBYTES]; 359 | uint8_t * packet2_mac = 360 | &packet2[hydro_kx_PUBLICKEYBYTES + hydro_kx_PUBLICKEYBYTES + hydro_kx_AEAD_MACBYTES]; 361 | 362 | if (psk == NULL) { 363 | psk = zero; 364 | } 365 | hydro_kx_init_state(state, "Noise_XXpsk0+psk3_hydro1"); 366 | 367 | hydro_hash_update(&state->h_st, peer_eph_pk, hydro_kx_PUBLICKEYBYTES); 368 | hydro_hash_update(&state->h_st, psk, hydro_kx_PSKBYTES); 369 | if (hydro_kx_aead_decrypt(state, NULL, packet1_mac, hydro_kx_AEAD_MACBYTES) != 0) { 370 | return -1; 371 | } 372 | 373 | hydro_kx_eph_keygen(state, &state->eph_kp); 374 | if (hydro_kx_dh(state, state->eph_kp.sk, peer_eph_pk) != 0) { 375 | return -1; 376 | } 377 | hydro_kx_aead_encrypt(state, packet2_enc_static_pk, static_kp->pk, sizeof static_kp->pk); 378 | if (hydro_kx_dh(state, static_kp->sk, peer_eph_pk) != 0) { 379 | return -1; 380 | } 381 | hydro_kx_aead_encrypt(state, packet2_mac, NULL, 0); 382 | 383 | memcpy(packet2_eph_pk, state->eph_kp.pk, sizeof state->eph_kp.pk); 384 | 385 | return 0; 386 | } 387 | 388 | int 389 | hydro_kx_xx_3(hydro_kx_state *state, hydro_kx_session_keypair *kp, 390 | uint8_t packet3[hydro_kx_XX_PACKET3BYTES], 391 | uint8_t peer_static_pk[hydro_kx_PUBLICKEYBYTES], 392 | const uint8_t packet2[hydro_kx_XX_PACKET2BYTES], const uint8_t psk[hydro_kx_PSKBYTES], 393 | const hydro_kx_keypair *static_kp) 394 | { 395 | uint8_t peer_static_pk_[hydro_kx_PUBLICKEYBYTES]; 396 | const uint8_t *peer_eph_pk = &packet2[0]; 397 | const uint8_t *peer_enc_static_pk = &packet2[hydro_kx_PUBLICKEYBYTES]; 398 | const uint8_t *packet2_mac = 399 | &packet2[hydro_kx_PUBLICKEYBYTES + hydro_kx_PUBLICKEYBYTES + hydro_kx_AEAD_MACBYTES]; 400 | uint8_t *packet3_enc_static_pk = &packet3[0]; 401 | uint8_t *packet3_mac = &packet3[hydro_kx_PUBLICKEYBYTES + hydro_kx_AEAD_MACBYTES]; 402 | 403 | if (psk == NULL) { 404 | psk = zero; 405 | } 406 | if (peer_static_pk == NULL) { 407 | peer_static_pk = peer_static_pk_; 408 | } 409 | hydro_hash_update(&state->h_st, peer_eph_pk, hydro_kx_PUBLICKEYBYTES); 410 | if (hydro_kx_dh(state, state->eph_kp.sk, peer_eph_pk) != 0 || 411 | hydro_kx_aead_decrypt(state, peer_static_pk, peer_enc_static_pk, 412 | hydro_kx_PUBLICKEYBYTES + hydro_kx_AEAD_MACBYTES) != 0 || 413 | hydro_kx_dh(state, state->eph_kp.sk, peer_static_pk) != 0 || 414 | hydro_kx_aead_decrypt(state, NULL, packet2_mac, hydro_kx_AEAD_MACBYTES) != 0) { 415 | return -1; 416 | } 417 | 418 | hydro_kx_aead_encrypt(state, packet3_enc_static_pk, static_kp->pk, sizeof static_kp->pk); 419 | if (hydro_kx_dh(state, static_kp->sk, peer_eph_pk) != 0) { 420 | return -1; 421 | } 422 | hydro_hash_update(&state->h_st, psk, hydro_kx_PSKBYTES); 423 | hydro_kx_aead_encrypt(state, packet3_mac, NULL, 0); 424 | hydro_kx_final(state, kp->rx, kp->tx); 425 | 426 | return 0; 427 | } 428 | 429 | int 430 | hydro_kx_xx_4(hydro_kx_state *state, hydro_kx_session_keypair *kp, 431 | uint8_t peer_static_pk[hydro_kx_PUBLICKEYBYTES], 432 | const uint8_t packet3[hydro_kx_XX_PACKET3BYTES], const uint8_t psk[hydro_kx_PSKBYTES]) 433 | { 434 | uint8_t peer_static_pk_[hydro_kx_PUBLICKEYBYTES]; 435 | const uint8_t *peer_enc_static_pk = &packet3[0]; 436 | const uint8_t *packet3_mac = &packet3[hydro_kx_PUBLICKEYBYTES + hydro_kx_AEAD_MACBYTES]; 437 | 438 | if (psk == NULL) { 439 | psk = zero; 440 | } 441 | if (peer_static_pk == NULL) { 442 | peer_static_pk = peer_static_pk_; 443 | } 444 | if (hydro_kx_aead_decrypt(state, peer_static_pk, peer_enc_static_pk, 445 | hydro_kx_PUBLICKEYBYTES + hydro_kx_AEAD_MACBYTES) != 0 || 446 | hydro_kx_dh(state, state->eph_kp.sk, peer_static_pk) != 0) { 447 | return -1; 448 | } 449 | hydro_hash_update(&state->h_st, psk, hydro_kx_PSKBYTES); 450 | if (hydro_kx_aead_decrypt(state, NULL, packet3_mac, hydro_kx_AEAD_MACBYTES) != 0) { 451 | return -1; 452 | } 453 | hydro_kx_final(state, kp->tx, kp->rx); 454 | 455 | return 0; 456 | } 457 | 458 | /* NOISE_NK */ 459 | 460 | int 461 | hydro_kx_nk_1(hydro_kx_state *state, uint8_t packet1[hydro_kx_NK_PACKET1BYTES], 462 | const uint8_t psk[hydro_kx_PSKBYTES], 463 | const uint8_t peer_static_pk[hydro_kx_PUBLICKEYBYTES]) 464 | { 465 | uint8_t *packet1_eph_pk = &packet1[0]; 466 | uint8_t *packet1_mac = &packet1[hydro_kx_PUBLICKEYBYTES]; 467 | 468 | if (psk == NULL) { 469 | psk = zero; 470 | } 471 | hydro_kx_init_state(state, "Noise_NKpsk0_hydro1"); 472 | hydro_hash_update(&state->h_st, peer_static_pk, hydro_x25519_PUBLICKEYBYTES); 473 | 474 | hydro_hash_update(&state->h_st, psk, hydro_kx_PSKBYTES); 475 | hydro_kx_eph_keygen(state, &state->eph_kp); 476 | if (hydro_kx_dh(state, state->eph_kp.sk, peer_static_pk) != 0) { 477 | return -1; 478 | } 479 | hydro_kx_aead_encrypt(state, packet1_mac, NULL, 0); 480 | memcpy(packet1_eph_pk, state->eph_kp.pk, sizeof state->eph_kp.pk); 481 | 482 | return 0; 483 | } 484 | 485 | int 486 | hydro_kx_nk_2(hydro_kx_session_keypair *kp, uint8_t packet2[hydro_kx_NK_PACKET2BYTES], 487 | const uint8_t packet1[hydro_kx_NK_PACKET1BYTES], const uint8_t psk[hydro_kx_PSKBYTES], 488 | const hydro_kx_keypair *static_kp) 489 | { 490 | hydro_kx_state state; 491 | const uint8_t *peer_eph_pk = &packet1[0]; 492 | const uint8_t *packet1_mac = &packet1[hydro_kx_PUBLICKEYBYTES]; 493 | uint8_t * packet2_eph_pk = &packet2[0]; 494 | uint8_t * packet2_mac = &packet2[hydro_kx_PUBLICKEYBYTES]; 495 | 496 | if (psk == NULL) { 497 | psk = zero; 498 | } 499 | hydro_kx_init_state(&state, "Noise_NKpsk0_hydro1"); 500 | hydro_hash_update(&state.h_st, static_kp->pk, hydro_kx_PUBLICKEYBYTES); 501 | 502 | hydro_hash_update(&state.h_st, psk, hydro_kx_PSKBYTES); 503 | hydro_hash_update(&state.h_st, peer_eph_pk, hydro_x25519_PUBLICKEYBYTES); 504 | if (hydro_kx_dh(&state, static_kp->sk, peer_eph_pk) != 0 || 505 | hydro_kx_aead_decrypt(&state, NULL, packet1_mac, hydro_kx_AEAD_MACBYTES) != 0) { 506 | return -1; 507 | } 508 | 509 | hydro_kx_eph_keygen(&state, &state.eph_kp); 510 | if (hydro_kx_dh(&state, state.eph_kp.sk, peer_eph_pk) != 0) { 511 | return -1; 512 | } 513 | hydro_kx_aead_encrypt(&state, packet2_mac, NULL, 0); 514 | hydro_kx_final(&state, kp->tx, kp->rx); 515 | memcpy(packet2_eph_pk, state.eph_kp.pk, sizeof state.eph_kp.pk); 516 | 517 | return 0; 518 | } 519 | 520 | int 521 | hydro_kx_nk_3(hydro_kx_state *state, hydro_kx_session_keypair *kp, 522 | const uint8_t packet2[hydro_kx_NK_PACKET2BYTES]) 523 | { 524 | const uint8_t *peer_eph_pk = &packet2[0]; 525 | const uint8_t *packet2_mac = &packet2[hydro_kx_PUBLICKEYBYTES]; 526 | 527 | hydro_hash_update(&state->h_st, peer_eph_pk, hydro_x25519_PUBLICKEYBYTES); 528 | if (hydro_kx_dh(state, state->eph_kp.sk, peer_eph_pk) != 0 || 529 | hydro_kx_aead_decrypt(state, NULL, packet2_mac, hydro_kx_AEAD_MACBYTES) != 0) { 530 | return -1; 531 | } 532 | hydro_kx_final(state, kp->rx, kp->tx); 533 | 534 | return 0; 535 | } 536 | -------------------------------------------------------------------------------- /impl/pwhash.h: -------------------------------------------------------------------------------- 1 | #define hydro_pwhash_ENC_ALGBYTES 1 2 | #define hydro_pwhash_HASH_ALGBYTES 1 3 | #define hydro_pwhash_THREADSBYTES 1 4 | #define hydro_pwhash_OPSLIMITBYTES 8 5 | #define hydro_pwhash_MEMLIMITBYTES 8 6 | #define hydro_pwhash_HASHBYTES 32 7 | #define hydro_pwhash_SALTBYTES 16 8 | #define hydro_pwhash_PARAMSBYTES \ 9 | (hydro_pwhash_HASH_ALGBYTES + hydro_pwhash_THREADSBYTES + hydro_pwhash_OPSLIMITBYTES + \ 10 | hydro_pwhash_MEMLIMITBYTES + hydro_pwhash_SALTBYTES + hydro_pwhash_HASHBYTES) 11 | #define hydro_pwhash_ENC_ALG 0x01 12 | #define hydro_pwhash_HASH_ALG 0x01 13 | #define hydro_pwhash_CONTEXT "hydro_pw" 14 | 15 | static int 16 | _hydro_pwhash_hash(uint8_t out[hydro_random_SEEDBYTES], size_t h_len, 17 | const uint8_t salt[hydro_pwhash_SALTBYTES], const char *passwd, 18 | size_t passwd_len, const char ctx[hydro_pwhash_CONTEXTBYTES], 19 | const uint8_t master_key[hydro_pwhash_MASTERKEYBYTES], uint64_t opslimit, 20 | size_t memlimit, uint8_t threads) 21 | { 22 | _hydro_attr_aligned_(16) uint8_t state[gimli_BLOCKBYTES]; 23 | hydro_hash_state h_st; 24 | uint8_t tmp64_u8[8]; 25 | uint64_t i; 26 | uint8_t tmp8; 27 | 28 | COMPILER_ASSERT(hydro_pwhash_MASTERKEYBYTES >= hydro_hash_KEYBYTES); 29 | hydro_hash_init(&h_st, ctx, master_key); 30 | 31 | STORE64_LE(tmp64_u8, (uint64_t) passwd_len); 32 | hydro_hash_update(&h_st, tmp64_u8, sizeof tmp64_u8); 33 | hydro_hash_update(&h_st, passwd, passwd_len); 34 | 35 | hydro_hash_update(&h_st, salt, hydro_pwhash_SALTBYTES); 36 | 37 | tmp8 = hydro_pwhash_HASH_ALG; 38 | hydro_hash_update(&h_st, &tmp8, 1); 39 | 40 | hydro_hash_update(&h_st, &threads, 1); 41 | 42 | STORE64_LE(tmp64_u8, (uint64_t) memlimit); 43 | hydro_hash_update(&h_st, tmp64_u8, sizeof tmp64_u8); 44 | 45 | STORE64_LE(tmp64_u8, (uint64_t) h_len); 46 | hydro_hash_update(&h_st, tmp64_u8, sizeof tmp64_u8); 47 | 48 | hydro_hash_final(&h_st, (uint8_t *) (void *) &state, sizeof state); 49 | 50 | gimli_core_u8(state, 1); 51 | COMPILER_ASSERT(gimli_RATE >= 8); 52 | for (i = 0; i < opslimit; i++) { 53 | mem_zero(state, gimli_RATE); 54 | STORE64_LE(state, i); 55 | gimli_core_u8(state, 0); 56 | } 57 | mem_zero(state, gimli_RATE); 58 | 59 | COMPILER_ASSERT(hydro_random_SEEDBYTES == gimli_CAPACITY); 60 | memcpy(out, state + gimli_RATE, hydro_random_SEEDBYTES); 61 | hydro_memzero(state, sizeof state); 62 | 63 | return 0; 64 | } 65 | 66 | void 67 | hydro_pwhash_keygen(uint8_t master_key[hydro_pwhash_MASTERKEYBYTES]) 68 | { 69 | hydro_random_buf(master_key, hydro_pwhash_MASTERKEYBYTES); 70 | } 71 | 72 | int 73 | hydro_pwhash_deterministic(uint8_t *h, size_t h_len, const char *passwd, size_t passwd_len, 74 | const char ctx[hydro_pwhash_CONTEXTBYTES], 75 | const uint8_t master_key[hydro_pwhash_MASTERKEYBYTES], uint64_t opslimit, 76 | size_t memlimit, uint8_t threads) 77 | { 78 | uint8_t seed[hydro_random_SEEDBYTES]; 79 | 80 | COMPILER_ASSERT(sizeof zero >= hydro_pwhash_SALTBYTES); 81 | COMPILER_ASSERT(sizeof zero >= hydro_pwhash_MASTERKEYBYTES); 82 | 83 | (void) memlimit; 84 | if (_hydro_pwhash_hash(seed, h_len, zero, passwd, passwd_len, ctx, master_key, opslimit, 85 | memlimit, threads) != 0) { 86 | return -1; 87 | } 88 | hydro_random_buf_deterministic(h, h_len, seed); 89 | hydro_memzero(seed, sizeof seed); 90 | 91 | return 0; 92 | } 93 | 94 | int 95 | hydro_pwhash_create(uint8_t stored[hydro_pwhash_STOREDBYTES], const char *passwd, size_t passwd_len, 96 | const uint8_t master_key[hydro_pwhash_MASTERKEYBYTES], uint64_t opslimit, 97 | size_t memlimit, uint8_t threads) 98 | { 99 | uint8_t *const enc_alg = &stored[0]; 100 | uint8_t *const secretbox = &enc_alg[hydro_pwhash_ENC_ALGBYTES]; 101 | uint8_t *const hash_alg = &secretbox[hydro_secretbox_HEADERBYTES]; 102 | uint8_t *const threads_u8 = &hash_alg[hydro_pwhash_HASH_ALGBYTES]; 103 | uint8_t *const opslimit_u8 = &threads_u8[hydro_pwhash_THREADSBYTES]; 104 | uint8_t *const memlimit_u8 = &opslimit_u8[hydro_pwhash_OPSLIMITBYTES]; 105 | uint8_t *const salt = &memlimit_u8[hydro_pwhash_MEMLIMITBYTES]; 106 | uint8_t *const h = &salt[hydro_pwhash_SALTBYTES]; 107 | 108 | COMPILER_ASSERT(hydro_pwhash_STOREDBYTES >= hydro_pwhash_ENC_ALGBYTES + 109 | hydro_secretbox_HEADERBYTES + 110 | hydro_pwhash_PARAMSBYTES); 111 | (void) memlimit; 112 | mem_zero(stored, hydro_pwhash_STOREDBYTES); 113 | *enc_alg = hydro_pwhash_ENC_ALG; 114 | *hash_alg = hydro_pwhash_HASH_ALG; 115 | *threads_u8 = threads; 116 | STORE64_LE(opslimit_u8, opslimit); 117 | STORE64_LE(memlimit_u8, (uint64_t) memlimit); 118 | hydro_random_buf(salt, hydro_pwhash_SALTBYTES); 119 | 120 | COMPILER_ASSERT(sizeof zero >= hydro_pwhash_MASTERKEYBYTES); 121 | if (_hydro_pwhash_hash(h, hydro_pwhash_HASHBYTES, salt, passwd, passwd_len, 122 | hydro_pwhash_CONTEXT, zero, opslimit, memlimit, threads) != 0) { 123 | return -1; 124 | } 125 | COMPILER_ASSERT(hydro_pwhash_MASTERKEYBYTES == hydro_secretbox_KEYBYTES); 126 | 127 | return hydro_secretbox_encrypt(secretbox, hash_alg, hydro_pwhash_PARAMSBYTES, 128 | (uint64_t) *enc_alg, hydro_pwhash_CONTEXT, master_key); 129 | } 130 | 131 | static int 132 | _hydro_pwhash_verify(uint8_t computed_h[hydro_pwhash_HASHBYTES], 133 | const uint8_t stored[hydro_pwhash_STOREDBYTES], const char *passwd, 134 | size_t passwd_len, const uint8_t master_key[hydro_pwhash_MASTERKEYBYTES], 135 | uint64_t opslimit_max, size_t memlimit_max, uint8_t threads_max) 136 | { 137 | const uint8_t *const enc_alg = &stored[0]; 138 | const uint8_t *const secretbox = &enc_alg[hydro_pwhash_ENC_ALGBYTES]; 139 | 140 | uint8_t params[hydro_pwhash_PARAMSBYTES]; 141 | uint8_t *const hash_alg = ¶ms[0]; 142 | uint8_t *const threads_u8 = &hash_alg[hydro_pwhash_HASH_ALGBYTES]; 143 | uint8_t *const opslimit_u8 = &threads_u8[hydro_pwhash_THREADSBYTES]; 144 | uint8_t *const memlimit_u8 = &opslimit_u8[hydro_pwhash_OPSLIMITBYTES]; 145 | uint8_t *const salt = &memlimit_u8[hydro_pwhash_MEMLIMITBYTES]; 146 | uint8_t *const h = &salt[hydro_pwhash_SALTBYTES]; 147 | 148 | uint64_t opslimit; 149 | size_t memlimit; 150 | uint8_t threads; 151 | 152 | (void) memlimit; 153 | if (*enc_alg != hydro_pwhash_ENC_ALG) { 154 | return -1; 155 | } 156 | if (hydro_secretbox_decrypt(params, secretbox, 157 | hydro_secretbox_HEADERBYTES + hydro_pwhash_PARAMSBYTES, 158 | (uint64_t) *enc_alg, hydro_pwhash_CONTEXT, master_key) != 0) { 159 | return -1; 160 | } 161 | if (*hash_alg != hydro_pwhash_HASH_ALG || (opslimit = LOAD64_LE(opslimit_u8)) > opslimit_max || 162 | (memlimit = (size_t) LOAD64_LE(memlimit_u8)) > memlimit_max || 163 | (threads = *threads_u8) > threads_max) { 164 | return -1; 165 | } 166 | if (_hydro_pwhash_hash(computed_h, hydro_pwhash_HASHBYTES, salt, passwd, passwd_len, 167 | hydro_pwhash_CONTEXT, zero, opslimit, memlimit, threads) == 0 && 168 | hydro_equal(computed_h, h, hydro_pwhash_HASHBYTES) == 1) { 169 | return 0; 170 | } 171 | return -1; 172 | } 173 | 174 | int 175 | hydro_pwhash_verify(const uint8_t stored[hydro_pwhash_STOREDBYTES], const char *passwd, 176 | size_t passwd_len, const uint8_t master_key[hydro_pwhash_MASTERKEYBYTES], 177 | uint64_t opslimit_max, size_t memlimit_max, uint8_t threads_max) 178 | { 179 | uint8_t computed_h[hydro_pwhash_HASHBYTES]; 180 | int ret; 181 | 182 | ret = _hydro_pwhash_verify(computed_h, stored, passwd, passwd_len, master_key, opslimit_max, 183 | memlimit_max, threads_max); 184 | hydro_memzero(computed_h, sizeof computed_h); 185 | 186 | return ret; 187 | } 188 | 189 | int 190 | hydro_pwhash_derive_static_key(uint8_t *static_key, size_t static_key_len, 191 | const uint8_t stored[hydro_pwhash_STOREDBYTES], const char *passwd, 192 | size_t passwd_len, const char ctx[hydro_pwhash_CONTEXTBYTES], 193 | const uint8_t master_key[hydro_pwhash_MASTERKEYBYTES], 194 | uint64_t opslimit_max, size_t memlimit_max, uint8_t threads_max) 195 | { 196 | uint8_t computed_h[hydro_pwhash_HASHBYTES]; 197 | 198 | if (_hydro_pwhash_verify(computed_h, stored, passwd, passwd_len, master_key, opslimit_max, 199 | memlimit_max, threads_max) != 0) { 200 | hydro_memzero(computed_h, sizeof computed_h); 201 | return -1; 202 | } 203 | COMPILER_ASSERT(hydro_kdf_CONTEXTBYTES <= hydro_pwhash_CONTEXTBYTES); 204 | COMPILER_ASSERT(hydro_kdf_KEYBYTES <= hydro_pwhash_HASHBYTES); 205 | hydro_kdf_derive_from_key(static_key, static_key_len, 0, ctx, computed_h); 206 | hydro_memzero(computed_h, sizeof computed_h); 207 | 208 | return 0; 209 | } 210 | 211 | int 212 | hydro_pwhash_reencrypt(uint8_t stored[hydro_pwhash_STOREDBYTES], 213 | const uint8_t master_key[hydro_pwhash_MASTERKEYBYTES], 214 | const uint8_t new_master_key[hydro_pwhash_MASTERKEYBYTES]) 215 | { 216 | uint8_t *const enc_alg = &stored[0]; 217 | uint8_t *const secretbox = &enc_alg[hydro_pwhash_ENC_ALGBYTES]; 218 | uint8_t *const params = &secretbox[hydro_secretbox_HEADERBYTES]; 219 | 220 | if (*enc_alg != hydro_pwhash_ENC_ALG) { 221 | return -1; 222 | } 223 | if (hydro_secretbox_decrypt(secretbox, secretbox, 224 | hydro_secretbox_HEADERBYTES + hydro_pwhash_PARAMSBYTES, 225 | (uint64_t) *enc_alg, hydro_pwhash_CONTEXT, master_key) != 0) { 226 | return -1; 227 | } 228 | memmove(params, secretbox, hydro_pwhash_PARAMSBYTES); 229 | return hydro_secretbox_encrypt(secretbox, params, hydro_pwhash_PARAMSBYTES, (uint64_t) *enc_alg, 230 | hydro_pwhash_CONTEXT, new_master_key); 231 | } 232 | 233 | int 234 | hydro_pwhash_upgrade(uint8_t stored[hydro_pwhash_STOREDBYTES], 235 | const uint8_t master_key[hydro_pwhash_MASTERKEYBYTES], uint64_t opslimit, 236 | size_t memlimit, uint8_t threads) 237 | { 238 | uint8_t *const enc_alg = &stored[0]; 239 | uint8_t *const secretbox = &enc_alg[hydro_pwhash_ENC_ALGBYTES]; 240 | uint8_t *const params = &secretbox[hydro_secretbox_HEADERBYTES]; 241 | uint8_t *const hash_alg = ¶ms[0]; 242 | uint8_t *const threads_u8 = &hash_alg[hydro_pwhash_HASH_ALGBYTES]; 243 | uint8_t *const opslimit_u8 = &threads_u8[hydro_pwhash_THREADSBYTES]; 244 | uint8_t *const memlimit_u8 = &opslimit_u8[hydro_pwhash_OPSLIMITBYTES]; 245 | uint8_t *const salt = &memlimit_u8[hydro_pwhash_MEMLIMITBYTES]; 246 | uint8_t *const h = &salt[hydro_pwhash_SALTBYTES]; 247 | 248 | _hydro_attr_aligned_(16) uint8_t state[gimli_BLOCKBYTES]; 249 | uint64_t i; 250 | uint64_t opslimit_prev; 251 | 252 | if (*enc_alg != hydro_pwhash_ENC_ALG) { 253 | return -1; 254 | } 255 | if (hydro_secretbox_decrypt(secretbox, secretbox, 256 | hydro_secretbox_HEADERBYTES + hydro_pwhash_PARAMSBYTES, 257 | (uint64_t) *enc_alg, hydro_pwhash_CONTEXT, master_key) != 0) { 258 | return -1; 259 | } 260 | memmove(params, secretbox, hydro_pwhash_PARAMSBYTES); 261 | opslimit_prev = LOAD64_LE(opslimit_u8); 262 | if (*hash_alg != hydro_pwhash_HASH_ALG) { 263 | mem_zero(stored, hydro_pwhash_STOREDBYTES); 264 | return -1; 265 | } 266 | COMPILER_ASSERT(hydro_random_SEEDBYTES == gimli_CAPACITY); 267 | memcpy(state + gimli_RATE, h, hydro_random_SEEDBYTES); 268 | for (i = opslimit_prev; i < opslimit; i++) { 269 | mem_zero(state, gimli_RATE); 270 | STORE64_LE(state, i); 271 | gimli_core_u8(state, 0); 272 | } 273 | mem_zero(state, gimli_RATE); 274 | memcpy(h, state + gimli_RATE, hydro_random_SEEDBYTES); 275 | *threads_u8 = threads; 276 | STORE64_LE(opslimit_u8, opslimit); 277 | STORE64_LE(memlimit_u8, (uint64_t) memlimit); 278 | 279 | return hydro_secretbox_encrypt(secretbox, params, hydro_pwhash_PARAMSBYTES, (uint64_t) *enc_alg, 280 | hydro_pwhash_CONTEXT, master_key); 281 | } 282 | -------------------------------------------------------------------------------- /impl/random.h: -------------------------------------------------------------------------------- 1 | static TLS struct { 2 | _hydro_attr_aligned_(16) uint8_t state[gimli_BLOCKBYTES]; 3 | uint64_t counter; 4 | uint8_t initialized; 5 | uint8_t available; 6 | } hydro_random_context; 7 | 8 | #if defined(AVR) && !defined(__unix__) 9 | # include "random/avr.h" 10 | #elif (defined(ESP32) || defined(ESP8266)) && !defined(__unix__) 11 | # include "random/esp32.h" 12 | #elif defined(PARTICLE) && defined(PLATFORM_ID) && PLATFORM_ID > 2 && !defined(__unix__) 13 | # include "random/particle.h" 14 | #elif (defined(NRF52832_XXAA) || defined(NRF52832_XXAB)) && !defined(__unix__) 15 | # include "random/nrf52832.h" 16 | #elif defined(_WIN32) 17 | # include "random/windows.h" 18 | #elif defined(__wasi__) 19 | # include "random/wasi.h" 20 | #elif defined(__linux__) && defined(__KERNEL__) 21 | # include "random/linux_kernel.h" 22 | #elif defined(__unix__) 23 | # include "random/unix.h" 24 | #elif defined(TARGET_LIKE_MBED) 25 | # include "random/mbed.h" 26 | #elif defined(RIOT_VERSION) 27 | # include "random/riot.h" 28 | #elif defined(STM32F4) || defined(STM32L4) 29 | # include "random/stm32.h" 30 | #elif defined(__RTTHREAD__) 31 | # include "random/rtthread.h" 32 | #elif defined(CH32V30x_D8) || defined(CH32V30x_D8C) 33 | # include "random/ch32.h" 34 | #elif defined(CHIBIOS) 35 | # include "random/chibios.h" 36 | #else 37 | # error Unsupported platform 38 | #endif 39 | 40 | static void 41 | hydro_random_ensure_initialized(void) 42 | { 43 | if (hydro_random_context.initialized == 0) { 44 | if (hydro_random_init() != 0) { 45 | abort(); 46 | } 47 | gimli_core_u8(hydro_random_context.state, 0); 48 | hydro_random_ratchet(); 49 | hydro_random_context.initialized = 1; 50 | } 51 | } 52 | 53 | void 54 | hydro_random_ratchet(void) 55 | { 56 | mem_zero(hydro_random_context.state, gimli_RATE); 57 | STORE64_LE(hydro_random_context.state, hydro_random_context.counter); 58 | hydro_random_context.counter++; 59 | gimli_core_u8(hydro_random_context.state, 0); 60 | hydro_random_context.available = gimli_RATE; 61 | } 62 | 63 | uint32_t 64 | hydro_random_u32(void) 65 | { 66 | uint32_t v; 67 | 68 | hydro_random_ensure_initialized(); 69 | if (hydro_random_context.available < 4) { 70 | hydro_random_ratchet(); 71 | } 72 | memcpy(&v, &hydro_random_context.state[gimli_RATE - hydro_random_context.available], 4); 73 | hydro_random_context.available -= 4; 74 | 75 | return v; 76 | } 77 | 78 | uint32_t 79 | hydro_random_uniform(const uint32_t upper_bound) 80 | { 81 | uint32_t min; 82 | uint32_t r; 83 | 84 | if (upper_bound < 2U) { 85 | return 0; 86 | } 87 | min = (1U + ~upper_bound) % upper_bound; /* = 2**32 mod upper_bound */ 88 | do { 89 | r = hydro_random_u32(); 90 | } while (r < min); 91 | /* r is now clamped to a set whose size mod upper_bound == 0 92 | * the worst case (2**31+1) requires 2 attempts on average */ 93 | 94 | return r % upper_bound; 95 | } 96 | 97 | void 98 | hydro_random_buf(void *out, size_t out_len) 99 | { 100 | uint8_t *p = (uint8_t *) out; 101 | size_t i; 102 | size_t leftover; 103 | 104 | hydro_random_ensure_initialized(); 105 | for (i = 0; i < out_len / gimli_RATE; i++) { 106 | gimli_core_u8(hydro_random_context.state, 0); 107 | memcpy(p + i * gimli_RATE, hydro_random_context.state, gimli_RATE); 108 | } 109 | leftover = out_len % gimli_RATE; 110 | if (leftover != 0) { 111 | gimli_core_u8(hydro_random_context.state, 0); 112 | mem_cpy(p + i * gimli_RATE, hydro_random_context.state, leftover); 113 | } 114 | hydro_random_ratchet(); 115 | } 116 | 117 | void 118 | hydro_random_buf_deterministic(void *out, size_t out_len, 119 | const uint8_t seed[hydro_random_SEEDBYTES]) 120 | { 121 | static const uint8_t prefix[] = { 7, 'd', 'r', 'b', 'g', '2', '5', '6' }; 122 | _hydro_attr_aligned_(16) uint8_t state[gimli_BLOCKBYTES]; 123 | uint8_t * p = (uint8_t *) out; 124 | size_t i; 125 | size_t leftover; 126 | 127 | mem_zero(state, gimli_BLOCKBYTES); 128 | COMPILER_ASSERT(sizeof prefix + 8 <= gimli_RATE); 129 | memcpy(state, prefix, sizeof prefix); 130 | STORE64_LE(state + sizeof prefix, (uint64_t) out_len); 131 | gimli_core_u8(state, 1); 132 | COMPILER_ASSERT(hydro_random_SEEDBYTES == gimli_RATE * 2); 133 | mem_xor(state, seed, gimli_RATE); 134 | gimli_core_u8(state, 2); 135 | mem_xor(state, seed + gimli_RATE, gimli_RATE); 136 | gimli_core_u8(state, 2); 137 | for (i = 0; i < out_len / gimli_RATE; i++) { 138 | gimli_core_u8(state, 0); 139 | memcpy(p + i * gimli_RATE, state, gimli_RATE); 140 | } 141 | leftover = out_len % gimli_RATE; 142 | if (leftover != 0) { 143 | gimli_core_u8(state, 0); 144 | mem_cpy(p + i * gimli_RATE, state, leftover); 145 | } 146 | } 147 | 148 | void 149 | hydro_random_reseed(void) 150 | { 151 | hydro_random_context.initialized = 0; 152 | hydro_random_ensure_initialized(); 153 | } 154 | -------------------------------------------------------------------------------- /impl/random/avr.h: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | static bool 4 | hydro_random_rbit(uint16_t x) 5 | { 6 | uint8_t x8; 7 | 8 | x8 = ((uint8_t) (x >> 8)) ^ (uint8_t) x; 9 | x8 = (x8 >> 4) ^ (x8 & 0xf); 10 | x8 = (x8 >> 2) ^ (x8 & 0x3); 11 | x8 = (x8 >> 1) ^ x8; 12 | 13 | return (bool) (x8 & 1); 14 | } 15 | 16 | static int 17 | hydro_random_init(void) 18 | { 19 | const char ctx[hydro_hash_CONTEXTBYTES] = { 'h', 'y', 'd', 'r', 'o', 'P', 'R', 'G' }; 20 | hydro_hash_state st; 21 | uint16_t ebits = 0; 22 | uint16_t tc; 23 | bool a, b; 24 | 25 | cli(); 26 | MCUSR = 0; 27 | WDTCSR |= _BV(WDCE) | _BV(WDE); 28 | WDTCSR = _BV(WDIE); 29 | sei(); 30 | 31 | hydro_hash_init(&st, ctx, NULL); 32 | 33 | while (ebits < 256) { 34 | delay(1); 35 | tc = TCNT1; 36 | hydro_hash_update(&st, (const uint8_t *) &tc, sizeof tc); 37 | a = hydro_random_rbit(tc); 38 | delay(1); 39 | tc = TCNT1; 40 | b = hydro_random_rbit(tc); 41 | hydro_hash_update(&st, (const uint8_t *) &tc, sizeof tc); 42 | if (a == b) { 43 | continue; 44 | } 45 | hydro_hash_update(&st, (const uint8_t *) &b, sizeof b); 46 | ebits++; 47 | } 48 | 49 | cli(); 50 | MCUSR = 0; 51 | WDTCSR |= _BV(WDCE) | _BV(WDE); 52 | WDTCSR = 0; 53 | sei(); 54 | 55 | hydro_hash_final(&st, hydro_random_context.state, sizeof hydro_random_context.state); 56 | hydro_random_context.counter = ~LOAD64_LE(hydro_random_context.state); 57 | 58 | return 0; 59 | } 60 | 61 | ISR(WDT_vect) { } 62 | -------------------------------------------------------------------------------- /impl/random/ch32.h: -------------------------------------------------------------------------------- 1 | #if defined(CH32V30x_D8) || defined(CH32V30x_D8C) 2 | # include 3 | #else 4 | # error CH32 implementation missing! 5 | #endif 6 | 7 | static int 8 | hydro_random_init(void) 9 | { 10 | const char ctx[hydro_hash_CONTEXTBYTES] = { 'h', 'y', 'd', 'r', 'o', 'P', 'R', 'G' }; 11 | hydro_hash_state st; 12 | uint16_t ebits = 0; 13 | 14 | // Enable RNG clock source 15 | RCC_AHBPeriphClockCmd(RCC_AHBPeriph_RNG, ENABLE); 16 | 17 | // RNG Peripheral enable 18 | RNG_Cmd(ENABLE); 19 | 20 | hydro_hash_init(&st, ctx, NULL); 21 | 22 | while (ebits < 256) { 23 | while (RNG_GetFlagStatus(RNG_FLAG_DRDY) == RESET); 24 | uint32_t r = RNG_GetRandomNumber(); 25 | 26 | hydro_hash_update(&st, (const uint32_t *) &r, sizeof r); 27 | ebits += 32; 28 | } 29 | 30 | hydro_hash_final(&st, hydro_random_context.state, sizeof hydro_random_context.state); 31 | hydro_random_context.counter = ~LOAD64_LE(hydro_random_context.state); 32 | 33 | return 0; 34 | } 35 | -------------------------------------------------------------------------------- /impl/random/chibios.h: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | /* Declarations from ChibiOS HAL TRNG module */ 6 | 7 | extern struct hal_trng_driver TRNGD1; 8 | 9 | void trngStart(struct hal_trng_driver *, const void *); 10 | bool trngGenerate(struct hal_trng_driver *, size_t size, uint8_t *); 11 | 12 | static int 13 | hydro_random_init(void) 14 | { 15 | trngStart(&TRNGD1, NULL); 16 | 17 | if (trngGenerate(&TRNGD1, sizeof hydro_random_context.state, 18 | hydro_random_context.state)) { 19 | return -1; 20 | } 21 | hydro_random_context.counter = ~LOAD64_LE(hydro_random_context.state); 22 | 23 | return 0; 24 | } 25 | -------------------------------------------------------------------------------- /impl/random/esp32.h: -------------------------------------------------------------------------------- 1 | // Important: RF *must* be activated on ESP board 2 | // https://techtutorialsx.com/2017/12/22/esp32-arduino-random-number-generation/ 3 | #ifdef ESP32 4 | #include 5 | #endif 6 | 7 | #ifdef ARDUINO 8 | #include 9 | #endif 10 | 11 | static int 12 | hydro_random_init(void) 13 | { 14 | const char ctx[hydro_hash_CONTEXTBYTES] = { 'h', 'y', 'd', 'r', 'o', 'P', 'R', 'G' }; 15 | hydro_hash_state st; 16 | uint16_t ebits = 0; 17 | 18 | hydro_hash_init(&st, ctx, NULL); 19 | 20 | while (ebits < 256) { 21 | uint32_t r = esp_random(); 22 | 23 | delay(10); 24 | hydro_hash_update(&st, (const uint32_t *) &r, sizeof r); 25 | ebits += 32; 26 | } 27 | 28 | hydro_hash_final(&st, hydro_random_context.state, sizeof hydro_random_context.state); 29 | hydro_random_context.counter = ~LOAD64_LE(hydro_random_context.state); 30 | 31 | return 0; 32 | } 33 | -------------------------------------------------------------------------------- /impl/random/linux_kernel.h: -------------------------------------------------------------------------------- 1 | static int 2 | hydro_random_init(void) 3 | { 4 | get_random_bytes(&hydro_random_context.state, 5 | sizeof hydro_random_context.state); 6 | hydro_random_context.counter = ~LOAD64_LE(hydro_random_context.state); 7 | 8 | return 0; 9 | } 10 | -------------------------------------------------------------------------------- /impl/random/mbed.h: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #if defined(MBEDTLS_ENTROPY_C) 5 | 6 | static int 7 | hydro_random_init(void) 8 | { 9 | mbedtls_entropy_context entropy; 10 | uint16_t pos = 0; 11 | 12 | mbedtls_entropy_init(&entropy); 13 | 14 | // Pull data directly out of the entropy pool for the state, as it's small enough. 15 | if (mbedtls_entropy_func(&entropy, (uint8_t *) &hydro_random_context.counter, 16 | sizeof hydro_random_context.counter) != 0) { 17 | return -1; 18 | } 19 | // mbedtls_entropy_func can't provide more than MBEDTLS_ENTROPY_BLOCK_SIZE in one go. 20 | // This constant depends of mbedTLS configuration (whether the PRNG is backed by SHA256/SHA512 21 | // at this time) Therefore, if necessary, we get entropy multiple times. 22 | 23 | do { 24 | const uint8_t dataLeftToConsume = gimli_BLOCKBYTES - pos; 25 | const uint8_t currentChunkSize = (dataLeftToConsume > MBEDTLS_ENTROPY_BLOCK_SIZE) 26 | ? MBEDTLS_ENTROPY_BLOCK_SIZE 27 | : dataLeftToConsume; 28 | 29 | // Forces mbedTLS to fetch fresh entropy, then get some to feed libhydrogen. 30 | if (mbedtls_entropy_gather(&entropy) != 0 || 31 | mbedtls_entropy_func(&entropy, &hydro_random_context.state[pos], currentChunkSize) != 32 | 0) { 33 | return -1; 34 | } 35 | pos += MBEDTLS_ENTROPY_BLOCK_SIZE; 36 | } while (pos < gimli_BLOCKBYTES); 37 | 38 | mbedtls_entropy_free(&entropy); 39 | 40 | return 0; 41 | } 42 | #else 43 | #error Need an entropy source 44 | #endif 45 | -------------------------------------------------------------------------------- /impl/random/nrf52832.h: -------------------------------------------------------------------------------- 1 | // Important: The SoftDevice *must* be activated to enable reading from the RNG 2 | // http://infocenter.nordicsemi.com/index.jsp?topic=%2Fcom.nordic.infocenter.nrf52832.ps.v1.1%2Frng.html 3 | 4 | #include 5 | 6 | static int 7 | hydro_random_init(void) 8 | { 9 | const char ctx[hydro_hash_CONTEXTBYTES] = { 'h', 'y', 'd', 'r', 'o', 'P', 'R', 'G' }; 10 | hydro_hash_state st; 11 | const uint8_t total_bytes = 32; 12 | uint8_t remaining_bytes = total_bytes; 13 | uint8_t available_bytes; 14 | uint8_t rand_buffer[32]; 15 | 16 | hydro_hash_init(&st, ctx, NULL); 17 | 18 | for (;;) { 19 | if (sd_rand_application_bytes_available_get(&available_bytes) != NRF_SUCCESS) { 20 | return -1; 21 | } 22 | if (available_bytes > 0) { 23 | if (available_bytes > remaining_bytes) { 24 | available_bytes = remaining_bytes; 25 | } 26 | if (sd_rand_application_vector_get(rand_buffer, available_bytes) != NRF_SUCCESS) { 27 | return -1; 28 | } 29 | hydro_hash_update(&st, rand_buffer, total_bytes); 30 | remaining_bytes -= available_bytes; 31 | } 32 | if (remaining_bytes <= 0) { 33 | break; 34 | } 35 | delay(10); 36 | } 37 | hydro_hash_final(&st, hydro_random_context.state, sizeof hydro_random_context.state); 38 | hydro_random_context.counter = ~LOAD64_LE(hydro_random_context.state); 39 | 40 | return 0; 41 | } 42 | -------------------------------------------------------------------------------- /impl/random/particle.h: -------------------------------------------------------------------------------- 1 | // Note: All particle platforms except for the Spark Core have a HW RNG. Only allow building on 2 | // supported platforms for now. PLATFORM_ID definitions: 3 | // https://github.com/particle-iot/device-os/blob/mesh-develop/hal/shared/platforms.h 4 | 5 | #include 6 | 7 | static int 8 | hydro_random_init(void) 9 | { 10 | const char ctx[hydro_hash_CONTEXTBYTES] = { 'h', 'y', 'd', 'r', 'o', 'P', 'R', 'G' }; 11 | hydro_hash_state st; 12 | uint16_t ebits = 0; 13 | 14 | hydro_hash_init(&st, ctx, NULL); 15 | 16 | while (ebits < 256) { 17 | uint32_t r = HAL_RNG_GetRandomNumber(); 18 | hydro_hash_update(&st, (const uint32_t *) &r, sizeof r); 19 | ebits += 32; 20 | } 21 | 22 | hydro_hash_final(&st, hydro_random_context.state, sizeof hydro_random_context.state); 23 | hydro_random_context.counter = ~LOAD64_LE(hydro_random_context.state); 24 | 25 | return 0; 26 | } 27 | -------------------------------------------------------------------------------- /impl/random/riot.h: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | static int 4 | hydro_random_init(void) 5 | { 6 | random_bytes(hydro_random_context.state, sizeof(hydro_random_context.state)); 7 | hydro_random_context.counter = ~LOAD64_LE(hydro_random_context.state); 8 | 9 | return 0; 10 | } 11 | -------------------------------------------------------------------------------- /impl/random/rtthread.h: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #define DBG_TAG "libhydrogen" 5 | #define DBG_LVL DBG_LOG 6 | #include 7 | 8 | static int 9 | hydrogen_init(void) { 10 | if (hydro_init() != 0) { 11 | abort(); 12 | } 13 | LOG_I("libhydrogen initialized"); 14 | return 0; 15 | } 16 | INIT_APP_EXPORT(hydrogen_init); 17 | 18 | static int 19 | hydro_random_init(void) 20 | { 21 | const char ctx[hydro_hash_CONTEXTBYTES] = { 'h', 'y', 'd', 'r', 'o', 'P', 'R', 'G' }; 22 | hydro_hash_state st; 23 | uint16_t ebits = 0; 24 | 25 | hydro_hash_init(&st, ctx, NULL); 26 | 27 | while (ebits < 256) { 28 | uint32_t r = rt_hwcrypto_rng_update(); 29 | hydro_hash_update(&st, (const uint32_t *) &r, sizeof r); 30 | ebits += 32; 31 | } 32 | 33 | hydro_hash_final(&st, hydro_random_context.state, sizeof hydro_random_context.state); 34 | hydro_random_context.counter = ~LOAD64_LE(hydro_random_context.state); 35 | 36 | return 0; 37 | } 38 | -------------------------------------------------------------------------------- /impl/random/stm32.h: -------------------------------------------------------------------------------- 1 | 2 | // Use hardware RNG peripheral 3 | // Working with HAL, LL Driver (untested) 4 | #if defined(STM32F4) || defined(STM32L4) 5 | 6 | # if defined(STM32F4) 7 | # include "stm32f4xx.h" 8 | # elif defined(STM32L4) 9 | # include "stm32l4xx_hal_rng.h" 10 | 11 | static RNG_HandleTypeDef RngHandle; 12 | # endif 13 | 14 | static int 15 | hydro_random_init(void) 16 | { 17 | const char ctx[hydro_hash_CONTEXTBYTES] = { 'h', 'y', 'd', 'r', 'o', 'P', 'R', 'G' }; 18 | hydro_hash_state st; 19 | uint16_t ebits = 0; 20 | 21 | __IO uint32_t tmpreg; 22 | 23 | # if defined(STM32F4) 24 | // Enable RNG clock source 25 | SET_BIT(RCC->AHB2ENR, RCC_AHB2ENR_RNGEN); 26 | 27 | // Delay after an RCC peripheral clock enabling 28 | tmpreg = READ_BIT(RCC->AHB2ENR, RCC_AHB2ENR_RNGEN); 29 | UNUSED(tmpreg); 30 | 31 | // RNG Peripheral enable 32 | SET_BIT(RNG->CR, RNG_CR_RNGEN); 33 | # elif defined(STM32L4) 34 | RngHandle.Instance = RNG; 35 | HAL_RNG_Init(&RngHandle); 36 | # endif 37 | 38 | hydro_hash_init(&st, ctx, NULL); 39 | 40 | while (ebits < 256) { 41 | uint32_t r = 0; 42 | # if defined(STM32F4) 43 | while (!(READ_BIT(RNG->SR, RNG_SR_DRDY))) { 44 | } 45 | 46 | r = RNG->DR; 47 | # elif defined(STM32L4) 48 | if (HAL_RNG_GenerateRandomNumber(&RngHandle, &r) != HAL_OK) { 49 | continue; 50 | } 51 | # endif 52 | hydro_hash_update(&st, (const uint32_t *) &r, sizeof r); 53 | ebits += 32; 54 | } 55 | 56 | hydro_hash_final(&st, hydro_random_context.state, sizeof hydro_random_context.state); 57 | hydro_random_context.counter = ~LOAD64_LE(hydro_random_context.state); 58 | 59 | return 0; 60 | } 61 | #else 62 | # error SMT32 implementation missing! 63 | #endif 64 | -------------------------------------------------------------------------------- /impl/random/unix.h: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #ifdef __linux__ 4 | #include 5 | #endif 6 | #include 7 | #include 8 | 9 | #ifdef __linux__ 10 | static int 11 | hydro_random_block_on_dev_random(void) 12 | { 13 | struct pollfd pfd; 14 | int fd; 15 | int pret; 16 | 17 | fd = open("/dev/random", O_RDONLY); 18 | if (fd == -1) { 19 | return 0; 20 | } 21 | pfd.fd = fd; 22 | pfd.events = POLLIN; 23 | pfd.revents = 0; 24 | do { 25 | pret = poll(&pfd, 1, -1); 26 | } while (pret < 0 && (errno == EINTR || errno == EAGAIN)); 27 | if (pret != 1) { 28 | (void) close(fd); 29 | errno = EIO; 30 | return -1; 31 | } 32 | return close(fd); 33 | } 34 | #endif 35 | 36 | static ssize_t 37 | hydro_random_safe_read(const int fd, void *const buf_, size_t len) 38 | { 39 | unsigned char *buf = (unsigned char *) buf_; 40 | ssize_t readnb; 41 | 42 | do { 43 | while ((readnb = read(fd, buf, len)) < (ssize_t) 0 && (errno == EINTR || errno == EAGAIN)) { 44 | } 45 | if (readnb < (ssize_t) 0) { 46 | return readnb; 47 | } 48 | if (readnb == (ssize_t) 0) { 49 | break; 50 | } 51 | len -= (size_t) readnb; 52 | buf += readnb; 53 | } while (len > (ssize_t) 0); 54 | 55 | return (ssize_t) (buf - (unsigned char *) buf_); 56 | } 57 | 58 | static int 59 | hydro_random_init(void) 60 | { 61 | uint8_t tmp[gimli_BLOCKBYTES + 8]; 62 | int fd; 63 | int ret = -1; 64 | 65 | #ifdef __linux__ 66 | if (hydro_random_block_on_dev_random() != 0) { 67 | return -1; 68 | } 69 | #endif 70 | do { 71 | fd = open("/dev/urandom", O_RDONLY); 72 | if (fd == -1 && errno != EINTR) { 73 | return -1; 74 | } 75 | } while (fd == -1); 76 | if (hydro_random_safe_read(fd, tmp, sizeof tmp) == (ssize_t) sizeof tmp) { 77 | memcpy(hydro_random_context.state, tmp, gimli_BLOCKBYTES); 78 | memcpy(&hydro_random_context.counter, tmp + gimli_BLOCKBYTES, 8); 79 | hydro_memzero(tmp, sizeof tmp); 80 | ret = 0; 81 | } 82 | ret |= close(fd); 83 | 84 | return ret; 85 | } 86 | -------------------------------------------------------------------------------- /impl/random/wasi.h: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | static int 4 | hydro_random_init(void) 5 | { 6 | if (getentropy(hydro_random_context.state, sizeof hydro_random_context.state) != 0) { 7 | return -1; 8 | } 9 | hydro_random_context.counter = ~LOAD64_LE(hydro_random_context.state); 10 | 11 | return 0; 12 | } 13 | -------------------------------------------------------------------------------- /impl/random/windows.h: -------------------------------------------------------------------------------- 1 | #include 2 | #define RtlGenRandom SystemFunction036 3 | #if defined(__cplusplus) 4 | extern "C" 5 | #endif 6 | BOOLEAN NTAPI 7 | RtlGenRandom(PVOID RandomBuffer, ULONG RandomBufferLength); 8 | #pragma comment(lib, "advapi32.lib") 9 | 10 | static int 11 | hydro_random_init(void) 12 | { 13 | if (!RtlGenRandom((PVOID) hydro_random_context.state, 14 | (ULONG) sizeof hydro_random_context.state)) { 15 | return -1; 16 | } 17 | hydro_random_context.counter = ~LOAD64_LE(hydro_random_context.state); 18 | 19 | return 0; 20 | } 21 | -------------------------------------------------------------------------------- /impl/secretbox.h: -------------------------------------------------------------------------------- 1 | #define hydro_secretbox_IVBYTES 20 2 | #define hydro_secretbox_SIVBYTES 20 3 | #define hydro_secretbox_MACBYTES 16 4 | 5 | void 6 | hydro_secretbox_keygen(uint8_t key[hydro_secretbox_KEYBYTES]) 7 | { 8 | hydro_random_buf(key, hydro_secretbox_KEYBYTES); 9 | } 10 | 11 | static void 12 | hydro_secretbox_xor_enc(uint8_t buf[gimli_BLOCKBYTES], uint8_t *out, const uint8_t *in, 13 | size_t inlen) 14 | { 15 | size_t i; 16 | size_t leftover; 17 | 18 | for (i = 0; i < inlen / gimli_RATE; i++) { 19 | mem_xor2(&out[i * gimli_RATE], &in[i * gimli_RATE], buf, gimli_RATE); 20 | memcpy(buf, &out[i * gimli_RATE], gimli_RATE); 21 | gimli_core_u8(buf, gimli_TAG_PAYLOAD); 22 | } 23 | leftover = inlen % gimli_RATE; 24 | if (leftover != 0) { 25 | mem_xor2(&out[i * gimli_RATE], &in[i * gimli_RATE], buf, leftover); 26 | mem_cpy(buf, &out[i * gimli_RATE], leftover); 27 | } 28 | gimli_pad_u8(buf, leftover, gimli_DOMAIN_AEAD); 29 | gimli_core_u8(buf, gimli_TAG_PAYLOAD); 30 | } 31 | 32 | static void 33 | hydro_secretbox_xor_dec(uint8_t buf[gimli_BLOCKBYTES], uint8_t *out, const uint8_t *in, 34 | size_t inlen) 35 | { 36 | size_t i; 37 | size_t leftover; 38 | 39 | for (i = 0; i < inlen / gimli_RATE; i++) { 40 | mem_xor2(&out[i * gimli_RATE], &in[i * gimli_RATE], buf, gimli_RATE); 41 | memcpy(buf, &in[i * gimli_RATE], gimli_RATE); 42 | gimli_core_u8(buf, gimli_TAG_PAYLOAD); 43 | } 44 | leftover = inlen % gimli_RATE; 45 | if (leftover != 0) { 46 | mem_xor2(&out[i * gimli_RATE], &in[i * gimli_RATE], buf, leftover); 47 | mem_cpy(buf, &in[i * gimli_RATE], leftover); 48 | } 49 | gimli_pad_u8(buf, leftover, gimli_DOMAIN_AEAD); 50 | gimli_core_u8(buf, gimli_TAG_PAYLOAD); 51 | } 52 | 53 | static void 54 | hydro_secretbox_setup(uint8_t buf[gimli_BLOCKBYTES], uint64_t msg_id, 55 | const char ctx[hydro_secretbox_CONTEXTBYTES], 56 | const uint8_t key[hydro_secretbox_KEYBYTES], 57 | const uint8_t iv[hydro_secretbox_IVBYTES], uint8_t key_tag) 58 | { 59 | static const uint8_t prefix[] = { 6, 's', 'b', 'x', '2', '5', '6', 8 }; 60 | uint8_t msg_id_le[8]; 61 | 62 | mem_zero(buf, gimli_BLOCKBYTES); 63 | COMPILER_ASSERT(hydro_secretbox_CONTEXTBYTES == 8); 64 | COMPILER_ASSERT(sizeof prefix + hydro_secretbox_CONTEXTBYTES <= gimli_RATE); 65 | memcpy(buf, prefix, sizeof prefix); 66 | memcpy(buf + sizeof prefix, ctx, hydro_secretbox_CONTEXTBYTES); 67 | COMPILER_ASSERT(sizeof prefix + hydro_secretbox_CONTEXTBYTES == gimli_RATE); 68 | gimli_core_u8(buf, gimli_TAG_HEADER); 69 | 70 | COMPILER_ASSERT(hydro_secretbox_KEYBYTES == 2 * gimli_RATE); 71 | mem_xor(buf, key, gimli_RATE); 72 | gimli_core_u8(buf, key_tag); 73 | mem_xor(buf, key + gimli_RATE, gimli_RATE); 74 | gimli_core_u8(buf, key_tag); 75 | 76 | COMPILER_ASSERT(hydro_secretbox_IVBYTES < gimli_RATE * 2); 77 | buf[0] ^= hydro_secretbox_IVBYTES; 78 | mem_xor(&buf[1], iv, gimli_RATE - 1); 79 | gimli_core_u8(buf, gimli_TAG_HEADER); 80 | mem_xor(buf, iv + gimli_RATE - 1, hydro_secretbox_IVBYTES - (gimli_RATE - 1)); 81 | STORE64_LE(msg_id_le, msg_id); 82 | COMPILER_ASSERT(hydro_secretbox_IVBYTES - gimli_RATE + 8 <= gimli_RATE); 83 | mem_xor(buf + hydro_secretbox_IVBYTES - gimli_RATE, msg_id_le, 8); 84 | gimli_core_u8(buf, gimli_TAG_HEADER); 85 | } 86 | 87 | static void 88 | hydro_secretbox_final(uint8_t *buf, const uint8_t key[hydro_secretbox_KEYBYTES], uint8_t tag) 89 | { 90 | COMPILER_ASSERT(hydro_secretbox_KEYBYTES == gimli_CAPACITY); 91 | mem_xor(buf + gimli_RATE, key, hydro_secretbox_KEYBYTES); 92 | gimli_core_u8(buf, tag); 93 | mem_xor(buf + gimli_RATE, key, hydro_secretbox_KEYBYTES); 94 | gimli_core_u8(buf, tag); 95 | } 96 | 97 | static int 98 | hydro_secretbox_encrypt_iv(uint8_t *c, const void *m_, size_t mlen, uint64_t msg_id, 99 | const char ctx[hydro_secretbox_CONTEXTBYTES], 100 | const uint8_t key[hydro_secretbox_KEYBYTES], 101 | const uint8_t iv[hydro_secretbox_IVBYTES]) 102 | { 103 | _hydro_attr_aligned_(16) uint32_t state[gimli_BLOCKBYTES / 4]; 104 | uint8_t * buf = (uint8_t *) (void *) state; 105 | const uint8_t * m = (const uint8_t *) m_; 106 | uint8_t * siv = &c[0]; 107 | uint8_t * mac = &c[hydro_secretbox_SIVBYTES]; 108 | uint8_t * ct = &c[hydro_secretbox_SIVBYTES + hydro_secretbox_MACBYTES]; 109 | size_t i; 110 | size_t leftover; 111 | 112 | if (c == m) { 113 | memmove(c + hydro_secretbox_HEADERBYTES, m, mlen); 114 | m = c + hydro_secretbox_HEADERBYTES; 115 | } 116 | 117 | /* first pass: compute the SIV */ 118 | 119 | hydro_secretbox_setup(buf, msg_id, ctx, key, iv, gimli_TAG_KEY0); 120 | for (i = 0; i < mlen / gimli_RATE; i++) { 121 | mem_xor(buf, &m[i * gimli_RATE], gimli_RATE); 122 | gimli_core_u8(buf, gimli_TAG_PAYLOAD); 123 | } 124 | leftover = mlen % gimli_RATE; 125 | if (leftover != 0) { 126 | mem_xor(buf, &m[i * gimli_RATE], leftover); 127 | } 128 | gimli_pad_u8(buf, leftover, gimli_DOMAIN_XOF); 129 | gimli_core_u8(buf, gimli_TAG_PAYLOAD); 130 | 131 | hydro_secretbox_final(buf, key, gimli_TAG_FINAL0); 132 | COMPILER_ASSERT(hydro_secretbox_SIVBYTES <= gimli_CAPACITY); 133 | memcpy(siv, buf + gimli_RATE, hydro_secretbox_SIVBYTES); 134 | 135 | /* second pass: encrypt the message, mix the key, squeeze an extra block for 136 | * the MAC */ 137 | 138 | COMPILER_ASSERT(hydro_secretbox_SIVBYTES == hydro_secretbox_IVBYTES); 139 | hydro_secretbox_setup(buf, msg_id, ctx, key, siv, gimli_TAG_KEY); 140 | hydro_secretbox_xor_enc(buf, ct, m, mlen); 141 | 142 | hydro_secretbox_final(buf, key, gimli_TAG_FINAL); 143 | COMPILER_ASSERT(hydro_secretbox_MACBYTES <= gimli_CAPACITY); 144 | memcpy(mac, buf + gimli_RATE, hydro_secretbox_MACBYTES); 145 | 146 | return 0; 147 | } 148 | 149 | void 150 | hydro_secretbox_probe_create(uint8_t probe[hydro_secretbox_PROBEBYTES], const uint8_t *c, 151 | size_t c_len, const char ctx[hydro_secretbox_CONTEXTBYTES], 152 | const uint8_t key[hydro_secretbox_KEYBYTES]) 153 | { 154 | const uint8_t *mac; 155 | 156 | if (c_len < hydro_secretbox_HEADERBYTES) { 157 | abort(); 158 | } 159 | mac = &c[hydro_secretbox_SIVBYTES]; 160 | COMPILER_ASSERT(hydro_secretbox_CONTEXTBYTES >= hydro_hash_CONTEXTBYTES); 161 | COMPILER_ASSERT(hydro_secretbox_KEYBYTES >= hydro_hash_KEYBYTES); 162 | hydro_hash_hash(probe, hydro_secretbox_PROBEBYTES, mac, hydro_secretbox_MACBYTES, ctx, key); 163 | } 164 | 165 | int 166 | hydro_secretbox_probe_verify(const uint8_t probe[hydro_secretbox_PROBEBYTES], const uint8_t *c, 167 | size_t c_len, const char ctx[hydro_secretbox_CONTEXTBYTES], 168 | const uint8_t key[hydro_secretbox_KEYBYTES]) 169 | { 170 | uint8_t computed_probe[hydro_secretbox_PROBEBYTES]; 171 | const uint8_t *mac; 172 | 173 | if (c_len < hydro_secretbox_HEADERBYTES) { 174 | return -1; 175 | } 176 | mac = &c[hydro_secretbox_SIVBYTES]; 177 | hydro_hash_hash(computed_probe, hydro_secretbox_PROBEBYTES, mac, hydro_secretbox_MACBYTES, ctx, 178 | key); 179 | if (hydro_equal(computed_probe, probe, hydro_secretbox_PROBEBYTES) == 1) { 180 | return 0; 181 | } 182 | hydro_memzero(computed_probe, hydro_secretbox_PROBEBYTES); 183 | return -1; 184 | } 185 | 186 | int 187 | hydro_secretbox_encrypt(uint8_t *c, const void *m_, size_t mlen, uint64_t msg_id, 188 | const char ctx[hydro_secretbox_CONTEXTBYTES], 189 | const uint8_t key[hydro_secretbox_KEYBYTES]) 190 | { 191 | uint8_t iv[hydro_secretbox_IVBYTES]; 192 | 193 | hydro_random_buf(iv, sizeof iv); 194 | 195 | return hydro_secretbox_encrypt_iv(c, m_, mlen, msg_id, ctx, key, iv); 196 | } 197 | 198 | int 199 | hydro_secretbox_decrypt(void *m_, const uint8_t *c, size_t clen, uint64_t msg_id, 200 | const char ctx[hydro_secretbox_CONTEXTBYTES], 201 | const uint8_t key[hydro_secretbox_KEYBYTES]) 202 | { 203 | _hydro_attr_aligned_(16) uint32_t state[gimli_BLOCKBYTES / 4]; 204 | uint32_t pub_mac[hydro_secretbox_MACBYTES / 4]; 205 | uint8_t * buf = (uint8_t *) (void *) state; 206 | const uint8_t * siv; 207 | const uint8_t * mac; 208 | const uint8_t * ct; 209 | uint8_t * m = (uint8_t *) m_; 210 | size_t mlen; 211 | uint32_t cv; 212 | 213 | if (clen < hydro_secretbox_HEADERBYTES) { 214 | return -1; 215 | } 216 | siv = &c[0]; 217 | mac = &c[hydro_secretbox_SIVBYTES]; 218 | ct = &c[hydro_secretbox_SIVBYTES + hydro_secretbox_MACBYTES]; 219 | 220 | mlen = clen - hydro_secretbox_HEADERBYTES; 221 | memcpy(pub_mac, mac, sizeof pub_mac); 222 | COMPILER_ASSERT(hydro_secretbox_SIVBYTES == hydro_secretbox_IVBYTES); 223 | hydro_secretbox_setup(buf, msg_id, ctx, key, siv, gimli_TAG_KEY); 224 | hydro_secretbox_xor_dec(buf, m, ct, mlen); 225 | 226 | hydro_secretbox_final(buf, key, gimli_TAG_FINAL); 227 | COMPILER_ASSERT(hydro_secretbox_MACBYTES <= gimli_CAPACITY); 228 | COMPILER_ASSERT(gimli_RATE % 4 == 0); 229 | cv = hydro_mem_ct_cmp_u32(state + gimli_RATE / 4, pub_mac, hydro_secretbox_MACBYTES / 4); 230 | hydro_mem_ct_zero_u32(state, gimli_BLOCKBYTES / 4); 231 | if (cv != 0) { 232 | mem_zero(m, mlen); 233 | return -1; 234 | } 235 | return 0; 236 | } 237 | -------------------------------------------------------------------------------- /impl/sign.h: -------------------------------------------------------------------------------- 1 | #define hydro_sign_CHALLENGEBYTES 32 2 | #define hydro_sign_NONCEBYTES 32 3 | #define hydro_sign_PREHASHBYTES 64 4 | 5 | static void 6 | hydro_sign_p2(uint8_t sig[hydro_x25519_BYTES], const uint8_t challenge[hydro_sign_CHALLENGEBYTES], 7 | const uint8_t eph_sk[hydro_x25519_BYTES], const uint8_t sk[hydro_x25519_BYTES]) 8 | { 9 | hydro_x25519_scalar_t scalar1, scalar2, scalar3; 10 | 11 | COMPILER_ASSERT(hydro_sign_CHALLENGEBYTES == hydro_x25519_BYTES); 12 | hydro_x25519_swapin(scalar1, eph_sk); 13 | hydro_x25519_swapin(scalar2, sk); 14 | hydro_x25519_swapin(scalar3, challenge); 15 | hydro_x25519_sc_montmul(scalar1, scalar2, scalar3); 16 | mem_zero(scalar2, sizeof scalar2); 17 | hydro_x25519_sc_montmul(scalar2, scalar1, hydro_x25519_sc_r2); 18 | hydro_x25519_swapout(sig, scalar2); 19 | } 20 | 21 | static void 22 | hydro_sign_challenge(uint8_t challenge[hydro_sign_CHALLENGEBYTES], 23 | const uint8_t nonce[hydro_sign_NONCEBYTES], 24 | const uint8_t pk[hydro_sign_PUBLICKEYBYTES], 25 | const uint8_t prehash[hydro_sign_PREHASHBYTES]) 26 | { 27 | hydro_hash_state st; 28 | 29 | hydro_hash_init(&st, (const char *) zero, NULL); 30 | hydro_hash_update(&st, nonce, hydro_sign_NONCEBYTES); 31 | hydro_hash_update(&st, pk, hydro_sign_PUBLICKEYBYTES); 32 | hydro_hash_update(&st, prehash, hydro_sign_PREHASHBYTES); 33 | hydro_hash_final(&st, challenge, hydro_sign_CHALLENGEBYTES); 34 | } 35 | 36 | static int 37 | hydro_sign_prehash(uint8_t csig[hydro_sign_BYTES], const uint8_t prehash[hydro_sign_PREHASHBYTES], 38 | const uint8_t sk[hydro_sign_SECRETKEYBYTES]) 39 | { 40 | hydro_hash_state st; 41 | uint8_t challenge[hydro_sign_CHALLENGEBYTES]; 42 | const uint8_t * pk = &sk[hydro_x25519_SECRETKEYBYTES]; 43 | uint8_t * nonce = &csig[0]; 44 | uint8_t * sig = &csig[hydro_sign_NONCEBYTES]; 45 | uint8_t * eph_sk = sig; 46 | 47 | hydro_random_buf(eph_sk, hydro_x25519_SECRETKEYBYTES); 48 | COMPILER_ASSERT(hydro_x25519_SECRETKEYBYTES == hydro_hash_KEYBYTES); 49 | hydro_hash_init(&st, (const char *) zero, sk); 50 | hydro_hash_update(&st, eph_sk, hydro_x25519_SECRETKEYBYTES); 51 | hydro_hash_update(&st, prehash, hydro_sign_PREHASHBYTES); 52 | hydro_hash_final(&st, eph_sk, hydro_x25519_SECRETKEYBYTES); 53 | 54 | hydro_x25519_scalarmult_base_uniform(nonce, eph_sk); 55 | hydro_sign_challenge(challenge, nonce, pk, prehash); 56 | 57 | COMPILER_ASSERT(hydro_sign_BYTES == hydro_sign_NONCEBYTES + hydro_x25519_SECRETKEYBYTES); 58 | COMPILER_ASSERT(hydro_x25519_SECRETKEYBYTES <= hydro_sign_CHALLENGEBYTES); 59 | hydro_sign_p2(sig, challenge, eph_sk, sk); 60 | 61 | return 0; 62 | } 63 | 64 | static int 65 | hydro_sign_verify_core(hydro_x25519_fe xs[5], const hydro_x25519_limb_t *other1, 66 | const uint8_t other2[hydro_x25519_BYTES]) 67 | { 68 | hydro_x25519_limb_t * z2 = xs[1], *x3 = xs[2], *z3 = xs[3]; 69 | hydro_x25519_fe xo2; 70 | const hydro_x25519_limb_t sixteen = 16; 71 | 72 | hydro_x25519_swapin(xo2, other2); 73 | memcpy(x3, other1, 2 * sizeof(hydro_x25519_fe)); 74 | hydro_x25519_ladder_part1(xs); 75 | 76 | /* Here z2 = t2^2 */ 77 | hydro_x25519_mul1(z2, other1); 78 | hydro_x25519_mul1(z2, other1 + hydro_x25519_NLIMBS); 79 | hydro_x25519_mul1(z2, xo2); 80 | 81 | hydro_x25519_mul(z2, z2, &sixteen, 1); 82 | 83 | hydro_x25519_mul1(z3, xo2); 84 | hydro_x25519_sub(z3, z3, x3); 85 | hydro_x25519_sqr1(z3); 86 | 87 | /* check equality */ 88 | hydro_x25519_sub(z3, z3, z2); 89 | 90 | /* canon(z2): both sides are zero. canon(z3): the two sides are equal. */ 91 | /* Reject sigs where both sides are zero. */ 92 | return hydro_x25519_canon(z2) | ~hydro_x25519_canon(z3); 93 | } 94 | 95 | static int 96 | hydro_sign_verify_p2(const uint8_t sig[hydro_x25519_BYTES], 97 | const uint8_t challenge[hydro_sign_CHALLENGEBYTES], 98 | const uint8_t nonce[hydro_sign_NONCEBYTES], 99 | const uint8_t pk[hydro_x25519_BYTES]) 100 | { 101 | hydro_x25519_fe xs[7]; 102 | 103 | hydro_x25519_core(xs, challenge, pk, 0); 104 | hydro_x25519_core(xs + 2, sig, hydro_x25519_BASE_POINT, 0); 105 | 106 | return hydro_sign_verify_core(xs + 2, xs[0], nonce); 107 | } 108 | 109 | static int 110 | hydro_sign_verify_challenge(const uint8_t csig[hydro_sign_BYTES], 111 | const uint8_t challenge[hydro_sign_CHALLENGEBYTES], 112 | const uint8_t pk[hydro_sign_PUBLICKEYBYTES]) 113 | { 114 | const uint8_t *nonce = &csig[0]; 115 | const uint8_t *sig = &csig[hydro_sign_NONCEBYTES]; 116 | 117 | return hydro_sign_verify_p2(sig, challenge, nonce, pk); 118 | } 119 | 120 | void 121 | hydro_sign_keygen(hydro_sign_keypair *kp) 122 | { 123 | uint8_t *pk_copy = &kp->sk[hydro_x25519_SECRETKEYBYTES]; 124 | 125 | COMPILER_ASSERT(hydro_sign_SECRETKEYBYTES == 126 | hydro_x25519_SECRETKEYBYTES + hydro_x25519_PUBLICKEYBYTES); 127 | COMPILER_ASSERT(hydro_sign_PUBLICKEYBYTES == hydro_x25519_PUBLICKEYBYTES); 128 | hydro_random_buf(kp->sk, hydro_x25519_SECRETKEYBYTES); 129 | hydro_x25519_scalarmult_base_uniform(kp->pk, kp->sk); 130 | memcpy(pk_copy, kp->pk, hydro_x25519_PUBLICKEYBYTES); 131 | } 132 | 133 | void 134 | hydro_sign_keygen_deterministic(hydro_sign_keypair *kp, const uint8_t seed[hydro_sign_SEEDBYTES]) 135 | { 136 | uint8_t *pk_copy = &kp->sk[hydro_x25519_SECRETKEYBYTES]; 137 | 138 | COMPILER_ASSERT(hydro_sign_SEEDBYTES >= hydro_random_SEEDBYTES); 139 | hydro_random_buf_deterministic(kp->sk, hydro_x25519_SECRETKEYBYTES, seed); 140 | hydro_x25519_scalarmult_base_uniform(kp->pk, kp->sk); 141 | memcpy(pk_copy, kp->pk, hydro_x25519_PUBLICKEYBYTES); 142 | } 143 | 144 | int 145 | hydro_sign_init(hydro_sign_state *state, const char ctx[hydro_sign_CONTEXTBYTES]) 146 | { 147 | return hydro_hash_init(&state->hash_st, ctx, NULL); 148 | } 149 | 150 | int 151 | hydro_sign_update(hydro_sign_state *state, const void *m_, size_t mlen) 152 | { 153 | return hydro_hash_update(&state->hash_st, m_, mlen); 154 | } 155 | 156 | int 157 | hydro_sign_final_create(hydro_sign_state *state, uint8_t csig[hydro_sign_BYTES], 158 | const uint8_t sk[hydro_sign_SECRETKEYBYTES]) 159 | { 160 | uint8_t prehash[hydro_sign_PREHASHBYTES]; 161 | 162 | hydro_hash_final(&state->hash_st, prehash, sizeof prehash); 163 | 164 | return hydro_sign_prehash(csig, prehash, sk); 165 | } 166 | 167 | int 168 | hydro_sign_final_verify(hydro_sign_state *state, const uint8_t csig[hydro_sign_BYTES], 169 | const uint8_t pk[hydro_sign_PUBLICKEYBYTES]) 170 | { 171 | uint8_t challenge[hydro_sign_CHALLENGEBYTES]; 172 | uint8_t prehash[hydro_sign_PREHASHBYTES]; 173 | const uint8_t *nonce = &csig[0]; 174 | 175 | hydro_hash_final(&state->hash_st, prehash, sizeof prehash); 176 | hydro_sign_challenge(challenge, nonce, pk, prehash); 177 | 178 | return hydro_sign_verify_challenge(csig, challenge, pk); 179 | } 180 | 181 | int 182 | hydro_sign_create(uint8_t csig[hydro_sign_BYTES], const void *m_, size_t mlen, 183 | const char ctx[hydro_sign_CONTEXTBYTES], 184 | const uint8_t sk[hydro_sign_SECRETKEYBYTES]) 185 | { 186 | hydro_sign_state st; 187 | 188 | if (hydro_sign_init(&st, ctx) != 0 || hydro_sign_update(&st, m_, mlen) != 0 || 189 | hydro_sign_final_create(&st, csig, sk) != 0) { 190 | return -1; 191 | } 192 | return 0; 193 | } 194 | 195 | int 196 | hydro_sign_verify(const uint8_t csig[hydro_sign_BYTES], const void *m_, size_t mlen, 197 | const char ctx[hydro_sign_CONTEXTBYTES], 198 | const uint8_t pk[hydro_sign_PUBLICKEYBYTES]) 199 | { 200 | hydro_sign_state st; 201 | 202 | if (hydro_sign_init(&st, ctx) != 0 || hydro_sign_update(&st, m_, mlen) != 0 || 203 | hydro_sign_final_verify(&st, csig, pk) != 0) { 204 | return -1; 205 | } 206 | return 0; 207 | } 208 | -------------------------------------------------------------------------------- /impl/x25519.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Based on Michael Hamburg's STROBE reference implementation. 3 | * Copyright (c) 2015-2016 Cryptography Research, Inc. 4 | * MIT License (MIT) 5 | */ 6 | 7 | #if defined(__GNUC__) && defined(__SIZEOF_INT128__) 8 | #define hydro_x25519_WBITS 64 9 | #else 10 | #define hydro_x25519_WBITS 32 11 | #endif 12 | 13 | #if hydro_x25519_WBITS == 64 14 | typedef uint64_t hydro_x25519_limb_t; 15 | typedef __uint128_t hydro_x25519_dlimb_t; 16 | typedef __int128_t hydro_x25519_sdlimb_t; 17 | #define hydro_x25519_eswap_limb(X) LOAD64_LE((const uint8_t *) &(X)) 18 | #define hydro_x25519_LIMB(x) x##ull 19 | #elif hydro_x25519_WBITS == 32 20 | typedef uint32_t hydro_x25519_limb_t; 21 | typedef uint64_t hydro_x25519_dlimb_t; 22 | typedef int64_t hydro_x25519_sdlimb_t; 23 | #define hydro_x25519_eswap_limb(X) LOAD32_LE((const uint8_t *) &(X)) 24 | #define hydro_x25519_LIMB(x) (uint32_t)(x##ull), (uint32_t) ((x##ull) >> 32) 25 | #else 26 | #error "Need to know hydro_x25519_WBITS" 27 | #endif 28 | 29 | #define hydro_x25519_NLIMBS (256 / hydro_x25519_WBITS) 30 | typedef hydro_x25519_limb_t hydro_x25519_fe[hydro_x25519_NLIMBS]; 31 | 32 | typedef hydro_x25519_limb_t hydro_x25519_scalar_t[hydro_x25519_NLIMBS]; 33 | 34 | static const hydro_x25519_limb_t hydro_x25519_MONTGOMERY_FACTOR = 35 | (hydro_x25519_limb_t) 0xd2b51da312547e1bull; 36 | 37 | static const hydro_x25519_scalar_t hydro_x25519_sc_p = { hydro_x25519_LIMB(0x5812631a5cf5d3ed), 38 | hydro_x25519_LIMB(0x14def9dea2f79cd6), 39 | hydro_x25519_LIMB(0x0000000000000000), 40 | hydro_x25519_LIMB(0x1000000000000000) }; 41 | 42 | static const hydro_x25519_scalar_t hydro_x25519_sc_r2 = { hydro_x25519_LIMB(0xa40611e3449c0f01), 43 | hydro_x25519_LIMB(0xd00e1ba768859347), 44 | hydro_x25519_LIMB(0xceec73d217f5be65), 45 | hydro_x25519_LIMB(0x0399411b7c309a3d) }; 46 | 47 | static const uint8_t hydro_x25519_BASE_POINT[hydro_x25519_BYTES] = { 9 }; 48 | 49 | static const hydro_x25519_limb_t hydro_x25519_a24[1] = { 121665 }; 50 | 51 | static inline hydro_x25519_limb_t 52 | hydro_x25519_umaal(hydro_x25519_limb_t *carry, hydro_x25519_limb_t acc, hydro_x25519_limb_t mand, 53 | hydro_x25519_limb_t mier) 54 | { 55 | hydro_x25519_dlimb_t tmp = (hydro_x25519_dlimb_t) mand * mier + acc + *carry; 56 | 57 | *carry = tmp >> hydro_x25519_WBITS; 58 | return (hydro_x25519_limb_t) tmp; 59 | } 60 | 61 | static inline hydro_x25519_limb_t 62 | hydro_x25519_adc(hydro_x25519_limb_t *carry, hydro_x25519_limb_t acc, hydro_x25519_limb_t mand) 63 | { 64 | hydro_x25519_dlimb_t total = (hydro_x25519_dlimb_t) *carry + acc + mand; 65 | 66 | *carry = total >> hydro_x25519_WBITS; 67 | return (hydro_x25519_limb_t) total; 68 | } 69 | 70 | static inline hydro_x25519_limb_t 71 | hydro_x25519_adc0(hydro_x25519_limb_t *carry, hydro_x25519_limb_t acc) 72 | { 73 | hydro_x25519_dlimb_t total = (hydro_x25519_dlimb_t) *carry + acc; 74 | 75 | *carry = total >> hydro_x25519_WBITS; 76 | return (hydro_x25519_limb_t) total; 77 | } 78 | 79 | static void 80 | hydro_x25519_propagate(hydro_x25519_fe x, hydro_x25519_limb_t over) 81 | { 82 | hydro_x25519_limb_t carry; 83 | int i; 84 | 85 | over = x[hydro_x25519_NLIMBS - 1] >> (hydro_x25519_WBITS - 1) | over << 1; 86 | x[hydro_x25519_NLIMBS - 1] &= ~((hydro_x25519_limb_t) 1 << (hydro_x25519_WBITS - 1)); 87 | carry = over * 19; 88 | for (i = 0; i < hydro_x25519_NLIMBS; i++) { 89 | x[i] = hydro_x25519_adc0(&carry, x[i]); 90 | } 91 | } 92 | 93 | static void 94 | hydro_x25519_add(hydro_x25519_fe out, const hydro_x25519_fe a, const hydro_x25519_fe b) 95 | { 96 | hydro_x25519_limb_t carry = 0; 97 | int i; 98 | 99 | for (i = 0; i < hydro_x25519_NLIMBS; i++) { 100 | out[i] = hydro_x25519_adc(&carry, a[i], b[i]); 101 | } 102 | hydro_x25519_propagate(out, carry); 103 | } 104 | 105 | static void 106 | hydro_x25519_sub(hydro_x25519_fe out, const hydro_x25519_fe a, const hydro_x25519_fe b) 107 | { 108 | hydro_x25519_sdlimb_t carry = -76; 109 | int i; 110 | 111 | for (i = 0; i < hydro_x25519_NLIMBS; i++) { 112 | out[i] = (hydro_x25519_limb_t) (carry = carry + a[i] - b[i]); 113 | carry >>= hydro_x25519_WBITS; 114 | } 115 | hydro_x25519_propagate(out, (hydro_x25519_limb_t) (2 + carry)); 116 | } 117 | 118 | static void 119 | hydro_x25519_swapin(hydro_x25519_limb_t *x, const uint8_t *in) 120 | { 121 | int i; 122 | 123 | memcpy(x, in, sizeof(hydro_x25519_fe)); 124 | for (i = 0; i < hydro_x25519_NLIMBS; i++) { 125 | x[i] = hydro_x25519_eswap_limb(x[i]); 126 | } 127 | } 128 | 129 | static void 130 | hydro_x25519_swapout(uint8_t *out, hydro_x25519_limb_t *x) 131 | { 132 | int i; 133 | 134 | for (i = 0; i < hydro_x25519_NLIMBS; i++) { 135 | x[i] = hydro_x25519_eswap_limb(x[i]); 136 | } 137 | memcpy(out, x, sizeof(hydro_x25519_fe)); 138 | } 139 | 140 | static void 141 | hydro_x25519_mul(hydro_x25519_fe out, const hydro_x25519_fe a, const hydro_x25519_limb_t b[], 142 | const int nb) 143 | { 144 | hydro_x25519_limb_t accum[2 * hydro_x25519_NLIMBS] = { 0 }; 145 | hydro_x25519_limb_t carry2; 146 | int i, j; 147 | 148 | for (i = 0; i < nb; i++) { 149 | hydro_x25519_limb_t mand = b[i]; 150 | carry2 = 0; 151 | 152 | for (j = 0; j < hydro_x25519_NLIMBS; j++) { 153 | accum[i + j] = hydro_x25519_umaal(&carry2, accum[i + j], mand, a[j]); 154 | } 155 | accum[i + j] = carry2; 156 | } 157 | carry2 = 0; 158 | for (j = 0; j < hydro_x25519_NLIMBS; j++) { 159 | const hydro_x25519_limb_t mand = 38; 160 | 161 | out[j] = hydro_x25519_umaal(&carry2, accum[j], mand, accum[j + hydro_x25519_NLIMBS]); 162 | } 163 | hydro_x25519_propagate(out, carry2); 164 | } 165 | 166 | static void 167 | hydro_x25519_sqr(hydro_x25519_fe out, const hydro_x25519_fe a) 168 | { 169 | hydro_x25519_mul(out, a, a, hydro_x25519_NLIMBS); 170 | } 171 | 172 | static void 173 | hydro_x25519_mul1(hydro_x25519_fe out, const hydro_x25519_fe a) 174 | { 175 | hydro_x25519_mul(out, a, out, hydro_x25519_NLIMBS); 176 | } 177 | 178 | static void 179 | hydro_x25519_sqr1(hydro_x25519_fe a) 180 | { 181 | hydro_x25519_mul1(a, a); 182 | } 183 | 184 | static void 185 | hydro_x25519_condswap(hydro_x25519_limb_t a[2 * hydro_x25519_NLIMBS], 186 | hydro_x25519_limb_t b[2 * hydro_x25519_NLIMBS], hydro_x25519_limb_t doswap) 187 | { 188 | int i; 189 | 190 | for (i = 0; i < 2 * hydro_x25519_NLIMBS; i++) { 191 | hydro_x25519_limb_t xorv = (a[i] ^ b[i]) & doswap; 192 | a[i] ^= xorv; 193 | b[i] ^= xorv; 194 | } 195 | } 196 | 197 | static int 198 | hydro_x25519_canon(hydro_x25519_fe x) 199 | { 200 | hydro_x25519_sdlimb_t carry; 201 | hydro_x25519_limb_t carry0 = 19; 202 | hydro_x25519_limb_t res; 203 | int i; 204 | 205 | for (i = 0; i < hydro_x25519_NLIMBS; i++) { 206 | x[i] = hydro_x25519_adc0(&carry0, x[i]); 207 | } 208 | hydro_x25519_propagate(x, carry0); 209 | carry = -19; 210 | res = 0; 211 | for (i = 0; i < hydro_x25519_NLIMBS; i++) { 212 | res |= x[i] = (hydro_x25519_limb_t) (carry += x[i]); 213 | carry >>= hydro_x25519_WBITS; 214 | } 215 | return ((hydro_x25519_dlimb_t) res - 1) >> hydro_x25519_WBITS; 216 | } 217 | 218 | static void 219 | hydro_x25519_ladder_part1(hydro_x25519_fe xs[5]) 220 | { 221 | hydro_x25519_limb_t *x2 = xs[0], *z2 = xs[1], *x3 = xs[2], *z3 = xs[3], *t1 = xs[4]; 222 | 223 | hydro_x25519_add(t1, x2, z2); // t1 = A 224 | hydro_x25519_sub(z2, x2, z2); // z2 = B 225 | hydro_x25519_add(x2, x3, z3); // x2 = C 226 | hydro_x25519_sub(z3, x3, z3); // z3 = D 227 | hydro_x25519_mul1(z3, t1); // z3 = DA 228 | hydro_x25519_mul1(x2, z2); // x3 = BC 229 | hydro_x25519_add(x3, z3, x2); // x3 = DA+CB 230 | hydro_x25519_sub(z3, z3, x2); // z3 = DA-CB 231 | hydro_x25519_sqr1(t1); // t1 = AA 232 | hydro_x25519_sqr1(z2); // z2 = BB 233 | hydro_x25519_sub(x2, t1, z2); // x2 = E = AA-BB 234 | hydro_x25519_mul(z2, x2, hydro_x25519_a24, // z2 = E*a24 235 | sizeof(hydro_x25519_a24) / sizeof(hydro_x25519_a24[0])); 236 | hydro_x25519_add(z2, z2, t1); // z2 = E*a24 + AA 237 | } 238 | 239 | static void 240 | hydro_x25519_ladder_part2(hydro_x25519_fe xs[5], const hydro_x25519_fe x1) 241 | { 242 | hydro_x25519_limb_t *x2 = xs[0], *z2 = xs[1], *x3 = xs[2], *z3 = xs[3], *t1 = xs[4]; 243 | 244 | hydro_x25519_sqr1(z3); // z3 = (DA-CB)^2 245 | hydro_x25519_mul1(z3, x1); // z3 = x1 * (DA-CB)^2 246 | hydro_x25519_sqr1(x3); // x3 = (DA+CB)^2 247 | hydro_x25519_mul1(z2, x2); // z2 = AA*(E*a24+AA) 248 | hydro_x25519_sub(x2, t1, x2); // x2 = BB again 249 | hydro_x25519_mul1(x2, t1); // x2 = AA*BB 250 | } 251 | 252 | static void 253 | hydro_x25519_core(hydro_x25519_fe xs[5], const uint8_t scalar[hydro_x25519_BYTES], 254 | const uint8_t *x1, bool clamp) 255 | { 256 | hydro_x25519_limb_t swap; 257 | hydro_x25519_limb_t *x2 = xs[0], *x3 = xs[2], *z3 = xs[3]; 258 | hydro_x25519_fe x1i; 259 | int i; 260 | 261 | hydro_x25519_swapin(x1i, x1); 262 | x1 = (const uint8_t *) x1i; 263 | swap = 0; 264 | mem_zero(xs, 4 * sizeof(hydro_x25519_fe)); 265 | x2[0] = z3[0] = 1; 266 | memcpy(x3, x1, sizeof(hydro_x25519_fe)); 267 | for (i = 255; i >= 0; i--) { 268 | uint8_t bytei = scalar[i / 8]; 269 | hydro_x25519_limb_t doswap; 270 | hydro_x25519_fe x1_dup; 271 | 272 | if (clamp) { 273 | if (i / 8 == 0) { 274 | bytei &= ~7; 275 | } else if (i / 8 == hydro_x25519_BYTES - 1) { 276 | bytei &= 0x7F; 277 | bytei |= 0x40; 278 | } 279 | } 280 | doswap = 1U + ~(hydro_x25519_limb_t) ((bytei >> (i % 8)) & 1); 281 | hydro_x25519_condswap(x2, x3, swap ^ doswap); 282 | swap = doswap; 283 | hydro_x25519_ladder_part1(xs); 284 | memcpy(x1_dup, x1, sizeof x1_dup); 285 | hydro_x25519_ladder_part2(xs, x1_dup); 286 | } 287 | hydro_x25519_condswap(x2, x3, swap); 288 | } 289 | 290 | static int 291 | hydro_x25519_scalarmult(uint8_t out[hydro_x25519_BYTES], 292 | const uint8_t scalar[hydro_x25519_SECRETKEYBYTES], 293 | const uint8_t x1[hydro_x25519_PUBLICKEYBYTES], bool clamp) 294 | { 295 | hydro_x25519_fe xs[5]; 296 | hydro_x25519_limb_t *x2, *z2, *z3; 297 | hydro_x25519_limb_t *prev; 298 | int i; 299 | int ret; 300 | 301 | hydro_x25519_core(xs, scalar, x1, clamp); 302 | 303 | /* Precomputed inversion chain */ 304 | x2 = xs[0]; 305 | z2 = xs[1]; 306 | z3 = xs[3]; 307 | prev = z2; 308 | 309 | /* Raise to the p-2 = 0x7f..ffeb */ 310 | for (i = 253; i >= 0; i--) { 311 | hydro_x25519_sqr(z3, prev); 312 | prev = z3; 313 | if (i >= 8 || (0xeb >> i & 1)) { 314 | hydro_x25519_mul1(z3, z2); 315 | } 316 | } 317 | 318 | /* Here prev = z3 */ 319 | /* x2 /= z2 */ 320 | hydro_x25519_mul1(x2, z3); 321 | ret = hydro_x25519_canon(x2); 322 | hydro_x25519_swapout(out, x2); 323 | 324 | if (clamp == 0) { 325 | return 0; 326 | } 327 | return ret; 328 | } 329 | 330 | static inline int 331 | hydro_x25519_scalarmult_base(uint8_t pk[hydro_x25519_PUBLICKEYBYTES], 332 | const uint8_t sk[hydro_x25519_SECRETKEYBYTES]) 333 | { 334 | return hydro_x25519_scalarmult(pk, sk, hydro_x25519_BASE_POINT, 1); 335 | } 336 | 337 | static inline void 338 | hydro_x25519_scalarmult_base_uniform(uint8_t pk[hydro_x25519_PUBLICKEYBYTES], 339 | const uint8_t sk[hydro_x25519_SECRETKEYBYTES]) 340 | { 341 | if (hydro_x25519_scalarmult(pk, sk, hydro_x25519_BASE_POINT, 0) != 0) { 342 | abort(); 343 | } 344 | } 345 | 346 | static void 347 | hydro_x25519_sc_montmul(hydro_x25519_scalar_t out, const hydro_x25519_scalar_t a, 348 | const hydro_x25519_scalar_t b) 349 | { 350 | hydro_x25519_limb_t hic = 0; 351 | int i, j; 352 | 353 | for (i = 0; i < hydro_x25519_NLIMBS; i++) { 354 | hydro_x25519_limb_t carry = 0, carry2 = 0, mand = a[i], 355 | mand2 = hydro_x25519_MONTGOMERY_FACTOR; 356 | 357 | for (j = 0; j < hydro_x25519_NLIMBS; j++) { 358 | hydro_x25519_limb_t acc = out[j]; 359 | 360 | acc = hydro_x25519_umaal(&carry, acc, mand, b[j]); 361 | if (j == 0) { 362 | mand2 *= acc; 363 | } 364 | acc = hydro_x25519_umaal(&carry2, acc, mand2, hydro_x25519_sc_p[j]); 365 | if (j > 0) { 366 | out[j - 1] = acc; 367 | } 368 | } 369 | 370 | /* Add two carry registers and high carry */ 371 | out[hydro_x25519_NLIMBS - 1] = hydro_x25519_adc(&hic, carry, carry2); 372 | } 373 | 374 | /* Reduce */ 375 | hydro_x25519_sdlimb_t scarry = 0; 376 | for (i = 0; i < hydro_x25519_NLIMBS; i++) { 377 | out[i] = (hydro_x25519_limb_t) (scarry = scarry + out[i] - hydro_x25519_sc_p[i]); 378 | scarry >>= hydro_x25519_WBITS; 379 | } 380 | hydro_x25519_limb_t need_add = (hydro_x25519_limb_t) - (scarry + hic); 381 | 382 | hydro_x25519_limb_t carry = 0; 383 | for (i = 0; i < hydro_x25519_NLIMBS; i++) { 384 | out[i] = hydro_x25519_umaal(&carry, out[i], need_add, hydro_x25519_sc_p[i]); 385 | } 386 | } 387 | -------------------------------------------------------------------------------- /jhydro.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2019 Calvin Rose 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining a copy 5 | * of this software and associated documentation files (the "Software"), to 6 | * deal in the Software without restriction, including without limitation the 7 | * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 8 | * sell copies of the Software, and to permit persons to whom the Software is 9 | * furnished to do so, subject to the following conditions: 10 | * 11 | * The above copyright notice and this permission notice shall be included in 12 | * all copies or substantial portions of the Software. 13 | * 14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 19 | * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 20 | * IN THE SOFTWARE. 21 | */ 22 | 23 | #include 24 | #include 25 | #include 26 | #include 27 | 28 | /*********/ 29 | /* Utils */ 30 | /*********/ 31 | 32 | /* Get an optional buffer for keygen functions, and ensure it has capacity for 33 | * len bytes */ 34 | static JanetBuffer *util_keygen_prep(int32_t argc, const Janet *argv, int len) { 35 | janet_arity(argc, 0, 1); 36 | JanetBuffer *buffer; 37 | if (argc == 0) { 38 | buffer = janet_buffer(len); 39 | buffer->count = len; 40 | } else { 41 | buffer = janet_getbuffer(argv, 0); 42 | janet_buffer_ensure(buffer, len, 1); 43 | if (buffer->count < len) { 44 | buffer->count = len; 45 | } 46 | } 47 | return buffer; 48 | } 49 | 50 | /* Get a byte view with at least nbytes bytes. Otherwise the same janet_getbytes. */ 51 | static JanetByteView util_getnbytes(const Janet *argv, int32_t n, int nbytes) { 52 | JanetByteView view = janet_getbytes(argv, n); 53 | if (view.len != nbytes) { 54 | janet_panicf("bad slot #%d, expected %d bytes, got %d", n, nbytes, view.len); 55 | } 56 | return view; 57 | } 58 | 59 | /* Get a positive, 32 bit integer */ 60 | static int32_t util_getnat(const Janet *argv, int32_t n) { 61 | int32_t x = janet_getinteger(argv, n); 62 | if (x < 0) { 63 | janet_panicf("bad slot #%d, expected non-negative integer, got %d", n, x); 64 | } 65 | return x; 66 | } 67 | 68 | /****************************/ 69 | /* Random Number Generation */ 70 | /****************************/ 71 | 72 | static Janet cfun_random_u32(int32_t argc, Janet *argv) { 73 | (void) argv; 74 | janet_fixarity(argc, 0); 75 | uint32_t x = hydro_random_u32(); 76 | return janet_wrap_number((double) x); 77 | } 78 | 79 | static Janet cfun_random_uniform(int32_t argc, Janet *argv) { 80 | janet_fixarity(argc, 1); 81 | double d = janet_getnumber(argv, 0); 82 | if (d < 0 || d > UINT32_MAX || floor(d) != d) { 83 | janet_panicf("expected integer in range [0, 2^32), got %v", argv[0]); 84 | } 85 | uint32_t x = hydro_random_uniform((uint32_t) d); 86 | return janet_wrap_number((double) x); 87 | } 88 | 89 | static Janet cfun_random_buf(int32_t argc, Janet *argv) { 90 | janet_arity(argc, 1, 2); 91 | JanetBuffer *buf; 92 | size_t outlen; 93 | if (janet_checktype(argv[0], JANET_NUMBER)) { 94 | janet_fixarity(argc, 1); 95 | size_t outlen = janet_getsize(argv, 0); 96 | if (outlen > INT32_MAX) janet_panic("size too large"); 97 | buf = janet_buffer(outlen); 98 | hydro_random_buf(buf->data, outlen); 99 | buf->count = outlen; 100 | } else { 101 | buf = janet_getbuffer(argv, 0); 102 | if (argc < 2) { 103 | outlen = buf->count; 104 | buf->count = 0; 105 | } else { 106 | outlen = janet_getsize(argv, 1); 107 | janet_buffer_extra(buf, outlen); 108 | } 109 | if (outlen > INT32_MAX) janet_panic("size too large"); 110 | hydro_random_buf(buf->data + buf->count, outlen); 111 | buf->count += outlen; 112 | } 113 | return janet_wrap_buffer(buf); 114 | } 115 | 116 | static Janet cfun_random_ratchet(int32_t argc, Janet *argv) { 117 | janet_fixarity(argc, 0); 118 | (void) argv; 119 | hydro_random_ratchet(); 120 | return janet_wrap_nil(); 121 | } 122 | 123 | static Janet cfun_random_reseed(int32_t argc, Janet *argv) { 124 | janet_fixarity(argc, 0); 125 | (void) argv; 126 | hydro_random_reseed(); 127 | return janet_wrap_nil(); 128 | } 129 | 130 | static Janet cfun_random_buf_deterministic(int32_t argc, Janet *argv) { 131 | janet_fixarity(argc, 3); 132 | JanetBuffer *buf = janet_getbuffer(argv, 0); 133 | size_t len = janet_getsize(argv, 1); 134 | if (len > INT32_MAX) janet_panic("size too large"); 135 | JanetByteView seed = util_getnbytes(argv, 2, hydro_random_SEEDBYTES); 136 | janet_buffer_extra(buf, len); 137 | hydro_random_buf_deterministic(buf->data + buf->count, len, seed.bytes); 138 | buf->count += len; 139 | return janet_wrap_buffer(buf); 140 | } 141 | 142 | /***********/ 143 | /* Hashing */ 144 | /***********/ 145 | 146 | static Janet cfun_hash_keygen(int32_t argc, Janet *argv) { 147 | JanetBuffer *buffer = util_keygen_prep(argc, argv, hydro_hash_KEYBYTES); 148 | hydro_hash_keygen(buffer->data); 149 | return janet_wrap_buffer(buffer); 150 | } 151 | 152 | static const JanetAbstractType HashState = { 153 | "jhydro/hash-state", 154 | #ifdef JANET_ATEND_NAME 155 | JANET_ATEND_NAME 156 | #endif 157 | }; 158 | 159 | static Janet cfun_hash_new(int32_t argc, Janet *argv) { 160 | janet_fixarity(argc, 2); 161 | JanetByteView ctx = util_getnbytes(argv, 0, hydro_hash_CONTEXTBYTES); 162 | JanetByteView key = util_getnbytes(argv, 1, hydro_hash_KEYBYTES); 163 | hydro_hash_state *state = janet_abstract(&HashState, sizeof(hydro_hash_state)); 164 | int result = hydro_hash_init(state, (const char *) ctx.bytes, key.bytes); 165 | if (result) { 166 | janet_panic("failed to create hash-state"); 167 | } 168 | return janet_wrap_abstract(state); 169 | } 170 | 171 | static Janet cfun_hash_update(int32_t argc, Janet *argv) { 172 | janet_fixarity(argc, 2); 173 | hydro_hash_state *state = janet_getabstract(argv, 0, &HashState); 174 | JanetByteView bytes = janet_getbytes(argv, 1); 175 | int result = hydro_hash_update(state, (const char *) bytes.bytes, bytes.len); 176 | if (result) { 177 | janet_panic("failed to update hash-state"); 178 | } 179 | return argv[0]; 180 | } 181 | 182 | static Janet cfun_hash_final(int32_t argc, Janet *argv) { 183 | janet_fixarity(argc, 2); 184 | hydro_hash_state *state = janet_getabstract(argv, 0, &HashState); 185 | int32_t outlen = janet_getinteger(argv, 1); 186 | if (outlen < 1) { 187 | janet_panicf("outlen must be a positive integer, got %v", argv[1]); 188 | } 189 | uint8_t *out = janet_string_begin(outlen); 190 | int result = hydro_hash_final(state, out, outlen); 191 | if (result) { 192 | janet_panic("failed to generate hash"); 193 | } 194 | return janet_wrap_string(janet_string_end(out)); 195 | } 196 | 197 | static Janet cfun_hash_hash(int32_t argc, Janet *argv) { 198 | janet_arity(argc, 3, 4); 199 | int32_t size = util_getnat(argv, 0); 200 | if (size < hydro_hash_BYTES_MIN || size > hydro_hash_BYTES_MAX) 201 | janet_panicf("hash size must be in range [%d, %d], got %v", 202 | hydro_hash_BYTES_MIN, hydro_hash_BYTES_MAX, 203 | argv[0]); 204 | JanetByteView msg = janet_getbytes(argv, 1); 205 | JanetByteView ctx = util_getnbytes(argv, 2, hydro_hash_CONTEXTBYTES); 206 | JanetByteView key; 207 | key.bytes = NULL; 208 | key.len = 0; 209 | if (argc >= 4 && !janet_checktype(argv[4], JANET_NIL)) { 210 | key = util_getnbytes(argv, 3, hydro_hash_KEYBYTES); 211 | } 212 | uint8_t *out = janet_string_begin(size); 213 | int result = hydro_hash_hash(out, size, (const char *) msg.bytes, msg.len, (const char *) ctx.bytes, key.bytes); 214 | if (result) { 215 | janet_panic("failed to hash message"); 216 | } 217 | return janet_wrap_string(janet_string_end(out)); 218 | } 219 | 220 | /**************/ 221 | /* Secret Box */ 222 | /**************/ 223 | 224 | static Janet cfun_secretbox_keygen(int32_t argc, Janet *argv) { 225 | JanetBuffer *buffer = util_keygen_prep(argc, argv, hydro_secretbox_KEYBYTES); 226 | hydro_secretbox_keygen(buffer->data); 227 | return janet_wrap_buffer(buffer); 228 | } 229 | 230 | static Janet cfun_secretbox_encrypt(int32_t argc, Janet *argv) { 231 | janet_arity(argc, 4, 5); 232 | JanetByteView msg = janet_getbytes(argv, 0); 233 | uint64_t msg_id = (uint64_t) janet_getinteger64(argv, 1); 234 | JanetByteView ctx = util_getnbytes(argv, 2, hydro_secretbox_CONTEXTBYTES); 235 | JanetByteView key = util_getnbytes(argv, 3, hydro_secretbox_KEYBYTES); 236 | JanetBuffer *cipher; 237 | if (argc == 5) { 238 | cipher = janet_getbuffer(argv, 4); 239 | janet_buffer_extra(cipher, msg.len + hydro_secretbox_HEADERBYTES); 240 | } else { 241 | cipher = janet_buffer(msg.len + hydro_secretbox_HEADERBYTES); 242 | } 243 | int result = hydro_secretbox_encrypt(cipher->data + cipher->count, 244 | msg.bytes, msg.len, msg_id, (const char *) ctx.bytes, key.bytes); 245 | if (result) { 246 | janet_panic("encryption failed"); 247 | } 248 | cipher->count += msg.len + hydro_secretbox_HEADERBYTES; 249 | return janet_wrap_buffer(cipher); 250 | } 251 | 252 | static Janet cfun_secretbox_decrypt(int32_t argc, Janet *argv) { 253 | janet_arity(argc, 4, 5); 254 | JanetByteView ciphertext = janet_getbytes(argv, 0); 255 | uint64_t msg_id = (uint64_t) janet_getinteger64(argv, 1); 256 | JanetByteView ctx = util_getnbytes(argv, 2, hydro_secretbox_CONTEXTBYTES); 257 | JanetByteView key = util_getnbytes(argv, 3, hydro_secretbox_KEYBYTES); 258 | JanetBuffer *msg; 259 | if (argc == 5) { 260 | msg = janet_getbuffer(argv, 4); 261 | janet_buffer_extra(msg, ciphertext.len - hydro_secretbox_HEADERBYTES); 262 | } else { 263 | msg = janet_buffer(ciphertext.len - hydro_secretbox_HEADERBYTES); 264 | } 265 | int result = hydro_secretbox_decrypt(msg->data + msg->count, 266 | ciphertext.bytes, ciphertext.len, msg_id, (const char *) ctx.bytes, key.bytes); 267 | if (result) { 268 | janet_panic("decryption failed"); 269 | } 270 | msg->count += ciphertext.len - hydro_secretbox_HEADERBYTES; 271 | return janet_wrap_buffer(msg); 272 | } 273 | 274 | static Janet cfun_secretbox_probe_create(int32_t argc, Janet *argv) { 275 | janet_fixarity(argc, 3); 276 | JanetByteView c = janet_getbytes(argv, 0); 277 | JanetByteView ctx = util_getnbytes(argv, 1, hydro_secretbox_CONTEXTBYTES); 278 | JanetByteView key = util_getnbytes(argv, 2, hydro_secretbox_KEYBYTES); 279 | uint8_t *probe = janet_string_begin(hydro_secretbox_PROBEBYTES); 280 | hydro_secretbox_probe_create(probe, c.bytes, c.len, (const char *) ctx.bytes, key.bytes); 281 | return janet_wrap_string(janet_string_end(probe)); 282 | } 283 | 284 | static Janet cfun_secretbox_probe_verify(int32_t argc, Janet *argv) { 285 | janet_fixarity(argc, 4); 286 | JanetByteView probe = util_getnbytes(argv, 0, hydro_secretbox_PROBEBYTES); 287 | JanetByteView c = janet_getbytes(argv, 1); 288 | JanetByteView ctx = util_getnbytes(argv, 2, hydro_secretbox_CONTEXTBYTES); 289 | JanetByteView key = util_getnbytes(argv, 3, hydro_secretbox_KEYBYTES); 290 | return janet_wrap_boolean( 291 | !hydro_secretbox_probe_verify(probe.bytes, c.bytes, c.len, (const char *) ctx.bytes, key.bytes)); 292 | } 293 | 294 | /*******/ 295 | /* KDF */ 296 | /*******/ 297 | 298 | static Janet cfun_kdf_keygen(int32_t argc, Janet *argv) { 299 | JanetBuffer *buffer = util_keygen_prep(argc, argv, hydro_kdf_KEYBYTES); 300 | hydro_kdf_keygen(buffer->data); 301 | return janet_wrap_buffer(buffer); 302 | } 303 | 304 | static Janet cfun_kdf_derive_from_key(int32_t argc, Janet *argv) { 305 | janet_fixarity(argc, 4); 306 | int32_t subkey_len = janet_getinteger(argv, 0); 307 | if (subkey_len < hydro_kdf_BYTES_MIN) 308 | janet_panicf("subkey length must be at least %d, got %d", 309 | hydro_kdf_BYTES_MIN, subkey_len); 310 | if (subkey_len > hydro_kdf_BYTES_MAX) 311 | janet_panicf("subkey length must be at most %d, got %d", 312 | hydro_kdf_BYTES_MAX, subkey_len); 313 | uint64_t subkey_id = (uint64_t) janet_getinteger64(argv, 1); 314 | JanetByteView ctx = util_getnbytes(argv, 2, hydro_kdf_CONTEXTBYTES); 315 | JanetByteView key = util_getnbytes(argv, 3, hydro_kdf_KEYBYTES); 316 | uint8_t *subkey = janet_string_begin(subkey_len); 317 | int result = hydro_kdf_derive_from_key(subkey, subkey_len, subkey_id, (const char *) ctx.bytes, key.bytes); 318 | if (result) { 319 | janet_panic("failed to derive key"); 320 | } 321 | return janet_wrap_string(janet_string_end(subkey)); 322 | } 323 | 324 | /*************************/ 325 | /* Public Key Signatures */ 326 | /*************************/ 327 | 328 | static Janet util_make_keypair(hydro_sign_keypair *kp) { 329 | Janet pk = janet_stringv(kp->pk, hydro_sign_PUBLICKEYBYTES); 330 | Janet sk = janet_stringv(kp->sk, hydro_sign_SECRETKEYBYTES); 331 | JanetKV *st = janet_struct_begin(2); 332 | janet_struct_put(st, janet_ckeywordv("public-key"), pk); 333 | janet_struct_put(st, janet_ckeywordv("secret-key"), sk); 334 | return janet_wrap_struct(janet_struct_end(st)); 335 | } 336 | 337 | static Janet cfun_sign_keygen(int32_t argc, Janet *argv) { 338 | hydro_sign_keypair kp; 339 | (void) argv; 340 | janet_fixarity(argc, 0); 341 | hydro_sign_keygen(&kp); 342 | return util_make_keypair(&kp); 343 | } 344 | 345 | static Janet cfun_sign_keygen_deterministic(int32_t argc, Janet *argv) { 346 | hydro_sign_keypair kp; 347 | janet_fixarity(argc, 1); 348 | JanetByteView seed = util_getnbytes(argv, 0, hydro_sign_SEEDBYTES); 349 | hydro_sign_keygen_deterministic(&kp, seed.bytes); 350 | return util_make_keypair(&kp); 351 | } 352 | 353 | static Janet cfun_sign_create(int32_t argc, Janet *argv) { 354 | janet_fixarity(argc, 3); 355 | JanetByteView msg = janet_getbytes(argv, 0); 356 | JanetByteView ctx = util_getnbytes(argv, 1, hydro_sign_CONTEXTBYTES); 357 | JanetByteView sk = util_getnbytes(argv, 2, hydro_sign_SECRETKEYBYTES); 358 | uint8_t *csig = janet_string_begin(hydro_sign_BYTES); 359 | int result = hydro_sign_create(csig, msg.bytes, msg.len, (const char *) ctx.bytes, sk.bytes); 360 | if (result) { 361 | janet_panic("failed to create signature"); 362 | } 363 | return janet_wrap_string(janet_string_end(csig)); 364 | } 365 | 366 | static Janet cfun_sign_verify(int32_t argc, Janet *argv) { 367 | janet_fixarity(argc, 4); 368 | JanetByteView csig = util_getnbytes(argv, 0, hydro_sign_BYTES); 369 | JanetByteView msg = janet_getbytes(argv, 1); 370 | JanetByteView ctx = util_getnbytes(argv, 2, hydro_sign_CONTEXTBYTES); 371 | JanetByteView pk = util_getnbytes(argv, 3, hydro_sign_PUBLICKEYBYTES); 372 | return janet_wrap_boolean(!hydro_sign_verify( 373 | csig.bytes, msg.bytes, msg.len, (const char *) ctx.bytes, pk.bytes)); 374 | } 375 | 376 | static const JanetAbstractType SignState = { 377 | "jhydro/sign-state", 378 | #ifdef JANET_ATEND_NAME 379 | JANET_ATEND_NAME 380 | #endif 381 | }; 382 | 383 | static Janet cfun_sign_new(int32_t argc, Janet *argv) { 384 | janet_fixarity(argc, 1); 385 | JanetByteView ctx = util_getnbytes(argv, 0, hydro_sign_CONTEXTBYTES); 386 | hydro_sign_state *state = janet_abstract(&SignState, sizeof(hydro_sign_state)); 387 | int result = hydro_sign_init(state, (const char *) ctx.bytes); 388 | if (result) { 389 | janet_panic("failed to create signature state"); 390 | } 391 | return janet_wrap_abstract(state); 392 | } 393 | 394 | static Janet cfun_sign_update(int32_t argc, Janet *argv) { 395 | janet_fixarity(argc, 2); 396 | hydro_sign_state *state = janet_getabstract(argv, 0, &SignState); 397 | JanetByteView msg = janet_getbytes(argv, 1); 398 | int result = hydro_sign_update(state, msg.bytes, msg.len); 399 | if (result) { 400 | janet_panic("failed to update signature state"); 401 | } 402 | return argv[0]; 403 | } 404 | 405 | static Janet cfun_sign_final_create(int32_t argc, Janet *argv) { 406 | janet_fixarity(argc, 2); 407 | hydro_sign_state *state = janet_getabstract(argv, 0, &SignState); 408 | JanetByteView sk = util_getnbytes(argv, 1, hydro_sign_SECRETKEYBYTES); 409 | uint8_t *csig = janet_string_begin(hydro_sign_BYTES); 410 | int result = hydro_sign_final_create(state, csig, sk.bytes); 411 | if (result) { 412 | janet_panic("failed to create signature"); 413 | } 414 | return janet_wrap_string(janet_string_end(csig)); 415 | } 416 | 417 | static Janet cfun_sign_final_verify(int32_t argc, Janet *argv) { 418 | janet_fixarity(argc, 3); 419 | hydro_sign_state *state = janet_getabstract(argv, 0, &SignState); 420 | JanetByteView csig = util_getnbytes(argv, 1, hydro_sign_BYTES); 421 | JanetByteView pk = util_getnbytes(argv, 2, hydro_sign_PUBLICKEYBYTES); 422 | int result = hydro_sign_final_verify(state, csig.bytes, pk.bytes); 423 | return janet_wrap_boolean(!result); 424 | } 425 | 426 | /*******************/ 427 | /* Password Hashing */ 428 | /*******************/ 429 | 430 | typedef struct { 431 | uint64_t opslimit; 432 | size_t memlimit; 433 | uint8_t threads; 434 | } PwhashOpts; 435 | 436 | static PwhashOpts util_pwhash_opts(int32_t argc, const Janet *argv, int32_t n) { 437 | PwhashOpts opts; 438 | opts.opslimit = 2000; 439 | opts.memlimit = 2000; 440 | opts.threads = 4; 441 | if (argc > n && !janet_checktype(argv[n], JANET_NIL)) { 442 | opts.opslimit = (uint64_t) util_getnat(argv, n); 443 | } 444 | if (argc > n + 1 && !janet_checktype(argv[n], JANET_NIL)) { 445 | opts.memlimit = (size_t) util_getnat(argv, n + 1); 446 | } 447 | if (argc > n + 2 && !janet_checktype(argv[n], JANET_NIL)) { 448 | int32_t threads_int = util_getnat(argv, n + 2); 449 | if (threads_int > 255) { 450 | janet_panicf("expected integer in range [0, 255] for threads, got %v", argv[6]); 451 | } 452 | opts.threads = (uint8_t) threads_int; 453 | } 454 | return opts; 455 | } 456 | 457 | static Janet cfun_pwhash_keygen(int32_t argc, Janet *argv) { 458 | JanetBuffer *buffer = util_keygen_prep(argc, argv, hydro_pwhash_MASTERKEYBYTES); 459 | hydro_pwhash_keygen(buffer->data); 460 | return janet_wrap_buffer(buffer); 461 | } 462 | 463 | static Janet cfun_pwhash_deterministic(int32_t argc, Janet *argv) { 464 | janet_arity(argc, 4, 7); 465 | int32_t h_len = util_getnat(argv, 0); 466 | JanetByteView passwd = janet_getbytes(argv, 1); 467 | JanetByteView ctx = util_getnbytes(argv, 2, hydro_pwhash_CONTEXTBYTES); 468 | JanetByteView mk = util_getnbytes(argv, 3, hydro_pwhash_MASTERKEYBYTES); 469 | PwhashOpts opts = util_pwhash_opts(argc, argv, 4); 470 | uint8_t *str = janet_string_begin(h_len); 471 | int result = hydro_pwhash_deterministic(str, h_len, (const char *) passwd.bytes, passwd.len, 472 | (const char *) ctx.bytes, mk.bytes, opts.opslimit, opts.memlimit, opts.threads); 473 | if (result) { 474 | janet_panic("failed to hash password"); 475 | } 476 | return janet_wrap_string(janet_string_end(str)); 477 | } 478 | 479 | static Janet cfun_pwhash_create(int32_t argc, Janet *argv) { 480 | janet_arity(argc, 2, 5); 481 | JanetByteView passwd = janet_getbytes(argv, 0); 482 | JanetByteView mk = util_getnbytes(argv, 1, hydro_pwhash_MASTERKEYBYTES); 483 | PwhashOpts opts = util_pwhash_opts(argc, argv, 2); 484 | uint8_t *stored = janet_string_begin(hydro_pwhash_STOREDBYTES); 485 | int result = hydro_pwhash_create(stored, (const char *) passwd.bytes, 486 | passwd.len, mk.bytes, opts.opslimit, opts.memlimit, opts.threads); 487 | if (result) { 488 | janet_panic("failed hashing password"); 489 | } 490 | return janet_wrap_string(janet_string_end(stored)); 491 | } 492 | 493 | static Janet cfun_pwhash_verify(int32_t argc, Janet *argv) { 494 | janet_arity(argc, 3, 6); 495 | JanetByteView stored = util_getnbytes(argv, 0, hydro_pwhash_STOREDBYTES); 496 | JanetByteView passwd = janet_getbytes(argv, 1); 497 | JanetByteView mk = util_getnbytes(argv, 2, hydro_pwhash_MASTERKEYBYTES); 498 | PwhashOpts opts = util_pwhash_opts(argc, argv, 3); 499 | int result = hydro_pwhash_verify(stored.bytes, (const char *) passwd.bytes, passwd.len, 500 | mk.bytes, opts.opslimit, opts.memlimit, opts.threads); 501 | return janet_wrap_boolean(!result); 502 | } 503 | 504 | static Janet cfun_pwhash_derive_static_key(int32_t argc, Janet *argv) { 505 | janet_arity(argc, 5, 8); 506 | int32_t klen = util_getnat(argv, 0); 507 | JanetByteView stored = util_getnbytes(argv, 1, hydro_pwhash_STOREDBYTES); 508 | JanetByteView passwd = janet_getbytes(argv, 2); 509 | JanetByteView ctx = util_getnbytes(argv, 3, hydro_pwhash_CONTEXTBYTES); 510 | JanetByteView mk = util_getnbytes(argv, 4, hydro_pwhash_MASTERKEYBYTES); 511 | PwhashOpts opts = util_pwhash_opts(argc, argv, 5); 512 | uint8_t *static_key = janet_string_begin(klen); 513 | int result = hydro_pwhash_derive_static_key(static_key, klen, stored.bytes, 514 | (const char *) passwd.bytes, passwd.len, 515 | (const char *) ctx.bytes, 516 | mk.bytes, 517 | opts.opslimit, opts.memlimit, opts.threads); 518 | if (result) { 519 | janet_panic("failed to create static key"); 520 | } 521 | return janet_wrap_string(janet_string_end(static_key)); 522 | } 523 | 524 | static Janet cfun_pwhash_reencrypt(int32_t argc, Janet *argv) { 525 | janet_fixarity(argc, 3); 526 | JanetByteView stored = util_getnbytes(argv, 0, hydro_pwhash_STOREDBYTES); 527 | JanetByteView mk = util_getnbytes(argv, 1, hydro_pwhash_MASTERKEYBYTES); 528 | JanetByteView newmk = util_getnbytes(argv, 2, hydro_pwhash_MASTERKEYBYTES); 529 | uint8_t *newstored = janet_string_begin(hydro_pwhash_STOREDBYTES); 530 | memcpy(newstored, stored.bytes, hydro_pwhash_STOREDBYTES); 531 | int result = hydro_pwhash_reencrypt(newstored, mk.bytes, newmk.bytes); 532 | if (result) { 533 | janet_panic("failed to reencrypt password hash"); 534 | } 535 | return janet_wrap_string(janet_string_end(newstored)); 536 | } 537 | 538 | static Janet cfun_pwhash_upgrade(int32_t argc, Janet *argv) { 539 | janet_arity(argc, 2, 5); 540 | JanetByteView stored = util_getnbytes(argv, 0, hydro_pwhash_STOREDBYTES); 541 | JanetByteView mk = util_getnbytes(argv, 1, hydro_pwhash_MASTERKEYBYTES); 542 | PwhashOpts opts = util_pwhash_opts(argc, argv, 2); 543 | uint8_t *newstored = janet_string_begin(hydro_pwhash_STOREDBYTES); 544 | memcpy(newstored, stored.bytes, hydro_pwhash_STOREDBYTES); 545 | int result = hydro_pwhash_upgrade(newstored, mk.bytes, 546 | opts.opslimit, opts.memlimit, opts.threads); 547 | if (result) { 548 | janet_panic("failed to upgrade password hash"); 549 | } 550 | return janet_wrap_string(janet_string_end(newstored)); 551 | } 552 | 553 | /* Utilities */ 554 | 555 | static Janet cfun_memzero(int32_t argc, Janet *argv) { 556 | janet_fixarity(argc, 1); 557 | JanetBuffer *buffer = janet_getbuffer(argv, 0); 558 | hydro_memzero(buffer->data, buffer->count); 559 | return janet_wrap_buffer(buffer); 560 | } 561 | 562 | static Janet cfun_increment(int32_t argc, Janet *argv) { 563 | janet_fixarity(argc, 1); 564 | JanetBuffer *buffer = janet_getbuffer(argv, 0); 565 | hydro_increment(buffer->data, buffer->count); 566 | return janet_wrap_buffer(buffer); 567 | } 568 | 569 | static Janet cfun_equal(int32_t argc, Janet *argv) { 570 | janet_fixarity(argc, 2); 571 | JanetByteView lhs = janet_getbytes(argv, 0); 572 | JanetByteView rhs = janet_getbytes(argv, 1); 573 | if (lhs.len != rhs.len) return janet_wrap_false(); 574 | return janet_wrap_boolean(hydro_equal(lhs.bytes, rhs.bytes, lhs.len)); 575 | } 576 | 577 | static Janet cfun_compare(int32_t argc, Janet *argv) { 578 | janet_fixarity(argc, 2); 579 | JanetByteView lhs = janet_getbytes(argv, 0); 580 | JanetByteView rhs = janet_getbytes(argv, 1); 581 | if (lhs.len < rhs.len) return janet_wrap_integer(-1); 582 | if (lhs.len > rhs.len) return janet_wrap_integer(1); 583 | return janet_wrap_integer(hydro_compare(lhs.bytes, rhs.bytes, lhs.len)); 584 | } 585 | 586 | static Janet cfun_bin2hex(int32_t argc, Janet *argv) { 587 | janet_arity(argc, 1, 2); 588 | JanetByteView bin = janet_getbytes(argv, 0); 589 | JanetBuffer *hex = (argc == 2) ? janet_getbuffer(argv, 1) : janet_buffer(bin.len * 2 + 1); 590 | if (argc == 2) { 591 | janet_buffer_extra(hex, 2 * bin.len + 1); 592 | } 593 | hydro_bin2hex((char *)(hex->data + hex->count), bin.len * 2 + 1, bin.bytes, bin.len); 594 | hex->count += 2 * bin.len; 595 | return janet_wrap_buffer(hex); 596 | } 597 | 598 | static Janet cfun_hex2bin(int32_t argc, Janet *argv) { 599 | janet_arity(argc, 1, 3); 600 | JanetByteView hex = janet_getbytes(argv, 0); 601 | JanetBuffer *bin = (argc >= 2) ? janet_getbuffer(argv, 1) : janet_buffer(hex.len >> 1); 602 | const char *ignore = NULL; 603 | if (argc >= 3 && !janet_checktype(argv[2], JANET_NIL)) { 604 | ignore = janet_getcstring(argv, 2); 605 | } 606 | janet_buffer_extra(bin, (hex.len >> 1)); 607 | int result = hydro_hex2bin(bin->data + bin->count, 608 | hex.len >> 1, (const char *) hex.bytes, hex.len, 609 | ignore, NULL); 610 | if (result < 0) { 611 | janet_panic("failed to convert hex to binary"); 612 | } 613 | bin->count += result; 614 | return janet_wrap_buffer(bin); 615 | } 616 | 617 | static Janet cfun_pad(int32_t argc, Janet *argv) { 618 | janet_fixarity(argc, 2); 619 | JanetBuffer *buffer = janet_getbuffer(argv, 0); 620 | size_t pad = janet_getsize(argv, 1); 621 | janet_buffer_extra(buffer, pad + 2); 622 | int result = hydro_pad(buffer->data, buffer->count, pad, buffer->capacity); 623 | if (result < 0) { 624 | janet_panic("failed to pad bytes"); 625 | } 626 | buffer->count = result; 627 | return janet_wrap_buffer(buffer); 628 | } 629 | 630 | static Janet cfun_unpad(int32_t argc, Janet *argv) { 631 | janet_fixarity(argc, 2); 632 | JanetBuffer *buffer = janet_getbuffer(argv, 0); 633 | size_t blocksize = janet_getsize(argv, 1); 634 | int result = hydro_unpad(buffer->data, buffer->count, blocksize); 635 | if (result < 0) { 636 | janet_panic("failed to unpad buffer"); 637 | } 638 | buffer->count = result; 639 | return janet_wrap_buffer(buffer); 640 | } 641 | 642 | /* Key Exchange (KX) */ 643 | 644 | static Janet util_kx_sessionkeypair(hydro_kx_session_keypair *kp) { 645 | JanetKV *st = janet_struct_begin(2); 646 | Janet tx = janet_stringv(kp->tx, hydro_kx_SESSIONKEYBYTES); 647 | Janet rx = janet_stringv(kp->rx, hydro_kx_SESSIONKEYBYTES); 648 | janet_struct_put(st, janet_ckeywordv("tx"), tx); 649 | janet_struct_put(st, janet_ckeywordv("rx"), rx); 650 | return janet_wrap_struct(janet_struct_end(st)); 651 | } 652 | 653 | static Janet cfun_kx_keygen(int32_t argc, Janet *argv) { 654 | (void) argv; 655 | janet_fixarity(argc, 0); 656 | hydro_kx_keypair kp; 657 | hydro_kx_keygen(&kp); 658 | JanetKV *st = janet_struct_begin(2); 659 | Janet pk = janet_stringv(kp.pk, hydro_kx_PUBLICKEYBYTES); 660 | Janet sk = janet_stringv(kp.sk, hydro_kx_SECRETKEYBYTES); 661 | janet_struct_put(st, janet_ckeywordv("public-key"), pk); 662 | janet_struct_put(st, janet_ckeywordv("secret-key"), sk); 663 | return janet_wrap_struct(janet_struct_end(st)); 664 | } 665 | 666 | static Janet cfun_kx_n_1(int32_t argc, Janet *argv) { 667 | janet_fixarity(argc, 3); 668 | JanetBuffer *packet = janet_getbuffer(argv, 0); 669 | JanetByteView psk = util_getnbytes(argv, 1, hydro_kx_PSKBYTES); 670 | JanetByteView peer_psk = util_getnbytes(argv, 2, hydro_kx_PUBLICKEYBYTES); 671 | hydro_kx_session_keypair kp; 672 | janet_buffer_extra(packet, hydro_kx_N_PACKET1BYTES); 673 | int result = hydro_kx_n_1(&kp, packet->data + packet->count, psk.bytes, peer_psk.bytes); 674 | if (result < 0) { 675 | janet_panic("failed to generate packet 1 to send to peer"); 676 | } 677 | packet->count += hydro_kx_N_PACKET1BYTES; 678 | return util_kx_sessionkeypair(&kp); 679 | } 680 | 681 | static Janet cfun_kx_n_2(int32_t argc, Janet *argv) { 682 | janet_fixarity(argc, 4); 683 | JanetByteView packet = util_getnbytes(argv, 0, hydro_kx_N_PACKET1BYTES); 684 | JanetByteView psk = util_getnbytes(argv, 1, hydro_kx_PSKBYTES); 685 | JanetByteView static_pk = util_getnbytes(argv, 2, hydro_kx_PUBLICKEYBYTES); 686 | JanetByteView static_sk = util_getnbytes(argv, 3, hydro_kx_SECRETKEYBYTES); 687 | hydro_kx_keypair static_kp; 688 | memcpy(static_kp.sk, static_sk.bytes, hydro_kx_SECRETKEYBYTES); 689 | memcpy(static_kp.pk, static_pk.bytes, hydro_kx_PUBLICKEYBYTES); 690 | hydro_kx_session_keypair kp; 691 | int result = hydro_kx_n_2(&kp, packet.bytes, psk.bytes, &static_kp); 692 | if (result < 0) { 693 | janet_panic("failed to generate packet 2 to send to peer"); 694 | } 695 | return util_kx_sessionkeypair(&kp); 696 | } 697 | 698 | /* KK variant */ 699 | 700 | static const JanetAbstractType KxState = { 701 | "jhydro/kx-state", 702 | #ifdef JANET_ATEND_NAME 703 | JANET_ATEND_NAME 704 | #endif 705 | }; 706 | 707 | static Janet cfun_kx_kk_1(int32_t argc, Janet *argv) { 708 | janet_fixarity(argc, 4); 709 | JanetBuffer *packet1 = janet_getbuffer(argv, 0); 710 | JanetByteView static_pk = util_getnbytes(argv, 1, hydro_kx_PUBLICKEYBYTES); 711 | JanetByteView pk = util_getnbytes(argv, 2, hydro_kx_PUBLICKEYBYTES); 712 | JanetByteView sk = util_getnbytes(argv, 3, hydro_kx_SECRETKEYBYTES); 713 | hydro_kx_state *state = janet_abstract(&KxState, sizeof(hydro_kx_state)); 714 | janet_buffer_extra(packet1, hydro_kx_KK_PACKET1BYTES); 715 | hydro_kx_keypair kp; 716 | memcpy(&kp.pk, pk.bytes, hydro_kx_PUBLICKEYBYTES); 717 | memcpy(&kp.sk, sk.bytes, hydro_kx_SECRETKEYBYTES); 718 | int result = hydro_kx_kk_1(state, packet1->data + packet1->count, static_pk.bytes, &kp); 719 | if (result < 0) { 720 | janet_panic("failed to generate packet 1 to send to peer"); 721 | } 722 | packet1->count += hydro_kx_KK_PACKET1BYTES; 723 | return janet_wrap_abstract(state); 724 | } 725 | 726 | static Janet cfun_kx_kk_2(int32_t argc, Janet *argv) { 727 | janet_fixarity(argc, 5); 728 | JanetBuffer *packet2 = janet_getbuffer(argv, 0); 729 | janet_buffer_extra(packet2, hydro_kx_KK_PACKET2BYTES); 730 | JanetByteView packet1 = util_getnbytes(argv, 1, hydro_kx_KK_PACKET1BYTES); 731 | JanetByteView static_pk = util_getnbytes(argv, 2, hydro_kx_PUBLICKEYBYTES); 732 | JanetByteView pk = util_getnbytes(argv, 3, hydro_kx_PUBLICKEYBYTES); 733 | JanetByteView sk = util_getnbytes(argv, 4, hydro_kx_SECRETKEYBYTES); 734 | hydro_kx_keypair kp; 735 | memcpy(&kp.pk, pk.bytes, hydro_kx_PUBLICKEYBYTES); 736 | memcpy(&kp.sk, sk.bytes, hydro_kx_SECRETKEYBYTES); 737 | hydro_kx_session_keypair skp; 738 | int result = hydro_kx_kk_2(&skp, packet2->data, packet1.bytes, static_pk.bytes, &kp); 739 | if (result < 0) { 740 | janet_panic("failed to generate session keypair"); 741 | } 742 | packet2->count += hydro_kx_KK_PACKET2BYTES; 743 | return util_kx_sessionkeypair(&skp); 744 | } 745 | 746 | static Janet cfun_kx_kk_3(int32_t argc, Janet *argv) { 747 | janet_fixarity(argc, 4); 748 | hydro_kx_state *state = janet_getabstract(argv, 0, &KxState); 749 | JanetByteView packet2 = util_getnbytes(argv, 1, hydro_kx_KK_PACKET2BYTES); 750 | JanetByteView pk = util_getnbytes(argv, 2, hydro_kx_PUBLICKEYBYTES); 751 | JanetByteView sk = util_getnbytes(argv, 3, hydro_kx_SECRETKEYBYTES); 752 | hydro_kx_session_keypair skp; 753 | hydro_kx_keypair kp; 754 | memcpy(&kp.pk, pk.bytes, hydro_kx_PUBLICKEYBYTES); 755 | memcpy(&kp.sk, sk.bytes, hydro_kx_SECRETKEYBYTES); 756 | int result = hydro_kx_kk_3(state, &skp, packet2.bytes, &kp); 757 | if (result < 0) { 758 | janet_panic("failed to generate session keypair"); 759 | } 760 | return util_kx_sessionkeypair(&skp); 761 | } 762 | 763 | /* XX Variant */ 764 | 765 | static Janet cfun_kx_xx_1(int32_t argc, Janet *argv) { 766 | janet_fixarity(argc, 2); 767 | JanetBuffer *packet1 = janet_getbuffer(argv, 0); 768 | JanetByteView psk = util_getnbytes(argv, 1, hydro_kx_PSKBYTES); 769 | janet_buffer_extra(packet1, hydro_kx_XX_PACKET1BYTES); 770 | hydro_kx_state *state = janet_abstract(&KxState, sizeof(hydro_kx_state)); 771 | int result = hydro_kx_xx_1(state, packet1->data + packet1->count, psk.bytes); 772 | if (result) { 773 | janet_panic("failed to generate packet 1 to send to peer"); 774 | } 775 | packet1->count += hydro_kx_XX_PACKET1BYTES; 776 | return janet_wrap_abstract(state); 777 | } 778 | 779 | static Janet cfun_kx_xx_2(int32_t argc, Janet *argv) { 780 | janet_fixarity(argc, 5); 781 | JanetBuffer *packet2 = janet_getbuffer(argv, 0); 782 | JanetByteView packet1 = util_getnbytes(argv, 1, hydro_kx_XX_PACKET1BYTES); 783 | JanetByteView psk = util_getnbytes(argv, 2, hydro_kx_PSKBYTES); 784 | JanetByteView pk = util_getnbytes(argv, 3, hydro_kx_PUBLICKEYBYTES); 785 | JanetByteView sk = util_getnbytes(argv, 4, hydro_kx_SECRETKEYBYTES); 786 | hydro_kx_keypair kp; 787 | memcpy(&kp.pk, pk.bytes, hydro_kx_PUBLICKEYBYTES); 788 | memcpy(&kp.sk, sk.bytes, hydro_kx_SECRETKEYBYTES); 789 | hydro_kx_state *state = janet_abstract(&KxState, sizeof(hydro_kx_state)); 790 | janet_buffer_extra(packet2, hydro_kx_XX_PACKET2BYTES); 791 | int result = hydro_kx_xx_2(state, packet2->data + packet2->count, packet1.bytes, psk.bytes, &kp); 792 | if (result < 0) { 793 | janet_panic("failed to generate packet 2 to send to peer"); 794 | } 795 | packet2->count += hydro_kx_XX_PACKET2BYTES; 796 | return janet_wrap_abstract(state); 797 | } 798 | 799 | static Janet cfun_kx_xx_3(int32_t argc, Janet *argv) { 800 | janet_arity(argc, 6, 7); 801 | hydro_kx_state *state = janet_getabstract(argv, 0, &KxState); 802 | JanetBuffer *packet3 = janet_getbuffer(argv, 1); 803 | JanetByteView packet2 = util_getnbytes(argv, 2, hydro_kx_XX_PACKET2BYTES); 804 | JanetByteView psk = util_getnbytes(argv, 3, hydro_kx_PSKBYTES); 805 | JanetByteView pk = util_getnbytes(argv, 4, hydro_kx_PUBLICKEYBYTES); 806 | JanetByteView sk = util_getnbytes(argv, 5, hydro_kx_SECRETKEYBYTES); 807 | hydro_kx_keypair kp; 808 | hydro_kx_session_keypair skp; 809 | memcpy(&kp.pk, pk.bytes, hydro_kx_PUBLICKEYBYTES); 810 | memcpy(&kp.sk, sk.bytes, hydro_kx_SECRETKEYBYTES); 811 | janet_buffer_extra(packet3, hydro_kx_XX_PACKET3BYTES); 812 | uint8_t *peer_pk = NULL; 813 | if (argc > 6) { 814 | JanetBuffer *buffer = janet_getbuffer(argv, 6); 815 | janet_buffer_extra(buffer, hydro_kx_PUBLICKEYBYTES); 816 | peer_pk = buffer->data + buffer->count; 817 | buffer->count += hydro_kx_PUBLICKEYBYTES; 818 | } 819 | int result = hydro_kx_xx_3(state, &skp, packet3->data + packet3->count, peer_pk, packet2.bytes, psk.bytes, &kp); 820 | if (result < 0) { 821 | janet_panic("failed to generate session keypair"); 822 | } 823 | packet3->count += hydro_kx_XX_PACKET3BYTES; 824 | return util_kx_sessionkeypair(&skp); 825 | } 826 | 827 | static Janet cfun_kx_xx_4(int32_t argc, Janet *argv) { 828 | janet_arity(argc, 3, 4); 829 | hydro_kx_state *state = janet_getabstract(argv, 0, &KxState); 830 | JanetByteView packet3 = util_getnbytes(argv, 1, hydro_kx_XX_PACKET3BYTES); 831 | JanetByteView psk = util_getnbytes(argv, 2, hydro_kx_PSKBYTES); 832 | uint8_t *peer_pk = NULL; 833 | hydro_kx_session_keypair skp; 834 | if (argc > 3) { 835 | JanetBuffer *buffer = janet_getbuffer(argv, 3); 836 | janet_buffer_extra(buffer, hydro_kx_PUBLICKEYBYTES); 837 | peer_pk = buffer->data + buffer->count; 838 | buffer->count += hydro_kx_PUBLICKEYBYTES; 839 | } 840 | int result = hydro_kx_xx_4(state, &skp, peer_pk, packet3.bytes, psk.bytes); 841 | if (result) { 842 | janet_panic("failed to generate session keypair"); 843 | } 844 | return util_kx_sessionkeypair(&skp); 845 | } 846 | 847 | /****************/ 848 | /* Module Entry */ 849 | /****************/ 850 | 851 | static const JanetReg cfuns[] = { 852 | 853 | /* Random */ 854 | { "random/u32", cfun_random_u32, "(random/u32)\n\n" 855 | "Generate a psuedo random 32 bit unsigned integer" 856 | }, 857 | { "random/uniform", cfun_random_uniform, "(random/uniform top)\n\n" 858 | "Generate a random 32 bit unsigned integer less than top." 859 | }, 860 | { "random/buf", cfun_random_buf, "(random/buf buf &opt size)\n\n" 861 | "Fill a buffer with random bytes. If size is not provided, it will clear " 862 | "and fill the given buffer. If size is provided, will append size random " 863 | "bytes to the buffer. if you provide just the size argument," 864 | "a new randomized buffer will be returned." 865 | }, 866 | { "random/ratchet", cfun_random_ratchet, "(random/ratchet)\n\n" 867 | "Increment the internal state of the RNG." 868 | }, 869 | { "random/reseed", cfun_random_reseed, "(random/reseed)\n\n" 870 | "Provide a new random seed for the internal RNG." 871 | }, 872 | { "random/buf-deterministic", cfun_random_buf_deterministic, 873 | "(random/buf-deterministic buf len seed)\n\n" 874 | "Generate len random bytes and push them into a buffer buf. seed " 875 | "is a byte sequence of 32 bytes that initializes the state of the RNG. " 876 | "With same seed and len returns always the same buffer. Suitable for testing. " 877 | "Returns the modified buffer." 878 | }, 879 | /* Hashing */ 880 | { "hash/keygen", cfun_hash_keygen, "(hash/keygen &opt buf)\n\n" 881 | "Generate a key suitable for use in hashing. The key is a buffer of at " 882 | "least 32 bytes. If a buffer buf is provided, the first 32 bytes of buf " 883 | "will be set to a new random key. Returns a key buffer." 884 | }, 885 | { "hash/new-state", cfun_hash_new, "(hash/new-state ctx key)\n\n" 886 | "Create a new hash-state. Takes a context ctx and a key and returns a new abstract type, " 887 | "jhydro/hash-state. Both ctx and key should be byte sequences, of lengths 8 and 32 " 888 | "respectively. Returns the new state." 889 | }, 890 | { "hash/update", cfun_hash_update, "(hash/update state bytes)\n\n" 891 | "Add more bytes to the hash state. Returns the modified state" 892 | }, 893 | { "hash/final", cfun_hash_final, "(hash/final state len)\n\n" 894 | "Get the final hash after digesting all of the input as a string. The resulting " 895 | "hash will be a string of length len." 896 | }, 897 | { "hash/hash", cfun_hash_hash, "(hash/hash size input ctx &opt key)\n\n" 898 | "Hash some input bytes into an output string of length size. Optionally provide " 899 | "a key that can be used to generate different hashes on the same input." 900 | }, 901 | /* Secret Box - symmetric encryption */ 902 | { "secretbox/keygen", cfun_secretbox_keygen, "(secretbox/keygen)\n\n" 903 | "Generate a key suitable for secretbox. The returned key is a 32 byte buffer." 904 | }, 905 | { "secretbox/encrypt", cfun_secretbox_encrypt, 906 | "(secretbox/encrypt msg msg-id ctx key &opt buf)\n\n" 907 | "Encrypt a message with a secretbox key and return the cipher text in a buffer. " 908 | "Also requires a message id, which is an integer, and a ctx, which is a non-secret " 909 | "byte-sequence. Lastly, requires a secret symmetric key for encryption. An optional " 910 | "buffer will prevent Janet from creating a new buffer, and instead append to and return " 911 | "the provided buffer." 912 | }, 913 | { "secretbox/decrypt", cfun_secretbox_decrypt, 914 | "(secretbox/decrypt cipher-text msg-id ctx key &opt buf)\n\n" 915 | "Decrypt a cipher text that was produced with secretbox/encrypt. msg-id, " 916 | "ctx, and key must be the same as those used to encrypt the message. An optional " 917 | "buffer can be used to contain the plain text, otherwise a new buffer is created. " 918 | "Returns a buffer containing the plain text." 919 | }, 920 | { "secretbox/probe-create", cfun_secretbox_probe_create, 921 | "(secretbox/probe-create cipher-text ctx key)\n\n" 922 | "Create a probe for some cipher text created by secretbox/encrypt. The " 923 | "resulting probe is a constant length string that can be used to verify if cipher text " 924 | "is valid before decrypting the entire text. Probes can help mitigate " 925 | "attack with large invalid ciphertexts. Returns a string." 926 | }, 927 | { "secretbox/probe-verify", cfun_secretbox_probe_verify, 928 | "(secretbox/probe-verify probe cipher-text ctx key)\n\n" 929 | "Use a probe produced by secretbox/probe-create to check if some cipher text " 930 | "is genuine. If the cipher text is not forged or tampered with, returns true, otherwise " 931 | "false. Genuine cipher text can then be decrypted. Returns a boolean." 932 | }, 933 | /* KDF */ 934 | { "kdf/keygen", cfun_kdf_keygen, "(kdf/keygen &opt buf)\n\n" 935 | "Generate a key for use in KDFs. Returns the modified buf if provided, or " 936 | "a new random buffer." 937 | }, 938 | { "kdf/derive-from-key", cfun_kdf_derive_from_key, 939 | "(kdf/derive-from-key sublen subid ctx key)\n\n" 940 | "Generate a subkey from a master key. Takes a subid, which is " 941 | "a positive integer that represents the key id, and ctx, which is " 942 | "an 8 byte string that is usually an application constant. Finally, the " 943 | "last parameter is the master key. Returns a string of length sublen." 944 | }, 945 | /* Public Key Signatures */ 946 | { "sign/keygen", cfun_sign_keygen, "(sign/keygen)\n\n" 947 | "Create a random key pair for public key signing. Returns a struct containing a " 948 | ":public-key and a :secret-key as strings." 949 | }, 950 | { "sign/keygen-deterministic", cfun_sign_keygen_deterministic, 951 | "(sign/keygen-deterministic seed)\n\n" 952 | "Create a key pair from a seed. Seed should be a byte sequence of at least " 953 | "32 bytes; random/buf should work well. Returns a struct of two key value " 954 | "pairs, a :secret-key and a :public-key. Each key is a string." 955 | }, 956 | { "sign/create", cfun_sign_create, "(sign/create msg ctx sk)\n\n" 957 | "Create a new sigature from a message, ctx, and secret key. The message " 958 | "can be any byte sequence, the context ctx should be a byte sequence of " 959 | "8 bytes, and the secret key sk should be secret key as generated from sign/keygen or " 960 | "sign/keygen-deterministic. Returns a signature, which is a 64 byte string." 961 | }, 962 | { "sign/verify", cfun_sign_verify, "(sign/verify csig msg ctx pk)\n\n" 963 | "Check a signature to determine if a message is authentic. csig is the signature as " 964 | "generated by sign/create or sign/final-create, msg is the message that " 965 | "we are checking, ctx is the context string, and pk is the public key. Returns a boolean, " 966 | "true if the signature is valid, false otherwise." 967 | }, 968 | { "sign/new-state", cfun_sign_new, "(sign/new-state ctx)\n\n" 969 | "Create a new state machine for generating a signature. A state machine allows " 970 | "processing a message in chunks to generate a signature. A string ctx of 8 bytes " 971 | "is also required, and can be a hard coded string. Returns a new jhydro/sign-state." 972 | }, 973 | { "sign/update", cfun_sign_update, "(sign/update state msg)\n\n" 974 | "Process a message chunk for generating a signature. Returns the modified signature state." 975 | }, 976 | { "sign/final-create", cfun_sign_final_create, "(sign/final-create state sk)\n\n" 977 | "Create a signature from the sign-state. Takes a jhydro/sign-state state and a secret key sk. " 978 | "Returns the signature and also modifies the state." 979 | }, 980 | { "sign/final-verify", cfun_sign_final_verify, "(sign/final-verify state csig pk)\n\n" 981 | "Verify a signature with a public key. Given a sign-state state, signature csig, and " 982 | "public key pk, return true if csig is valid, otherwise false." 983 | }, 984 | /* Password Hashing */ 985 | { "pwhash/keygen", cfun_pwhash_keygen, "(pwhash/keygen &opt buf)\n\n" 986 | "Generate a master key for use in hashing passwords. The master key is used to " 987 | "encrypt all hashed passwords for an extra level of security. Returns a buffer with " 988 | "the new key." 989 | }, 990 | { "pwhash/deterministic", cfun_pwhash_deterministic, 991 | "(pwhash/deterministic hlen passwd ctx master-key &opt opslimit memlimit threads)\n\n" 992 | "Hash a password to produce a high entropy key. " 993 | "The returned hashed password is a string of length hlen." 994 | }, 995 | { "pwhash/create", cfun_pwhash_create, 996 | "(pwhash/create passwd masterkey &opt opslimit memlimit threads)\n\n" 997 | "Hash a password and get a blob that can be safely stored in a database. " 998 | "The returned result is a 128 byte string. Can take optional parameters to tune " 999 | "the difficulty of the hash." 1000 | }, 1001 | { "pwhash/verify", cfun_pwhash_verify, 1002 | "(pwhash/verify stored passwd master-key &opt opslimit memlimit threads)\n\n" 1003 | "Check if a password matches a stored password hash. Hashing options must be the same as " 1004 | "the ones used to created the stored hash." 1005 | }, 1006 | { "pwhash/derive-static-key", cfun_pwhash_derive_static_key, 1007 | "(pwhash/derive-static-key keylen stored passwd ctx master-key &opt opslimit memlimit threads)\n\n" 1008 | "Verifies that password is valid for the representative. This function can be used to derive a " 1009 | "high-entropy key from a password and user-specific hashed data stored in a database. " 1010 | "Returns a string with keylen bytes." 1011 | }, 1012 | { "pwhash/reencrypt", cfun_pwhash_reencrypt, 1013 | "(pwhash/reencrypt stored masterkey new-masterkey)\n\n" 1014 | "Re-encrypt a hashed password under a new master key without needing the original password, only " 1015 | "the previously hashed password and master key. Returns the new hashed password as a string." 1016 | }, 1017 | { "pwhash/upgrade", cfun_pwhash_upgrade, 1018 | "(pwhash/upgrade stored masterkey &opt opslimit memlimit threads)\n\n" 1019 | "Change the encryption parameters of a key to make decrypting faster or slower. This can " 1020 | "be used to scale difficulty of password hashing in the event of hardware advancements. Returns " 1021 | "the new password hash as a string." 1022 | }, 1023 | /* Utilities */ 1024 | { "util/memzero", cfun_memzero, "(util/memzero buffer)\n\n" 1025 | "Clear memory in a buffer to 0, not changing the size of the buffer. Returns the " 1026 | "modified buffer." 1027 | }, 1028 | { "util/++", cfun_increment, "(util/++ buffer)\n\n" 1029 | "Increment a buffer, treating it as a little endian large integer. If the increment results in an overflow, sets the " 1030 | "buffer to all zero bytes. Returns the modified buffer." 1031 | }, 1032 | { "util/=", cfun_equal, "(util/= lhs rhs)\n\n" 1033 | "Compare the contents of two equal length buffers without early returns, which helps prevent side channel attacks. This " 1034 | "is the function that should be used for comparing two buffers with cryptographic content. " 1035 | "If the two buffers are of different lengths, returns early. Returns a boolen." 1036 | }, 1037 | { "util/compare", cfun_compare, "(util/compare lhs rhs)\n\n" 1038 | "Compare two buffers without early returns to help prevent side channel attacks. Returns an integer -1, 0, or 1." 1039 | }, 1040 | { "util/bin2hex", cfun_bin2hex, "(util/bin2hex bin &opt hex)\n\n" 1041 | "Convert binary data into hexidecimal. The hex representation of bin, the input buffer, is " 1042 | "converted to a ascii hexidecimal and put in the buffer hex, or a new buffer if hex is not supplied. Returns " 1043 | "hex or a new buffer." 1044 | }, 1045 | { "util/hex2bin", cfun_hex2bin, "(util/hex2bin hex &opt bin ignore)\n\n" 1046 | "Convert a hexidecimal string to binary data. Can provide an optional bin to write into instead of creating a new " 1047 | "buffer, and also a string of characters to ignore while reading hex. Returns the buffer bin or a new buffer." 1048 | }, 1049 | { "util/pad", cfun_pad, "(util/pad buffer blocksize)\n\n" 1050 | "Pad a buffer according to the ISO/IEC 7816-4 algorithm. Returns the modified buffer." 1051 | }, 1052 | { "util/unpad", cfun_unpad, "(util/unpad buffer blocksize)\n\n" 1053 | "Unpad a buffer padded via util/pad. Returns the modifed buffer." 1054 | }, 1055 | /* Key Exchange */ 1056 | { "kx/keygen", cfun_kx_keygen, "(kx/keygen)\n\n" 1057 | "Generate a keypair for use in key exchanges. Contains both a public key and a secret key. " 1058 | "Returns a struct with two entries: :secret-key and a :public-key." 1059 | }, 1060 | { "kx/n1", cfun_kx_n_1, "(kx/n1 packet-buf psk peer-pk)\n\n" 1061 | "Create a session key and generate a packet on the client as the first step in the N variant key exchange. " 1062 | "Also take a pre-shared key, and the peer's public key. Returns a session key as a struct of two " 1063 | "entries, :tx and :rx, which are the transmit and receive keys for communicating with the peer." 1064 | }, 1065 | { "kx/n2", cfun_kx_n_2, "(kx/n2 packet1 psk pk sk)\n\n" 1066 | "Create a session key as the second step in the N variant key exchange on the server. " 1067 | "packet1 is what kx/n1 put into a buffer (packet-buf), psk is a pre-shared key, pk is the server's " 1068 | "public key, and sk is the server's secret key. Returns a session keypair that is a mirror of what is on " 1069 | "the client, but :tx and :rx are swapped." 1070 | }, 1071 | { "kx/kk1", cfun_kx_kk_1, "(kx/kk1 packet-1 static-pk pk sk)\n\n" 1072 | "Generate the first packet for the KK variant key exchange. Returns a jhydro/ks-state " 1073 | "abstract which contains some useful state for the key exchange. static-pk is the peer's " 1074 | "public key, and pk and sk are the client's public and secret keys. Modifies the buffer packet-1 " 1075 | "by appending new data." 1076 | }, 1077 | { "kx/kk2", cfun_kx_kk_2, "(kx/kk2 packet-2 packet-1 static-pk pk sk)\n\n" 1078 | "Generate the second packet and a session keypair in the KK variant key exchange. packet-2 is " 1079 | "a buffer to put the new packet in. packet-1 is the packet received from the peer. static-pk is the " 1080 | "other peer's public key, and pk and sk are the local client's public and secret keys. Returns a session keypair, " 1081 | "which is a struct of two entries, :rx and :tx." 1082 | }, 1083 | { "kx/kk3", cfun_kx_kk_3, "(kx/kk3 state packet-2 pk sk)\n\n" 1084 | "Generate a session key on the initiating peer in the KK variant key exchange. state is the " 1085 | "jhydro/kx-state from step 1, packet-2 is the packet from step 2, and pk and sk are the local client's " 1086 | "public and secret keys. Returns a session keypair, which is a struct of two entries, :rx and :tx." 1087 | }, 1088 | { "kx/xx1", cfun_kx_xx_1, "(kx/xx1 packet-1 psk)\n\n" 1089 | "First step in XX variant key exchange. Takes in a packet buffer and pre-shared key, and " 1090 | "generates the first packet. Also returns a jhydro/kx-state for use in future steps." 1091 | }, 1092 | { "kx/xx2", cfun_kx_xx_2, "(kx/xx2 packet-2 packet-1 psk pk sk)\n\n" 1093 | "Second step in XX variant key exchange. Takes a buffer for writing packet number 2 too, " 1094 | "packet 1, a pre-shared key, and the local public key and secret key. Writes the second packet " 1095 | "to packet-2, and returns a jhydro/kx-state." 1096 | }, 1097 | { "kx/xx3", cfun_kx_xx_3, "(kx/xx3 state packet-3 packet-2 psk pk sk &opt peer-pk)\n\n" 1098 | "Third step in XX variant key exchange. Takes the state returned from kx/xx1, a buffer " 1099 | "packet-3 to write the final packet into, the packet packet-2 send from the other peer, a " 1100 | "pre-shared key psk, and the public and secret keys of the local machine. Optionally " 1101 | "takes a buffer to write the remote peer's public key into, so you can reject connections if " 1102 | "they do not match the expected public key. Returns a session keypair, which is a struct with two " 1103 | "entries, :rx and :tx." 1104 | }, 1105 | { "kx/xx4", cfun_kx_xx_4, "(kx/xx4 state packet-3 psk &opt peer-pk)\n\n" 1106 | "Fourth and final step in the XX key exchange variant. Takes the state returned from kx/xx2, " 1107 | "the packet received from kx/xx3, and a pre-shared key psk. " 1108 | "Optionally takes a buffer peer-pk, which will have the remote peer's " 1109 | "public key written appended to it. Returns a session keypair, which contains :tx and :rx entires." 1110 | }, 1111 | {NULL, NULL, NULL} 1112 | }; 1113 | 1114 | JANET_MODULE_ENTRY(JanetTable *env) { 1115 | hydro_init(); 1116 | janet_cfuns(env, "jhydro", cfuns); 1117 | 1118 | /* Constants */ 1119 | 1120 | /* Random */ 1121 | janet_def(env, "random/seed-bytes", janet_wrap_integer(hydro_random_SEEDBYTES), 1122 | "Number of bytes in a seed for the RNG."); 1123 | 1124 | /* Hashing */ 1125 | janet_def(env, "hash/bytes", janet_wrap_integer(hydro_hash_BYTES), 1126 | "Number of bytes in a generic, simple hash."); 1127 | janet_def(env, "hash/bytes-max", janet_wrap_integer(hydro_hash_BYTES_MAX), 1128 | "Maximum number of bytes allowed when creating a keyed hash."); 1129 | janet_def(env, "hash/bytes-min", janet_wrap_integer(hydro_hash_BYTES_MIN), 1130 | "Minimum number of bytes allowed when creating a keyed hash."); 1131 | janet_def(env, "hash/context-bytes", janet_wrap_integer(hydro_hash_CONTEXTBYTES), 1132 | "Number of bytes required in context buffer for hashing."); 1133 | janet_def(env, "hash/key-bytes", janet_wrap_integer(hydro_hash_KEYBYTES), 1134 | "Number of bytes in a key required for hashing."); 1135 | 1136 | /* Secretbox */ 1137 | janet_def(env, "secretbox/context-bytes", 1138 | janet_wrap_integer(hydro_secretbox_CONTEXTBYTES), 1139 | "Number of bytes in a context for secretbox functions."); 1140 | janet_def(env, "secretbox/header-bytes", janet_wrap_integer(hydro_secretbox_HEADERBYTES), 1141 | "Number of bytes in the header of an encrypted message."); 1142 | janet_def(env, "secretbox/key-bytes", janet_wrap_integer(hydro_secretbox_KEYBYTES), 1143 | "Number of bytes in a secretbox key."); 1144 | janet_def(env, "secretbox/probe-bytes", janet_wrap_integer(hydro_secretbox_PROBEBYTES), 1145 | "Number of bytes in a secretbox probe."); 1146 | 1147 | /* KDF */ 1148 | janet_def(env, "kdf/context-bytes", janet_wrap_integer(hydro_kdf_CONTEXTBYTES), 1149 | "Number of bytes in context argument to jhydro/kdf functions."); 1150 | janet_def(env, "kdf/key-bytes", janet_wrap_integer(hydro_kdf_KEYBYTES), 1151 | "Number of bytes in a kdf key."); 1152 | janet_def(env, "kdf/bytes-max", janet_wrap_integer(hydro_kdf_BYTES_MAX), 1153 | "Maximum number of bytes allowed in kdf generated key."); 1154 | janet_def(env, "kdf/bytes-min", janet_wrap_integer(hydro_kdf_BYTES_MIN), 1155 | "Minimum number of bytes allowed in kdf generated key."); 1156 | 1157 | /* Signing */ 1158 | janet_def(env, "sign/bytes", janet_wrap_integer(hydro_sign_BYTES), 1159 | "Number of bytes in a signature."); 1160 | janet_def(env, "sign/context-bytes", janet_wrap_integer(hydro_sign_CONTEXTBYTES), 1161 | "Number of bytes needed for a signature context."); 1162 | janet_def(env, "sign/public-key-bytes", janet_wrap_integer(hydro_sign_PUBLICKEYBYTES), 1163 | "Number of bytes in a public key for making signatures."); 1164 | janet_def(env, "sign/secret-key-bytes", janet_wrap_integer(hydro_sign_SECRETKEYBYTES), 1165 | "Number of bytes in a secret key for making signatures."); 1166 | janet_def(env, "sign/seed-bytes", janet_wrap_integer(hydro_sign_SEEDBYTES), 1167 | "Number of bytes in a seed for generating a key."); 1168 | 1169 | /* KX */ 1170 | janet_def(env, "kx/session-key-bytes", janet_wrap_integer(hydro_kx_SESSIONKEYBYTES), 1171 | "Number of bytes in a session key (tx or rx key). These keys are used to encrypt and " 1172 | "decrypt messages between two peers."); 1173 | janet_def(env, "kx/public-key-bytes", janet_wrap_integer(hydro_kx_PUBLICKEYBYTES), 1174 | "Number of bytes in a public key intended for key exchange."); 1175 | janet_def(env, "kx/secret-key-bytes", janet_wrap_integer(hydro_kx_SECRETKEYBYTES), 1176 | "Number of bytes in a secret key intended for key exchange."); 1177 | janet_def(env, "kx/psk-bytes", janet_wrap_integer(hydro_kx_PSKBYTES), 1178 | "Number of bytes in a pre-shared key for key exchange."); 1179 | janet_def(env, "kx/n-packet-1-bytes", janet_wrap_integer(hydro_kx_N_PACKET1BYTES), 1180 | "Number of bytes in the first packet sent in the N variant key exchange."); 1181 | janet_def(env, "kx/kk-packet-1-bytes", janet_wrap_integer(hydro_kx_KK_PACKET1BYTES), 1182 | "Number of bytes in the first packet sent in the KK variant key exchange."); 1183 | janet_def(env, "kx/kk-packet-2-bytes", janet_wrap_integer(hydro_kx_KK_PACKET2BYTES), 1184 | "Number of bytes in the second packet sent in the KK variant key exchange."); 1185 | janet_def(env, "kx/xx-packet-1-bytes", janet_wrap_integer(hydro_kx_XX_PACKET1BYTES), 1186 | "Number of bytes in the first packet sent in the XX variant key exchange."); 1187 | janet_def(env, "kx/xx-packet-2-bytes", janet_wrap_integer(hydro_kx_XX_PACKET2BYTES), 1188 | "Number of bytes in the second packet sent in the XX variant key exchange."); 1189 | janet_def(env, "kx/xx-packet-3-bytes", janet_wrap_integer(hydro_kx_XX_PACKET3BYTES), 1190 | "Number of bytes in the third packet sent in the XX variant key exchange."); 1191 | } 1192 | -------------------------------------------------------------------------------- /project.janet: -------------------------------------------------------------------------------- 1 | (declare-project 2 | :name "jhydro" 3 | :description "Lightweight cryptographic and random number generation utils for Janet. Based on libhydrogen." 4 | :author "Calvin Rose" 5 | :license "MIT" 6 | :url "https://github.com/janet-lang/jhydro" 7 | :repo "git+https://github.com/janet-lang/jhydro.git" 8 | :dependencies ["spork"]) 9 | 10 | (declare-native 11 | :name "jhydro" 12 | :cflags [;default-cflags "-I."] 13 | :source @["jhydro.c" 14 | "hydrogen.c"]) 15 | -------------------------------------------------------------------------------- /test/suite1.janet: -------------------------------------------------------------------------------- 1 | (use ../build/jhydro) 2 | (use spork/test) 3 | 4 | (start-suite 1) 5 | 6 | (assert 7 | # ok, so this isn't strictly correct, but it is very unlikely. 8 | (all identity (seq [i :range [0 500]] 9 | (not= (random/u32) (random/u32)))) 10 | "u32") 11 | (assert (= 1024 (length (random/buf 1024))) "buffer 1") 12 | (assert (= 0 (length (random/buf 0))) "buffer 2") 13 | 14 | (assert-error "buffer 3" (random/buf -1)) 15 | 16 | (assert-error "buffer 4" (random/buf @"abc" -10)) 17 | 18 | (end-suite) 19 | -------------------------------------------------------------------------------- /test/suite2.janet: -------------------------------------------------------------------------------- 1 | (use ../build/jhydro) 2 | (use spork/test) 3 | 4 | (start-suite 2) 5 | 6 | (assert (deep= (util/hex2bin "a3") @"\xA3") "util/hex2bin") 7 | (assert (deep= (util/bin2hex "\xA3") @"a3") "util/bin2hex") 8 | 9 | (end-suite) 10 | -------------------------------------------------------------------------------- /test/suite3.janet: -------------------------------------------------------------------------------- 1 | (use ../build/jhydro) 2 | (use spork/test) 3 | 4 | (start-suite 3) 5 | 6 | # n variant 7 | (do 8 | (def {:public-key pk :secret-key sk} (kx/keygen)) 9 | (def packet @"") 10 | (def psk (random/buf kx/psk-bytes)) 11 | (def {:tx client-tx :rx client-rx} (kx/n1 packet psk pk)) 12 | (def {:tx server-tx :rx server-rx} (kx/n2 packet psk pk sk)) 13 | (assert (util/= client-tx server-rx) "client rx = server tx") 14 | (assert (util/= client-rx server-tx) "client tx = server rx")) 15 | 16 | # kk variant 17 | (do 18 | (def {:public-key pk1 :secret-key sk1} (kx/keygen)) 19 | (def {:public-key pk2 :secret-key sk2} (kx/keygen)) 20 | (def packet1 @"") 21 | (def packet2 @"") 22 | (def a-state (kx/kk1 packet1 pk2 pk1 sk1)) 23 | (def {:tx b-tx :rx b-rx} (kx/kk2 packet2 packet1 pk1 pk2 sk2)) 24 | (def {:tx a-tx :rx a-rx} (kx/kk3 a-state packet2 pk1 sk1)) 25 | (assert (util/= a-tx b-rx) "a tx = b rx") 26 | (assert (util/= a-rx b-tx) "a rx = b tx")) 27 | 28 | # xx variant 29 | (do 30 | (def {:public-key pk1 :secret-key sk1} (kx/keygen)) 31 | (def {:public-key pk2 :secret-key sk2} (kx/keygen)) 32 | (def packet1 @"") 33 | (def packet2 @"") 34 | (def packet3 @"") 35 | (def psk (random/buf kx/psk-bytes)) 36 | (def a-state (kx/xx1 packet1 psk)) 37 | (def b-state (kx/xx2 packet2 packet1 psk pk2 sk2)) 38 | (def {:tx b-tx :rx b-rx} (kx/xx3 a-state packet3 packet2 psk pk1 sk1)) 39 | (def {:tx a-tx :rx a-rx} (kx/xx4 b-state packet3 psk)) 40 | (assert (util/= a-tx b-rx) "a tx = b rx") 41 | (assert (util/= a-rx b-tx) "a rx = b tx")) 42 | 43 | (end-suite) 44 | --------------------------------------------------------------------------------