-
Notifications
You must be signed in to change notification settings - Fork 2
/
Copy pathencrypt_aes.hh
211 lines (204 loc) · 7.62 KB
/
encrypt_aes.hh
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
/*
* Copyright (c) 2016 Zhao DAI <[email protected]>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or any
* later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see accompanying file LICENSE.txt
* or <http://www.gnu.org/licenses/>.
*/
/**
* @file
* @brief [Advanced Encryption Standard](https://en.wikipedia.org/wiki/Advanced_Encryption_Standard)
* (AES) algorithm interface.
* @note [OpenSSL](https://www.openssl.org) is required.
* @author Zhao DAI
*/
#ifndef DOZERG_ENCRYPTOR_AES_H_20080306
#define DOZERG_ENCRYPTOR_AES_H_20080306
#include <string>
#include <vector>
#include <cstring> //memset
#include <openssl/aes.h>
#include "tools/ssl.hh" //Md5
NS_SERVER_BEGIN
/**
* @brief A convenient interface for [Advanced Encryption Standard]
* (https://en.wikipedia.org/wiki/Advanced_Encryption_Standard) (AES) algorithm.
* @note CEncryptorAes object can @em NOT be copied.
*/
class CEncryptorAes
{
typedef unsigned char __Char;
static const size_t kKeyLen = 16;
CEncryptorAes(const CEncryptorAes &); //disable copy and assignment
CEncryptorAes & operator =(const CEncryptorAes &);
public:
/// @brief Key sizes.
enum EKeyIntensity{
L128 = 128,
L192 = 192,
L256 = 256
};
/**
* @brief Construct a default object.
* Key size defaults to @c L128.
* @n You need @ref setKey or @ref setKeyAndIntensity before encryption/decryption operations.
*/
CEncryptorAes()
: intens_(L128)
{}
/**
* @brief Construct an object.
* @param key Encryption key (password)
* @param intensity Key size
*/
CEncryptorAes(const std::string & key, EKeyIntensity intensity)
: key_(key)
, intens_(intensity)
{
updateKeys();
}
/**
* @brief Set key size.
* @param intensity Key size
*/
void setIntensity(EKeyIntensity intensity){
intens_ = intensity;
updateKeys();
}
/**
* @brief Set encryption key (password).
* Password is an arbitrary string.
* @param key Encryption key (password)
*/
void setKey(const std::string & key){
key_ = key;
updateKeys();
}
/**
* @brief Set encryption key (password) and key size.
* Password is an arbitrary string.
* @param key Encryption key (password)
* @param intensity Key size
*/
void setKeyAndIntensity(const std::string & key, EKeyIntensity intensity){
key_ = key;
intens_ = intensity;
updateKeys();
}
/**
* @name Encryption
* @{
* @brief Encrypt given data.
* If @c from is non-zero, first @c from bytes of @c input will @em NOT be encrypted, i.e. data
* between @c input.begin() and @c input.begin()+from will be copied to @c output straightly,
* and data between @c input.begin()+from and @c input.end() will be encrypted and append to
* @c output.
* @param[in] input Data to be encrypted
* @param[out] output A buffer to receive the result
* @param[in] from Index in @c input from where data will be encrypted
* @return
* @li @c 0: Succeeded
* @li @c -1: Invalid parameter
*/
int encrypt(const std::vector<char> & input, std::vector<char> & output, size_t from = 0) const{
return encryptTemplate(input, output, from);
}
int encrypt(const std::vector<signed char> & input, std::vector<signed char> & output, size_t from = 0) const{
return encryptTemplate(input, output, from);
}
int encrypt(const std::vector<unsigned char> & input, std::vector<unsigned char> & output, size_t from = 0) const{
return encryptTemplate(input, output, from);
}
int encrypt(const std::string & input, std::string & output, size_t from = 0) const{
return encryptTemplate(input, output, from);
}
/** @} */
/**
* @name Decryption
* @{
* @brief Decrypt given data.
* If @c from is non-zero, first @c from bytes of @c input will @em NOT be decrypted, i.e. data
* between @c input.begin() and @c input.begin()+from will be copied to @c output straightly,
* and data between @c input.begin()+from and @c input.end() will be decrypted and append to
* @c output.
* @param[in] input Data to be decrypted
* @param[out] output A buffer to receive the result
* @param[in] from Index in @c input from where data will be decrypted
* @return
* @li @c 0: Succeeded
* @li @c -1: Invalid parameter
* @li @c -2: Input data format error
*/
int decrypt(const std::vector<char> & input, std::vector<char> & output, size_t from = 0) const{
return decryptTemplate(input, output, from);
}
int decrypt(const std::vector<signed char> & input, std::vector<signed char> & output, size_t from = 0) const{
return decryptTemplate(input, output, from);
}
int decrypt(const std::vector<unsigned char> & input, std::vector<unsigned char> & output, size_t from = 0) const{
return decryptTemplate(input, output, from);
}
int decrypt(const std::string & input, std::string & output, size_t from = 0) const{
return decryptTemplate(input, output, from);
}
/** @} */
private:
void updateKeys(){
std::string md5 = tools::Md5(key_);
AES_set_encrypt_key(reinterpret_cast<const __Char *>(&md5[0]), intens_, &enKey_);
AES_set_decrypt_key(reinterpret_cast<const __Char *>(&md5[0]), intens_, &deKey_);
}
template<class Buffer>
int encryptTemplate(const Buffer & input, Buffer & output, size_t from) const{
size_t inlen = input.size();
if(inlen < from)
return -1;
inlen -= from;
output.resize(from + (inlen / AES_BLOCK_SIZE + 1) * AES_BLOCK_SIZE);
std::copy(input.begin(), input.begin() + from, output.begin());
for(;inlen >= AES_BLOCK_SIZE;inlen -= AES_BLOCK_SIZE, from += AES_BLOCK_SIZE)
AES_encrypt(
reinterpret_cast<const __Char *>(&input[from]),
reinterpret_cast<__Char *>(&output[from]),
&enKey_);
unsigned char tmp[AES_BLOCK_SIZE];
memset(tmp, AES_BLOCK_SIZE - inlen, AES_BLOCK_SIZE);
memcpy(tmp, &input[from], inlen);
AES_encrypt(tmp, reinterpret_cast<__Char *>(&output[from]), &enKey_);
return 0;
}
template<class Buffer>
int decryptTemplate(const Buffer & input, Buffer & output, size_t from) const{
size_t inlen = input.size();
if(inlen < from || (inlen - from) % AES_BLOCK_SIZE != 0)
return -1;
output.resize(inlen);
std::copy(input.begin(), input.begin() + from, output.begin());
for(inlen -= from;inlen;inlen -= AES_BLOCK_SIZE, from += AES_BLOCK_SIZE)
AES_decrypt(
reinterpret_cast<const __Char *>(&input[from]),
reinterpret_cast<__Char *>(&output[from]),
&deKey_);
inlen = *output.rbegin();
if(inlen == 0 || inlen > AES_BLOCK_SIZE)
return -2;
output.resize(output.size() - inlen);
return 0;
}
std::string key_;
EKeyIntensity intens_;
AES_KEY enKey_;
AES_KEY deKey_;
};
NS_SERVER_END
#endif