aboutsummaryrefslogtreecommitdiffstats
path: root/src/lib
diff options
context:
space:
mode:
authorJack Lloyd <[email protected]>2017-11-19 13:11:17 -0500
committerJack Lloyd <[email protected]>2017-11-19 13:11:17 -0500
commitfea9c14d9696615f9d1cf52e0bb578c8a54c2c6a (patch)
treedaf6b5a425fe5abdb77b37301b950c3422fb1937 /src/lib
parent148f43b60917d5c6b8d0ad1204cd51e1841a2855 (diff)
Add AES key wrap with padding
Diffstat (limited to 'src/lib')
-rw-r--r--src/lib/misc/nist_keywrap/info.txt3
-rw-r--r--src/lib/misc/nist_keywrap/nist_keywrap.cpp209
-rw-r--r--src/lib/misc/nist_keywrap/nist_keywrap.h67
-rw-r--r--src/lib/misc/rfc3394/info.txt1
-rw-r--r--src/lib/misc/rfc3394/rfc3394.cpp76
-rw-r--r--src/lib/misc/rfc3394/rfc3394.h8
6 files changed, 290 insertions, 74 deletions
diff --git a/src/lib/misc/nist_keywrap/info.txt b/src/lib/misc/nist_keywrap/info.txt
new file mode 100644
index 000000000..3fb3639f0
--- /dev/null
+++ b/src/lib/misc/nist_keywrap/info.txt
@@ -0,0 +1,3 @@
+<defines>
+NIST_KEYWRAP -> 20171119
+</defines>
diff --git a/src/lib/misc/nist_keywrap/nist_keywrap.cpp b/src/lib/misc/nist_keywrap/nist_keywrap.cpp
new file mode 100644
index 000000000..c349f97aa
--- /dev/null
+++ b/src/lib/misc/nist_keywrap/nist_keywrap.cpp
@@ -0,0 +1,209 @@
+/*
+* (C) 2011,2017 Jack Lloyd
+*
+* Botan is released under the Simplified BSD License (see license.txt)
+*/
+
+#include <botan/nist_keywrap.h>
+#include <botan/block_cipher.h>
+#include <botan/loadstor.h>
+#include <botan/exceptn.h>
+
+namespace Botan {
+
+namespace {
+
+std::vector<uint8_t>
+raw_nist_key_wrap(const uint8_t input[],
+ size_t input_len,
+ const BlockCipher& bc,
+ uint64_t ICV)
+ {
+ const size_t n = (input_len + 7) / 8;
+
+ secure_vector<uint8_t> R((n + 1) * 8);
+ secure_vector<uint8_t> A(16);
+
+ store_be(ICV, A.data());
+
+ copy_mem(&R[8], input, input_len);
+
+ for(size_t j = 0; j <= 5; ++j)
+ {
+ for(size_t i = 1; i <= n; ++i)
+ {
+ const uint32_t t = static_cast<uint32_t>((n * j) + i);
+
+ copy_mem(&A[8], &R[8*i], 8);
+
+ bc.encrypt(A.data());
+ copy_mem(&R[8*i], &A[8], 8);
+
+ uint8_t t_buf[4] = { 0 };
+ store_be(t, t_buf);
+ xor_buf(&A[4], t_buf, 4);
+ }
+ }
+
+ copy_mem(R.data(), A.data(), 8);
+
+ return std::vector<uint8_t>(R.begin(), R.end());
+ }
+
+secure_vector<uint8_t>
+raw_nist_key_unwrap(const uint8_t input[],
+ size_t input_len,
+ const BlockCipher& bc,
+ uint64_t& ICV_out)
+ {
+ if(input_len < 16 || input_len % 8 != 0)
+ throw Invalid_Argument("Bad input size for NIST key unwrap");
+
+ const size_t n = (input_len - 8) / 8;
+
+ secure_vector<uint8_t> R(n * 8);
+ secure_vector<uint8_t> A(16);
+
+ for(size_t i = 0; i != 8; ++i)
+ A[i] = input[i];
+
+ copy_mem(R.data(), input + 8, input_len - 8);
+
+ for(size_t j = 0; j <= 5; ++j)
+ {
+ for(size_t i = n; i != 0; --i)
+ {
+ const uint32_t t = static_cast<uint32_t>((5 - j) * n + i);
+
+ uint8_t t_buf[4] = { 0 };
+ store_be(t, t_buf);
+
+ xor_buf(&A[4], t_buf, 4);
+
+ copy_mem(&A[8], &R[8*(i-1)], 8);
+
+ bc.decrypt(A.data());
+
+ copy_mem(&R[8*(i-1)], &A[8], 8);
+ }
+ }
+
+ ICV_out = load_be<uint64_t>(A.data(), 0);
+
+ return R;
+ }
+
+}
+
+std::vector<uint8_t>
+nist_key_wrap(const uint8_t input[],
+ size_t input_len,
+ const BlockCipher& bc)
+ {
+ if(bc.block_size() != 16)
+ throw Invalid_Argument("NIST key wrap algorithm requires a 128-bit cipher");
+
+ if(input_len % 8 != 0)
+ throw Invalid_Argument("Bad input size for NIST key wrap");
+
+ return raw_nist_key_wrap(input, input_len, bc, 0xA6A6A6A6A6A6A6A6);
+ }
+
+secure_vector<uint8_t>
+nist_key_unwrap(const uint8_t input[],
+ size_t input_len,
+ const BlockCipher& bc)
+ {
+ if(bc.block_size() != 16)
+ throw Invalid_Argument("NIST key wrap algorithm requires a 128-bit cipher");
+
+ if(input_len < 16 || input_len % 8 != 0)
+ throw Invalid_Argument("Bad input size for NIST key unwrap");
+
+ uint64_t ICV_out = 0;
+
+ secure_vector<uint8_t> R = raw_nist_key_unwrap(input, input_len, bc, ICV_out);
+
+ if(ICV_out != 0xA6A6A6A6A6A6A6A6)
+ throw Integrity_Failure("NIST key unwrap failed");
+
+ return R;
+ }
+
+std::vector<uint8_t>
+nist_key_wrap_padded(const uint8_t input[],
+ size_t input_len,
+ const BlockCipher& bc)
+ {
+ if(bc.block_size() != 16)
+ throw Invalid_Argument("NIST key wrap algorithm requires a 128-bit cipher");
+
+ const uint64_t ICV = 0xA65959A600000000 | static_cast<uint32_t>(input_len);
+
+ if(input_len <= 8)
+ {
+ /*
+ * Special case for small inputs: if input <= 8 bytes just use ECB
+ */
+ std::vector<uint8_t> block(16);
+ store_be(ICV, block.data());
+ copy_mem(block.data() + 8, input, input_len);
+ bc.encrypt(block);
+ return block;
+ }
+ else
+ {
+ return raw_nist_key_wrap(input, input_len, bc, ICV);
+ }
+ }
+
+secure_vector<uint8_t>
+nist_key_unwrap_padded(const uint8_t input[],
+ size_t input_len,
+ const BlockCipher& bc)
+ {
+ if(bc.block_size() != 16)
+ throw Invalid_Argument("NIST key wrap algorithm requires a 128-bit cipher");
+
+ if(input_len < 16 || input_len % 8 != 0)
+ throw Invalid_Argument("Bad input size for NIST key unwrap");
+
+ uint64_t ICV_out = 0;
+ secure_vector<uint8_t> R;
+
+ if(input_len == 16)
+ {
+ secure_vector<uint8_t> block(input, input + input_len);
+ bc.decrypt(block);
+
+ ICV_out = load_be<uint64_t>(block.data(), 0);
+ R.resize(8);
+ copy_mem(R.data(), block.data() + 8, 8);
+ }
+ else
+ {
+ R = raw_nist_key_unwrap(input, input_len, bc, ICV_out);
+ }
+
+ if((ICV_out >> 32) != 0xA65959A6)
+ throw Integrity_Failure("NIST key unwrap failed");
+
+ const size_t len = (ICV_out & 0xFFFFFFFF);
+
+ if(len > R.size() || len < R.size() - 8)
+ throw Integrity_Failure("NIST key unwrap failed");
+
+ const size_t padding = R.size() - len;
+
+ for(size_t i = 0; i != padding; ++i)
+ {
+ if(R[R.size() - i - 1] != 0)
+ throw Integrity_Failure("NIST key unwrap failed");
+ }
+
+ R.resize(R.size() - padding);
+
+ return R;
+ }
+
+}
diff --git a/src/lib/misc/nist_keywrap/nist_keywrap.h b/src/lib/misc/nist_keywrap/nist_keywrap.h
new file mode 100644
index 000000000..022b4016f
--- /dev/null
+++ b/src/lib/misc/nist_keywrap/nist_keywrap.h
@@ -0,0 +1,67 @@
+/*
+* (C) 2011,2017 Jack Lloyd
+*
+* Botan is released under the Simplified BSD License (see license.txt)
+*/
+
+#ifndef BOTAN_NIST_KEY_WRAP_H_
+#define BOTAN_NIST_KEY_WRAP_H_
+
+#include <botan/secmem.h>
+
+namespace Botan {
+
+class BlockCipher;
+
+/**
+* Key wrap. See RFC 3394 and NIST SP800-38F
+* @param input the value to be encrypted
+* @param input_len length of input, must be a multiple of 8
+* @param bc a keyed 128-bit block cipher that will be used to encrypt input
+* @return input encrypted under NIST key wrap algorithm
+*/
+std::vector<uint8_t> BOTAN_PUBLIC_API(2,4)
+nist_key_wrap(const uint8_t input[],
+ size_t input_len,
+ const BlockCipher& bc);
+
+/**
+* @param input the value to be decrypted, output of nist_key_wrap
+* @param input_len length of input
+* @param bc a keyed 128-bit block cipher that will be used to decrypt input
+* @return input decrypted under NIST key wrap algorithm
+* Throws an exception if decryption fails.
+*/
+secure_vector<uint8_t> BOTAN_PUBLIC_API(2,4)
+nist_key_unwrap(const uint8_t input[],
+ size_t input_len,
+ const BlockCipher& bc);
+
+/**
+* KWP (key wrap with padding). See RFC 5649 and NIST SP800-38F
+* @param input the value to be encrypted
+* @param input_len length of input
+* @param bc a keyed 128-bit block cipher that will be used to encrypt input
+* @return input encrypted under NIST key wrap algorithm
+*/
+std::vector<uint8_t> BOTAN_PUBLIC_API(2,4)
+nist_key_wrap_padded(const uint8_t input[],
+ size_t input_len,
+ const BlockCipher& bc);
+
+/**
+* @param input the value to be decrypted, output of nist_key_wrap
+* @param input_len length of input
+* @param bc a keyed 128-bit block cipher that will be used to decrypt input
+* @return input decrypted under NIST key wrap algorithm
+* Throws an exception if decryption fails.
+*/
+secure_vector<uint8_t> BOTAN_PUBLIC_API(2,4)
+nist_key_unwrap_padded(const uint8_t input[],
+ size_t input_len,
+ const BlockCipher& bc);
+
+
+}
+
+#endif
diff --git a/src/lib/misc/rfc3394/info.txt b/src/lib/misc/rfc3394/info.txt
index ac56ee833..075834219 100644
--- a/src/lib/misc/rfc3394/info.txt
+++ b/src/lib/misc/rfc3394/info.txt
@@ -4,4 +4,5 @@ RFC3394_KEYWRAP -> 20131128
<requires>
aes
+nist_keywrap
</requires>
diff --git a/src/lib/misc/rfc3394/rfc3394.cpp b/src/lib/misc/rfc3394/rfc3394.cpp
index 3bb792723..8e69933c7 100644
--- a/src/lib/misc/rfc3394/rfc3394.cpp
+++ b/src/lib/misc/rfc3394/rfc3394.cpp
@@ -6,18 +6,14 @@
*/
#include <botan/rfc3394.h>
+#include <botan/nist_keywrap.h>
#include <botan/block_cipher.h>
-#include <botan/loadstor.h>
-#include <botan/exceptn.h>
namespace Botan {
secure_vector<uint8_t> rfc3394_keywrap(const secure_vector<uint8_t>& key,
- const SymmetricKey& kek)
+ const SymmetricKey& kek)
{
- if(key.size() % 8 != 0)
- throw Invalid_Argument("Bad input key size for NIST key wrap");
-
if(kek.size() != 16 && kek.size() != 24 && kek.size() != 32)
throw Invalid_Argument("Bad KEK length " + std::to_string(kek.size()) + " for NIST key wrap");
@@ -25,40 +21,12 @@ secure_vector<uint8_t> rfc3394_keywrap(const secure_vector<uint8_t>& key,
std::unique_ptr<BlockCipher> aes(BlockCipher::create_or_throw(cipher_name));
aes->set_key(kek);
- const size_t n = key.size() / 8;
-
- secure_vector<uint8_t> R((n + 1) * 8);
- secure_vector<uint8_t> A(16);
-
- for(size_t i = 0; i != 8; ++i)
- A[i] = 0xA6;
-
- copy_mem(&R[8], key.data(), key.size());
-
- for(size_t j = 0; j <= 5; ++j)
- {
- for(size_t i = 1; i <= n; ++i)
- {
- const uint32_t t = static_cast<uint32_t>((n * j) + i);
-
- copy_mem(&A[8], &R[8*i], 8);
-
- aes->encrypt(A.data());
- copy_mem(&R[8*i], &A[8], 8);
-
- uint8_t t_buf[4] = { 0 };
- store_be(t, t_buf);
- xor_buf(&A[4], t_buf, 4);
- }
- }
-
- copy_mem(R.data(), A.data(), 8);
-
- return R;
+ std::vector<uint8_t> wrapped = nist_key_wrap(key.data(), key.size(), *aes);
+ return secure_vector<uint8_t>(wrapped.begin(), wrapped.end());
}
secure_vector<uint8_t> rfc3394_keyunwrap(const secure_vector<uint8_t>& key,
- const SymmetricKey& kek)
+ const SymmetricKey& kek)
{
if(key.size() < 16 || key.size() % 8 != 0)
throw Invalid_Argument("Bad input key size for NIST key unwrap");
@@ -70,39 +38,7 @@ secure_vector<uint8_t> rfc3394_keyunwrap(const secure_vector<uint8_t>& key,
std::unique_ptr<BlockCipher> aes(BlockCipher::create_or_throw(cipher_name));
aes->set_key(kek);
- const size_t n = (key.size() - 8) / 8;
-
- secure_vector<uint8_t> R(n * 8);
- secure_vector<uint8_t> A(16);
-
- for(size_t i = 0; i != 8; ++i)
- A[i] = key[i];
-
- copy_mem(R.data(), &key[8], key.size() - 8);
-
- for(size_t j = 0; j <= 5; ++j)
- {
- for(size_t i = n; i != 0; --i)
- {
- const uint32_t t = static_cast<uint32_t>((5 - j) * n + i);
-
- uint8_t t_buf[4] = { 0 };
- store_be(t, t_buf);
-
- xor_buf(&A[4], t_buf, 4);
-
- copy_mem(&A[8], &R[8*(i-1)], 8);
-
- aes->decrypt(A.data());
-
- copy_mem(&R[8*(i-1)], &A[8], 8);
- }
- }
-
- if(load_be<uint64_t>(A.data(), 0) != 0xA6A6A6A6A6A6A6A6)
- throw Integrity_Failure("NIST key unwrap failed");
-
- return R;
+ return nist_key_unwrap(key.data(), key.size(), *aes);
}
}
diff --git a/src/lib/misc/rfc3394/rfc3394.h b/src/lib/misc/rfc3394/rfc3394.h
index 77e602fda..9cfcfaaf6 100644
--- a/src/lib/misc/rfc3394/rfc3394.h
+++ b/src/lib/misc/rfc3394/rfc3394.h
@@ -5,8 +5,8 @@
* Botan is released under the Simplified BSD License (see license.txt)
*/
-#ifndef BOTAN_AES_KEY_WRAP_H_
-#define BOTAN_AES_KEY_WRAP_H_
+#ifndef BOTAN_RFC3394_H_
+#define BOTAN_RFC3394_H_
#include <botan/symkey.h>
@@ -21,7 +21,7 @@ namespace Botan {
* @return key encrypted under kek
*/
secure_vector<uint8_t> BOTAN_PUBLIC_API(2,0) rfc3394_keywrap(const secure_vector<uint8_t>& key,
- const SymmetricKey& kek);
+ const SymmetricKey& kek);
/**
* Decrypt a key under a key encryption key using the algorithm
@@ -32,7 +32,7 @@ secure_vector<uint8_t> BOTAN_PUBLIC_API(2,0) rfc3394_keywrap(const secure_vector
* @return key decrypted under kek
*/
secure_vector<uint8_t> BOTAN_PUBLIC_API(2,0) rfc3394_keyunwrap(const secure_vector<uint8_t>& key,
- const SymmetricKey& kek);
+ const SymmetricKey& kek);
}