1//
2// HMACEngine.h
3//
4// Library: Foundation
5// Package: Crypt
6// Module: HMACEngine
7//
8// Definition of the HMACEngine class.
9//
10// Copyright (c) 2004-2006, Applied Informatics Software Engineering GmbH.
11// and Contributors.
12//
13// SPDX-License-Identifier: BSL-1.0
14//
15
16
17#ifndef Foundation_HMACEngine_INCLUDED
18#define Foundation_HMACEngine_INCLUDED
19
20
21#include "Poco/Foundation.h"
22#include "Poco/DigestEngine.h"
23#include <cstring>
24
25
26namespace Poco {
27
28
29template <class Engine>
30class HMACEngine: public DigestEngine
31 /// This class implements the HMAC message
32 /// authentication code algorithm, as specified
33 /// in RFC 2104. The underlying DigestEngine
34 /// (MD5Engine, SHA1Engine, etc.) must be given as
35 /// template argument.
36 /// Since the HMACEngine is a DigestEngine, it can
37 /// be used with the DigestStream class to create
38 /// a HMAC for a stream.
39{
40public:
41 enum
42 {
43 BLOCK_SIZE = Engine::BLOCK_SIZE,
44 DIGEST_SIZE = Engine::DIGEST_SIZE
45 };
46
47 HMACEngine(const std::string& passphrase)
48 {
49 init(passphrase.data(), passphrase.length());
50 }
51
52 HMACEngine(const char* passphrase, std::size_t length)
53 {
54 poco_check_ptr (passphrase);
55
56 init(passphrase, length);
57 }
58
59 ~HMACEngine()
60 {
61 std::memset(_ipad, 0, BLOCK_SIZE);
62 std::memset(_opad, 0, BLOCK_SIZE);
63 delete [] _ipad;
64 delete [] _opad;
65 }
66
67 std::size_t digestLength() const
68 {
69 return DIGEST_SIZE;
70 }
71
72 void reset()
73 {
74 _engine.reset();
75 _engine.update(_ipad, BLOCK_SIZE);
76 }
77
78 const DigestEngine::Digest& digest()
79 {
80 const DigestEngine::Digest& d = _engine.digest();
81 char db[DIGEST_SIZE];
82 char* pdb = db;
83 for (DigestEngine::Digest::const_iterator it = d.begin(); it != d.end(); ++it)
84 *pdb++ = *it;
85 _engine.reset();
86 _engine.update(_opad, BLOCK_SIZE);
87 _engine.update(db, DIGEST_SIZE);
88 const DigestEngine::Digest& result = _engine.digest();
89 reset();
90 return result;
91 }
92
93protected:
94 void init(const char* passphrase, std::size_t length)
95 {
96 _ipad = new char[BLOCK_SIZE];
97 _opad = new char[BLOCK_SIZE];
98 std::memset(_ipad, 0, BLOCK_SIZE);
99 std::memset(_opad, 0, BLOCK_SIZE);
100 if (length > BLOCK_SIZE)
101 {
102 _engine.reset();
103 _engine.update(passphrase, length);
104 const DigestEngine::Digest& d = _engine.digest();
105 char* ipad = _ipad;
106 char* opad = _opad;
107 int n = BLOCK_SIZE;
108 for (DigestEngine::Digest::const_iterator it = d.begin(); it != d.end() && n-- > 0; ++it)
109 {
110 *ipad++ = *it;
111 *opad++ = *it;
112 }
113 }
114 else
115 {
116 std::memcpy(_ipad, passphrase, length);
117 std::memcpy(_opad, passphrase, length);
118 }
119 for (int i = 0; i < BLOCK_SIZE; ++i)
120 {
121 _ipad[i] ^= 0x36;
122 _opad[i] ^= 0x5c;
123 }
124 reset();
125 }
126
127 void updateImpl(const void* data, std::size_t length)
128 {
129 _engine.update(data, length);
130 }
131
132private:
133 HMACEngine();
134 HMACEngine(const HMACEngine&);
135 HMACEngine& operator = (const HMACEngine&);
136
137 Engine _engine;
138 char* _ipad;
139 char* _opad;
140};
141
142
143} // namespace Poco
144
145
146#endif // Foundation_HMACEngine_INCLUDED
147