summaryrefslogtreecommitdiffstats
path: root/xbmc/utils/Digest.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'xbmc/utils/Digest.cpp')
-rw-r--r--xbmc/utils/Digest.cpp169
1 files changed, 169 insertions, 0 deletions
diff --git a/xbmc/utils/Digest.cpp b/xbmc/utils/Digest.cpp
new file mode 100644
index 0000000..445a755
--- /dev/null
+++ b/xbmc/utils/Digest.cpp
@@ -0,0 +1,169 @@
1/*
2 * Copyright (C) 2018 Team Kodi
3 * This file is part of Kodi - https://kodi.tv
4 *
5 * SPDX-License-Identifier: GPL-2.0-or-later
6 * See LICENSES/README.md for more information.
7 */
8
9#include "Digest.h"
10
11#include "StringUtils.h"
12
13#include <array>
14#include <stdexcept>
15
16#include <openssl/evp.h>
17
18namespace KODI
19{
20namespace UTILITY
21{
22
23namespace
24{
25
26EVP_MD const * TypeToEVPMD(CDigest::Type type)
27{
28 switch (type)
29 {
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");
40 }
41}
42
43}
44
45std::ostream& operator<<(std::ostream& os, TypedDigest const& digest)
46{
47 return os << "{" << CDigest::TypeToString(digest.type) << "}" << digest.value;
48}
49
50std::string CDigest::TypeToString(Type type)
51{
52 switch (type)
53 {
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");
66 }
67}
68
69CDigest::Type CDigest::TypeFromString(std::string const& type)
70{
71 std::string typeLower{type};
72 StringUtils::ToLower(typeLower);
73 if (type == "md5")
74 {
75 return Type::MD5;
76 }
77 else if (type == "sha1")
78 {
79 return Type::SHA1;
80 }
81 else if (type == "sha256")
82 {
83 return Type::SHA256;
84 }
85 else if (type == "sha512")
86 {
87 return Type::SHA512;
88 }
89 else
90 {
91 throw std::invalid_argument(std::string("Unknown digest type \"") + type + "\"");
92 }
93}
94
95void CDigest::MdCtxDeleter::operator()(EVP_MD_CTX* context)
96{
97 EVP_MD_CTX_destroy(context);
98}
99
100CDigest::CDigest(Type type)
101: m_context{EVP_MD_CTX_create()}, m_md(TypeToEVPMD(type))
102{
103 if (1 != EVP_DigestInit_ex(m_context.get(), m_md, nullptr))
104 {
105 throw std::runtime_error("EVP_DigestInit_ex failed");
106 }
107}
108
109void CDigest::Update(std::string const& data)
110{
111 Update(data.c_str(), data.size());
112}
113
114void CDigest::Update(void const* data, std::size_t size)
115{
116 if (m_finalized)
117 {
118 throw std::logic_error("Finalized digest cannot be updated any more");
119 }
120
121 if (1 != EVP_DigestUpdate(m_context.get(), data, size))
122 {
123 throw std::runtime_error("EVP_DigestUpdate failed");
124 }
125}
126
127std::string CDigest::FinalizeRaw()
128{
129 if (m_finalized)
130 {
131 throw std::logic_error("Digest can only be finalized once");
132 }
133
134 m_finalized = true;
135
136 std::array<unsigned char, 64> digest;
137 std::size_t size = EVP_MD_size(m_md);
138 if (size > digest.size())
139 {
140 throw std::runtime_error("Digest unexpectedly long");
141 }
142 if (1 != EVP_DigestFinal_ex(m_context.get(), digest.data(), nullptr))
143 {
144 throw std::runtime_error("EVP_DigestFinal_ex failed");
145 }
146 return {reinterpret_cast<char*> (digest.data()), size};
147}
148
149std::string CDigest::Finalize()
150{
151 return StringUtils::ToHexadecimal(FinalizeRaw());
152}
153
154std::string CDigest::Calculate(Type type, std::string const& data)
155{
156 CDigest digest{type};
157 digest.Update(data);
158 return digest.Finalize();
159}
160
161std::string CDigest::Calculate(Type type, void const* data, std::size_t size)
162{
163 CDigest digest{type};
164 digest.Update(data, size);
165 return digest.Finalize();
166}
167
168}
169}