summaryrefslogtreecommitdiffstats
path: root/comm/third_party/libgcrypt/cipher/cipher-aeswrap.c
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--comm/third_party/libgcrypt/cipher/cipher-aeswrap.c209
1 files changed, 209 insertions, 0 deletions
diff --git a/comm/third_party/libgcrypt/cipher/cipher-aeswrap.c b/comm/third_party/libgcrypt/cipher/cipher-aeswrap.c
new file mode 100644
index 0000000000..c182657e1f
--- /dev/null
+++ b/comm/third_party/libgcrypt/cipher/cipher-aeswrap.c
@@ -0,0 +1,209 @@
+/* cipher-aeswrap.c - Generic AESWRAP mode implementation
+ * Copyright (C) 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 "bufhelp.h"
+#include "./cipher-internal.h"
+
+
+/* Perform the AES-Wrap algorithm as specified by RFC3394. We
+ implement this as a mode usable with any cipher algorithm of
+ blocksize 128. */
+gcry_err_code_t
+_gcry_cipher_aeswrap_encrypt (gcry_cipher_hd_t c,
+ byte *outbuf, size_t outbuflen,
+ const byte *inbuf, size_t inbuflen )
+{
+ int j, x;
+ size_t n, i;
+ unsigned char *r, *a, *b;
+ unsigned char t[8];
+ unsigned int burn, nburn;
+
+#if MAX_BLOCKSIZE < 8
+#error Invalid block size
+#endif
+ /* We require a cipher with a 128 bit block length. */
+ if (c->spec->blocksize != 16)
+ return GPG_ERR_INV_LENGTH;
+
+ /* The output buffer must be able to hold the input data plus one
+ additional block. */
+ if (outbuflen < inbuflen + 8)
+ return GPG_ERR_BUFFER_TOO_SHORT;
+ /* Input data must be multiple of 64 bits. */
+ if (inbuflen % 8)
+ return GPG_ERR_INV_ARG;
+
+ n = inbuflen / 8;
+
+ /* We need at least two 64 bit blocks. */
+ if (n < 2)
+ return GPG_ERR_INV_ARG;
+
+ burn = 0;
+
+ r = outbuf;
+ a = outbuf; /* We store A directly in OUTBUF. */
+ b = c->u_ctr.ctr; /* B is also used to concatenate stuff. */
+
+ /* Copy the inbuf to the outbuf. */
+ memmove (r+8, inbuf, inbuflen);
+
+ /* If an IV has been set we use that IV as the Alternative Initial
+ Value; if it has not been set we use the standard value. */
+ if (c->marks.iv)
+ memcpy (a, c->u_iv.iv, 8);
+ else
+ memset (a, 0xa6, 8);
+
+ memset (t, 0, sizeof t); /* t := 0. */
+
+ for (j = 0; j <= 5; j++)
+ {
+ for (i = 1; i <= n; i++)
+ {
+ /* B := AES_k( A | R[i] ) */
+ memcpy (b, a, 8);
+ memcpy (b+8, r+i*8, 8);
+ nburn = c->spec->encrypt (&c->context.c, b, b);
+ burn = nburn > burn ? nburn : burn;
+ /* t := t + 1 */
+ for (x = 7; x >= 0; x--)
+ {
+ t[x]++;
+ if (t[x])
+ break;
+ }
+ /* A := MSB_64(B) ^ t */
+ cipher_block_xor(a, b, t, 8);
+ /* R[i] := LSB_64(B) */
+ memcpy (r+i*8, b+8, 8);
+ }
+ }
+
+ if (burn > 0)
+ _gcry_burn_stack (burn + 4 * sizeof(void *));
+
+ return 0;
+}
+
+/* Perform the AES-Unwrap algorithm as specified by RFC3394. We
+ implement this as a mode usable with any cipher algorithm of
+ blocksize 128. */
+gcry_err_code_t
+_gcry_cipher_aeswrap_decrypt (gcry_cipher_hd_t c,
+ byte *outbuf, size_t outbuflen,
+ const byte *inbuf, size_t inbuflen)
+{
+ int j, x;
+ size_t n, i;
+ unsigned char *r, *a, *b;
+ unsigned char t[8];
+ unsigned int burn, nburn;
+
+#if MAX_BLOCKSIZE < 8
+#error Invalid block size
+#endif
+ /* We require a cipher with a 128 bit block length. */
+ if (c->spec->blocksize != 16)
+ return GPG_ERR_INV_LENGTH;
+
+ /* The output buffer must be able to hold the input data minus one
+ additional block. Fixme: The caller has more restrictive checks
+ - we may want to fix them for this mode. */
+ if (outbuflen + 8 < inbuflen)
+ return GPG_ERR_BUFFER_TOO_SHORT;
+ /* Input data must be multiple of 64 bits. */
+ if (inbuflen % 8)
+ return GPG_ERR_INV_ARG;
+
+ n = inbuflen / 8;
+
+ /* We need at least three 64 bit blocks. */
+ if (n < 3)
+ return GPG_ERR_INV_ARG;
+
+ burn = 0;
+
+ r = outbuf;
+ a = c->lastiv; /* We use c->LASTIV as buffer for A. */
+ b = c->u_ctr.ctr; /* B is also used to concatenate stuff. */
+
+ /* Copy the inbuf to the outbuf and save A. */
+ memcpy (a, inbuf, 8);
+ memmove (r, inbuf+8, inbuflen-8);
+ n--; /* Reduce to actual number of data blocks. */
+
+ /* t := 6 * n */
+ i = n * 6; /* The range is valid because: n = inbuflen / 8 - 1. */
+ for (x=0; x < 8 && x < sizeof (i); x++)
+ t[7-x] = i >> (8*x);
+ for (; x < 8; x++)
+ t[7-x] = 0;
+
+ for (j = 5; j >= 0; j--)
+ {
+ for (i = n; i >= 1; i--)
+ {
+ /* B := AES_k^1( (A ^ t)| R[i] ) */
+ cipher_block_xor(b, a, t, 8);
+ memcpy (b+8, r+(i-1)*8, 8);
+ nburn = c->spec->decrypt (&c->context.c, b, b);
+ burn = nburn > burn ? nburn : burn;
+ /* t := t - 1 */
+ for (x = 7; x >= 0; x--)
+ {
+ t[x]--;
+ if (t[x] != 0xff)
+ break;
+ }
+ /* A := MSB_64(B) */
+ memcpy (a, b, 8);
+ /* R[i] := LSB_64(B) */
+ memcpy (r+(i-1)*8, b+8, 8);
+ }
+ }
+
+ /* If an IV has been set we compare against this Alternative Initial
+ Value; if it has not been set we compare against the standard IV. */
+ if (c->marks.iv)
+ j = memcmp (a, c->u_iv.iv, 8);
+ else
+ {
+ for (j=0, x=0; x < 8; x++)
+ if (a[x] != 0xa6)
+ {
+ j=1;
+ break;
+ }
+ }
+
+ if (burn > 0)
+ _gcry_burn_stack (burn + 4 * sizeof(void *));
+
+ return j? GPG_ERR_CHECKSUM : 0;
+}