Merge pull request #26148 from ksooo/fix-secondstotimestring-warning
[xbmc.git] / xbmc / utils / Digest.cpp
blob445a75543523279e652e79c2cfc53c81be719588
1 /*
2 * Copyright (C) 2018 Team Kodi
3 * This file is part of Kodi - https://kodi.tv
5 * SPDX-License-Identifier: GPL-2.0-or-later
6 * See LICENSES/README.md for more information.
7 */
9 #include "Digest.h"
11 #include "StringUtils.h"
13 #include <array>
14 #include <stdexcept>
16 #include <openssl/evp.h>
18 namespace KODI
20 namespace UTILITY
23 namespace
26 EVP_MD const * TypeToEVPMD(CDigest::Type type)
28 switch (type)
30 case CDigest::Type::MD5:
31 return EVP_md5();
32 case CDigest::Type::SHA1:
33 return EVP_sha1();
34 case CDigest::Type::SHA256:
35 return EVP_sha256();
36 case CDigest::Type::SHA512:
37 return EVP_sha512();
38 default:
39 throw std::invalid_argument("Unknown digest type");
45 std::ostream& operator<<(std::ostream& os, TypedDigest const& digest)
47 return os << "{" << CDigest::TypeToString(digest.type) << "}" << digest.value;
50 std::string CDigest::TypeToString(Type type)
52 switch (type)
54 case Type::MD5:
55 return "md5";
56 case Type::SHA1:
57 return "sha1";
58 case Type::SHA256:
59 return "sha256";
60 case Type::SHA512:
61 return "sha512";
62 case Type::INVALID:
63 return "invalid";
64 default:
65 throw std::invalid_argument("Unknown digest type");
69 CDigest::Type CDigest::TypeFromString(std::string const& type)
71 std::string typeLower{type};
72 StringUtils::ToLower(typeLower);
73 if (type == "md5")
75 return Type::MD5;
77 else if (type == "sha1")
79 return Type::SHA1;
81 else if (type == "sha256")
83 return Type::SHA256;
85 else if (type == "sha512")
87 return Type::SHA512;
89 else
91 throw std::invalid_argument(std::string("Unknown digest type \"") + type + "\"");
95 void CDigest::MdCtxDeleter::operator()(EVP_MD_CTX* context)
97 EVP_MD_CTX_destroy(context);
100 CDigest::CDigest(Type type)
101 : m_context{EVP_MD_CTX_create()}, m_md(TypeToEVPMD(type))
103 if (1 != EVP_DigestInit_ex(m_context.get(), m_md, nullptr))
105 throw std::runtime_error("EVP_DigestInit_ex failed");
109 void CDigest::Update(std::string const& data)
111 Update(data.c_str(), data.size());
114 void CDigest::Update(void const* data, std::size_t size)
116 if (m_finalized)
118 throw std::logic_error("Finalized digest cannot be updated any more");
121 if (1 != EVP_DigestUpdate(m_context.get(), data, size))
123 throw std::runtime_error("EVP_DigestUpdate failed");
127 std::string CDigest::FinalizeRaw()
129 if (m_finalized)
131 throw std::logic_error("Digest can only be finalized once");
134 m_finalized = true;
136 std::array<unsigned char, 64> digest;
137 std::size_t size = EVP_MD_size(m_md);
138 if (size > digest.size())
140 throw std::runtime_error("Digest unexpectedly long");
142 if (1 != EVP_DigestFinal_ex(m_context.get(), digest.data(), nullptr))
144 throw std::runtime_error("EVP_DigestFinal_ex failed");
146 return {reinterpret_cast<char*> (digest.data()), size};
149 std::string CDigest::Finalize()
151 return StringUtils::ToHexadecimal(FinalizeRaw());
154 std::string CDigest::Calculate(Type type, std::string const& data)
156 CDigest digest{type};
157 digest.Update(data);
158 return digest.Finalize();
161 std::string CDigest::Calculate(Type type, void const* data, std::size_t size)
163 CDigest digest{type};
164 digest.Update(data, size);
165 return digest.Finalize();