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 char nonce[CHACHA20_POLY1305_IV_LEN]; 38 }; 39 40 static int 41 chacha20_poly1305_setkey(void *vctx, const uint8_t *key, int len) 42 { 43 struct chacha20_poly1305_cipher_ctx *ctx = vctx; 44 45 if (len != CHACHA20_POLY1305_KEY) 46 return (EINVAL); 47 48 ctx->key = key; 49 return (0); 50 } 51 52 static void 53 chacha20_poly1305_reinit(void *vctx, const uint8_t *iv) 54 { 55 struct chacha20_poly1305_cipher_ctx *ctx = vctx; 56 57 /* Block 0 is used for the poly1305 key. */ 58 memcpy(ctx->nonce, iv, sizeof(ctx->nonce)); 59 ctx->ic = 1; 60 } 61 62 static void 63 chacha20_poly1305_crypt(void *vctx, const uint8_t *in, uint8_t *out) 64 { 65 struct chacha20_poly1305_cipher_ctx *ctx = vctx; 66 int error; 67 68 error = crypto_stream_chacha20_ietf_xor_ic(out, in, 69 CHACHA20_NATIVE_BLOCK_LEN, ctx->nonce, ctx->ic, ctx->key); 70 KASSERT(error == 0, ("%s failed: %d", __func__, error)); 71 ctx->ic++; 72 } 73 74 static void 75 chacha20_poly1305_crypt_last(void *vctx, const uint8_t *in, uint8_t *out, 76 size_t len) 77 { 78 struct chacha20_poly1305_cipher_ctx *ctx = vctx; 79 80 int error; 81 82 error = crypto_stream_chacha20_ietf_xor_ic(out, in, len, ctx->nonce, 83 ctx->ic, ctx->key); 84 KASSERT(error == 0, ("%s failed: %d", __func__, error)); 85 } 86 87 struct enc_xform enc_xform_chacha20_poly1305 = { 88 .type = CRYPTO_CHACHA20_POLY1305, 89 .name = "ChaCha20-Poly1305", 90 .ctxsize = sizeof(struct chacha20_poly1305_cipher_ctx), 91 .blocksize = 1, 92 .native_blocksize = CHACHA20_NATIVE_BLOCK_LEN, 93 .ivsize = CHACHA20_POLY1305_IV_LEN, 94 .minkey = CHACHA20_POLY1305_KEY, 95 .maxkey = CHACHA20_POLY1305_KEY, 96 .encrypt = chacha20_poly1305_crypt, 97 .decrypt = chacha20_poly1305_crypt, 98 .setkey = chacha20_poly1305_setkey, 99 .reinit = chacha20_poly1305_reinit, 100 .encrypt_last = chacha20_poly1305_crypt_last, 101 .decrypt_last = chacha20_poly1305_crypt_last, 102 }; 103 104 struct chacha20_poly1305_auth_ctx { 105 struct crypto_onetimeauth_poly1305_state state; 106 const void *key; 107 }; 108 CTASSERT(sizeof(union authctx) >= sizeof(struct chacha20_poly1305_auth_ctx)); 109 110 static void 111 chacha20_poly1305_Init(void *vctx) 112 { 113 } 114 115 static void 116 chacha20_poly1305_Setkey(void *vctx, const uint8_t *key, u_int klen) 117 { 118 struct chacha20_poly1305_auth_ctx *ctx = vctx; 119 120 ctx->key = key; 121 } 122 123 static void 124 chacha20_poly1305_Reinit(void *vctx, const uint8_t *nonce, u_int noncelen) 125 { 126 struct chacha20_poly1305_auth_ctx *ctx = vctx; 127 char block[CHACHA20_NATIVE_BLOCK_LEN]; 128 129 crypto_stream_chacha20_ietf(block, sizeof(block), nonce, ctx->key); 130 crypto_onetimeauth_poly1305_init(&ctx->state, block); 131 explicit_bzero(block, sizeof(block)); 132 } 133 134 static int 135 chacha20_poly1305_Update(void *vctx, const void *data, u_int len) 136 { 137 struct chacha20_poly1305_auth_ctx *ctx = vctx; 138 139 crypto_onetimeauth_poly1305_update(&ctx->state, data, len); 140 return (0); 141 } 142 143 static void 144 chacha20_poly1305_Final(uint8_t *digest, void *vctx) 145 { 146 struct chacha20_poly1305_auth_ctx *ctx = vctx; 147 148 crypto_onetimeauth_poly1305_final(&ctx->state, digest); 149 } 150 151 struct auth_hash auth_hash_chacha20_poly1305 = { 152 .type = CRYPTO_POLY1305, 153 .name = "ChaCha20-Poly1305", 154 .keysize = POLY1305_KEY_LEN, 155 .hashsize = POLY1305_HASH_LEN, 156 .ctxsize = sizeof(struct chacha20_poly1305_auth_ctx), 157 .blocksize = crypto_onetimeauth_poly1305_BYTES, 158 .Init = chacha20_poly1305_Init, 159 .Setkey = chacha20_poly1305_Setkey, 160 .Reinit = chacha20_poly1305_Reinit, 161 .Update = chacha20_poly1305_Update, 162 .Final = chacha20_poly1305_Final, 163 }; 164