summaryrefslogtreecommitdiff
path: root/nist-keywrap.c
diff options
context:
space:
mode:
authorNicolas Mora <git@babelouest.org>2021-05-23 21:04:58 +0200
committerNiels Möller <nisse@lysator.liu.se>2021-05-23 21:06:32 +0200
commit0145efbcb7a4feefab0789d4470c185c44055da6 (patch)
treefcc5f2b285f356ef85a48065542cd286c73717e6 /nist-keywrap.c
parent3b1bb7cb3178f5123f1b047690a49f7c32b36daf (diff)
downloadnettle-0145efbcb7a4feefab0789d4470c185c44055da6.tar.gz
Implement aes key wrap and key unwrap (RFC 3394)
Diffstat (limited to 'nist-keywrap.c')
-rw-r--r--nist-keywrap.c200
1 files changed, 200 insertions, 0 deletions
diff --git a/nist-keywrap.c b/nist-keywrap.c
new file mode 100644
index 00000000..677a6bb5
--- /dev/null
+++ b/nist-keywrap.c
@@ -0,0 +1,200 @@
+/* nist-keywrap.c
+
+ AES Key Wrap function.
+ implements RFC 3394
+ https://tools.ietf.org/html/rfc3394
+
+ Copyright (C) 2021 Nicolas Mora
+ 2021 Niels Möller
+
+ This file is part of GNU Nettle.
+
+ GNU Nettle is free software: you can redistribute it and/or
+ modify it under the terms of either:
+
+ * the GNU Lesser General Public License as published by the Free
+ Software Foundation; either version 3 of the License, or (at your
+ option) any later version.
+
+ or
+
+ * the GNU General Public License as published by the Free
+ Software Foundation; either version 2 of the License, or (at your
+ option) any later version.
+
+ or both in parallel, as here.
+
+ GNU Nettle 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
+ General Public License for more details.
+
+ You should have received copies of the GNU General Public License and
+ the GNU Lesser General Public License along with this program. If
+ not, see http://www.gnu.org/licenses/.
+*/
+
+#if HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <assert.h>
+#include <string.h>
+
+#include "nist-keywrap.h"
+#include "memops.h"
+#include "macros.h"
+
+#if WORDS_BIGENDIAN
+#define bswap_if_le(x) (x)
+#elif HAVE_BUILTIN_BSWAP64
+#define bswap_if_le(x) (__builtin_bswap64 (x))
+#else
+static uint64_t
+bswap_if_le (uint64_t x)
+{
+ x = ((x >> 32) & UINT64_C (0xffffffff))
+ | ((x & UINT64_C (0xffffffff)) << 32);
+ x = ((x >> 16) & UINT64_C (0xffff0000ffff))
+ | ((x & UINT64_C (0xffff0000ffff)) << 16);
+ x = ((x >> 8) & UINT64_C (0xff00ff00ff00ff))
+ | ((x & UINT64_C (0xff00ff00ff00ff)) << 8);
+ return x;
+}
+#endif
+
+void
+nist_keywrap16 (const void *ctx, nettle_cipher_func *encrypt,
+ const uint8_t *iv, size_t ciphertext_length,
+ uint8_t *ciphertext, const uint8_t *cleartext)
+{
+ union nettle_block16 I, B;
+ union nettle_block8 A;
+ size_t i, j, n;
+ uint8_t *R = ciphertext + 8;
+
+ /* ciphertext_length must be at least 16
+ * and be divisible by 8 */
+ assert (ciphertext_length >= 16);
+ assert (!(ciphertext_length % 8));
+
+ n = (ciphertext_length - 8) / 8;
+ memcpy (R, cleartext, (ciphertext_length - 8));
+ memcpy (A.b, iv, 8);
+
+ for (j = 0; j < 6; j++)
+ {
+ for (i = 0; i < n; i++)
+ {
+ // I = A | R[1]
+ I.u64[0] = A.u64;
+ memcpy (I.b + 8, R + (i * 8), 8);
+
+ // B = AES(K, I)
+ encrypt (ctx, 16, B.b, I.b);
+
+ // A = MSB(64, B) ^ t where t = (n*j)+i
+ A.u64 = B.u64[0] ^ bswap_if_le ((n * j) + (i + 1));
+
+ // R[i] = LSB(64, B)
+ memcpy (R + (i * 8), B.b + 8, 8);
+ }
+ }
+
+ memcpy (ciphertext, A.b, 8);
+}
+
+int
+nist_keyunwrap16 (const void *ctx, nettle_cipher_func *decrypt,
+ const uint8_t *iv, size_t cleartext_length,
+ uint8_t *cleartext, const uint8_t *ciphertext)
+{
+ union nettle_block16 I, B;
+ union nettle_block8 A;
+ int i, j;
+ size_t n;
+ uint8_t *R = cleartext;
+
+ /* cleartext_length must be at least 8
+ * and be divisible by 8 */
+ assert (cleartext_length >= 8);
+ assert (!(cleartext_length % 8));
+
+ n = (cleartext_length / 8);
+ memcpy (A.b, ciphertext, 8);
+ memcpy (R, ciphertext + 8, cleartext_length);
+
+ for (j = 5; j >= 0; j--)
+ {
+ for (i = n - 1; i >= 0; i--)
+ {
+ // B = AES-1(K, (A ^ t) | R[i]) where t = n*j+i
+ I.u64[0] = A.u64 ^ bswap_if_le ((n * j) + (i + 1));
+ memcpy (I.b + 8, R + (i * 8), 8);
+ decrypt (ctx, 16, B.b, I.b);
+
+ // A = MSB(64, B)
+ A.u64 = B.u64[0];
+
+ // R[i] = LSB(64, B)
+ memcpy (R + (i * 8), B.b + 8, 8);
+ //R[i*8] = B.u64[1];
+ }
+ }
+
+ return memeql_sec (A.b, iv, 8);
+}
+
+void
+aes128_keywrap (struct aes128_ctx *ctx,
+ const uint8_t *iv, size_t ciphertext_length,
+ uint8_t *ciphertext, const uint8_t *cleartext)
+{
+ nist_keywrap16 (ctx, (nettle_cipher_func *) & aes128_encrypt,
+ iv, ciphertext_length, ciphertext, cleartext);
+}
+
+void
+aes192_keywrap (struct aes192_ctx *ctx,
+ const uint8_t *iv, size_t ciphertext_length,
+ uint8_t *ciphertext, const uint8_t *cleartext)
+{
+ nist_keywrap16 (ctx, (nettle_cipher_func *) & aes192_encrypt,
+ iv, ciphertext_length, ciphertext, cleartext);
+}
+
+void
+aes256_keywrap (struct aes256_ctx *ctx,
+ const uint8_t *iv, size_t ciphertext_length,
+ uint8_t *ciphertext, const uint8_t *cleartext)
+{
+ nist_keywrap16 (ctx, (nettle_cipher_func *) & aes256_encrypt,
+ iv, ciphertext_length, ciphertext, cleartext);
+}
+
+int
+aes128_keyunwrap (struct aes128_ctx *ctx,
+ const uint8_t *iv, size_t cleartext_length,
+ uint8_t *cleartext, const uint8_t *ciphertext)
+{
+ return nist_keyunwrap16 (ctx, (nettle_cipher_func *) & aes128_decrypt,
+ iv, cleartext_length, cleartext, ciphertext);
+}
+
+int
+aes192_keyunwrap (struct aes192_ctx *ctx,
+ const uint8_t *iv, size_t cleartext_length,
+ uint8_t *cleartext, const uint8_t *ciphertext)
+{
+ return nist_keyunwrap16 (ctx, (nettle_cipher_func *) & aes192_decrypt,
+ iv, cleartext_length, cleartext, ciphertext);
+}
+
+int
+aes256_keyunwrap (struct aes256_ctx *ctx,
+ const uint8_t *iv, size_t cleartext_length,
+ uint8_t *cleartext, const uint8_t *ciphertext)
+{
+ return nist_keyunwrap16 (ctx, (nettle_cipher_func *) & aes256_decrypt,
+ iv, cleartext_length, cleartext, ciphertext);
+}