Line data Source code
1 : /* cipher-ctr.c - Generic CTR mode implementation
2 : * Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003
3 : * 2005, 2007, 2008, 2009, 2011 Free Software Foundation, Inc.
4 : *
5 : * This file is part of Libgcrypt.
6 : *
7 : * Libgcrypt is free software; you can redistribute it and/or modify
8 : * it under the terms of the GNU Lesser general Public License as
9 : * published by the Free Software Foundation; either version 2.1 of
10 : * the License, or (at your option) any later version.
11 : *
12 : * Libgcrypt is distributed in the hope that it will be useful,
13 : * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 : * GNU Lesser General Public License for more details.
16 : *
17 : * You should have received a copy of the GNU Lesser General Public
18 : * License along with this program; if not, see <http://www.gnu.org/licenses/>.
19 : */
20 :
21 : #include <config.h>
22 : #include <stdio.h>
23 : #include <stdlib.h>
24 : #include <string.h>
25 : #include <errno.h>
26 :
27 : #include "g10lib.h"
28 : #include "cipher.h"
29 : #include "bufhelp.h"
30 : #include "./cipher-internal.h"
31 :
32 :
33 : gcry_err_code_t
34 310654 : _gcry_cipher_ctr_encrypt (gcry_cipher_hd_t c,
35 : unsigned char *outbuf, size_t outbuflen,
36 : const unsigned char *inbuf, size_t inbuflen)
37 : {
38 : size_t n;
39 : int i;
40 310654 : gcry_cipher_encrypt_t enc_fn = c->spec->encrypt;
41 310654 : unsigned int blocksize = c->spec->blocksize;
42 : size_t nblocks;
43 : unsigned int burn, nburn;
44 :
45 : /* Tell compiler that we require a cipher with a 64bit or 128 bit block
46 : * length, to allow better optimization of this function. */
47 310654 : if (blocksize > 16 || blocksize < 8 || blocksize & (8 - 1))
48 0 : return GPG_ERR_INV_LENGTH;
49 :
50 310654 : if (outbuflen < inbuflen)
51 80 : return GPG_ERR_BUFFER_TOO_SHORT;
52 :
53 310574 : burn = 0;
54 :
55 : /* First process a left over encrypted counter. */
56 310574 : if (c->unused)
57 : {
58 68112 : gcry_assert (c->unused < blocksize);
59 68112 : i = blocksize - c->unused;
60 68112 : n = c->unused > inbuflen ? inbuflen : c->unused;
61 68112 : buf_xor(outbuf, inbuf, &c->lastiv[i], n);
62 68112 : c->unused -= n;
63 68112 : inbuf += n;
64 68112 : outbuf += n;
65 68112 : inbuflen -= n;
66 : }
67 :
68 : /* Use a bulk method if available. */
69 310574 : nblocks = inbuflen / blocksize;
70 310574 : if (nblocks && c->bulk.ctr_enc)
71 : {
72 201344 : c->bulk.ctr_enc (&c->context.c, c->u_ctr.ctr, outbuf, inbuf, nblocks);
73 201344 : inbuf += nblocks * blocksize;
74 201344 : outbuf += nblocks * blocksize;
75 201344 : inbuflen -= nblocks * blocksize;
76 : }
77 :
78 : /* If we don't have a bulk method use the standard method. We also
79 : use this method for the a remaining partial block. */
80 310574 : if (inbuflen)
81 : {
82 : unsigned char tmp[MAX_BLOCKSIZE];
83 :
84 : do {
85 4497412 : nburn = enc_fn (&c->context.c, tmp, c->u_ctr.ctr);
86 4497412 : burn = nburn > burn ? nburn : burn;
87 :
88 4512220 : for (i = blocksize; i > 0; i--)
89 : {
90 4512220 : c->u_ctr.ctr[i-1]++;
91 4512220 : if (c->u_ctr.ctr[i-1] != 0)
92 4497412 : break;
93 : }
94 :
95 4497412 : n = blocksize < inbuflen ? blocksize : inbuflen;
96 4497412 : buf_xor(outbuf, inbuf, tmp, n);
97 :
98 4497412 : inbuflen -= n;
99 4497412 : outbuf += n;
100 4497412 : inbuf += n;
101 4497412 : } while (inbuflen);
102 :
103 : /* Save the unused bytes of the counter. */
104 103934 : c->unused = blocksize - n;
105 103934 : if (c->unused)
106 73706 : buf_cpy (c->lastiv+n, tmp+n, c->unused);
107 :
108 103934 : wipememory (tmp, sizeof tmp);
109 : }
110 :
111 310574 : if (burn > 0)
112 84228 : _gcry_burn_stack (burn + 4 * sizeof(void *));
113 :
114 310574 : return 0;
115 : }
|