LCOV - code coverage report
Current view: top level - cipher - cipher-xts.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 65 74 87.8 %
Date: 2017-03-02 16:44:37 Functions: 3 3 100.0 %

          Line data    Source code
       1             : /* cipher-xts.c  - XTS mode implementation
       2             :  * Copyright (C) 2017 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             : 
      31             : 
      32     2579600 : static inline void xts_gfmul_byA (unsigned char *out, const unsigned char *in)
      33             : {
      34     2579600 :   u64 hi = buf_get_le64 (in + 8);
      35     2579600 :   u64 lo = buf_get_le64 (in + 0);
      36     2579600 :   u64 carry = -(hi >> 63) & 0x87;
      37             : 
      38     2579600 :   hi = (hi << 1) + (lo >> 63);
      39     2579600 :   lo = (lo << 1) ^ carry;
      40             : 
      41     2579600 :   buf_put_le64 (out + 8, hi);
      42     2579600 :   buf_put_le64 (out + 0, lo);
      43     2579600 : }
      44             : 
      45             : 
      46       53518 : static inline void xts_inc128 (unsigned char *seqno)
      47             : {
      48       53518 :   u64 lo = buf_get_le64 (seqno + 0);
      49       53518 :   u64 hi = buf_get_le64 (seqno + 8);
      50             : 
      51       53518 :   hi += !(++lo);
      52             : 
      53       53518 :   buf_put_le64 (seqno + 0, lo);
      54       53518 :   buf_put_le64 (seqno + 8, hi);
      55       53518 : }
      56             : 
      57             : 
      58             : gcry_err_code_t
      59       53518 : _gcry_cipher_xts_crypt (gcry_cipher_hd_t c,
      60             :                         unsigned char *outbuf, size_t outbuflen,
      61             :                         const unsigned char *inbuf, size_t inbuflen,
      62             :                         int encrypt)
      63             : {
      64       53518 :   gcry_cipher_encrypt_t tweak_fn = c->spec->encrypt;
      65       53518 :   gcry_cipher_encrypt_t crypt_fn =
      66       53518 :     encrypt ? c->spec->encrypt : c->spec->decrypt;
      67             :   union
      68             :   {
      69             :     cipher_context_alignment_t xcx;
      70             :     byte x1[GCRY_XTS_BLOCK_LEN];
      71             :     u64 x64[GCRY_XTS_BLOCK_LEN / sizeof(u64)];
      72             :   } tmp;
      73             :   unsigned int burn, nburn;
      74             :   size_t nblocks;
      75             : 
      76       53518 :   if (c->spec->blocksize != GCRY_XTS_BLOCK_LEN)
      77           0 :     return GPG_ERR_CIPHER_ALGO;
      78       53518 :   if (outbuflen < inbuflen)
      79           0 :     return GPG_ERR_BUFFER_TOO_SHORT;
      80       53518 :   if (inbuflen < GCRY_XTS_BLOCK_LEN)
      81           0 :     return GPG_ERR_BUFFER_TOO_SHORT;
      82             : 
      83             :   /* Data-unit max length: 2^20 blocks. */
      84       53518 :   if (inbuflen > GCRY_XTS_BLOCK_LEN << 20)
      85           0 :     return GPG_ERR_INV_LENGTH;
      86             : 
      87       53518 :   nblocks = inbuflen / GCRY_XTS_BLOCK_LEN;
      88       53518 :   nblocks -= !encrypt && (inbuflen % GCRY_XTS_BLOCK_LEN) != 0;
      89             : 
      90             :   /* Generate first tweak value.  */
      91       53518 :   burn = tweak_fn (c->u_mode.xts.tweak_context, c->u_ctr.ctr, c->u_iv.iv);
      92             : 
      93             :   /* Use a bulk method if available.  */
      94       53518 :   if (nblocks && c->bulk.xts_crypt)
      95             :     {
      96           0 :       c->bulk.xts_crypt (c, c->u_ctr.ctr, outbuf, inbuf, nblocks, encrypt);
      97           0 :       inbuf  += nblocks * GCRY_XTS_BLOCK_LEN;
      98           0 :       outbuf += nblocks * GCRY_XTS_BLOCK_LEN;
      99           0 :       inbuflen -= nblocks * GCRY_XTS_BLOCK_LEN;
     100           0 :       nblocks = 0;
     101             :     }
     102             : 
     103             :   /* If we don't have a bulk method use the standard method.  We also
     104             :     use this method for the a remaining partial block.  */
     105             : 
     106     2686608 :   while (nblocks)
     107             :     {
     108             :       /* Xor-Encrypt/Decrypt-Xor block. */
     109     2579572 :       buf_xor (tmp.x64, inbuf, c->u_ctr.ctr, GCRY_XTS_BLOCK_LEN);
     110     2579572 :       nburn = crypt_fn (&c->context.c, tmp.x1, tmp.x1);
     111     2579572 :       burn = nburn > burn ? nburn : burn;
     112     2579572 :       buf_xor (outbuf, tmp.x64, c->u_ctr.ctr, GCRY_XTS_BLOCK_LEN);
     113             : 
     114     2579572 :       outbuf += GCRY_XTS_BLOCK_LEN;
     115     2579572 :       inbuf += GCRY_XTS_BLOCK_LEN;
     116     2579572 :       inbuflen -= GCRY_XTS_BLOCK_LEN;
     117     2579572 :       nblocks--;
     118             : 
     119             :       /* Generate next tweak. */
     120     2579572 :       xts_gfmul_byA (c->u_ctr.ctr, c->u_ctr.ctr);
     121             :     }
     122             : 
     123             :   /* Handle remaining data with ciphertext stealing. */
     124       53518 :   if (inbuflen)
     125             :     {
     126          56 :       if (!encrypt)
     127             :         {
     128          28 :           gcry_assert (inbuflen > GCRY_XTS_BLOCK_LEN);
     129          28 :           gcry_assert (inbuflen < GCRY_XTS_BLOCK_LEN * 2);
     130             : 
     131             :           /* Generate last tweak. */
     132          28 :           xts_gfmul_byA (tmp.x1, c->u_ctr.ctr);
     133             : 
     134             :           /* Decrypt last block first. */
     135          28 :           buf_xor (outbuf, inbuf, tmp.x64, GCRY_XTS_BLOCK_LEN);
     136          28 :           nburn = crypt_fn (&c->context.c, outbuf, outbuf);
     137          28 :           burn = nburn > burn ? nburn : burn;
     138          28 :           buf_xor (outbuf, outbuf, tmp.x64, GCRY_XTS_BLOCK_LEN);
     139             : 
     140          28 :           inbuflen -= GCRY_XTS_BLOCK_LEN;
     141          28 :           inbuf += GCRY_XTS_BLOCK_LEN;
     142          28 :           outbuf += GCRY_XTS_BLOCK_LEN;
     143             :         }
     144             : 
     145          56 :       gcry_assert (inbuflen < GCRY_XTS_BLOCK_LEN);
     146          56 :       outbuf -= GCRY_XTS_BLOCK_LEN;
     147             : 
     148             :       /* Steal ciphertext from previous block. */
     149          56 :       buf_cpy (tmp.x64, outbuf, GCRY_XTS_BLOCK_LEN);
     150          56 :       buf_cpy (tmp.x64, inbuf, inbuflen);
     151          56 :       buf_cpy (outbuf + GCRY_XTS_BLOCK_LEN, outbuf, inbuflen);
     152             : 
     153             :       /* Decrypt/Encrypt last block. */
     154          56 :       buf_xor (tmp.x64, tmp.x64, c->u_ctr.ctr, GCRY_XTS_BLOCK_LEN);
     155          56 :       nburn = crypt_fn (&c->context.c, tmp.x1, tmp.x1);
     156          56 :       burn = nburn > burn ? nburn : burn;
     157          56 :       buf_xor (outbuf, tmp.x64, c->u_ctr.ctr, GCRY_XTS_BLOCK_LEN);
     158             :     }
     159             : 
     160             :   /* Auto-increment data-unit sequence number */
     161       53518 :   xts_inc128 (c->u_iv.iv);
     162             : 
     163       53518 :   wipememory (&tmp, sizeof(tmp));
     164       53518 :   wipememory (c->u_ctr.ctr, sizeof(c->u_ctr.ctr));
     165             : 
     166       53518 :   if (burn > 0)
     167       39292 :     _gcry_burn_stack (burn + 4 * sizeof(void *));
     168             : 
     169       53518 :   return 0;
     170             : }

Generated by: LCOV version 1.13