// Copyright (C) 2014-2017 Internet Systems Consortium, Inc. ("ISC") // // This Source Code Form is subject to the terms of the Mozilla Public // License, v. 2.0. If a copy of the MPL was not distributed with this // file, You can obtain one at http://mozilla.org/MPL/2.0/. #include #include #include #include #include #include #include #include #if BOTAN_VERSION_CODE < BOTAN_VERSION_CODE_FOR(1,11,0) #define secure_vector SecureVector #endif namespace isc { namespace cryptolink { /// @brief Decode the HashAlgorithm enum into a name usable by Botan /// /// @param algorithm algorithm to be converted /// @return text representation of the algorithm name const std::string btn::getHashAlgorithmName(HashAlgorithm algorithm) { switch (algorithm) { case isc::cryptolink::MD5: return ("MD5"); case isc::cryptolink::SHA1: return ("SHA-1"); case isc::cryptolink::SHA256: return ("SHA-256"); case isc::cryptolink::SHA224: return ("SHA-224"); case isc::cryptolink::SHA384: return ("SHA-384"); case isc::cryptolink::SHA512: return ("SHA-512"); case isc::cryptolink::UNKNOWN_HASH: return ("Unknown"); } // compiler should have prevented us to reach this, since we have // no default. But we need a return value anyway return ("Unknown"); } /// @brief Botan implementation of Hash. Each method is the counterpart /// of the Hash corresponding method. class HashImpl { public: /// @brief Constructor for specific hash algorithm /// /// @param hash_algorithm The hash algorithm explicit HashImpl(const HashAlgorithm hash_algorithm) : hash_algorithm_(hash_algorithm), hash_() { Botan::HashFunction* hash; try { const std::string& name = btn::getHashAlgorithmName(hash_algorithm); #if BOTAN_VERSION_CODE >= BOTAN_VERSION_CODE_FOR(1,11,0) hash = Botan::HashFunction::create(name).release(); #else hash = Botan::get_hash(name); #endif } catch (const Botan::Algorithm_Not_Found&) { isc_throw(isc::cryptolink::UnsupportedAlgorithm, "Unknown hash algorithm: " << static_cast(hash_algorithm)); } catch (const Botan::Exception& exc) { isc_throw(isc::cryptolink::LibraryError, "Botan error: " << exc.what()); } hash_.reset(hash); } /// @brief Destructor ~HashImpl() { } /// @brief Returns the HashAlgorithm of the object HashAlgorithm getHashAlgorithm() const { return (hash_algorithm_); } /// @brief Returns the output size of the digest /// /// @return output size of the digest size_t getOutputLength() const { #if BOTAN_VERSION_CODE >= BOTAN_VERSION_CODE_FOR(1,9,0) return (hash_->output_length()); #elif BOTAN_VERSION_CODE >= BOTAN_VERSION_CODE_FOR(1,8,0) return (hash_->OUTPUT_LENGTH); #else #error "Unsupported Botan version (need 1.8 or higher)" // added to suppress irrelevant compiler errors return 0; #endif } /// @brief Adds data to the digest /// /// See @ref isc::cryptolink::Hash::update() for details. void update(const void* data, const size_t len) { try { hash_->update(static_cast(data), len); } catch (const Botan::Exception& exc) { isc_throw(isc::cryptolink::LibraryError, "Botan error: " << exc.what()); } } /// @brief Calculate the final digest /// /// See @ref isc::cryptolink::Hash::final() for details. void final(isc::util::OutputBuffer& result, size_t len) { try { Botan::secure_vector b_result(hash_->final()); if (len > b_result.size()) { len = b_result.size(); } result.writeData(&b_result[0], len); } catch (const Botan::Exception& exc) { isc_throw(isc::cryptolink::LibraryError, "Botan error: " << exc.what()); } } /// @brief Calculate the final digest /// /// See @ref isc::cryptolink::Hash::final() for details. void final(void* result, size_t len) { try { Botan::secure_vector b_result(hash_->final()); size_t output_size = getOutputLength(); if (output_size > len) { output_size = len; } std::memcpy(result, &b_result[0], output_size); } catch (const Botan::Exception& exc) { isc_throw(isc::cryptolink::LibraryError, "Botan error: " << exc.what()); } } /// @brief Calculate the final digest /// /// See @ref isc::cryptolink::Hash::final() for details. std::vector final(size_t len) { try { Botan::secure_vector b_result(hash_->final()); if (len > b_result.size()) { len = b_result.size(); } return (std::vector(&b_result[0], &b_result[len])); } catch (const Botan::Exception& exc) { isc_throw(isc::cryptolink::LibraryError, "Botan error: " << exc.what()); } } private: /// @brief The hash algorithm HashAlgorithm hash_algorithm_; /// @brief The protected pointer to the Botan HashFunction object boost::scoped_ptr hash_; }; Hash::Hash(const HashAlgorithm hash_algorithm) { impl_ = new HashImpl(hash_algorithm); } Hash::~Hash() { delete impl_; } HashAlgorithm Hash::getHashAlgorithm() const { return (impl_->getHashAlgorithm()); } size_t Hash::getOutputLength() const { return (impl_->getOutputLength()); } void Hash::update(const void* data, const size_t len) { impl_->update(data, len); } void Hash::final(isc::util::OutputBuffer& result, size_t len) { impl_->final(result, len); } void Hash::final(void* result, size_t len) { impl_->final(result, len); } std::vector Hash::final(size_t len) { return impl_->final(len); } } // namespace cryptolink } // namespace isc