1 /*- 2 * SPDX-License-Identifier: BSD-2-Clause-FreeBSD 3 * 4 * Copyright (c) 2020 Netflix Inc. 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: 9 * 1. Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * 2. Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution. 14 * 15 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 16 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 21 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 25 * SUCH DAMAGE. 26 */ 27 28 #include <opencrypto/xform_auth.h> 29 #include <opencrypto/xform_enc.h> 30 31 #include <sodium/crypto_onetimeauth_poly1305.h> 32 #include <sodium/crypto_stream_chacha20.h> 33 34 struct chacha20_poly1305_cipher_ctx { 35 const void *key; 36 uint32_t ic; 37 bool ietf; 38 char nonce[CHACHA20_POLY1305_IV_LEN]; 39 }; 40 41 static int 42 chacha20_poly1305_setkey(void *vctx, const uint8_t *key, int len) 43 { 44 struct chacha20_poly1305_cipher_ctx *ctx = vctx; 45 46 if (len != CHACHA20_POLY1305_KEY) 47 return (EINVAL); 48 49 ctx->key = key; 50 return (0); 51 } 52 53 static void 54 chacha20_poly1305_reinit(void *vctx, const uint8_t *iv, size_t ivlen) 55 { 56 struct chacha20_poly1305_cipher_ctx *ctx = vctx; 57 58 KASSERT(ivlen == 8 || ivlen == sizeof(ctx->nonce), 59 ("%s: invalid nonce length", __func__)); 60 61 /* Block 0 is used for the poly1305 key. */ 62 memcpy(ctx->nonce, iv, ivlen); 63 ctx->ietf = (ivlen == CHACHA20_POLY1305_IV_LEN); 64 ctx->ic = 1; 65 } 66 67 static void 68 chacha20_poly1305_crypt(void *vctx, const uint8_t *in, uint8_t *out) 69 { 70 struct chacha20_poly1305_cipher_ctx *ctx = vctx; 71 int error; 72 73 if (ctx->ietf) 74 error = crypto_stream_chacha20_ietf_xor_ic(out, in, 75 CHACHA20_NATIVE_BLOCK_LEN, ctx->nonce, ctx->ic, ctx->key); 76 else 77 error = crypto_stream_chacha20_xor_ic(out, in, 78 CHACHA20_NATIVE_BLOCK_LEN, ctx->nonce, ctx->ic, ctx->key); 79 KASSERT(error == 0, ("%s failed: %d", __func__, error)); 80 ctx->ic++; 81 } 82 83 static void 84 chacha20_poly1305_crypt_last(void *vctx, const uint8_t *in, uint8_t *out, 85 size_t len) 86 { 87 struct chacha20_poly1305_cipher_ctx *ctx = vctx; 88 89 int error; 90 91 if (ctx->ietf) 92 error = crypto_stream_chacha20_ietf_xor_ic(out, in, len, 93 ctx->nonce, ctx->ic, ctx->key); 94 else 95 error = crypto_stream_chacha20_xor_ic(out, in, len, ctx->nonce, 96 ctx->ic, ctx->key); 97 KASSERT(error == 0, ("%s failed: %d", __func__, error)); 98 } 99 100 const struct enc_xform enc_xform_chacha20_poly1305 = { 101 .type = CRYPTO_CHACHA20_POLY1305, 102 .name = "ChaCha20-Poly1305", 103 .ctxsize = sizeof(struct chacha20_poly1305_cipher_ctx), 104 .blocksize = 1, 105 .native_blocksize = CHACHA20_NATIVE_BLOCK_LEN, 106 .ivsize = CHACHA20_POLY1305_IV_LEN, 107 .minkey = CHACHA20_POLY1305_KEY, 108 .maxkey = CHACHA20_POLY1305_KEY, 109 .encrypt = chacha20_poly1305_crypt, 110 .decrypt = chacha20_poly1305_crypt, 111 .setkey = chacha20_poly1305_setkey, 112 .reinit = chacha20_poly1305_reinit, 113 .encrypt_last = chacha20_poly1305_crypt_last, 114 .decrypt_last = chacha20_poly1305_crypt_last, 115 }; 116 117 struct chacha20_poly1305_auth_ctx { 118 struct crypto_onetimeauth_poly1305_state state; 119 const void *key; 120 }; 121 CTASSERT(sizeof(union authctx) >= sizeof(struct chacha20_poly1305_auth_ctx)); 122 123 static void 124 chacha20_poly1305_Init(void *vctx) 125 { 126 } 127 128 static void 129 chacha20_poly1305_Setkey(void *vctx, const uint8_t *key, u_int klen) 130 { 131 struct chacha20_poly1305_auth_ctx *ctx = vctx; 132 133 ctx->key = key; 134 } 135 136 static void 137 chacha20_poly1305_Reinit(void *vctx, const uint8_t *nonce, u_int noncelen) 138 { 139 struct chacha20_poly1305_auth_ctx *ctx = vctx; 140 char block[CHACHA20_NATIVE_BLOCK_LEN]; 141 142 switch (noncelen) { 143 case 8: 144 crypto_stream_chacha20(block, sizeof(block), nonce, ctx->key); 145 break; 146 case CHACHA20_POLY1305_IV_LEN: 147 crypto_stream_chacha20_ietf(block, sizeof(block), nonce, ctx->key); 148 break; 149 default: 150 __assert_unreachable(); 151 } 152 crypto_onetimeauth_poly1305_init(&ctx->state, block); 153 explicit_bzero(block, sizeof(block)); 154 } 155 156 static int 157 chacha20_poly1305_Update(void *vctx, const void *data, u_int len) 158 { 159 struct chacha20_poly1305_auth_ctx *ctx = vctx; 160 161 crypto_onetimeauth_poly1305_update(&ctx->state, data, len); 162 return (0); 163 } 164 165 static void 166 chacha20_poly1305_Final(uint8_t *digest, void *vctx) 167 { 168 struct chacha20_poly1305_auth_ctx *ctx = vctx; 169 170 crypto_onetimeauth_poly1305_final(&ctx->state, digest); 171 } 172 173 const struct auth_hash auth_hash_chacha20_poly1305 = { 174 .type = CRYPTO_POLY1305, 175 .name = "ChaCha20-Poly1305", 176 .keysize = POLY1305_KEY_LEN, 177 .hashsize = POLY1305_HASH_LEN, 178 .ctxsize = sizeof(struct chacha20_poly1305_auth_ctx), 179 .blocksize = crypto_onetimeauth_poly1305_BYTES, 180 .Init = chacha20_poly1305_Init, 181 .Setkey = chacha20_poly1305_Setkey, 182 .Reinit = chacha20_poly1305_Reinit, 183 .Update = chacha20_poly1305_Update, 184 .Final = chacha20_poly1305_Final, 185 }; 186