linux/lib/crypto/poly1305.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0-or-later
   2/*
   3 * Poly1305 authenticator algorithm, RFC7539
   4 *
   5 * Copyright (C) 2015 Martin Willi
   6 *
   7 * Based on public domain code by Andrew Moon and Daniel J. Bernstein.
   8 */
   9
  10#include <crypto/internal/poly1305.h>
  11#include <linux/kernel.h>
  12#include <linux/module.h>
  13#include <asm/unaligned.h>
  14
  15void poly1305_init_generic(struct poly1305_desc_ctx *desc,
  16                           const u8 key[POLY1305_KEY_SIZE])
  17{
  18        poly1305_core_setkey(&desc->core_r, key);
  19        desc->s[0] = get_unaligned_le32(key + 16);
  20        desc->s[1] = get_unaligned_le32(key + 20);
  21        desc->s[2] = get_unaligned_le32(key + 24);
  22        desc->s[3] = get_unaligned_le32(key + 28);
  23        poly1305_core_init(&desc->h);
  24        desc->buflen = 0;
  25        desc->sset = true;
  26        desc->rset = 2;
  27}
  28EXPORT_SYMBOL_GPL(poly1305_init_generic);
  29
  30void poly1305_update_generic(struct poly1305_desc_ctx *desc, const u8 *src,
  31                             unsigned int nbytes)
  32{
  33        unsigned int bytes;
  34
  35        if (unlikely(desc->buflen)) {
  36                bytes = min(nbytes, POLY1305_BLOCK_SIZE - desc->buflen);
  37                memcpy(desc->buf + desc->buflen, src, bytes);
  38                src += bytes;
  39                nbytes -= bytes;
  40                desc->buflen += bytes;
  41
  42                if (desc->buflen == POLY1305_BLOCK_SIZE) {
  43                        poly1305_core_blocks(&desc->h, &desc->core_r, desc->buf,
  44                                             1, 1);
  45                        desc->buflen = 0;
  46                }
  47        }
  48
  49        if (likely(nbytes >= POLY1305_BLOCK_SIZE)) {
  50                poly1305_core_blocks(&desc->h, &desc->core_r, src,
  51                                     nbytes / POLY1305_BLOCK_SIZE, 1);
  52                src += nbytes - (nbytes % POLY1305_BLOCK_SIZE);
  53                nbytes %= POLY1305_BLOCK_SIZE;
  54        }
  55
  56        if (unlikely(nbytes)) {
  57                desc->buflen = nbytes;
  58                memcpy(desc->buf, src, nbytes);
  59        }
  60}
  61EXPORT_SYMBOL_GPL(poly1305_update_generic);
  62
  63void poly1305_final_generic(struct poly1305_desc_ctx *desc, u8 *dst)
  64{
  65        if (unlikely(desc->buflen)) {
  66                desc->buf[desc->buflen++] = 1;
  67                memset(desc->buf + desc->buflen, 0,
  68                       POLY1305_BLOCK_SIZE - desc->buflen);
  69                poly1305_core_blocks(&desc->h, &desc->core_r, desc->buf, 1, 0);
  70        }
  71
  72        poly1305_core_emit(&desc->h, desc->s, dst);
  73        *desc = (struct poly1305_desc_ctx){};
  74}
  75EXPORT_SYMBOL_GPL(poly1305_final_generic);
  76
  77MODULE_LICENSE("GPL");
  78MODULE_AUTHOR("Martin Willi <martin@strongswan.org>");
  79