File: Digest.cpp

package info (click to toggle)
kodi 2%3A20.1%2Bdfsg-1
  • links: PTS, VCS
  • area: main
  • in suites: bookworm
  • size: 143,820 kB
  • sloc: cpp: 664,925; xml: 68,398; ansic: 37,223; python: 6,903; sh: 4,209; javascript: 2,325; makefile: 1,754; perl: 969; java: 513; cs: 390; objc: 340
file content (165 lines) | stat: -rw-r--r-- 3,212 bytes parent folder | download | duplicates (3)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
/*
 *  Copyright (C) 2018 Team Kodi
 *  This file is part of Kodi - https://kodi.tv
 *
 *  SPDX-License-Identifier: GPL-2.0-or-later
 *  See LICENSES/README.md for more information.
 */

#include "Digest.h"

#include "StringUtils.h"

#include <array>
#include <stdexcept>

#include <gcrypt.h>

namespace KODI
{
namespace UTILITY
{

namespace
{

int const TypeToInt(CDigest::Type type)
{
  switch (type)
  {
    case CDigest::Type::MD5:
      return GCRY_MD_MD5;
    case CDigest::Type::SHA1:
      return GCRY_MD_SHA1;
    case CDigest::Type::SHA256:
      return GCRY_MD_SHA256;
    case CDigest::Type::SHA512:
      return GCRY_MD_SHA512;
    default:
      throw std::invalid_argument("Unknown digest type");
  }
}

}

std::ostream& operator<<(std::ostream& os, TypedDigest const& digest)
{
  return os << "{" << CDigest::TypeToString(digest.type) << "}" << digest.value;
}

std::string CDigest::TypeToString(Type type)
{
  switch (type)
  {
    case Type::MD5:
      return "md5";
    case Type::SHA1:
      return "sha1";
    case Type::SHA256:
      return "sha256";
    case Type::SHA512:
      return "sha512";
    case Type::INVALID:
      return "invalid";
    default:
      throw std::invalid_argument("Unknown digest type");
  }
}

CDigest::Type CDigest::TypeFromString(std::string const& type)
{
  std::string typeLower{type};
  StringUtils::ToLower(typeLower);
  if (type == "md5")
  {
    return Type::MD5;
  }
  else if (type == "sha1")
  {
    return Type::SHA1;
  }
  else if (type == "sha256")
  {
    return Type::SHA256;
  }
  else if (type == "sha512")
  {
    return Type::SHA512;
  }
  else
  {
    throw std::invalid_argument(std::string("Unknown digest type \"") + type + "\"");
  }
}

void CDigest::MdCtxDeleter::operator()(gcry_md_hd_t context)
{
  gcry_md_close(context);
}

CDigest::CDigest(Type type)
    : m_context(), m_md(TypeToInt(type))
{
  gcry_md_hd_t hd = NULL;
  if (GPG_ERR_NO_ERROR != gcry_md_open(&hd, m_md, 0))
  {
    throw std::runtime_error("gcry_md_open failed");
  }
  m_context.reset(hd);
}

void CDigest::Update(std::string const& data)
{
  Update(data.c_str(), data.size());
}

void CDigest::Update(void const* data, std::size_t size)
{
  if (m_finalized)
  {
    throw std::logic_error("Finalized digest cannot be updated any more");
  }

  gcry_md_write(m_context.get(), data, size);
}

std::string CDigest::FinalizeRaw()
{
  if (m_finalized)
  {
    throw std::logic_error("Digest can only be finalized once");
  }

  m_finalized = true;

  std::array<unsigned char, 64> digest;
  std::size_t size = gcry_md_get_algo_dlen(m_md);
  if (size > digest.size())
  {
    throw std::runtime_error("Digest unexpectedly long");
  }
  memcpy(digest.data(), gcry_md_read(m_context.get(), m_md), size);
  return {reinterpret_cast<char*> (digest.data()), size};
}

std::string CDigest::Finalize()
{
  return StringUtils::ToHexadecimal(FinalizeRaw());
}

std::string CDigest::Calculate(Type type, std::string const& data)
{
  CDigest digest{type};
  digest.Update(data);
  return digest.Finalize();
}

std::string CDigest::Calculate(Type type, void const* data, std::size_t size)
{
  CDigest digest{type};
  digest.Update(data, size);
  return digest.Finalize();
}

}
}