-
Notifications
You must be signed in to change notification settings - Fork 0
/
aesphm.h
234 lines (191 loc) · 8.53 KB
/
aesphm.h
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
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
#ifndef AESPHM_H_INCLUDED
#define AESPHM_H_INCLUDED
#include "algparam.h"
NAMESPACE_BEGIN(CryptoPP)
// PADDED AND HASHED AES MESSAGE ENCRYPTION
// ==========================================================================
// This class implements a message-based, rather than byte-based or
// block-based, encryption method. The class uses CFB, but is not itself a
// stream encryptor; it merely uses AES in CFB mode for the internal
// encryption process. The minimum ciphertext size is 46 bytes, and the
// generated ciphertext will be 32 to 46 bytes larger than the corresponding
// plaintext. Adding random padding is necessary to hide the real length of
// small messages, and to make some attacks a bit more difficult.
// SECURITY
// ==========================================================================
// AES PHM provides the following security features:
// - Encrypting twice with the same plaintext and the same key will never
// produce the same ciphertext. The minimum estimated possibility that any
// two encryptions of the same message with the same key will produce the
// same plaintext is 2^-96, assuming a flawless random number generator
// is supplied. (Padding is at least 32 bits, IV seed is 64 bits)
// - The exact length of plaintext cannot be determined by looking at the
// ciphertext. Plaintext is padded so that padded plaintext length is
// always (3 + 15*n) bytes, where n = 1, 2, 3, 4, ...
// - The decryption routine is always able to validate that the supplied
// combination of ciphertext and key is valid. Any tampering with the
// ciphertext will be detected. The estimated failure rate for this
// detection process is 2^-160, assuming SHA1 is an ideal hash function.
// (An HMAC<SHA> code is appended to encrypted messages)
// ENCRYPTION PROCESS
// ==========================================================================
// input: <plaintext>, output: <ciphertext>
//
// <encrypted> = encrypted-with-AES-in-CFB-mode(<padding>, <plaintext>)
// <ciphertext> = <encrypted>, <iv-seed>, <mac>
//
// The total length of padding is equal to the value of the lowest 4 bits of
// the first byte of the padding, plus 3.
//
// Due to unfortunate placement of the padding length indicator at the
// very beginning of the ciphertext, the whole message must be loaded in
// memory before it can be encrypted. Likewise, storage of the IV seed
// after the ciphertext prevents decryption from commencing before the
// whole message has been read. This makes AES PHM inappropriate for
// encrypting very large messages.
//
// AES CFB encryption parameters are:
// - the encryption key is obtained by hashing the passphrase with SHA256;
// - the IV is obtained from a randomly generated 64-bit seed.
//
// The MAC is HMAC-SHA over <raw-ciphertext> and <iv-seed>.
// KEY LIFETIME
// ==========================================================================
// An attacker that spots two messages encrypted with the same key and IV
// will be able to recover the plaintext. Note that the IV is calculated from
// a 64-bit seed. Assuming the underlying random data provider is flawless,
// the following table lists 1) the number of total messages encrypted with
// the same key, and 2) the corresponding probability that at least two of
// these messages will have been encrypted with the same IV:
//
// total collision probability
// --------------------------------
// 2^27 00.05%
// 2^28 00.2 %
// 2^29 00.8 %
// 2^30 03 %
// 2^31 11 %
// 2^32 39 %
// 2^33 86 %
// 2^34 99.9 %
//
// If you plan to encrypt a very large number of messages without changing
// the key, consider these numbers and use them to calculate the lifetime of
// your encryption keys.
class AESPHM
{
public:
// Provides an upper limit, but not an exact limit, to the length of the ciphertext
// that will be produced when encrypting plaintext of a specified size.
static unsigned int MaxCiphertextLen(unsigned int plaintextLen) { return plaintextLen + 50; }
// Use MaxCiphertextLen() to allocate an output buffer of appropriate size
static unsigned int Encrypt(
RandomNumberGenerator& rng,
ConstByteArrayParameter const& passphrase,
byte* output,
ConstByteArrayParameter const& input);
// Allocate an output buffer that is as large as the input
static DecodingResult Decrypt(
ConstByteArrayParameter const& passphrase,
byte* output,
ConstByteArrayParameter const& input);
};
/*
class AES_PHM_Encryption : public Filter
{
public:
// The key may be arbitrary data; may also be textual passphrase
AES_PHM_Encryption(RandomNumberGenerator& rng, byte const* pbKey, unsigned int nKeyLen, BufferedTransformation* pOutQueue = 0);
// Provides an upper limit, but not an exact limit, to the length of the ciphertext
// that will be produced when encrypting plaintext of a specified size.
static unsigned int MaxCiphertextLen(unsigned int nPlaintextLen) { return nPlaintextLen + 50; }
unsigned int MaxCiphertextLen() const { return MaxCiphertextLen(GetPlaintextLen()); }
// Store data for later encryption (see MessageEnd())
void Put(byte b) { Put(&b, 1); }
void Put(byte const* pbData, unsigned int nDataLen);
// For applications which want to write to m_sbbPlaintext directly
// to avoid creating multiple copies of input data, or to avoid
// excess memory allocations. When feeding input data other than through
// the Put() interface, always call SetPlaintextLen() before calling MessageEnd().
SecByteBlock& GetPlaintextBuffer() { return m_sbbPlaintext; }
unsigned GetPlaintextLen() const { return m_nPlaintextLen; }
void SetPlaintextLen(unsigned int nPlaintextLen) { m_nPlaintextLen = nPlaintextLen; }
// Starts the actual encryption process
void MessageEnd(int nPropagation = -1);
private:
RandomNumberGenerator& m_rng;
SecByteBlock m_sbbKey;
SecByteBlock m_sbbPlaintext;
unsigned int m_nPlaintextLen;
};
template <class InStringType, class OutStringType>
void AES_PHM_Encrypt(
RandomNumberGenerator& rng,
byte const* pbKey,
unsigned int nKeyLen,
InStringType const& sInput,
OutStringType& sOutput)
{
CryptoPP::StringSource(sInput, true,
new CryptoPP::AES_PHM_Encryption(rng, pbKey, nKeyLen,
new CryptoPP::StringSinkTemplate<OutStringType>(sOutput)));
}
template <class KeyStringType, class InStringType, class OutStringType>
void AES_PHM_Encrypt(
RandomNumberGenerator& rng,
KeyStringType const& sKey,
InStringType const& sInput,
OutStringType& sOutput)
{
AES_PHM_Encrypt(rng, (byte const*) sKey.data(), sKey.length(), sInput, sOutput);
}
class AES_PHM_Decryption : public Filter
{
public:
class InvalidCiphertextOrKey : public BufferedTransformation::Err
{
public:
InvalidCiphertextOrKey() : BufferedTransformation::Err(
DATA_INTEGRITY_CHECK_FAILED,
"AES_PHM_Decryption: Invalid Ciphertext or Key") {}
};
AES_PHM_Decryption(byte const* pbKey, unsigned int nKeyLen, BufferedTransformation* pOutQueue = 0);
// Store data for later decryption (see MessageEnd())
void Put(byte b) { Put(&b, 1); }
void Put(byte const* pbData, unsigned int nDataLen);
// For applications which want to write to m_sbbCiphertext directly
// to avoid creating multiple copies of input data, or to avoid
// excess memory allocations. When feeding input data other than through
// the Put() interface, always call SetPlaintextLen() before calling MessageEnd().
SecByteBlock& GetCiphertextBuffer() { return m_sbbCiphertext; }
unsigned int GetCiphertextLen() const {return m_nCiphertextLen; }
void SetCiphertextLen(unsigned int nCiphertextLen) { m_nCiphertextLen = nCiphertextLen; }
// Starts the actual decryption process
void MessageEnd(int nPropagation = -1);
private:
SecByteBlock m_sbbKey;
SecByteBlock m_sbbCiphertext;
unsigned int m_nCiphertextLen;
};
template <class InStringType, class OutStringType>
void AES_PHM_Decrypt(
byte const* pbKey,
unsigned int nKeyLen,
InStringType const& sInput,
OutStringType& sOutput)
{
CryptoPP::StringSource(sInput, true,
new CryptoPP::AES_PHM_Decryption(pbKey, nKeyLen,
new CryptoPP::StringSinkTemplate<OutStringType>(sOutput)));
}
template <class KeyStringType, class InStringType, class OutStringType>
void AES_PHM_Decrypt(
KeyStringType const& sKey,
InStringType const& sInput,
OutStringType& sOutput)
{
AES_PHM_Decrypt((byte const*) sKey.data(), sKey.length(), sInput, sOutput);
}
*/
NAMESPACE_END
#endif