Path: blob/main/sys/crypto/openssl/ossl_poly1305.c
39536 views
/*1* Copyright 2015-2018 The OpenSSL Project Authors. All Rights Reserved.2*3* Licensed under the OpenSSL license (the "License"). You may not use4* this file except in compliance with the License. You can obtain a copy5* in the file LICENSE in the source distribution or at6* https://www.openssl.org/source/license.html7*/89#include <sys/libkern.h>10#include <sys/malloc.h>1112#include <opencrypto/cryptodev.h>13#include <opencrypto/xform_auth.h>1415#include <crypto/openssl/ossl.h>16#include <crypto/openssl/ossl_poly1305.h>1718#define POLY1305_ASM1920/* From crypto/poly1305/poly1305.c */2122/* pick 32-bit unsigned integer in little endian order */23static unsigned int U8TOU32(const unsigned char *p)24{25return (((unsigned int)(p[0] & 0xff)) |26((unsigned int)(p[1] & 0xff) << 8) |27((unsigned int)(p[2] & 0xff) << 16) |28((unsigned int)(p[3] & 0xff) << 24));29}3031/*32* Implementations can be classified by amount of significant bits in33* words making up the multi-precision value, or in other words radix34* or base of numerical representation, e.g. base 2^64, base 2^32,35* base 2^26. Complementary characteristic is how wide is the result of36* multiplication of pair of digits, e.g. it would take 128 bits to37* accommodate multiplication result in base 2^64 case. These are used38* interchangeably. To describe implementation that is. But interface39* is designed to isolate this so that low-level primitives implemented40* in assembly can be self-contained/self-coherent.41*/42int poly1305_init(void *ctx, const unsigned char key[16], void *func);43void poly1305_blocks(void *ctx, const unsigned char *inp, size_t len,44unsigned int padbit);45void poly1305_emit(void *ctx, unsigned char mac[16],46const unsigned int nonce[4]);4748void Poly1305_Init(POLY1305 *ctx, const unsigned char key[32])49{50ctx->nonce[0] = U8TOU32(&key[16]);51ctx->nonce[1] = U8TOU32(&key[20]);52ctx->nonce[2] = U8TOU32(&key[24]);53ctx->nonce[3] = U8TOU32(&key[28]);5455/*56* Unlike reference poly1305_init assembly counterpart is expected57* to return a value: non-zero if it initializes ctx->func, and zero58* otherwise. Latter is to simplify assembly in cases when there no59* multiple code paths to switch between.60*/61if (!poly1305_init(ctx->opaque, key, &ctx->func)) {62ctx->func.blocks = poly1305_blocks;63ctx->func.emit = poly1305_emit;64}6566ctx->num = 0;6768}6970#ifdef POLY1305_ASM71/*72* This "eclipses" poly1305_blocks and poly1305_emit, but it's73* conscious choice imposed by -Wshadow compiler warnings.74*/75# define poly1305_blocks (*poly1305_blocks_p)76# define poly1305_emit (*poly1305_emit_p)77#endif7879void Poly1305_Update(POLY1305 *ctx, const unsigned char *inp, size_t len)80{81#ifdef POLY1305_ASM82/*83* As documented, poly1305_blocks is never called with input84* longer than single block and padbit argument set to 0. This85* property is fluently used in assembly modules to optimize86* padbit handling on loop boundary.87*/88poly1305_blocks_f poly1305_blocks_p = ctx->func.blocks;89#endif90size_t rem, num;9192if ((num = ctx->num)) {93rem = POLY1305_BLOCK_SIZE - num;94if (len >= rem) {95memcpy(ctx->data + num, inp, rem);96poly1305_blocks(ctx->opaque, ctx->data, POLY1305_BLOCK_SIZE, 1);97inp += rem;98len -= rem;99} else {100/* Still not enough data to process a block. */101memcpy(ctx->data + num, inp, len);102ctx->num = num + len;103return;104}105}106107rem = len % POLY1305_BLOCK_SIZE;108len -= rem;109110if (len >= POLY1305_BLOCK_SIZE) {111poly1305_blocks(ctx->opaque, inp, len, 1);112inp += len;113}114115if (rem)116memcpy(ctx->data, inp, rem);117118ctx->num = rem;119}120121void Poly1305_Final(POLY1305 *ctx, unsigned char mac[16])122{123#ifdef POLY1305_ASM124poly1305_blocks_f poly1305_blocks_p = ctx->func.blocks;125poly1305_emit_f poly1305_emit_p = ctx->func.emit;126#endif127size_t num;128129if ((num = ctx->num)) {130ctx->data[num++] = 1; /* pad bit */131while (num < POLY1305_BLOCK_SIZE)132ctx->data[num++] = 0;133poly1305_blocks(ctx->opaque, ctx->data, POLY1305_BLOCK_SIZE, 0);134}135136poly1305_emit(ctx->opaque, mac, ctx->nonce);137138/* zero out the state */139OPENSSL_cleanse(ctx, sizeof(*ctx));140}141142static void143ossl_poly1305_init(void *vctx)144{145}146147static void148ossl_poly1305_setkey(void *vctx, const uint8_t *key, u_int klen)149{150MPASS(klen == 32);151Poly1305_Init(vctx, key);152}153154int155ossl_poly1305_update(void *vctx, const void *buf, u_int len)156{157Poly1305_Update(vctx, buf, len);158return (0);159}160161static void162ossl_poly1305_final(uint8_t *digest, void *vctx)163{164Poly1305_Final(vctx, digest);165}166167struct auth_hash ossl_hash_poly1305 = {168.type = CRYPTO_POLY1305,169.name = "OpenSSL-Poly1305",170.hashsize = POLY1305_HASH_LEN,171.ctxsize = sizeof(struct poly1305_context),172.blocksize = POLY1305_BLOCK_SIZE,173.Init = ossl_poly1305_init,174.Setkey = ossl_poly1305_setkey,175.Update = ossl_poly1305_update,176.Final = ossl_poly1305_final,177};178179_Static_assert(sizeof(struct poly1305_context) <=180sizeof(struct ossl_hash_context), "ossl_hash_context too small");181182183