summaryrefslogtreecommitdiff
path: root/cipher/cipher-ctr.c
diff options
context:
space:
mode:
authorWerner Koch <wk@gnupg.org>2011-08-03 21:34:39 +0200
committerWerner Koch <wk@gnupg.org>2011-08-03 21:34:39 +0200
commitad792d462d001858af89485380bf8f8a4a8dcd5d (patch)
tree62a59d3f1eb66fe10276355032217f7fb2be2763 /cipher/cipher-ctr.c
parent5e14de02b323d207151429d37f006ec30bbf7783 (diff)
downloadlibgcrypt-ad792d462d001858af89485380bf8f8a4a8dcd5d.tar.gz
Factor cipher mode code out to separate files.
This is a preparation for adding more modes which are more complicated and thus ask for separate file. For uniformity we do this for all modes except ECB. It has also the advantage that it makes CPU specific variants of the code more easy to implement (e.g. the XOR operations).
Diffstat (limited to 'cipher/cipher-ctr.c')
-rw-r--r--cipher/cipher-ctr.c106
1 files changed, 106 insertions, 0 deletions
diff --git a/cipher/cipher-ctr.c b/cipher/cipher-ctr.c
new file mode 100644
index 00000000..a334abc5
--- /dev/null
+++ b/cipher/cipher-ctr.c
@@ -0,0 +1,106 @@
+/* cipher-ctr.c - Generic CTR mode implementation
+ * Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003
+ * 2005, 2007, 2008, 2009, 2011 Free Software Foundation, Inc.
+ *
+ * This file is part of Libgcrypt.
+ *
+ * Libgcrypt is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser general Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * Libgcrypt is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <config.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+
+#include "g10lib.h"
+#include "cipher.h"
+#include "ath.h"
+#include "./cipher-internal.h"
+
+
+gcry_err_code_t
+_gcry_cipher_ctr_encrypt (gcry_cipher_hd_t c,
+ unsigned char *outbuf, unsigned int outbuflen,
+ const unsigned char *inbuf, unsigned int inbuflen)
+{
+ unsigned int n;
+ int i;
+ unsigned int blocksize = c->cipher->blocksize;
+ unsigned int nblocks;
+
+ if (outbuflen < inbuflen)
+ return GPG_ERR_BUFFER_TOO_SHORT;
+
+ /* First process a left over encrypted counter. */
+ if (c->unused)
+ {
+ gcry_assert (c->unused < blocksize);
+ i = blocksize - c->unused;
+ for (n=0; c->unused && n < inbuflen; c->unused--, n++, i++)
+ {
+ /* XOR input with encrypted counter and store in output. */
+ outbuf[n] = inbuf[n] ^ c->lastiv[i];
+ }
+ inbuf += n;
+ outbuf += n;
+ inbuflen -= n;
+ }
+
+
+ /* Use a bulk method if available. */
+ nblocks = inbuflen / blocksize;
+ if (nblocks && c->bulk.ctr_enc)
+ {
+ c->bulk.ctr_enc (&c->context.c, c->u_ctr.ctr, outbuf, inbuf, nblocks);
+ inbuf += nblocks * blocksize;
+ outbuf += nblocks * blocksize;
+ inbuflen -= nblocks * blocksize;
+ }
+
+ /* If we don't have a bulk method use the standard method. We also
+ use this method for the a remaining partial block. */
+ if (inbuflen)
+ {
+ unsigned char tmp[MAX_BLOCKSIZE];
+
+ for (n=0; n < inbuflen; n++)
+ {
+ if ((n % blocksize) == 0)
+ {
+ c->cipher->encrypt (&c->context.c, tmp, c->u_ctr.ctr);
+
+ for (i = blocksize; i > 0; i--)
+ {
+ c->u_ctr.ctr[i-1]++;
+ if (c->u_ctr.ctr[i-1] != 0)
+ break;
+ }
+ }
+
+ /* XOR input with encrypted counter and store in output. */
+ outbuf[n] = inbuf[n] ^ tmp[n % blocksize];
+ }
+
+ /* Save the unused bytes of the counter. */
+ n %= blocksize;
+ c->unused = (blocksize - n) % blocksize;
+ if (c->unused)
+ memcpy (c->lastiv+n, tmp+n, c->unused);
+
+ wipememory (tmp, sizeof tmp);
+ }
+
+ return 0;
+}