aboutsummaryrefslogtreecommitdiffstats
path: root/src/lib/prov/commoncrypto/commoncrypto_hash.cpp
blob: 40bab29dda89f3995a959f9e4c1ce9f4da6523e4 (plain)
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
/*
* CommonCrypto Hash Functions
* (C) 2018 Jose Pereira
*
* Botan is released under the Simplified BSD License (see license.txt)
*/

#include <botan/internal/commoncrypto.h>
#include <botan/hash.h>
#include <unordered_map>

#include <CommonCrypto/CommonCrypto.h>

namespace Botan {

namespace {

template <class CTX>
class CommonCrypto_HashFunction final : public HashFunction
   {
   public:

      struct digest_config_t {
         std::string name;
         size_t digestLength;
         size_t blockSize;
         int (*init)(CTX *);
         int (*update)(CTX *, const void *, CC_LONG len);
         int (*final)(unsigned char *, CTX*);
         };

      void clear() override
         {
         if(m_info.init(&m_ctx) != 1)
            throw CommonCrypto_Error("CC_" + m_info.name + "_Init");
         }

      std::string provider() const override { return "commoncrypto"; }
      std::string name() const override { return m_info.name; }

      HashFunction* clone() const override
         {
         return new CommonCrypto_HashFunction(m_info);
         }

      std::unique_ptr<HashFunction> copy_state() const override
         {
         return std::unique_ptr<CommonCrypto_HashFunction>(
            new CommonCrypto_HashFunction(m_info, m_ctx));
         }

      size_t output_length() const override
         {
         return m_info.digestLength;
         }

      size_t hash_block_size() const override
         {
         return m_info.blockSize;
         }

      CommonCrypto_HashFunction(const digest_config_t& info) :
         m_info(info)
         {
         clear();
         }

      CommonCrypto_HashFunction(const digest_config_t& info, const CTX &ctx) :
         m_ctx(ctx), m_info(info) {}

   private:
      void add_data(const uint8_t input[], size_t length) override
         {
         /* update len parameter is 32 bit unsigned integer, feed input in parts */
         while (length > 0)
            {
            CC_LONG update_len = (length > 0xFFFFFFFFUL) ? 0xFFFFFFFFUL : static_cast<CC_LONG>(length);
            m_info.update(&m_ctx, input, update_len);
            input += update_len;
            length -= update_len;
            }
         }

      void final_result(uint8_t output[]) override
         {
         if(m_info.final(output, &m_ctx) != 1)
            throw CommonCrypto_Error("CC_" + m_info.name + "_Final");
         clear();
         }

      CTX m_ctx;
      digest_config_t m_info;
   };
}

std::unique_ptr<HashFunction>
make_commoncrypto_hash(const std::string& name)
   {
#define MAKE_COMMONCRYPTO_HASH_3(name, hash, ctx)               \
   std::unique_ptr<HashFunction>(                               \
      new CommonCrypto_HashFunction<CC_ ## ctx ## _CTX >({      \
            name,                                               \
            CC_ ## hash ## _DIGEST_LENGTH,                      \
            CC_ ## hash ## _BLOCK_BYTES,                        \
            CC_ ## hash ## _Init,                               \
            CC_ ## hash ## _Update,                             \
            CC_ ## hash ## _Final                               \
         }));

#define MAKE_COMMONCRYPTO_HASH_2(name, id)      \
   MAKE_COMMONCRYPTO_HASH_3(name, id, id)

#define MAKE_COMMONCRYPTO_HASH_1(id)            \
   MAKE_COMMONCRYPTO_HASH_2(#id, id)

#if defined(BOTAN_HAS_SHA2_32)
   if(name == "SHA-224")
      return MAKE_COMMONCRYPTO_HASH_3(name, SHA224, SHA256);
   if(name == "SHA-256")
      return MAKE_COMMONCRYPTO_HASH_2(name, SHA256);
#endif
#if defined(BOTAN_HAS_SHA2_64)
   if(name == "SHA-384")
      return MAKE_COMMONCRYPTO_HASH_3(name, SHA384, SHA512);
   if(name == "SHA-512")
      return MAKE_COMMONCRYPTO_HASH_2(name, SHA512);
#endif

#if defined(BOTAN_HAS_SHA1)
   if(name == "SHA-160" || name == "SHA-1" || name == "SHA1")
      return MAKE_COMMONCRYPTO_HASH_2(name, SHA1);
#endif

   return nullptr;
   }

}