/* * Copyright (c) 2021-2022 Ribose Inc. * 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 COPYRIGHT HOLDERS AND CONTRIBUTORS * ``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 COPYRIGHT HOLDERS OR CONTRIBUTORS * 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. */ #include "config.h" #include "hash.hpp" #include "types.h" #include "utils.h" #include "str-utils.h" #include "hash_sha1cd.hpp" #if defined(CRYPTO_BACKEND_BOTAN) #include "hash_botan.hpp" #endif #if defined(CRYPTO_BACKEND_OPENSSL) #include "hash_ossl.hpp" #include "hash_crc24.hpp" #endif static const struct hash_alg_map_t { pgp_hash_alg_t type; const char * name; size_t len; } hash_alg_map[] = {{PGP_HASH_MD5, "MD5", 16}, {PGP_HASH_SHA1, "SHA1", 20}, {PGP_HASH_RIPEMD, "RIPEMD160", 20}, {PGP_HASH_SHA256, "SHA256", 32}, {PGP_HASH_SHA384, "SHA384", 48}, {PGP_HASH_SHA512, "SHA512", 64}, {PGP_HASH_SHA224, "SHA224", 28}, {PGP_HASH_SM3, "SM3", 32}, {PGP_HASH_SHA3_256, "SHA3-256", 32}, {PGP_HASH_SHA3_512, "SHA3-512", 64}}; namespace rnp { pgp_hash_alg_t Hash::alg() const { return alg_; } size_t Hash::size() const { return Hash::size(alg_); } std::unique_ptr Hash::create(pgp_hash_alg_t alg) { if (alg == PGP_HASH_SHA1) { return Hash_SHA1CD::create(); } #if !defined(ENABLE_SM2) if (alg == PGP_HASH_SM3) { RNP_LOG("SM3 hash is not available."); throw rnp_exception(RNP_ERROR_BAD_PARAMETERS); } #endif #if defined(CRYPTO_BACKEND_OPENSSL) return Hash_OpenSSL::create(alg); #elif defined(CRYPTO_BACKEND_BOTAN) return Hash_Botan::create(alg); #else #error "Crypto backend not specified" #endif } std::unique_ptr CRC24::create() { #if defined(CRYPTO_BACKEND_OPENSSL) return CRC24_RNP::create(); #elif defined(CRYPTO_BACKEND_BOTAN) return CRC24_Botan::create(); #else #error "Crypto backend not specified" #endif } void Hash::add(uint32_t val) { uint8_t ibuf[4]; STORE32BE(ibuf, val); add(ibuf, sizeof(ibuf)); } void Hash::add(const pgp_mpi_t &val) { size_t len = mpi_bytes(&val); size_t idx = 0; while ((idx < len) && (!val.mpi[idx])) { idx++; } if (idx >= len) { add(0); return; } add(len - idx); if (val.mpi[idx] & 0x80) { uint8_t padbyte = 0; add(&padbyte, 1); } add(val.mpi + idx, len - idx); } Hash::~Hash() { } pgp_hash_alg_t Hash::alg(const char *name) { if (!name) { return PGP_HASH_UNKNOWN; } for (size_t i = 0; i < ARRAY_SIZE(hash_alg_map); i++) { if (rnp::str_case_eq(name, hash_alg_map[i].name)) { return hash_alg_map[i].type; } } return PGP_HASH_UNKNOWN; } const char * Hash::name(pgp_hash_alg_t alg) { const char *ret = NULL; ARRAY_LOOKUP_BY_ID(hash_alg_map, type, name, alg, ret); return ret; } size_t Hash::size(pgp_hash_alg_t alg) { size_t val = 0; ARRAY_LOOKUP_BY_ID(hash_alg_map, type, len, alg, val); return val; } void HashList::add_alg(pgp_hash_alg_t alg) { if (!get(alg)) { hashes.emplace_back(rnp::Hash::create(alg)); } } const Hash * HashList::get(pgp_hash_alg_t alg) const { for (auto &hash : hashes) { if (hash->alg() == alg) { return hash.get(); } } return NULL; } void HashList::add(const void *buf, size_t len) { for (auto &hash : hashes) { hash->add(buf, len); } } } // namespace rnp