diff options
Diffstat (limited to 'SoftHSMv2/src/lib/crypto/BotanAES.cpp')
-rw-r--r-- | SoftHSMv2/src/lib/crypto/BotanAES.cpp | 354 |
1 files changed, 354 insertions, 0 deletions
diff --git a/SoftHSMv2/src/lib/crypto/BotanAES.cpp b/SoftHSMv2/src/lib/crypto/BotanAES.cpp new file mode 100644 index 0000000..0c67a09 --- /dev/null +++ b/SoftHSMv2/src/lib/crypto/BotanAES.cpp @@ -0,0 +1,354 @@ +/* + * Copyright (c) 2010 .SE (The Internet Infrastructure Foundation) + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN + * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/***************************************************************************** + BotanAES.cpp + + Botan AES implementation + *****************************************************************************/ + +#include "config.h" +#include "BotanAES.h" +#include <algorithm> +#include <botan/rfc3394.h> +#include <botan/version.h> + +#if BOTAN_VERSION_CODE < BOTAN_VERSION_CODE_FOR(1,11,14) +#include <botan/libstate.h> +#endif + +// Wrap/Unwrap keys +bool BotanAES::wrapKey(const SymmetricKey* key, const SymWrap::Type mode, const ByteString& in, ByteString& out) +{ + // Check key bit length; AES only supports 128, 192 or 256 bit keys + if ((key->getBitLen() != 128) && + (key->getBitLen() != 192) && + (key->getBitLen() != 256)) + { + ERROR_MSG("Invalid AES key length (%d bits)", key->getBitLen()); + + return false; + } + + // Determine the wrapping mode + if (mode == SymWrap::AES_KEYWRAP) + { + // RFC 3394 AES key wrap + if (in.size() < 16) + { + ERROR_MSG("key data to wrap too small"); + + return false; + } + if ((in.size() % 8) != 0) + { + ERROR_MSG("key data to wrap not aligned"); + + return false; + } + +#if BOTAN_VERSION_CODE >= BOTAN_VERSION_CODE_FOR(1,11,0) + Botan::secure_vector<Botan::byte> data(in.size()); + memcpy(data.data(), in.const_byte_str(), in.size()); + Botan::secure_vector<Botan::byte> wrapped; +#else + Botan::MemoryVector<Botan::byte> data(in.size()); + memcpy(data.begin(), in.const_byte_str(), in.size()); + Botan::SecureVector<Botan::byte> wrapped; +#endif + Botan::SymmetricKey botanKey = Botan::SymmetricKey(key->getKeyBits().const_byte_str(), key->getKeyBits().size()); +#if BOTAN_VERSION_CODE < BOTAN_VERSION_CODE_FOR(1,11,14) + Botan::Algorithm_Factory& af = Botan::global_state().algorithm_factory(); + try + { + wrapped = Botan::rfc3394_keywrap(data, botanKey, af); + } +#else + try + { + wrapped = Botan::rfc3394_keywrap(data, botanKey); + } +#endif + catch (...) + { + ERROR_MSG("AES key wrap failed"); + + return false; + } + out.resize(wrapped.size()); +#if BOTAN_VERSION_CODE >= BOTAN_VERSION_CODE_FOR(1,11,0) + memcpy(&out[0], wrapped.data(), out.size()); +#else + memcpy(&out[0], wrapped.begin(), out.size()); +#endif + + return true; + } +#ifdef HAVE_AES_KEY_WRAP_PAD + else if (mode == SymWrap::AES_KEYWRAP_PAD) + { + // RFC 5649 AES key wrap with pad +#if BOTAN_VERSION_CODE >= BOTAN_VERSION_CODE_FOR(1,11,0) + Botan::secure_vector<Botan::byte> data(in.size()); + memcpy(data.data(), in.const_byte_str(), in.size()); + Botan::secure_vector<Botan::byte> wrapped; +#else + Botan::MemoryVector<Botan::byte> data(in.size()); + memcpy(data.begin(), in.const_byte_str(), in.size()); + Botan::SecureVector<Botan::byte> wrapped; +#endif + Botan::SymmetricKey botanKey = Botan::SymmetricKey(key->getKeyBits().const_byte_str(), key->getKeyBits().size()); +#if BOTAN_VERSION_CODE < BOTAN_VERSION_CODE_FOR(1,11,14) + Botan::Algorithm_Factory& af = Botan::global_state().algorithm_factory(); + try + { + wrapped = Botan::rfc5649_keywrap(data, botanKey, af); + } +#else + try + { + wrapped = Botan::rfc5649_keywrap(data, botanKey); + } +#endif + catch (...) + { + ERROR_MSG("AES key wrap failed"); + + return false; + } + out.resize(wrapped.size()); +#if BOTAN_VERSION_CODE >= BOTAN_VERSION_CODE_FOR(1,11,0) + memcpy(&out[0], wrapped.data(), out.size()); +#else + memcpy(&out[0], wrapped.begin(), out.size()); +#endif + + return true; + } +#endif + else + { + ERROR_MSG("unknown AES key wrap mode %i", mode); + + return false; + } +} + +bool BotanAES::unwrapKey(const SymmetricKey* key, const SymWrap::Type mode, const ByteString& in, ByteString& out) +{ + // Check key bit length; AES only supports 128, 192 or 256 bit keys + if ((key->getBitLen() != 128) && + (key->getBitLen() != 192) && + (key->getBitLen() != 256)) + { + ERROR_MSG("Invalid AES key length (%d bits)", key->getBitLen()); + + return false; + } + + // Determine the unwrapping mode + if (mode == SymWrap::AES_KEYWRAP) + { + // RFC 3394 AES key wrap + if (in.size() < 24) + { + ERROR_MSG("key data to unwrap too small"); + + return false; + } + if ((in.size() % 8) != 0) + { + ERROR_MSG("key data to unwrap not aligned"); + + return false; + } + +#if BOTAN_VERSION_CODE >= BOTAN_VERSION_CODE_FOR(1,11,0) + Botan::secure_vector<Botan::byte> wrapped(in.size()); + memcpy(wrapped.data(), in.const_byte_str(), in.size()); + Botan::secure_vector<Botan::byte> unwrapped; +#else + Botan::MemoryVector<Botan::byte> wrapped(in.size()); + memcpy(wrapped.begin(), in.const_byte_str(), in.size()); + Botan::SecureVector<Botan::byte> unwrapped; +#endif + Botan::SymmetricKey botanKey = Botan::SymmetricKey(key->getKeyBits().const_byte_str(), key->getKeyBits().size()); +#if BOTAN_VERSION_CODE < BOTAN_VERSION_CODE_FOR(1,11,14) + Botan::Algorithm_Factory& af = Botan::global_state().algorithm_factory(); + try + { + unwrapped = Botan::rfc3394_keyunwrap(wrapped, botanKey, af); + } +#else + try + { + unwrapped = Botan::rfc3394_keyunwrap(wrapped, botanKey); + } +#endif + catch (...) + { + ERROR_MSG("AES key unwrap failed"); + + return false; + } + out.resize(unwrapped.size()); +#if BOTAN_VERSION_CODE >= BOTAN_VERSION_CODE_FOR(1,11,0) + memcpy(&out[0], unwrapped.data(), out.size()); +#else + memcpy(&out[0], unwrapped.begin(), out.size()); +#endif + + return true; + } +#ifdef HAVE_AES_KEY_WRAP_PAD + else if (mode == SymWrap::AES_KEYWRAP_PAD) + { + // RFC 5649 AES key wrap with wrap + if (in.size() < 16) + { + ERROR_MSG("key data to unwrap too small"); + + return false; + } + if ((in.size() % 8) != 0) + { + ERROR_MSG("key data to unwrap not aligned"); + + return false; + } + +#if BOTAN_VERSION_CODE >= BOTAN_VERSION_CODE_FOR(1,11,0) + Botan::secure_vector<Botan::byte> wrapped(in.size()); + memcpy(wrapped.data(), in.const_byte_str(), in.size()); + Botan::secure_vector<Botan::byte> unwrapped; +#else + Botan::MemoryVector<Botan::byte> wrapped(in.size()); + memcpy(wrapped.begin(), in.const_byte_str(), in.size()); + Botan::SecureVector<Botan::byte> unwrapped; +#endif + Botan::SymmetricKey botanKey = Botan::SymmetricKey(key->getKeyBits().const_byte_str(), key->getKeyBits().size()); +#if BOTAN_VERSION_CODE < BOTAN_VERSION_CODE_FOR(1,11,14) + Botan::Algorithm_Factory& af = Botan::global_state().algorithm_factory(); + try + { + unwrapped = Botan::rfc5649_keyunwrap(wrapped, botanKey, af); + } +#else + try + { + unwrapped = Botan::rfc5649_keyunwrap(wrapped, botanKey); + } +#endif + catch (...) + { + ERROR_MSG("AES key unwrap failed"); + + return false; + } + out.resize(unwrapped.size()); +#if BOTAN_VERSION_CODE >= BOTAN_VERSION_CODE_FOR(1,11,0) + memcpy(&out[0], unwrapped.data(), out.size()); +#else + memcpy(&out[0], unwrapped.begin(), out.size()); +#endif + + return true; + } +#endif + else + { + ERROR_MSG("unknown AES key wrap mode %i", mode); + + return false; + } +} + +std::string BotanAES::getCipher() const +{ + std::string algo; + std::string mode; + std::string padding; + + if (currentKey == NULL) return ""; + + // Check currentKey bit length; AES only supports 128, 192 or 256 bit keys + switch (currentKey->getBitLen()) + { + case 128: + algo = "AES-128"; + break; + case 192: + algo = "AES-192"; + break; + case 256: + algo = "AES-256"; + break; + default: + ERROR_MSG("Invalid AES currentKey length (%d bits)", currentKey->getBitLen()); + + return ""; + } + + // Determine the cipher mode + switch (currentCipherMode) + { + case SymMode::CBC: + mode = "CBC"; + break; + case SymMode::CTR: + return algo + "/CTR-BE"; + case SymMode::ECB: + mode = "ECB"; + break; +#ifdef WITH_AES_GCM + case SymMode::GCM: + return algo + "/GCM(" + std::to_string(currentTagBytes) + ")"; +#endif + default: + ERROR_MSG("Invalid AES cipher mode %i", currentCipherMode); + + return ""; + } + + // Check padding mode + if (currentPaddingMode) + { + padding = "PKCS7"; + } + else + { + padding = "NoPadding"; + } + + return algo + "/" + mode + "/" + padding; +} + +size_t BotanAES::getBlockSize() const +{ + // The block size is 128 bits + return 128 >> 3; +} + |