LCOV - code coverage report
Current view: top level - cipher - cipher-poly1305.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 113 142 79.6 %
Date: 2017-03-02 16:44:37 Functions: 13 13 100.0 %

          Line data    Source code
       1             : /* cipher-poly1305.c  -  Poly1305 based AEAD cipher mode, RFC-7539
       2             :  * Copyright (C) 2014 Jussi Kivilinna <jussi.kivilinna@iki.fi>
       3             :  *
       4             :  * This file is part of Libgcrypt.
       5             :  *
       6             :  * Libgcrypt is free software; you can redistribute it and/or modify
       7             :  * it under the terms of the GNU Lesser general Public License as
       8             :  * published by the Free Software Foundation; either version 2.1 of
       9             :  * the License, or (at your option) any later version.
      10             :  *
      11             :  * Libgcrypt is distributed in the hope that it will be useful,
      12             :  * but WITHOUT ANY WARRANTY; without even the implied warranty of
      13             :  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      14             :  * GNU Lesser General Public License for more details.
      15             :  *
      16             :  * You should have received a copy of the GNU Lesser General Public
      17             :  * License along with this program; if not, see <http://www.gnu.org/licenses/>.
      18             :  */
      19             : 
      20             : #include <config.h>
      21             : #include <stdio.h>
      22             : #include <stdlib.h>
      23             : #include <string.h>
      24             : #include <errno.h>
      25             : 
      26             : #include "g10lib.h"
      27             : #include "cipher.h"
      28             : #include "bufhelp.h"
      29             : #include "./cipher-internal.h"
      30             : #include "./poly1305-internal.h"
      31             : 
      32             : 
      33             : static inline int
      34       13676 : poly1305_bytecounter_add (u32 ctr[2], size_t add)
      35             : {
      36       13676 :   int overflow = 0;
      37             : 
      38             :   if (sizeof(add) > sizeof(u32))
      39             :     {
      40       13676 :       u32 high_add = ((add >> 31) >> 1) & 0xffffffff;
      41       13676 :       ctr[1] += high_add;
      42       13676 :       if (ctr[1] < high_add)
      43           0 :         overflow = 1;
      44             :     }
      45             : 
      46       13676 :   ctr[0] += add;
      47       13676 :   if (ctr[0] >= add)
      48       13676 :     return overflow;
      49             : 
      50           0 :   ctr[1] += 1;
      51           0 :   return (ctr[1] < 1) || overflow;
      52             : }
      53             : 
      54             : 
      55             : static void
      56        2976 : poly1305_fill_bytecounts (gcry_cipher_hd_t c)
      57             : {
      58             :   u32 lenbuf[4];
      59             : 
      60        2976 :   lenbuf[0] = le_bswap32(c->u_mode.poly1305.aadcount[0]);
      61        2976 :   lenbuf[1] = le_bswap32(c->u_mode.poly1305.aadcount[1]);
      62        2976 :   lenbuf[2] = le_bswap32(c->u_mode.poly1305.datacount[0]);
      63        2976 :   lenbuf[3] = le_bswap32(c->u_mode.poly1305.datacount[1]);
      64        2976 :   _gcry_poly1305_update (&c->u_mode.poly1305.ctx, (byte*)lenbuf,
      65             :                          sizeof(lenbuf));
      66             : 
      67        2976 :   wipememory(lenbuf, sizeof(lenbuf));
      68        2976 : }
      69             : 
      70             : 
      71             : static void
      72        6208 : poly1305_do_padding (gcry_cipher_hd_t c, u32 ctr[2])
      73             : {
      74             :   static const byte zero_padding_buf[15] = {};
      75             :   u32 padding_count;
      76             : 
      77             :   /* Padding to 16 byte boundary. */
      78        6208 :   if (ctr[0] % 16 > 0)
      79             :     {
      80         808 :       padding_count = 16 - ctr[0] % 16;
      81             : 
      82         808 :       _gcry_poly1305_update (&c->u_mode.poly1305.ctx, zero_padding_buf,
      83             :                              padding_count);
      84             :     }
      85        6208 : }
      86             : 
      87             : 
      88             : static void
      89        3232 : poly1305_aad_finish (gcry_cipher_hd_t c)
      90             : {
      91             :   /* After AAD, feed padding bytes so we get 16 byte alignment. */
      92        3232 :   poly1305_do_padding (c, c->u_mode.poly1305.aadcount);
      93             : 
      94             :   /* Start of encryption marks end of AAD stream. */
      95        3232 :   c->u_mode.poly1305.aad_finalized = 1;
      96             : 
      97        3232 :   c->u_mode.poly1305.datacount[0] = 0;
      98        3232 :   c->u_mode.poly1305.datacount[1] = 0;
      99        3232 : }
     100             : 
     101             : 
     102             : static gcry_err_code_t
     103         256 : poly1305_set_zeroiv (gcry_cipher_hd_t c)
     104             : {
     105         256 :   byte zero[8] = { 0, };
     106             : 
     107         256 :   return _gcry_cipher_poly1305_setiv (c, zero, sizeof(zero));
     108             : }
     109             : 
     110             : 
     111             : gcry_err_code_t
     112        1192 : _gcry_cipher_poly1305_authenticate (gcry_cipher_hd_t c,
     113             :                                     const byte * aadbuf, size_t aadbuflen)
     114             : {
     115        1192 :   if (c->u_mode.poly1305.bytecount_over_limits)
     116           0 :     return GPG_ERR_INV_LENGTH;
     117        1192 :   if (c->u_mode.poly1305.aad_finalized)
     118           0 :     return GPG_ERR_INV_STATE;
     119        1192 :   if (c->marks.tag)
     120           0 :     return GPG_ERR_INV_STATE;
     121             : 
     122        1192 :   if (!c->marks.iv)
     123           0 :     poly1305_set_zeroiv(c);
     124             : 
     125        1192 :   if (poly1305_bytecounter_add(c->u_mode.poly1305.aadcount, aadbuflen))
     126             :     {
     127           0 :       c->u_mode.poly1305.bytecount_over_limits = 1;
     128           0 :       return GPG_ERR_INV_LENGTH;
     129             :     }
     130             : 
     131        1192 :   _gcry_poly1305_update (&c->u_mode.poly1305.ctx, aadbuf, aadbuflen);
     132             : 
     133        1192 :   return 0;
     134             : }
     135             : 
     136             : 
     137             : gcry_err_code_t
     138        6876 : _gcry_cipher_poly1305_encrypt (gcry_cipher_hd_t c,
     139             :                                byte *outbuf, size_t outbuflen,
     140             :                                const byte *inbuf, size_t inbuflen)
     141             : {
     142             :   gcry_err_code_t err;
     143             : 
     144        6876 :   if (outbuflen < inbuflen)
     145           0 :     return GPG_ERR_BUFFER_TOO_SHORT;
     146        6876 :   if (c->marks.tag)
     147           0 :     return GPG_ERR_INV_STATE;
     148        6876 :   if (c->u_mode.poly1305.bytecount_over_limits)
     149           0 :     return GPG_ERR_INV_LENGTH;
     150             : 
     151        6876 :   if (!c->marks.iv)
     152             :     {
     153         128 :       err = poly1305_set_zeroiv(c);
     154         128 :       if (err)
     155           0 :         return err;
     156             :     }
     157             : 
     158        6876 :   if (!c->u_mode.poly1305.aad_finalized)
     159        2250 :     poly1305_aad_finish(c);
     160             : 
     161        6876 :   if (poly1305_bytecounter_add(c->u_mode.poly1305.datacount, inbuflen))
     162             :     {
     163           0 :       c->u_mode.poly1305.bytecount_over_limits = 1;
     164           0 :       return GPG_ERR_INV_LENGTH;
     165             :     }
     166             : 
     167        6876 :   c->spec->stencrypt(&c->context.c, outbuf, (byte*)inbuf, inbuflen);
     168             : 
     169        6876 :   _gcry_poly1305_update (&c->u_mode.poly1305.ctx, outbuf, inbuflen);
     170             : 
     171        6876 :   return 0;
     172             : }
     173             : 
     174             : 
     175             : gcry_err_code_t
     176        5608 : _gcry_cipher_poly1305_decrypt (gcry_cipher_hd_t c,
     177             :                                byte *outbuf, size_t outbuflen,
     178             :                                const byte *inbuf, size_t inbuflen)
     179             : {
     180             :   gcry_err_code_t err;
     181             : 
     182        5608 :   if (outbuflen < inbuflen)
     183           0 :     return GPG_ERR_BUFFER_TOO_SHORT;
     184        5608 :   if (c->marks.tag)
     185           0 :     return GPG_ERR_INV_STATE;
     186        5608 :   if (c->u_mode.poly1305.bytecount_over_limits)
     187           0 :     return GPG_ERR_INV_LENGTH;
     188             : 
     189        5608 :   if (!c->marks.iv)
     190             :     {
     191         128 :       err = poly1305_set_zeroiv(c);
     192         128 :       if (err)
     193           0 :         return err;
     194             :     }
     195             : 
     196        5608 :   if (!c->u_mode.poly1305.aad_finalized)
     197         982 :     poly1305_aad_finish(c);
     198             : 
     199        5608 :   if (poly1305_bytecounter_add(c->u_mode.poly1305.datacount, inbuflen))
     200             :     {
     201           0 :       c->u_mode.poly1305.bytecount_over_limits = 1;
     202           0 :       return GPG_ERR_INV_LENGTH;
     203             :     }
     204             : 
     205        5608 :   _gcry_poly1305_update (&c->u_mode.poly1305.ctx, inbuf, inbuflen);
     206             : 
     207        5608 :   c->spec->stdecrypt(&c->context.c, outbuf, (byte*)inbuf, inbuflen);
     208        5608 :   return 0;
     209             : }
     210             : 
     211             : 
     212             : static gcry_err_code_t
     213        2976 : _gcry_cipher_poly1305_tag (gcry_cipher_hd_t c,
     214             :                            byte * outbuf, size_t outbuflen, int check)
     215             : {
     216             :   gcry_err_code_t err;
     217             : 
     218        2976 :   if (outbuflen < POLY1305_TAGLEN)
     219           0 :     return GPG_ERR_BUFFER_TOO_SHORT;
     220        2976 :   if (c->u_mode.poly1305.bytecount_over_limits)
     221           0 :     return GPG_ERR_INV_LENGTH;
     222             : 
     223        2976 :   if (!c->marks.iv)
     224             :     {
     225           0 :       err = poly1305_set_zeroiv(c);
     226           0 :       if (err)
     227           0 :         return err;
     228             :     }
     229             : 
     230        2976 :   if (!c->u_mode.poly1305.aad_finalized)
     231           0 :     poly1305_aad_finish(c);
     232             : 
     233        2976 :   if (!c->marks.tag)
     234             :     {
     235             :       /* After data, feed padding bytes so we get 16 byte alignment. */
     236        2976 :       poly1305_do_padding (c, c->u_mode.poly1305.datacount);
     237             : 
     238             :       /* Write byte counts to poly1305. */
     239        2976 :       poly1305_fill_bytecounts(c);
     240             : 
     241        2976 :       _gcry_poly1305_finish(&c->u_mode.poly1305.ctx, c->u_iv.iv);
     242             : 
     243        2976 :       c->marks.tag = 1;
     244             :     }
     245             : 
     246        2976 :   if (!check)
     247             :     {
     248        2122 :       memcpy (outbuf, c->u_iv.iv, POLY1305_TAGLEN);
     249             :     }
     250             :   else
     251             :     {
     252             :       /* OUTBUFLEN gives the length of the user supplied tag in OUTBUF
     253             :        * and thus we need to compare its length first.  */
     254         854 :       if (outbuflen != POLY1305_TAGLEN
     255         854 :           || !buf_eq_const (outbuf, c->u_iv.iv, POLY1305_TAGLEN))
     256         822 :         return GPG_ERR_CHECKSUM;
     257             :     }
     258             : 
     259        2154 :   return 0;
     260             : }
     261             : 
     262             : 
     263             : gcry_err_code_t
     264        2122 : _gcry_cipher_poly1305_get_tag (gcry_cipher_hd_t c, unsigned char *outtag,
     265             :                           size_t taglen)
     266             : {
     267        2122 :   return _gcry_cipher_poly1305_tag (c, outtag, taglen, 0);
     268             : }
     269             : 
     270             : gcry_err_code_t
     271         854 : _gcry_cipher_poly1305_check_tag (gcry_cipher_hd_t c, const unsigned char *intag,
     272             :                             size_t taglen)
     273             : {
     274         854 :   return _gcry_cipher_poly1305_tag (c, (unsigned char *) intag, taglen, 1);
     275             : }
     276             : 
     277             : 
     278             : void
     279          67 : _gcry_cipher_poly1305_setkey (gcry_cipher_hd_t c)
     280             : {
     281          67 :   c->u_mode.poly1305.aadcount[0] = 0;
     282          67 :   c->u_mode.poly1305.aadcount[1] = 0;
     283             : 
     284          67 :   c->u_mode.poly1305.datacount[0] = 0;
     285          67 :   c->u_mode.poly1305.datacount[1] = 0;
     286             : 
     287          67 :   c->u_mode.poly1305.bytecount_over_limits = 0;
     288          67 :   c->u_mode.poly1305.aad_finalized = 0;
     289          67 :   c->marks.tag = 0;
     290          67 :   c->marks.iv = 0;
     291          67 : }
     292             : 
     293             : 
     294             : gcry_err_code_t
     295        3232 : _gcry_cipher_poly1305_setiv (gcry_cipher_hd_t c, const byte *iv, size_t ivlen)
     296             : {
     297             :   byte tmpbuf[64]; /* size of ChaCha20 block */
     298             :   gcry_err_code_t err;
     299             : 
     300             :   /* IV must be 96-bits */
     301        3232 :   if (!iv && ivlen != (96 / 8))
     302           0 :     return GPG_ERR_INV_ARG;
     303             : 
     304        3232 :   memset(&c->u_mode.poly1305.ctx, 0, sizeof(c->u_mode.poly1305.ctx));
     305             : 
     306        3232 :   c->u_mode.poly1305.aadcount[0] = 0;
     307        3232 :   c->u_mode.poly1305.aadcount[1] = 0;
     308             : 
     309        3232 :   c->u_mode.poly1305.datacount[0] = 0;
     310        3232 :   c->u_mode.poly1305.datacount[1] = 0;
     311             : 
     312        3232 :   c->u_mode.poly1305.bytecount_over_limits = 0;
     313        3232 :   c->u_mode.poly1305.aad_finalized = 0;
     314        3232 :   c->marks.tag = 0;
     315        3232 :   c->marks.iv = 0;
     316             : 
     317             :   /* Set up IV for stream cipher. */
     318        3232 :   c->spec->setiv (&c->context.c, iv, ivlen);
     319             : 
     320             :   /* Get the first block from ChaCha20. */
     321        3232 :   memset(tmpbuf, 0, sizeof(tmpbuf));
     322        3232 :   c->spec->stencrypt(&c->context.c, tmpbuf, tmpbuf, sizeof(tmpbuf));
     323             : 
     324             :   /* Use the first 32-bytes as Poly1305 key. */
     325        3232 :   err = _gcry_poly1305_init (&c->u_mode.poly1305.ctx, tmpbuf, POLY1305_KEYLEN);
     326             : 
     327        3232 :   wipememory(tmpbuf, sizeof(tmpbuf));
     328             : 
     329        3232 :   if (err)
     330           0 :     return err;
     331             : 
     332        3232 :   c->marks.iv = 1;
     333        3232 :   return 0;
     334             : }

Generated by: LCOV version 1.13