-
Notifications
You must be signed in to change notification settings - Fork 203
Expand file tree
/
Copy pathqaesencryption.h
More file actions
255 lines (229 loc) · 12.4 KB
/
qaesencryption.h
File metadata and controls
255 lines (229 loc) · 12.4 KB
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
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
#ifndef QAESENCRYPTION_H
#define QAESENCRYPTION_H
#ifdef QtAES_EXPORTS
#include "qtaes_export.h"
#else
#define QTAESSHARED_EXPORT
#endif
#include <QObject>
#include <QByteArray>
#include <QCryptographicHash>
#include <QMessageAuthenticationCode>
#ifdef QTAES_CONSTANT_TIME_SBOX
#include "aes_ct_sbox.h"
#endif
#ifdef __linux__
#ifndef __LP64__
#define do_rdtsc _do_rdtsc
#endif
#endif
/*!
* \class QAESEncryption
* \brief AES encryption/decryption for Qt supporting 128/192/256-bit keys and ECB, CBC, CFB, OFB, CTR modes.
*
* \note \b Thread safety: instances are thread-safe for concurrent encode/decode calls.
* All mutable state during an operation is kept on the call stack; no member variables
* are written after construction. The static methods (Crypt, Decrypt, ExpandKey,
* RemovePadding, generateKey) are also safe to call concurrently.
*
* \note \b API stability: encode(), decode(), removePadding(), and the static equivalents
* (Crypt, Decrypt, RemovePadding, generateKey) form the stable public surface.
* ExpandKey() is provided for advanced use and may change in future versions.
*/
class QTAESSHARED_EXPORT QAESEncryption : public QObject
{
Q_OBJECT
public:
enum Aes {
AES_128,
AES_192,
AES_256
};
enum Mode {
ECB,
CBC,
CFB,
OFB,
CTR ///< Counter mode — stream cipher, no padding, encrypt == decrypt
};
enum Padding {
ZERO,
PKCS7,
ISO,
NONE ///< No padding — valid only for CFB and OFB (stream cipher modes); allows arbitrary-length plaintext.
};
/*!
* \brief static method call to encrypt data given by rawText
* \param level: AES::Aes level
* \param mode: AES::Mode mode
* \param rawText: input text
* \param key: user-key (key.size either 128, 192, 256 bits depending on AES::Aes)
* \param iv: initialisation-vector (iv.size is 128 bits (16 Bytes))
* \param padding: AES::Padding standard
* \param ok: if non-null, set to true on success or false if key/IV/alignment is invalid
* \return encrypted cipher
*/
static QByteArray Crypt(QAESEncryption::Aes level, QAESEncryption::Mode mode, const QByteArray &rawText, const QByteArray &key,
const QByteArray &iv = QByteArray(), QAESEncryption::Padding padding = QAESEncryption::ISO,
bool *ok = nullptr);
/*!
* \brief static method call to decrypt data given by rawText
* \param level: AES::Aes level
* \param mode: AES::Mode mode
* \param rawText: input text
* \param key: user-key (key.size either 128, 192, 256 bits depending on AES::Aes)
* \param iv: initialisation-vector (iv.size is 128 bits (16 Bytes))
* \param padding: AES::Padding standard
* \param ok: if non-null, set to true on success or false if key/IV/alignment is invalid
* \return decrypted cipher with padding
*/
static QByteArray Decrypt(QAESEncryption::Aes level, QAESEncryption::Mode mode, const QByteArray &rawText, const QByteArray &key,
const QByteArray &iv = QByteArray(), QAESEncryption::Padding padding = QAESEncryption::ISO,
bool *ok = nullptr);
/*!
* \brief Expand a raw key into the Rijndael key schedule (advanced use).
*
* Most callers do not need this — encode() and decode() handle key expansion
* internally. This method is provided for advanced scenarios where the caller
* wants to inspect or cache the expanded key schedule.
*
* \param level AES key size.
* \param mode Cipher mode (affects key schedule direction).
* \param key Raw user key (16, 24, or 32 bytes).
* \param isEncryptionKey Pass \c true for encryption; \c false only when
* decrypting with AES-NI in ECB or CBC mode.
* \return Expanded key schedule bytes.
*/
static QByteArray ExpandKey(QAESEncryption::Aes level, QAESEncryption::Mode mode, const QByteArray &key, bool isEncryptionKey);
/*!
* \brief static method call to remove padding from decrypted cipher given by rawText
* \param rawText: inputText
* \param padding: AES::Padding standard
* \return decrypted cipher with padding removed
*/
static QByteArray RemovePadding(const QByteArray &rawText, QAESEncryption::Padding padding = QAESEncryption::ISO,
bool *ok = nullptr);
/*!
* \brief Derives an AES-ready key from a password and salt using PBKDF2 (RFC 2898).
* Only QtCore is required — no QtNetwork dependency.
* \param password User-supplied password.
* \param salt Random salt (store alongside ciphertext; do not reuse across encryptions).
* \param level Target AES key size: AES_128 => 16 bytes, AES_192 => 24 bytes, AES_256 => 32 bytes.
* \param algo HMAC hash algorithm (default: Sha256).
* \param iterations PBKDF2 iteration count (default: 10000; capped at 500000).
* \return Derived key of the exact byte length required by \a level, or empty on invalid input.
*
* \note This implementation uses Qt's QMessageAuthenticationCode, which is a general-purpose
* utility and is not guaranteed to be constant-time or security-audited as a cryptographic
* primitive. For security-critical applications, prefer a dedicated library such as
* OpenSSL (PKCS5_PBKDF2_HMAC) or libsodium.
*/
static QByteArray generateKey(const QByteArray &password,
const QByteArray &salt,
QAESEncryption::Aes level,
QCryptographicHash::Algorithm algo = QCryptographicHash::Sha256,
int iterations = 10000);
QAESEncryption(QAESEncryption::Aes level, QAESEncryption::Mode mode,
QAESEncryption::Padding padding = QAESEncryption::ISO);
/*!
* \brief object method call to encrypt data given by rawText
* \param rawText: input text
* \param key: user-key (key.size either 128, 192, 256 bits depending on AES::Aes)
* \param iv: initialisation-vector (iv.size is 128 bits (16 Bytes))
* \return encrypted cipher
*/
QByteArray encode(const QByteArray &rawText, const QByteArray &key, const QByteArray &iv = QByteArray(),
bool *ok = nullptr);
/*!
* \brief object method call to decrypt data given by rawText
* \param rawText: input text
* \param key: user-key (key.size either 128, 192, 256 bits depending on AES::Aes)
* \param iv: initialisation-vector (iv.size is 128 bits (16 Bytes))
* \param padding: AES::Padding standard
* \return decrypted cipher with padding
*/
QByteArray decode(const QByteArray &rawText, const QByteArray &key, const QByteArray &iv = QByteArray(),
bool *ok = nullptr);
/*!
* \brief object method call to remove padding from decrypted cipher given by rawText
* \param rawText: inputText
* \param ok: if non-null, set to true on success or false if PKCS7 padding is invalid
* \return decrypted cipher with padding removed
*/
QByteArray removePadding(const QByteArray &rawText, bool *ok = nullptr);
Q_SIGNALS:
public Q_SLOTS:
private:
int m_nb;
int m_blocklen;
int m_level;
int m_mode;
int m_nk;
int m_keyLen;
int m_nr;
int m_expandedKey;
int m_padding;
bool m_aesNIAvailable;
QByteArray expandKey(const QByteArray &key, bool isEncryptionKey);
#ifdef QTAES_CONSTANT_TIME_SBOX
quint8 getSBoxValue(quint8 num){return AesCt::sbox(num);}
quint8 getSBoxInvert(quint8 num){return AesCt::invSbox(num);}
#else
quint8 getSBoxValue(quint8 num){return sbox[num];}
quint8 getSBoxInvert(quint8 num){return rsbox[num];}
#endif
void addRoundKey(QByteArray &state, const quint8 round, const QByteArray &expKey);
void subBytes(QByteArray &state);
void shiftRows(QByteArray &state);
void mixColumns(QByteArray &state);
void invMixColumns(QByteArray &state);
void invSubBytes(QByteArray &state);
void invShiftRows(QByteArray &state);
QByteArray getPadding(int currSize, int alignment);
QByteArray cipher(const QByteArray &expKey, const QByteArray &in);
QByteArray invCipher(const QByteArray &expKey, const QByteArray &in);
QByteArray byteXor(const QByteArray &a, const QByteArray &b);
QByteArray xcryptOFB(const QByteArray &input, const QByteArray &expandedKey, const QByteArray &iv);
QByteArray xcryptCTR(const QByteArray &input, const QByteArray &expandedKey, const QByteArray &iv);
const quint8 sbox[256] = {
//0 1 2 3 4 5 6 7 8 9 A B C D E F
0x63, 0x7c, 0x77, 0x7b, 0xf2, 0x6b, 0x6f, 0xc5, 0x30, 0x01, 0x67, 0x2b, 0xfe, 0xd7, 0xab, 0x76,
0xca, 0x82, 0xc9, 0x7d, 0xfa, 0x59, 0x47, 0xf0, 0xad, 0xd4, 0xa2, 0xaf, 0x9c, 0xa4, 0x72, 0xc0,
0xb7, 0xfd, 0x93, 0x26, 0x36, 0x3f, 0xf7, 0xcc, 0x34, 0xa5, 0xe5, 0xf1, 0x71, 0xd8, 0x31, 0x15,
0x04, 0xc7, 0x23, 0xc3, 0x18, 0x96, 0x05, 0x9a, 0x07, 0x12, 0x80, 0xe2, 0xeb, 0x27, 0xb2, 0x75,
0x09, 0x83, 0x2c, 0x1a, 0x1b, 0x6e, 0x5a, 0xa0, 0x52, 0x3b, 0xd6, 0xb3, 0x29, 0xe3, 0x2f, 0x84,
0x53, 0xd1, 0x00, 0xed, 0x20, 0xfc, 0xb1, 0x5b, 0x6a, 0xcb, 0xbe, 0x39, 0x4a, 0x4c, 0x58, 0xcf,
0xd0, 0xef, 0xaa, 0xfb, 0x43, 0x4d, 0x33, 0x85, 0x45, 0xf9, 0x02, 0x7f, 0x50, 0x3c, 0x9f, 0xa8,
0x51, 0xa3, 0x40, 0x8f, 0x92, 0x9d, 0x38, 0xf5, 0xbc, 0xb6, 0xda, 0x21, 0x10, 0xff, 0xf3, 0xd2,
0xcd, 0x0c, 0x13, 0xec, 0x5f, 0x97, 0x44, 0x17, 0xc4, 0xa7, 0x7e, 0x3d, 0x64, 0x5d, 0x19, 0x73,
0x60, 0x81, 0x4f, 0xdc, 0x22, 0x2a, 0x90, 0x88, 0x46, 0xee, 0xb8, 0x14, 0xde, 0x5e, 0x0b, 0xdb,
0xe0, 0x32, 0x3a, 0x0a, 0x49, 0x06, 0x24, 0x5c, 0xc2, 0xd3, 0xac, 0x62, 0x91, 0x95, 0xe4, 0x79,
0xe7, 0xc8, 0x37, 0x6d, 0x8d, 0xd5, 0x4e, 0xa9, 0x6c, 0x56, 0xf4, 0xea, 0x65, 0x7a, 0xae, 0x08,
0xba, 0x78, 0x25, 0x2e, 0x1c, 0xa6, 0xb4, 0xc6, 0xe8, 0xdd, 0x74, 0x1f, 0x4b, 0xbd, 0x8b, 0x8a,
0x70, 0x3e, 0xb5, 0x66, 0x48, 0x03, 0xf6, 0x0e, 0x61, 0x35, 0x57, 0xb9, 0x86, 0xc1, 0x1d, 0x9e,
0xe1, 0xf8, 0x98, 0x11, 0x69, 0xd9, 0x8e, 0x94, 0x9b, 0x1e, 0x87, 0xe9, 0xce, 0x55, 0x28, 0xdf,
0x8c, 0xa1, 0x89, 0x0d, 0xbf, 0xe6, 0x42, 0x68, 0x41, 0x99, 0x2d, 0x0f, 0xb0, 0x54, 0xbb, 0x16 };
const quint8 rsbox[256] = {
0x52, 0x09, 0x6a, 0xd5, 0x30, 0x36, 0xa5, 0x38, 0xbf, 0x40, 0xa3, 0x9e, 0x81, 0xf3, 0xd7, 0xfb,
0x7c, 0xe3, 0x39, 0x82, 0x9b, 0x2f, 0xff, 0x87, 0x34, 0x8e, 0x43, 0x44, 0xc4, 0xde, 0xe9, 0xcb,
0x54, 0x7b, 0x94, 0x32, 0xa6, 0xc2, 0x23, 0x3d, 0xee, 0x4c, 0x95, 0x0b, 0x42, 0xfa, 0xc3, 0x4e,
0x08, 0x2e, 0xa1, 0x66, 0x28, 0xd9, 0x24, 0xb2, 0x76, 0x5b, 0xa2, 0x49, 0x6d, 0x8b, 0xd1, 0x25,
0x72, 0xf8, 0xf6, 0x64, 0x86, 0x68, 0x98, 0x16, 0xd4, 0xa4, 0x5c, 0xcc, 0x5d, 0x65, 0xb6, 0x92,
0x6c, 0x70, 0x48, 0x50, 0xfd, 0xed, 0xb9, 0xda, 0x5e, 0x15, 0x46, 0x57, 0xa7, 0x8d, 0x9d, 0x84,
0x90, 0xd8, 0xab, 0x00, 0x8c, 0xbc, 0xd3, 0x0a, 0xf7, 0xe4, 0x58, 0x05, 0xb8, 0xb3, 0x45, 0x06,
0xd0, 0x2c, 0x1e, 0x8f, 0xca, 0x3f, 0x0f, 0x02, 0xc1, 0xaf, 0xbd, 0x03, 0x01, 0x13, 0x8a, 0x6b,
0x3a, 0x91, 0x11, 0x41, 0x4f, 0x67, 0xdc, 0xea, 0x97, 0xf2, 0xcf, 0xce, 0xf0, 0xb4, 0xe6, 0x73,
0x96, 0xac, 0x74, 0x22, 0xe7, 0xad, 0x35, 0x85, 0xe2, 0xf9, 0x37, 0xe8, 0x1c, 0x75, 0xdf, 0x6e,
0x47, 0xf1, 0x1a, 0x71, 0x1d, 0x29, 0xc5, 0x89, 0x6f, 0xb7, 0x62, 0x0e, 0xaa, 0x18, 0xbe, 0x1b,
0xfc, 0x56, 0x3e, 0x4b, 0xc6, 0xd2, 0x79, 0x20, 0x9a, 0xdb, 0xc0, 0xfe, 0x78, 0xcd, 0x5a, 0xf4,
0x1f, 0xdd, 0xa8, 0x33, 0x88, 0x07, 0xc7, 0x31, 0xb1, 0x12, 0x10, 0x59, 0x27, 0x80, 0xec, 0x5f,
0x60, 0x51, 0x7f, 0xa9, 0x19, 0xb5, 0x4a, 0x0d, 0x2d, 0xe5, 0x7a, 0x9f, 0x93, 0xc9, 0x9c, 0xef,
0xa0, 0xe0, 0x3b, 0x4d, 0xae, 0x2a, 0xf5, 0xb0, 0xc8, 0xeb, 0xbb, 0x3c, 0x83, 0x53, 0x99, 0x61,
0x17, 0x2b, 0x04, 0x7e, 0xba, 0x77, 0xd6, 0x26, 0xe1, 0x69, 0x14, 0x63, 0x55, 0x21, 0x0c, 0x7d };
// The round constant word array, Rcon[i], contains the values given by
// x to th e power (i-1) being powers of x (x is denoted as {02}) in the field GF(2^8)
// Only the first 14 elements are needed
const quint8 Rcon[14] = {
0x8d, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1b, 0x36, 0x6c, 0xd8, 0xab};
};
#endif // QAESENCRYPTION_H