LCOV - code coverage report
Current view: top level - cipher - mac-poly1305.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 107 129 82.9 %
Date: 2017-03-02 16:44:37 Functions: 11 11 100.0 %

          Line data    Source code
       1             : /* mac-poly1305.c  -  Poly1305 based MACs
       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 "mac-internal.h"
      28             : #include "poly1305-internal.h"
      29             : 
      30             : 
      31             : struct poly1305mac_context_s {
      32             :   poly1305_context_t ctx;
      33             :   gcry_cipher_hd_t hd;
      34             :   struct {
      35             :     unsigned int key_set:1;
      36             :     unsigned int nonce_set:1;
      37             :     unsigned int tag:1;
      38             :   } marks;
      39             :   byte tag[POLY1305_TAGLEN];
      40             :   byte key[POLY1305_KEYLEN];
      41             : };
      42             : 
      43             : 
      44             : static gcry_err_code_t
      45         100 : poly1305mac_open (gcry_mac_hd_t h)
      46             : {
      47             :   struct poly1305mac_context_s *mac_ctx;
      48         100 :   int secure = (h->magic == CTX_MAGIC_SECURE);
      49         100 :   unsigned int flags = (secure ? GCRY_CIPHER_SECURE : 0);
      50             :   gcry_err_code_t err;
      51             :   int cipher_algo;
      52             : 
      53         100 :   if (secure)
      54           0 :     mac_ctx = xtrycalloc_secure (1, sizeof(*mac_ctx));
      55             :   else
      56         100 :     mac_ctx = xtrycalloc (1, sizeof(*mac_ctx));
      57             : 
      58         100 :   if (!mac_ctx)
      59           0 :     return gpg_err_code_from_syserror ();
      60             : 
      61         100 :   h->u.poly1305mac.ctx = mac_ctx;
      62             : 
      63         100 :   switch (h->spec->algo)
      64             :     {
      65             :     default:
      66             :       /* already checked. */
      67             :     case GCRY_MAC_POLY1305:
      68             :       /* plain Poly1305. */
      69          72 :       cipher_algo = -1;
      70          72 :       return 0;
      71             :     case GCRY_MAC_POLY1305_AES:
      72          20 :       cipher_algo = GCRY_CIPHER_AES;
      73          20 :       break;
      74             :     case GCRY_MAC_POLY1305_CAMELLIA:
      75           2 :       cipher_algo = GCRY_CIPHER_CAMELLIA128;
      76           2 :       break;
      77             :     case GCRY_MAC_POLY1305_TWOFISH:
      78           2 :       cipher_algo = GCRY_CIPHER_TWOFISH;
      79           2 :       break;
      80             :     case GCRY_MAC_POLY1305_SERPENT:
      81           2 :       cipher_algo = GCRY_CIPHER_SERPENT128;
      82           2 :       break;
      83             :     case GCRY_MAC_POLY1305_SEED:
      84           2 :       cipher_algo = GCRY_CIPHER_SEED;
      85           2 :       break;
      86             :     }
      87             : 
      88          28 :   err = _gcry_cipher_open_internal (&mac_ctx->hd, cipher_algo,
      89             :                                     GCRY_CIPHER_MODE_ECB, flags);
      90          28 :   if (err)
      91           0 :     goto err_free;
      92             : 
      93          28 :   return 0;
      94             : 
      95             : err_free:
      96           0 :   xfree(h->u.poly1305mac.ctx);
      97           0 :   return err;
      98             : }
      99             : 
     100             : 
     101             : static void
     102         100 : poly1305mac_close (gcry_mac_hd_t h)
     103             : {
     104         100 :   struct poly1305mac_context_s *mac_ctx = h->u.poly1305mac.ctx;
     105             : 
     106         100 :   if (h->spec->algo != GCRY_MAC_POLY1305)
     107          28 :     _gcry_cipher_close (mac_ctx->hd);
     108             : 
     109         100 :   xfree(mac_ctx);
     110         100 : }
     111             : 
     112             : 
     113             : static gcry_err_code_t
     114          28 : poly1305mac_prepare_key (gcry_mac_hd_t h, const unsigned char *key, size_t keylen)
     115             : {
     116          28 :   struct poly1305mac_context_s *mac_ctx = h->u.poly1305mac.ctx;
     117          28 :   size_t block_keylen = keylen - 16;
     118             : 
     119             :   /* Need at least 16 + 1 byte key. */
     120          28 :   if (keylen <= 16)
     121           0 :     return GPG_ERR_INV_KEYLEN;
     122             : 
     123             :   /* For Poly1305-AES, first part of key is passed to Poly1305 as is. */
     124          28 :   memcpy (mac_ctx->key, key + block_keylen, 16);
     125             : 
     126             :   /* Remaining part is used as key for the block cipher. */
     127          28 :   return _gcry_cipher_setkey (mac_ctx->hd, key, block_keylen);
     128             : }
     129             : 
     130             : 
     131             : static gcry_err_code_t
     132         100 : poly1305mac_setkey (gcry_mac_hd_t h, const unsigned char *key, size_t keylen)
     133             : {
     134         100 :   struct poly1305mac_context_s *mac_ctx = h->u.poly1305mac.ctx;
     135             :   gcry_err_code_t err;
     136             : 
     137         100 :   memset(&mac_ctx->ctx, 0, sizeof(mac_ctx->ctx));
     138         100 :   memset(&mac_ctx->tag, 0, sizeof(mac_ctx->tag));
     139         100 :   memset(&mac_ctx->key, 0, sizeof(mac_ctx->key));
     140             : 
     141         100 :   mac_ctx->marks.key_set = 0;
     142         100 :   mac_ctx->marks.nonce_set = 0;
     143         100 :   mac_ctx->marks.tag = 0;
     144             : 
     145         100 :   if (h->spec->algo != GCRY_MAC_POLY1305)
     146             :     {
     147          28 :       err = poly1305mac_prepare_key (h, key, keylen);
     148          28 :       if (err)
     149           0 :         return err;
     150             : 
     151             :       /* Poly1305-AES/etc also need nonce. */
     152          28 :       mac_ctx->marks.key_set = 1;
     153          28 :       mac_ctx->marks.nonce_set = 0;
     154             :     }
     155             :   else
     156             :     {
     157             :       /* For plain Poly1305, key is the nonce and setup is complete now. */
     158             : 
     159          72 :       if (keylen != POLY1305_KEYLEN)
     160           0 :         return GPG_ERR_INV_KEYLEN;
     161             : 
     162          72 :       memcpy (mac_ctx->key, key, keylen);
     163             : 
     164          72 :       err = _gcry_poly1305_init (&mac_ctx->ctx, mac_ctx->key, POLY1305_KEYLEN);
     165          72 :       if (err)
     166             :         {
     167           0 :           memset(&mac_ctx->key, 0, sizeof(mac_ctx->key));
     168           0 :           return err;
     169             :         }
     170             : 
     171          72 :       mac_ctx->marks.key_set = 1;
     172          72 :       mac_ctx->marks.nonce_set = 1;
     173             :     }
     174             : 
     175         100 :   return 0;
     176             : }
     177             : 
     178             : 
     179             : static gcry_err_code_t
     180          28 : poly1305mac_setiv (gcry_mac_hd_t h, const unsigned char *iv, size_t ivlen)
     181             : {
     182          28 :   struct poly1305mac_context_s *mac_ctx = h->u.poly1305mac.ctx;
     183             :   gcry_err_code_t err;
     184             : 
     185          28 :   if (h->spec->algo == GCRY_MAC_POLY1305)
     186           0 :     return GPG_ERR_INV_ARG;
     187             : 
     188          28 :   if (ivlen != 16)
     189           0 :     return GPG_ERR_INV_ARG;
     190             : 
     191          28 :   if (!mac_ctx->marks.key_set)
     192           0 :     return 0;
     193             : 
     194          28 :   memset(&mac_ctx->ctx, 0, sizeof(mac_ctx->ctx));
     195          28 :   memset(&mac_ctx->tag, 0, sizeof(mac_ctx->tag));
     196          28 :   mac_ctx->marks.nonce_set = 0;
     197          28 :   mac_ctx->marks.tag = 0;
     198             : 
     199             :   /* Prepare second part of the poly1305 key. */
     200             : 
     201          28 :   err = _gcry_cipher_encrypt (mac_ctx->hd, mac_ctx->key + 16, 16, iv, 16);
     202          28 :   if (err)
     203           0 :     return err;
     204             : 
     205          28 :   err = _gcry_poly1305_init (&mac_ctx->ctx, mac_ctx->key, POLY1305_KEYLEN);
     206          28 :   if (err)
     207           0 :     return err;
     208             : 
     209          28 :   mac_ctx->marks.nonce_set = 1;
     210          28 :   return 0;
     211             : }
     212             : 
     213             : 
     214             : static gcry_err_code_t
     215        4964 : poly1305mac_reset (gcry_mac_hd_t h)
     216             : {
     217        4964 :   struct poly1305mac_context_s *mac_ctx = h->u.poly1305mac.ctx;
     218             : 
     219        4964 :   if (!mac_ctx->marks.key_set || !mac_ctx->marks.nonce_set)
     220           0 :     return GPG_ERR_INV_STATE;
     221             : 
     222        4964 :   memset(&mac_ctx->ctx, 0, sizeof(mac_ctx->ctx));
     223        4964 :   memset(&mac_ctx->tag, 0, sizeof(mac_ctx->tag));
     224             : 
     225        4964 :   mac_ctx->marks.key_set = 1;
     226        4964 :   mac_ctx->marks.nonce_set = 1;
     227        4964 :   mac_ctx->marks.tag = 0;
     228             : 
     229        4964 :   return _gcry_poly1305_init (&mac_ctx->ctx, mac_ctx->key, POLY1305_KEYLEN);
     230             : }
     231             : 
     232             : 
     233             : static gcry_err_code_t
     234      683000 : poly1305mac_write (gcry_mac_hd_t h, const unsigned char *buf, size_t buflen)
     235             : {
     236      683000 :   struct poly1305mac_context_s *mac_ctx = h->u.poly1305mac.ctx;
     237             : 
     238      683000 :   if (!mac_ctx->marks.key_set || !mac_ctx->marks.nonce_set ||
     239             :       mac_ctx->marks.tag)
     240           0 :     return GPG_ERR_INV_STATE;
     241             : 
     242      683000 :   _gcry_poly1305_update (&mac_ctx->ctx, buf, buflen);
     243      683000 :   return 0;
     244             : }
     245             : 
     246             : 
     247             : static gcry_err_code_t
     248        5146 : poly1305mac_read (gcry_mac_hd_t h, unsigned char *outbuf, size_t *outlen)
     249             : {
     250        5146 :   struct poly1305mac_context_s *mac_ctx = h->u.poly1305mac.ctx;
     251             : 
     252        5146 :   if (!mac_ctx->marks.key_set || !mac_ctx->marks.nonce_set)
     253           0 :     return GPG_ERR_INV_STATE;
     254             : 
     255        5146 :   if (!mac_ctx->marks.tag)
     256             :     {
     257        5058 :       _gcry_poly1305_finish(&mac_ctx->ctx, mac_ctx->tag);
     258             : 
     259        5058 :       memset(&mac_ctx->ctx, 0, sizeof(mac_ctx->ctx));
     260        5058 :       mac_ctx->marks.tag = 1;
     261             :     }
     262             : 
     263        5146 :   if (*outlen == 0)
     264          88 :     return 0;
     265             : 
     266        5058 :   if (*outlen <= POLY1305_TAGLEN)
     267        5058 :     buf_cpy (outbuf, mac_ctx->tag, *outlen);
     268             :   else
     269             :     {
     270           0 :       buf_cpy (outbuf, mac_ctx->tag, POLY1305_TAGLEN);
     271           0 :       *outlen = POLY1305_TAGLEN;
     272             :     }
     273             : 
     274        5058 :   return 0;
     275             : }
     276             : 
     277             : 
     278             : static gcry_err_code_t
     279          88 : poly1305mac_verify (gcry_mac_hd_t h, const unsigned char *buf, size_t buflen)
     280             : {
     281          88 :   struct poly1305mac_context_s *mac_ctx = h->u.poly1305mac.ctx;
     282             :   gcry_err_code_t err;
     283          88 :   size_t outlen = 0;
     284             : 
     285             :   /* Check and finalize tag. */
     286          88 :   err = poly1305mac_read(h, NULL, &outlen);
     287          88 :   if (err)
     288           0 :     return err;
     289             : 
     290          88 :   if (buflen > POLY1305_TAGLEN)
     291           0 :     return GPG_ERR_INV_LENGTH;
     292             : 
     293          88 :   return buf_eq_const (buf, mac_ctx->tag, buflen) ? 0 : GPG_ERR_CHECKSUM;
     294             : }
     295             : 
     296             : 
     297             : static unsigned int
     298          94 : poly1305mac_get_maclen (int algo)
     299             : {
     300             :   (void)algo;
     301             : 
     302          94 :   return POLY1305_TAGLEN;
     303             : }
     304             : 
     305             : 
     306             : static unsigned int
     307          12 : poly1305mac_get_keylen (int algo)
     308             : {
     309             :   (void)algo;
     310             : 
     311          12 :   return POLY1305_KEYLEN;
     312             : }
     313             : 
     314             : 
     315             : static gcry_mac_spec_ops_t poly1305mac_ops = {
     316             :   poly1305mac_open,
     317             :   poly1305mac_close,
     318             :   poly1305mac_setkey,
     319             :   poly1305mac_setiv,
     320             :   poly1305mac_reset,
     321             :   poly1305mac_write,
     322             :   poly1305mac_read,
     323             :   poly1305mac_verify,
     324             :   poly1305mac_get_maclen,
     325             :   poly1305mac_get_keylen
     326             : };
     327             : 
     328             : 
     329             : gcry_mac_spec_t _gcry_mac_type_spec_poly1305mac = {
     330             :   GCRY_MAC_POLY1305, {0, 0}, "POLY1305",
     331             :   &poly1305mac_ops
     332             : };
     333             : #if USE_AES
     334             : gcry_mac_spec_t _gcry_mac_type_spec_poly1305mac_aes = {
     335             :   GCRY_MAC_POLY1305_AES, {0, 0}, "POLY1305_AES",
     336             :   &poly1305mac_ops
     337             : };
     338             : #endif
     339             : #if USE_CAMELLIA
     340             : gcry_mac_spec_t _gcry_mac_type_spec_poly1305mac_camellia = {
     341             :   GCRY_MAC_POLY1305_CAMELLIA, {0, 0}, "POLY1305_CAMELLIA",
     342             :   &poly1305mac_ops
     343             : };
     344             : #endif
     345             : #if USE_TWOFISH
     346             : gcry_mac_spec_t _gcry_mac_type_spec_poly1305mac_twofish = {
     347             :   GCRY_MAC_POLY1305_TWOFISH, {0, 0}, "POLY1305_TWOFISH",
     348             :   &poly1305mac_ops
     349             : };
     350             : #endif
     351             : #if USE_SERPENT
     352             : gcry_mac_spec_t _gcry_mac_type_spec_poly1305mac_serpent = {
     353             :   GCRY_MAC_POLY1305_SERPENT, {0, 0}, "POLY1305_SERPENT",
     354             :   &poly1305mac_ops
     355             : };
     356             : #endif
     357             : #if USE_SEED
     358             : gcry_mac_spec_t _gcry_mac_type_spec_poly1305mac_seed = {
     359             :   GCRY_MAC_POLY1305_SEED, {0, 0}, "POLY1305_SEED",
     360             :   &poly1305mac_ops
     361             : };
     362             : #endif

Generated by: LCOV version 1.13