diff options
author | NingSun <ning.sun@intel.com> | 2018-02-08 08:34:03 -0800 |
---|---|---|
committer | NingSun <ning.sun@intel.com> | 2018-02-08 09:14:52 -0800 |
commit | 0c89b3ccba7c9b7332ab67ae1936aff51ca62367 (patch) | |
tree | 70c1b1d160d4c6d0a83395ca9a87c1264d0d3439 /SoftHSMv2/src/lib/crypto/BotanRSA.cpp | |
parent | 945613b4db4e07f75d2bc7463db580ddfaa700fd (diff) |
Initial sshsm project structure
Issue-ID: AAF-94
Change-Id: I5e82fff418e7567b161acf9b98013a9b85ffc5b4
Signed-off-by: NingSun <ning.sun@intel.com>
Diffstat (limited to 'SoftHSMv2/src/lib/crypto/BotanRSA.cpp')
-rw-r--r-- | SoftHSMv2/src/lib/crypto/BotanRSA.cpp | 1219 |
1 files changed, 1219 insertions, 0 deletions
diff --git a/SoftHSMv2/src/lib/crypto/BotanRSA.cpp b/SoftHSMv2/src/lib/crypto/BotanRSA.cpp new file mode 100644 index 0000000..2fbb4e2 --- /dev/null +++ b/SoftHSMv2/src/lib/crypto/BotanRSA.cpp @@ -0,0 +1,1219 @@ +/* + * 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. + */ + +/***************************************************************************** + BotanRSA.cpp + + Botan RSA asymmetric algorithm implementation + *****************************************************************************/ + +#include "config.h" +#include "log.h" +#include "BotanRSA.h" +#include "BotanRNG.h" +#include "CryptoFactory.h" +#include "BotanCryptoFactory.h" +#include "RSAParameters.h" +#include "BotanRSAKeyPair.h" +#include <algorithm> +#include <botan/rsa.h> +#include <botan/version.h> +#include <sstream> + +// Constructor +BotanRSA::BotanRSA() +{ + signer = NULL; + verifier = NULL; +} + +// Destructor +BotanRSA::~BotanRSA() +{ + delete signer; + delete verifier; +} + +// Signing functions +bool BotanRSA::sign(PrivateKey* privateKey, const ByteString& dataToSign, + ByteString& signature, const AsymMech::Type mechanism, + const void* param /* = NULL */, const size_t paramLen /* = 0 */) +{ + std::string emsa = ""; + + switch (mechanism) + { + case AsymMech::RSA: + emsa = "Raw"; + break; + case AsymMech::RSA_PKCS: + emsa = "EMSA3(Raw)"; + break; +#ifdef WITH_RAW_PSS + case AsymMech::RSA_PKCS_PSS: + emsa = getCipherRawPss(privateKey->getBitLength(), dataToSign.size(), param, paramLen); + if (emsa == "") + { + return false; + } + break; +#endif + default: + // Call default implementation + return AsymmetricAlgorithm::sign(privateKey, dataToSign, signature, mechanism, param, paramLen); + } + + // Check if the private key is the right type + if (!privateKey->isOfType(BotanRSAPrivateKey::type)) + { + ERROR_MSG("Invalid key type supplied"); + + return false; + } + + BotanRSAPrivateKey* pk = (BotanRSAPrivateKey*) privateKey; + Botan::RSA_PrivateKey* botanKey = pk->getBotanKey(); + + if (!botanKey) + { + ERROR_MSG("Could not get the Botan private key"); + + return false; + } + + try + { +#if BOTAN_VERSION_CODE >= BOTAN_VERSION_CODE_FOR(1,11,33) + BotanRNG* rng = (BotanRNG*)BotanCryptoFactory::i()->getRNG(); + signer = new Botan::PK_Signer(*botanKey, *rng->getRNG(), emsa); +#else + signer = new Botan::PK_Signer(*botanKey, emsa); +#endif + // Should we add DISABLE_FAULT_PROTECTION? Makes this operation faster. + } + catch (...) + { + ERROR_MSG("Could not create the signer token"); + + return false; + } + + // Perform the signature operation +#if BOTAN_VERSION_CODE >= BOTAN_VERSION_CODE_FOR(1,11,0) + std::vector<Botan::byte> signResult; +#else + Botan::SecureVector<Botan::byte> signResult; +#endif + try + { + BotanRNG* rng = (BotanRNG*)BotanCryptoFactory::i()->getRNG(); + signResult = signer->sign_message(dataToSign.const_byte_str(), dataToSign.size(), *rng->getRNG()); + } + catch (std::exception& e) + { + ERROR_MSG("Could not sign the data: %s", e.what()); + + delete signer; + signer = NULL; + + return false; + } + + // Return the result + signature.resize(signResult.size()); +#if BOTAN_VERSION_CODE >= BOTAN_VERSION_CODE_FOR(1,11,0) + memcpy(&signature[0], signResult.data(), signResult.size()); +#else + memcpy(&signature[0], signResult.begin(), signResult.size()); +#endif + + delete signer; + signer = NULL; + + return true; +} + +bool BotanRSA::signInit(PrivateKey* privateKey, const AsymMech::Type mechanism, + const void* param /* = NULL */, const size_t paramLen /* = 0 */) +{ + if (!AsymmetricAlgorithm::signInit(privateKey, mechanism, param, paramLen)) + { + return false; + } + + // Check if the private key is the right type + if (!privateKey->isOfType(BotanRSAPrivateKey::type)) + { + ERROR_MSG("Invalid key type supplied"); + + ByteString dummy; + AsymmetricAlgorithm::signFinal(dummy); + + return false; + } + + std::string emsa; + std::ostringstream request; + size_t sLen; + + switch (mechanism) + { + case AsymMech::RSA_MD5_PKCS: + emsa = "EMSA3(MD5)"; + break; + case AsymMech::RSA_SHA1_PKCS: + emsa = "EMSA3(SHA-160)"; + break; + case AsymMech::RSA_SHA224_PKCS: + emsa = "EMSA3(SHA-224)"; + break; + case AsymMech::RSA_SHA256_PKCS: + emsa = "EMSA3(SHA-256)"; + break; + case AsymMech::RSA_SHA384_PKCS: + emsa = "EMSA3(SHA-384)"; + break; + case AsymMech::RSA_SHA512_PKCS: + emsa = "EMSA3(SHA-512)"; + break; + case AsymMech::RSA_SHA1_PKCS_PSS: + if (param == NULL || paramLen != sizeof(RSA_PKCS_PSS_PARAMS) || + ((RSA_PKCS_PSS_PARAMS*) param)->hashAlg != HashAlgo::SHA1 || + ((RSA_PKCS_PSS_PARAMS*) param)->mgf != AsymRSAMGF::MGF1_SHA1) + { + ERROR_MSG("Invalid parameters"); + ByteString dummy; + AsymmetricAlgorithm::signFinal(dummy); + return false; + } + sLen = ((RSA_PKCS_PSS_PARAMS*) param)->sLen; + if (sLen > ((privateKey->getBitLength()+6)/8-2-20)) + { + ERROR_MSG("sLen (%lu) is too large for current key size (%lu)", + (unsigned long)sLen, privateKey->getBitLength()); + ByteString dummy; + AsymmetricAlgorithm::signFinal(dummy); + return false; + } + request << "EMSA4(SHA-160,MGF1," << sLen << ")"; + emsa = request.str(); + break; + case AsymMech::RSA_SHA224_PKCS_PSS: + if (param == NULL || paramLen != sizeof(RSA_PKCS_PSS_PARAMS) || + ((RSA_PKCS_PSS_PARAMS*) param)->hashAlg != HashAlgo::SHA224 || + ((RSA_PKCS_PSS_PARAMS*) param)->mgf != AsymRSAMGF::MGF1_SHA224) + { + ERROR_MSG("Invalid parameters"); + ByteString dummy; + AsymmetricAlgorithm::signFinal(dummy); + return false; + } + sLen = ((RSA_PKCS_PSS_PARAMS*) param)->sLen; + if (sLen > ((privateKey->getBitLength()+6)/8-2-28)) + { + ERROR_MSG("sLen (%lu) is too large for current key size (%lu)", + (unsigned long)sLen, privateKey->getBitLength()); + ByteString dummy; + AsymmetricAlgorithm::signFinal(dummy); + return false; + } + request << "EMSA4(SHA-224,MGF1," << sLen << ")"; + emsa = request.str(); + break; + case AsymMech::RSA_SHA256_PKCS_PSS: + if (param == NULL || paramLen != sizeof(RSA_PKCS_PSS_PARAMS) || + ((RSA_PKCS_PSS_PARAMS*) param)->hashAlg != HashAlgo::SHA256 || + ((RSA_PKCS_PSS_PARAMS*) param)->mgf != AsymRSAMGF::MGF1_SHA256) + { + ERROR_MSG("Invalid parameters"); + ByteString dummy; + AsymmetricAlgorithm::signFinal(dummy); + return false; + } + sLen = ((RSA_PKCS_PSS_PARAMS*) param)->sLen; + if (sLen > ((privateKey->getBitLength()+6)/8-2-32)) + { + ERROR_MSG("sLen (%lu) is too large for current key size (%lu)", + (unsigned long)sLen, privateKey->getBitLength()); + ByteString dummy; + AsymmetricAlgorithm::signFinal(dummy); + return false; + } + request << "EMSA4(SHA-256,MGF1," << sLen << ")"; + emsa = request.str(); + break; + case AsymMech::RSA_SHA384_PKCS_PSS: + if (param == NULL || paramLen != sizeof(RSA_PKCS_PSS_PARAMS) || + ((RSA_PKCS_PSS_PARAMS*) param)->hashAlg != HashAlgo::SHA384 || + ((RSA_PKCS_PSS_PARAMS*) param)->mgf != AsymRSAMGF::MGF1_SHA384) + { + ERROR_MSG("Invalid parameters"); + ByteString dummy; + AsymmetricAlgorithm::signFinal(dummy); + return false; + } + sLen = ((RSA_PKCS_PSS_PARAMS*) param)->sLen; + if (sLen > ((privateKey->getBitLength()+6)/8-2-48)) + { + ERROR_MSG("sLen (%lu) is too large for current key size (%lu)", + (unsigned long)sLen, privateKey->getBitLength()); + ByteString dummy; + AsymmetricAlgorithm::signFinal(dummy); + return false; + } + request << "EMSA4(SHA-384,MGF1," << sLen << ")"; + emsa = request.str(); + break; + case AsymMech::RSA_SHA512_PKCS_PSS: + if (param == NULL || paramLen != sizeof(RSA_PKCS_PSS_PARAMS) || + ((RSA_PKCS_PSS_PARAMS*) param)->hashAlg != HashAlgo::SHA512 || + ((RSA_PKCS_PSS_PARAMS*) param)->mgf != AsymRSAMGF::MGF1_SHA512) + { + ERROR_MSG("Invalid parameters"); + ByteString dummy; + AsymmetricAlgorithm::signFinal(dummy); + return false; + } + sLen = ((RSA_PKCS_PSS_PARAMS*) param)->sLen; + if (sLen > ((privateKey->getBitLength()+6)/8-2-64)) + { + ERROR_MSG("sLen (%lu) is too large for current key size (%lu)", + (unsigned long)sLen, privateKey->getBitLength()); + ByteString dummy; + AsymmetricAlgorithm::signFinal(dummy); + return false; + } + request << "EMSA4(SHA-512,MGF1," << sLen << ")"; + emsa = request.str(); + break; + case AsymMech::RSA_SSL: + emsa = "EMSA3(Parallel(MD5,SHA-160))"; + break; + default: + ERROR_MSG("Invalid mechanism supplied (%i)", mechanism); + + ByteString dummy; + AsymmetricAlgorithm::signFinal(dummy); + + return false; + } + + BotanRSAPrivateKey* pk = (BotanRSAPrivateKey*) currentPrivateKey; + Botan::RSA_PrivateKey* botanKey = pk->getBotanKey(); + + if (!botanKey) + { + ERROR_MSG("Could not get the Botan private key"); + + ByteString dummy; + AsymmetricAlgorithm::signFinal(dummy); + + return false; + } + + try + { +#if BOTAN_VERSION_CODE >= BOTAN_VERSION_CODE_FOR(1,11,33) + BotanRNG* rng = (BotanRNG*)BotanCryptoFactory::i()->getRNG(); + signer = new Botan::PK_Signer(*botanKey, *rng->getRNG(), emsa); +#else + signer = new Botan::PK_Signer(*botanKey, emsa); +#endif + // Should we add DISABLE_FAULT_PROTECTION? Makes this operation faster. + } + catch (...) + { + ERROR_MSG("Could not create the signer token"); + + ByteString dummy; + AsymmetricAlgorithm::signFinal(dummy); + + return false; + } + + return true; +} + +bool BotanRSA::signUpdate(const ByteString& dataToSign) +{ + if (!AsymmetricAlgorithm::signUpdate(dataToSign)) + { + return false; + } + + try + { + if (dataToSign.size() != 0) + { + signer->update(dataToSign.const_byte_str(), + dataToSign.size()); + } + } + catch (...) + { + ERROR_MSG("Could not add data to signer token"); + + ByteString dummy; + AsymmetricAlgorithm::signFinal(dummy); + + delete signer; + signer = NULL; + + return false; + } + + return true; +} + +bool BotanRSA::signFinal(ByteString& signature) +{ + if (!AsymmetricAlgorithm::signFinal(signature)) + { + return false; + } + + // Perform the signature operation +#if BOTAN_VERSION_CODE >= BOTAN_VERSION_CODE_FOR(1,11,0) + std::vector<Botan::byte> signResult; +#else + Botan::SecureVector<Botan::byte> signResult; +#endif + try + { + BotanRNG* rng = (BotanRNG*)BotanCryptoFactory::i()->getRNG(); + signResult = signer->signature(*rng->getRNG()); + } + catch (...) + { + ERROR_MSG("Could not sign the data"); + + delete signer; + signer = NULL; + + return false; + } + + // Return the result + signature.resize(signResult.size()); +#if BOTAN_VERSION_CODE >= BOTAN_VERSION_CODE_FOR(1,11,0) + memcpy(&signature[0], signResult.data(), signResult.size()); +#else + memcpy(&signature[0], signResult.begin(), signResult.size()); +#endif + + delete signer; + signer = NULL; + + return true; +} + +// Verification functions +bool BotanRSA::verify(PublicKey* publicKey, const ByteString& originalData, + const ByteString& signature, const AsymMech::Type mechanism, + const void* param /* = NULL */, const size_t paramLen /* = 0 */) +{ + std::string emsa = ""; + + switch (mechanism) + { + case AsymMech::RSA: + emsa = "Raw"; + break; + case AsymMech::RSA_PKCS: + emsa = "EMSA3(Raw)"; + break; +#ifdef WITH_RAW_PSS + case AsymMech::RSA_PKCS_PSS: + emsa = getCipherRawPss(publicKey->getBitLength(), originalData.size(), param, paramLen); + if (emsa == "") + { + return false; + } + break; +#endif + default: + // Call the generic function + return AsymmetricAlgorithm::verify(publicKey, originalData, signature, mechanism, param, paramLen); + } + + // Check if the public key is the right type + if (!publicKey->isOfType(BotanRSAPublicKey::type)) + { + ERROR_MSG("Invalid key type supplied"); + + return false; + } + + BotanRSAPublicKey* pk = (BotanRSAPublicKey*) publicKey; + Botan::RSA_PublicKey* botanKey = pk->getBotanKey(); + + if (!botanKey) + { + ERROR_MSG("Could not get the Botan public key"); + + return false; + } + + try + { + verifier = new Botan::PK_Verifier(*botanKey, emsa); + } + catch (...) + { + ERROR_MSG("Could not create the verifier token"); + + return false; + } + + // Perform the verify operation + bool verResult; + try + { + verResult = verifier->verify_message(originalData.const_byte_str(), + originalData.size(), + signature.const_byte_str(), + signature.size()); + } + catch (...) + { + ERROR_MSG("Could not check the signature"); + + delete verifier; + verifier = NULL; + + return false; + } + + delete verifier; + verifier = NULL; + + return verResult; +} + +bool BotanRSA::verifyInit(PublicKey* publicKey, const AsymMech::Type mechanism, + const void* param /* = NULL */, const size_t paramLen /* = 0 */) +{ + if (!AsymmetricAlgorithm::verifyInit(publicKey, mechanism, param, paramLen)) + { + return false; + } + + // Check if the public key is the right type + if (!publicKey->isOfType(BotanRSAPublicKey::type)) + { + ERROR_MSG("Invalid key type supplied"); + + ByteString dummy; + AsymmetricAlgorithm::verifyFinal(dummy); + + return false; + } + + std::string emsa; + std::ostringstream request; + size_t sLen; + + switch (mechanism) + { + case AsymMech::RSA_MD5_PKCS: + emsa = "EMSA3(MD5)"; + break; + case AsymMech::RSA_SHA1_PKCS: + emsa = "EMSA3(SHA-160)"; + break; + case AsymMech::RSA_SHA224_PKCS: + emsa = "EMSA3(SHA-224)"; + break; + case AsymMech::RSA_SHA256_PKCS: + emsa = "EMSA3(SHA-256)"; + break; + case AsymMech::RSA_SHA384_PKCS: + emsa = "EMSA3(SHA-384)"; + break; + case AsymMech::RSA_SHA512_PKCS: + emsa = "EMSA3(SHA-512)"; + break; + case AsymMech::RSA_SHA1_PKCS_PSS: + if (param == NULL || paramLen != sizeof(RSA_PKCS_PSS_PARAMS) || + ((RSA_PKCS_PSS_PARAMS*) param)->hashAlg != HashAlgo::SHA1 || + ((RSA_PKCS_PSS_PARAMS*) param)->mgf != AsymRSAMGF::MGF1_SHA1) + { + ERROR_MSG("Invalid parameters"); + ByteString dummy; + AsymmetricAlgorithm::verifyFinal(dummy); + return false; + } + sLen = ((RSA_PKCS_PSS_PARAMS*) param)->sLen; + if (sLen > ((publicKey->getBitLength()+6)/8-2-20)) + { + ERROR_MSG("sLen (%lu) is too large for current key size (%lu)", + (unsigned long)sLen, publicKey->getBitLength()); + ByteString dummy; + AsymmetricAlgorithm::verifyFinal(dummy); + return false; + } + request << "EMSA4(SHA-160,MGF1," << sLen << ")"; + emsa = request.str(); + break; + case AsymMech::RSA_SHA224_PKCS_PSS: + if (param == NULL || paramLen != sizeof(RSA_PKCS_PSS_PARAMS) || + ((RSA_PKCS_PSS_PARAMS*) param)->hashAlg != HashAlgo::SHA224 || + ((RSA_PKCS_PSS_PARAMS*) param)->mgf != AsymRSAMGF::MGF1_SHA224) + { + ERROR_MSG("Invalid parameters"); + ByteString dummy; + AsymmetricAlgorithm::verifyFinal(dummy); + return false; + } + sLen = ((RSA_PKCS_PSS_PARAMS*) param)->sLen; + if (sLen > ((publicKey->getBitLength()+6)/8-2-28)) + { + ERROR_MSG("sLen (%lu) is too large for current key size (%lu)", + (unsigned long)sLen, publicKey->getBitLength()); + ByteString dummy; + AsymmetricAlgorithm::verifyFinal(dummy); + return false; + } + request << "EMSA4(SHA-224,MGF1," << sLen << ")"; + emsa = request.str(); + break; + case AsymMech::RSA_SHA256_PKCS_PSS: + if (param == NULL || paramLen != sizeof(RSA_PKCS_PSS_PARAMS) || + ((RSA_PKCS_PSS_PARAMS*) param)->hashAlg != HashAlgo::SHA256 || + ((RSA_PKCS_PSS_PARAMS*) param)->mgf != AsymRSAMGF::MGF1_SHA256) + { + ERROR_MSG("Invalid parameters"); + ByteString dummy; + AsymmetricAlgorithm::verifyFinal(dummy); + return false; + } + sLen = ((RSA_PKCS_PSS_PARAMS*) param)->sLen; + if (sLen > ((publicKey->getBitLength()+6)/8-2-32)) + { + ERROR_MSG("sLen (%lu) is too large for current key size (%lu)", + (unsigned long)sLen, publicKey->getBitLength()); + ByteString dummy; + AsymmetricAlgorithm::verifyFinal(dummy); + return false; + } + request << "EMSA4(SHA-256,MGF1," << sLen << ")"; + emsa = request.str(); + break; + case AsymMech::RSA_SHA384_PKCS_PSS: + if (param == NULL || paramLen != sizeof(RSA_PKCS_PSS_PARAMS) || + ((RSA_PKCS_PSS_PARAMS*) param)->hashAlg != HashAlgo::SHA384 || + ((RSA_PKCS_PSS_PARAMS*) param)->mgf != AsymRSAMGF::MGF1_SHA384) + { + ERROR_MSG("Invalid parameters"); + ByteString dummy; + AsymmetricAlgorithm::verifyFinal(dummy); + return false; + } + sLen = ((RSA_PKCS_PSS_PARAMS*) param)->sLen; + if (sLen > ((publicKey->getBitLength()+6)/8-2-48)) + { + ERROR_MSG("sLen (%lu) is too large for current key size (%lu)", + (unsigned long)sLen, publicKey->getBitLength()); + ByteString dummy; + AsymmetricAlgorithm::verifyFinal(dummy); + return false; + } + request << "EMSA4(SHA-384,MGF1," << sLen << ")"; + emsa = request.str(); + break; + case AsymMech::RSA_SHA512_PKCS_PSS: + if (param == NULL || paramLen != sizeof(RSA_PKCS_PSS_PARAMS) || + ((RSA_PKCS_PSS_PARAMS*) param)->hashAlg != HashAlgo::SHA512 || + ((RSA_PKCS_PSS_PARAMS*) param)->mgf != AsymRSAMGF::MGF1_SHA512) + { + ERROR_MSG("Invalid parameters"); + ByteString dummy; + AsymmetricAlgorithm::verifyFinal(dummy); + return false; + } + sLen = ((RSA_PKCS_PSS_PARAMS*) param)->sLen; + if (sLen > ((publicKey->getBitLength()+6)/8-2-64)) + { + ERROR_MSG("sLen (%lu) is too large for current key size (%lu)", + (unsigned long)sLen, publicKey->getBitLength()); + ByteString dummy; + AsymmetricAlgorithm::verifyFinal(dummy); + return false; + } + request << "EMSA4(SHA-512,MGF1," << sLen << ")"; + emsa = request.str(); + break; + case AsymMech::RSA_SSL: + emsa = "EMSA3(Parallel(MD5,SHA-160))"; + break; + default: + ERROR_MSG("Invalid mechanism supplied (%i)", mechanism); + + ByteString dummy; + AsymmetricAlgorithm::verifyFinal(dummy); + + return false; + } + + BotanRSAPublicKey* pk = (BotanRSAPublicKey*) currentPublicKey; + Botan::RSA_PublicKey* botanKey = pk->getBotanKey(); + + if (!botanKey) + { + ERROR_MSG("Could not get the Botan public key"); + + ByteString dummy; + AsymmetricAlgorithm::verifyFinal(dummy); + + return false; + } + + try + { + verifier = new Botan::PK_Verifier(*botanKey, emsa); + } + catch (...) + { + ERROR_MSG("Could not create the verifier token"); + + ByteString dummy; + AsymmetricAlgorithm::verifyFinal(dummy); + + return false; + } + + return true; +} + +bool BotanRSA::verifyUpdate(const ByteString& originalData) +{ + if (!AsymmetricAlgorithm::verifyUpdate(originalData)) + { + return false; + } + + try + { + if (originalData.size() != 0) + { + verifier->update(originalData.const_byte_str(), + originalData.size()); + } + } + catch (...) + { + ERROR_MSG("Could not add data to the verifier token"); + + ByteString dummy; + AsymmetricAlgorithm::verifyFinal(dummy); + + delete verifier; + verifier = NULL; + + return false; + } + + return true; +} + +bool BotanRSA::verifyFinal(const ByteString& signature) +{ + if (!AsymmetricAlgorithm::verifyFinal(signature)) + { + return false; + } + + // Perform the verify operation + bool verResult; + try + { + verResult = verifier->check_signature(signature.const_byte_str(), signature.size()); + } + catch (...) + { + ERROR_MSG("Could not check the signature"); + + delete verifier; + verifier = NULL; + + return false; + } + + delete verifier; + verifier = NULL; + + return verResult; +} + +// Encryption functions +bool BotanRSA::encrypt(PublicKey* publicKey, const ByteString& data, + ByteString& encryptedData, const AsymMech::Type padding) +{ + // Check if the public key is the right type + if (!publicKey->isOfType(BotanRSAPublicKey::type)) + { + ERROR_MSG("Invalid key type supplied"); + + return false; + } + + std::string eme; + + switch (padding) + { + case AsymMech::RSA_PKCS: + eme = "PKCS1v15"; + break; + case AsymMech::RSA_PKCS_OAEP: + eme = "EME1(SHA-160)"; + break; + case AsymMech::RSA: + eme = "Raw"; + break; + default: + ERROR_MSG("Invalid padding mechanism supplied (%i)", padding); + + return false; + } + + BotanRSAPublicKey* pk = (BotanRSAPublicKey*) publicKey; + Botan::RSA_PublicKey* botanKey = pk->getBotanKey(); + + if (!botanKey) + { + ERROR_MSG("Could not get the Botan public key"); + + return false; + } + + Botan::PK_Encryptor_EME* encryptor = NULL; + try + { +#if BOTAN_VERSION_CODE >= BOTAN_VERSION_CODE_FOR(1,11,33) + BotanRNG* rng = (BotanRNG*)BotanCryptoFactory::i()->getRNG(); + encryptor = new Botan::PK_Encryptor_EME(*botanKey, *rng->getRNG(), eme); +#else + encryptor = new Botan::PK_Encryptor_EME(*botanKey, eme); +#endif + } + catch (...) + { + ERROR_MSG("Could not create the encryptor token"); + + return false; + } + + // Perform the encryption operation +#if BOTAN_VERSION_CODE >= BOTAN_VERSION_CODE_FOR(1,11,0) + std::vector<Botan::byte> encResult; +#else + Botan::SecureVector<Botan::byte> encResult; +#endif + try + { + BotanRNG* rng = (BotanRNG*)BotanCryptoFactory::i()->getRNG(); + encResult = encryptor->encrypt(data.const_byte_str(), data.size(), *rng->getRNG()); + } + catch (...) + { + ERROR_MSG("Could not encrypt the data"); + + delete encryptor; + + return false; + } + + // Return the result + encryptedData.resize(encResult.size()); +#if BOTAN_VERSION_CODE >= BOTAN_VERSION_CODE_FOR(1,11,0) + memcpy(&encryptedData[0], encResult.data(), encResult.size()); +#else + memcpy(&encryptedData[0], encResult.begin(), encResult.size()); +#endif + + delete encryptor; + + return true; +} + +// Decryption functions +bool BotanRSA::decrypt(PrivateKey* privateKey, const ByteString& encryptedData, + ByteString& data, const AsymMech::Type padding) +{ + // Check if the private key is the right type + if (!privateKey->isOfType(BotanRSAPrivateKey::type)) + { + ERROR_MSG("Invalid key type supplied"); + + return false; + } + + std::string eme; + + switch (padding) + { + case AsymMech::RSA_PKCS: + eme = "PKCS1v15"; + break; + case AsymMech::RSA_PKCS_OAEP: + eme = "EME1(SHA-160)"; + break; + case AsymMech::RSA: + eme = "Raw"; + break; + default: + ERROR_MSG("Invalid padding mechanism supplied (%i)", padding); + + return false; + } + + BotanRSAPrivateKey* pk = (BotanRSAPrivateKey*) privateKey; + Botan::RSA_PrivateKey* botanKey = pk->getBotanKey(); + + if (!botanKey) + { + ERROR_MSG("Could not get the Botan private key"); + + return false; + } + + Botan::PK_Decryptor_EME* decryptor = NULL; + try + { +#if BOTAN_VERSION_CODE >= BOTAN_VERSION_CODE_FOR(1,11,33) + BotanRNG* rng = (BotanRNG*)BotanCryptoFactory::i()->getRNG(); + decryptor = new Botan::PK_Decryptor_EME(*botanKey, *rng->getRNG(), eme); +#else + decryptor = new Botan::PK_Decryptor_EME(*botanKey, eme); +#endif + } + catch (...) + { + ERROR_MSG("Could not create the decryptor token"); + + return false; + } + + // Perform the decryption operation +#if BOTAN_VERSION_CODE >= BOTAN_VERSION_CODE_FOR(1,11,0) + Botan::secure_vector<Botan::byte> decResult; +#else + Botan::SecureVector<Botan::byte> decResult; +#endif + try + { + decResult = decryptor->decrypt(encryptedData.const_byte_str(), encryptedData.size()); + } + catch (...) + { + ERROR_MSG("Could not decrypt the data"); + + delete decryptor; + + return false; + } + + // Return the result + if (padding == AsymMech::RSA) + { + // We compensate that Botan removes leading zeros + int modSize = pk->getN().size(); + int decSize = decResult.size(); + data.resize(modSize); +#if BOTAN_VERSION_CODE >= BOTAN_VERSION_CODE_FOR(1,11,0) + memcpy(&data[0] + modSize - decSize, decResult.data(), decSize); +#else + memcpy(&data[0] + modSize - decSize, decResult.begin(), decSize); +#endif + } + else + { + data.resize(decResult.size()); +#if BOTAN_VERSION_CODE >= BOTAN_VERSION_CODE_FOR(1,11,0) + memcpy(&data[0], decResult.data(), decResult.size()); +#else + memcpy(&data[0], decResult.begin(), decResult.size()); +#endif + } + + delete decryptor; + + return true; +} + +// Key factory +bool BotanRSA::generateKeyPair(AsymmetricKeyPair** ppKeyPair, AsymmetricParameters* parameters, RNG* /*rng = NULL */) +{ + // Check parameters + if ((ppKeyPair == NULL) || + (parameters == NULL)) + { + return false; + } + + if (!parameters->areOfType(RSAParameters::type)) + { + ERROR_MSG("Invalid parameters supplied for RSA key generation"); + + return false; + } + + RSAParameters* params = (RSAParameters*) parameters; + + if (params->getBitLength() < getMinKeySize() || params->getBitLength() > getMaxKeySize()) + { + ERROR_MSG("This RSA key size (%lu) is not supported", params->getBitLength()); + + return false; + } + + // Retrieve the desired public exponent + unsigned long e = params->getE().long_val(); + + // Check the public exponent + if ((e == 0) || (e % 2 != 1)) + { + ERROR_MSG("Invalid RSA public exponent %d", e); + + return false; + } + + // Create an asymmetric key-pair object to return + BotanRSAKeyPair* kp = new BotanRSAKeyPair(); + + // Generate the key-pair + Botan::RSA_PrivateKey* rsa = NULL; + try { + BotanRNG* rng = (BotanRNG*)BotanCryptoFactory::i()->getRNG(); + rsa = new Botan::RSA_PrivateKey(*rng->getRNG(), params->getBitLength(), e); + } + catch (std::exception& ex) { + ERROR_MSG("RSA key generation failed: %s", ex.what()); + + delete kp; + + return false; + } + + ((BotanRSAPublicKey*) kp->getPublicKey())->setFromBotan(rsa); + ((BotanRSAPrivateKey*) kp->getPrivateKey())->setFromBotan(rsa); + + *ppKeyPair = kp; + + // Release the key + delete rsa; + + return true; +} + +unsigned long BotanRSA::getMinKeySize() +{ + return 1024; +} + +unsigned long BotanRSA::getMaxKeySize() +{ + return 4096; +} + +bool BotanRSA::reconstructKeyPair(AsymmetricKeyPair** ppKeyPair, ByteString& serialisedData) +{ + // Check input + if ((ppKeyPair == NULL) || + (serialisedData.size() == 0)) + { + return false; + } + + ByteString dPub = ByteString::chainDeserialise(serialisedData); + ByteString dPriv = ByteString::chainDeserialise(serialisedData); + + BotanRSAKeyPair* kp = new BotanRSAKeyPair(); + + bool rv = true; + + if (!((RSAPublicKey*) kp->getPublicKey())->deserialise(dPub)) + { + rv = false; + } + + if (!((RSAPrivateKey*) kp->getPrivateKey())->deserialise(dPriv)) + { + rv = false; + } + + if (!rv) + { + delete kp; + + return false; + } + + *ppKeyPair = kp; + + return true; +} + +bool BotanRSA::reconstructPublicKey(PublicKey** ppPublicKey, ByteString& serialisedData) +{ + // Check input + if ((ppPublicKey == NULL) || + (serialisedData.size() == 0)) + { + return false; + } + + BotanRSAPublicKey* pub = new BotanRSAPublicKey(); + + if (!pub->deserialise(serialisedData)) + { + delete pub; + + return false; + } + + *ppPublicKey = pub; + + return true; +} + +bool BotanRSA::reconstructPrivateKey(PrivateKey** ppPrivateKey, ByteString& serialisedData) +{ + // Check input + if ((ppPrivateKey == NULL) || + (serialisedData.size() == 0)) + { + return false; + } + + BotanRSAPrivateKey* priv = new BotanRSAPrivateKey(); + + if (!priv->deserialise(serialisedData)) + { + delete priv; + + return false; + } + + *ppPrivateKey = priv; + + return true; +} + +PublicKey* BotanRSA::newPublicKey() +{ + return (PublicKey*) new BotanRSAPublicKey(); +} + +PrivateKey* BotanRSA::newPrivateKey() +{ + return (PrivateKey*) new BotanRSAPrivateKey(); +} + +AsymmetricParameters* BotanRSA::newParameters() +{ + return (AsymmetricParameters*) new RSAParameters(); +} + +bool BotanRSA::reconstructParameters(AsymmetricParameters** ppParams, ByteString& serialisedData) +{ + // Check input parameters + if ((ppParams == NULL) || (serialisedData.size() == 0)) + { + return false; + } + + RSAParameters* params = new RSAParameters(); + + if (!params->deserialise(serialisedData)) + { + delete params; + + return false; + } + + *ppParams = params; + + return true; +} + +#ifdef WITH_RAW_PSS +std::string BotanRSA::getCipherRawPss(size_t bitLength, size_t dataSize, const void* param, const size_t paramLen) +{ + if (param == NULL || paramLen != sizeof(RSA_PKCS_PSS_PARAMS)) + { + ERROR_MSG("Invalid parameters"); + return ""; + } + + std::string hashStr = ""; + size_t allowedLen = 0; + switch (((RSA_PKCS_PSS_PARAMS*) param)->hashAlg) + { + case HashAlgo::SHA1: + hashStr = "SHA-160"; + allowedLen = 20; + break; + case HashAlgo::SHA224: + hashStr = "SHA-224"; + allowedLen = 28; + break; + case HashAlgo::SHA256: + hashStr = "SHA-256"; + allowedLen = 32; + break; + case HashAlgo::SHA384: + hashStr = "SHA-384"; + allowedLen = 48; + break; + case HashAlgo::SHA512: + hashStr = "SHA-512"; + allowedLen = 64; + break; + default: + ERROR_MSG("Invalid hash parameter"); + return ""; + } + + if (dataSize != allowedLen) + { + ERROR_MSG("Data to sign does not match expected (%d) for RSA PSS", (int)allowedLen); + return ""; + } + + size_t sLen = ((RSA_PKCS_PSS_PARAMS*) param)->sLen; + if (sLen > ((bitLength+6)/8-2-20)) + { + ERROR_MSG("sLen (%lu) is too large for current key size (%lu)", + (unsigned long)sLen, bitLength); + return ""; + } + + std::ostringstream request; + request << "PSSR_Raw(" << hashStr << ",MGF1," << sLen << ")"; + return request.str(); +} +#endif |