diff options
author | Jack Lloyd <[email protected]> | 2017-11-19 13:11:17 -0500 |
---|---|---|
committer | Jack Lloyd <[email protected]> | 2017-11-19 13:11:17 -0500 |
commit | fea9c14d9696615f9d1cf52e0bb578c8a54c2c6a (patch) | |
tree | daf6b5a425fe5abdb77b37301b950c3422fb1937 /src/lib | |
parent | 148f43b60917d5c6b8d0ad1204cd51e1841a2855 (diff) |
Add AES key wrap with padding
Diffstat (limited to 'src/lib')
-rw-r--r-- | src/lib/misc/nist_keywrap/info.txt | 3 | ||||
-rw-r--r-- | src/lib/misc/nist_keywrap/nist_keywrap.cpp | 209 | ||||
-rw-r--r-- | src/lib/misc/nist_keywrap/nist_keywrap.h | 67 | ||||
-rw-r--r-- | src/lib/misc/rfc3394/info.txt | 1 | ||||
-rw-r--r-- | src/lib/misc/rfc3394/rfc3394.cpp | 76 | ||||
-rw-r--r-- | src/lib/misc/rfc3394/rfc3394.h | 8 |
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); } |