Path: blob/main/contrib/bearssl/src/symcipher/poly1305_i15.c
39483 views
/*1* Copyright (c) 2017 Thomas Pornin <[email protected]>2*3* Permission is hereby granted, free of charge, to any person obtaining4* a copy of this software and associated documentation files (the5* "Software"), to deal in the Software without restriction, including6* without limitation the rights to use, copy, modify, merge, publish,7* distribute, sublicense, and/or sell copies of the Software, and to8* permit persons to whom the Software is furnished to do so, subject to9* the following conditions:10*11* The above copyright notice and this permission notice shall be12* included in all copies or substantial portions of the Software.13*14* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,15* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF16* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND17* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS18* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN19* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN20* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE21* SOFTWARE.22*/2324#include "inner.h"2526/*27* This is a "reference" implementation of Poly1305 that uses the28* generic "i15" code for big integers. It is slow, but it handles all29* big-integer operations with generic code, thereby avoiding most30* tricky situations with carry propagation and modular reduction.31*/3233/*34* Modulus: 2^130-5.35*/36static const uint16_t P1305[] = {370x008A,380x7FFB, 0x7FFF, 0x7FFF, 0x7FFF, 0x7FFF, 0x7FFF, 0x7FFF, 0x7FFF, 0x03FF39};4041/*42* -p mod 2^15.43*/44#define P0I 0x4CCD4546/*47* R^2 mod p, for conversion to Montgomery representation (R = 2^135,48* since we use 9 words of 15 bits each, and 15*9 = 135).49*/50static const uint16_t R2[] = {510x008A,520x6400, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x000053};5455/*56* Perform the inner processing of blocks for Poly1305. The "r" array57* is in Montgomery representation, while the "a" array is not.58*/59static void60poly1305_inner(uint16_t *a, const uint16_t *r, const void *data, size_t len)61{62const unsigned char *buf;6364buf = data;65while (len > 0) {66unsigned char tmp[16], rev[16];67uint16_t b[10];68uint32_t ctl;69int i;7071/*72* If there is a partial block, right-pad it with zeros.73*/74if (len < 16) {75memset(tmp, 0, sizeof tmp);76memcpy(tmp, buf, len);77buf = tmp;78len = 16;79}8081/*82* Decode next block and apply the "high bit". Since83* decoding is little-endian, we must byte-swap the buffer.84*/85for (i = 0; i < 16; i ++) {86rev[i] = buf[15 - i];87}88br_i15_decode_mod(b, rev, sizeof rev, P1305);89b[9] |= 0x0100;9091/*92* Add the accumulator to the decoded block (modular93* addition).94*/95ctl = br_i15_add(b, a, 1);96ctl |= NOT(br_i15_sub(b, P1305, 0));97br_i15_sub(b, P1305, ctl);9899/*100* Multiply by r, result is the new accumulator value.101*/102br_i15_montymul(a, b, r, P1305, P0I);103104buf += 16;105len -= 16;106}107}108109/*110* Byteswap a 16-byte value.111*/112static void113byteswap16(unsigned char *buf)114{115int i;116117for (i = 0; i < 8; i ++) {118unsigned x;119120x = buf[i];121buf[i] = buf[15 - i];122buf[15 - i] = x;123}124}125126/* see bearssl_block.h */127void128br_poly1305_i15_run(const void *key, const void *iv,129void *data, size_t len, const void *aad, size_t aad_len,130void *tag, br_chacha20_run ichacha, int encrypt)131{132unsigned char pkey[32], foot[16];133uint16_t t[10], r[10], acc[10];134135/*136* Compute the MAC key. The 'r' value is the first 16 bytes of137* pkey[].138*/139memset(pkey, 0, sizeof pkey);140ichacha(key, iv, 0, pkey, sizeof pkey);141142/*143* If encrypting, ChaCha20 must run first, followed by Poly1305.144* When decrypting, the operations are reversed.145*/146if (encrypt) {147ichacha(key, iv, 1, data, len);148}149150/*151* Run Poly1305. We must process the AAD, then ciphertext, then152* the footer (with the lengths). Note that the AAD and ciphertext153* are meant to be padded with zeros up to the next multiple of 16,154* and the length of the footer is 16 bytes as well.155*/156157/*158* Apply the "clamping" operation on the encoded 'r' value.159*/160pkey[ 3] &= 0x0F;161pkey[ 7] &= 0x0F;162pkey[11] &= 0x0F;163pkey[15] &= 0x0F;164pkey[ 4] &= 0xFC;165pkey[ 8] &= 0xFC;166pkey[12] &= 0xFC;167168/*169* Decode the clamped 'r' value. Decoding should use little-endian170* so we must byteswap the value first.171*/172byteswap16(pkey);173br_i15_decode_mod(t, pkey, 16, P1305);174175/*176* Convert 'r' to Montgomery representation.177*/178br_i15_montymul(r, t, R2, P1305, P0I);179180/*181* Accumulator is 0.182*/183br_i15_zero(acc, 0x8A);184185/*186* Process the additional authenticated data, ciphertext, and187* footer in due order.188*/189br_enc64le(foot, (uint64_t)aad_len);190br_enc64le(foot + 8, (uint64_t)len);191poly1305_inner(acc, r, aad, aad_len);192poly1305_inner(acc, r, data, len);193poly1305_inner(acc, r, foot, sizeof foot);194195/*196* Decode the value 's'. Again, a byteswap is needed.197*/198byteswap16(pkey + 16);199br_i15_decode_mod(t, pkey + 16, 16, P1305);200201/*202* Add the value 's' to the accumulator. That addition is done203* modulo 2^128, so we just ignore the carry.204*/205br_i15_add(acc, t, 1);206207/*208* Encode the result (128 low bits) to the tag. Encoding should209* be little-endian.210*/211br_i15_encode(tag, 16, acc);212byteswap16(tag);213214/*215* If decrypting, then ChaCha20 runs _after_ Poly1305.216*/217if (!encrypt) {218ichacha(key, iv, 1, data, len);219}220}221222223