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 0 : _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 0 : gcry_cipher_encrypt_t enc_fn = c->spec->encrypt;
41 0 : unsigned int blocksize = c->spec->blocksize;
42 : size_t nblocks;
43 : unsigned int burn, nburn;
44 :
45 0 : if (outbuflen < inbuflen)
46 0 : return GPG_ERR_BUFFER_TOO_SHORT;
47 :
48 0 : burn = 0;
49 :
50 : /* First process a left over encrypted counter. */
51 0 : if (c->unused)
52 : {
53 0 : gcry_assert (c->unused < blocksize);
54 0 : i = blocksize - c->unused;
55 0 : n = c->unused > inbuflen ? inbuflen : c->unused;
56 0 : buf_xor(outbuf, inbuf, &c->lastiv[i], n);
57 0 : c->unused -= n;
58 0 : inbuf += n;
59 0 : outbuf += n;
60 0 : inbuflen -= n;
61 : }
62 :
63 : /* Use a bulk method if available. */
64 0 : nblocks = inbuflen / blocksize;
65 0 : if (nblocks && c->bulk.ctr_enc)
66 : {
67 0 : c->bulk.ctr_enc (&c->context.c, c->u_ctr.ctr, outbuf, inbuf, nblocks);
68 0 : inbuf += nblocks * blocksize;
69 0 : outbuf += nblocks * blocksize;
70 0 : inbuflen -= nblocks * blocksize;
71 : }
72 :
73 : /* If we don't have a bulk method use the standard method. We also
74 : use this method for the a remaining partial block. */
75 0 : if (inbuflen)
76 : {
77 : unsigned char tmp[MAX_BLOCKSIZE];
78 :
79 : do {
80 0 : nburn = enc_fn (&c->context.c, tmp, c->u_ctr.ctr);
81 0 : burn = nburn > burn ? nburn : burn;
82 :
83 0 : for (i = blocksize; i > 0; i--)
84 : {
85 0 : c->u_ctr.ctr[i-1]++;
86 0 : if (c->u_ctr.ctr[i-1] != 0)
87 0 : break;
88 : }
89 :
90 0 : n = blocksize < inbuflen ? blocksize : inbuflen;
91 0 : buf_xor(outbuf, inbuf, tmp, n);
92 :
93 0 : inbuflen -= n;
94 0 : outbuf += n;
95 0 : inbuf += n;
96 0 : } while (inbuflen);
97 :
98 : /* Save the unused bytes of the counter. */
99 0 : c->unused = blocksize - n;
100 0 : if (c->unused)
101 0 : buf_cpy (c->lastiv+n, tmp+n, c->unused);
102 :
103 0 : wipememory (tmp, sizeof tmp);
104 : }
105 :
106 0 : if (burn > 0)
107 0 : _gcry_burn_stack (burn + 4 * sizeof(void *));
108 :
109 0 : return 0;
110 : }
|