mirror of
https://github.com/QuasarApp/Qt-AES.git
synced 2025-04-26 13:44:33 +00:00
Merge remote-tracking branch 'base/master' into HEAD
This commit is contained in:
commit
d14c463d28
12
README.md
12
README.md
@ -1,6 +1,7 @@
|
||||
# Qt-AES
|
||||
Small and portable AES encryption class for Qt.
|
||||
Supports all key sizes - 128/192/256 bits - ECB, CBC, CFB and OFB modes
|
||||
Native support for all key sizes - 128/192/256 bits - ECB, CBC, CFB and OFB modes
|
||||
AES-NI support for all key sizes - ECB, CBC modes
|
||||
|
||||
## Usage
|
||||
|
||||
@ -9,12 +10,12 @@ Supports all key sizes - 128/192/256 bits - ECB, CBC, CFB and OFB modes
|
||||
// Encode of rawText with key
|
||||
// iv is used in CBC mode
|
||||
// return the encrypted byte array
|
||||
QByteArray encode(const QByteArray rawText, const QByteArray key, const QByteArray iv = NULL);
|
||||
QByteArray encode(const QByteArray rawText, const QByteArray key, const QByteArray iv = QByteArray());
|
||||
|
||||
// Decode of rawText with key
|
||||
// iv is used in CBC mode
|
||||
// return the decrypted byte array
|
||||
QByteArray decode(const QByteArray rawText, const QByteArray key, const QByteArray iv = NULL);
|
||||
QByteArray decode(const QByteArray rawText, const QByteArray key, const QByteArray iv = QByteArray());
|
||||
|
||||
// Key expansion in Rijndael schedule
|
||||
// return the new expanded key as byte array
|
||||
@ -108,6 +109,11 @@ QString decodedString = QString(QAESEncryption::RemovePadding(decodeText));
|
||||
|
||||
```
|
||||
|
||||
## AES New Instructions Set
|
||||
To use the hardware acceleration provided by the AES New Instructions Set, define USE_INTEL_AES_IF_AVAILABLE
|
||||
If the CPU supports it, the code will switch to use AESNI automatically.
|
||||
The feature is enabled by default
|
||||
|
||||
## Unit Testing
|
||||
The unit testing vectors used are included in [NIST-Recommendation for Block Cipher Modes of Operation](http://nvlpubs.nist.gov/nistpubs/Legacy/SP/nistspecialpublication800-38a.pdf)
|
||||
|
||||
|
63
aesni/aesni-enc-cbc.h
Normal file
63
aesni/aesni-enc-cbc.h
Normal file
@ -0,0 +1,63 @@
|
||||
#ifndef AESNIENCCBC_H
|
||||
#define AESNIENCCBC_H
|
||||
|
||||
#include <wmmintrin.h>
|
||||
|
||||
namespace {
|
||||
|
||||
void AES_CBC_encrypt(const unsigned char *in,
|
||||
unsigned char *out,
|
||||
unsigned char ivec[16],
|
||||
unsigned long length,
|
||||
const char *key,
|
||||
int number_of_rounds)
|
||||
{
|
||||
__m128i feedback,data;
|
||||
unsigned long i;
|
||||
int j;
|
||||
if (length%16)
|
||||
length = length/16+1;
|
||||
else length /=16;
|
||||
feedback=_mm_loadu_si128 ((__m128i*)ivec);
|
||||
for(i=0; i < length; i++) {
|
||||
data = _mm_loadu_si128 (&((__m128i*)in)[i]);
|
||||
feedback = _mm_xor_si128 (data,feedback);
|
||||
feedback = _mm_xor_si128 (feedback,((__m128i*)key)[0]);
|
||||
for(j=1; j <number_of_rounds; j++)
|
||||
feedback = _mm_aesenc_si128 (feedback,((__m128i*)key)[j]);
|
||||
feedback = _mm_aesenclast_si128 (feedback,((__m128i*)key)[j]); _mm_storeu_si128 (&((__m128i*)out)[i],feedback);
|
||||
}
|
||||
}
|
||||
|
||||
#if 0
|
||||
void AES_CBC_decrypt(const unsigned char *in,
|
||||
unsigned char *out,
|
||||
unsigned char ivec[16],
|
||||
unsigned long length,
|
||||
const char *key,
|
||||
int number_of_rounds)
|
||||
{
|
||||
__m128i data,feedback,last_in;
|
||||
unsigned long i;
|
||||
int j;
|
||||
if (length%16)
|
||||
length = length/16+1;
|
||||
else length /=16;
|
||||
feedback=_mm_loadu_si128 ((__m128i*)ivec);
|
||||
for(i=0; i < length; i++) {
|
||||
last_in=_mm_loadu_si128 (&((__m128i*)in)[i]);
|
||||
data = _mm_xor_si128 (last_in,((__m128i*)key)[0]);
|
||||
for(j=1; j <number_of_rounds; j++) {
|
||||
data = _mm_aesdec_si128 (data,((__m128i*)key)[j]);
|
||||
}
|
||||
data = _mm_aesdeclast_si128 (data,((__m128i*)key)[j]);
|
||||
data = _mm_xor_si128 (data,feedback);
|
||||
_mm_storeu_si128 (&((__m128i*)out)[i],data);
|
||||
feedback=last_in;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
#endif // AESNIENCCBC_H
|
61
aesni/aesni-enc-ecb.h
Normal file
61
aesni/aesni-enc-ecb.h
Normal file
@ -0,0 +1,61 @@
|
||||
#ifndef AESNIENCECB_H
|
||||
#define AESNIENCECB_H
|
||||
|
||||
#include <wmmintrin.h>
|
||||
|
||||
namespace {
|
||||
|
||||
/* Note – the length of the output buffer is assumed to be a multiple of 16 bytes */
|
||||
void AES_ECB_encrypt(const unsigned char *in, //pointer to the PLAINTEXT
|
||||
unsigned char *out, //pointer to the CIPHERTEXT buffer
|
||||
unsigned long length, //text length in bytes
|
||||
const char *key, //pointer to the expanded key schedule
|
||||
int number_of_rounds) //number of AES rounds 10,12 or 14
|
||||
{
|
||||
__m128i tmp;
|
||||
unsigned long i;
|
||||
int j;
|
||||
if(length%16)
|
||||
length = length/16+1;
|
||||
else
|
||||
length = length/16;
|
||||
for(i = 0; i < length; i++) {
|
||||
tmp = _mm_loadu_si128 (&((__m128i*)in)[i]);
|
||||
tmp = _mm_xor_si128 (tmp,((__m128i*)key)[0]);
|
||||
for(j=1; j <number_of_rounds; j++) {
|
||||
tmp = _mm_aesenc_si128 (tmp, ((__m128i*)key)[j]);
|
||||
}
|
||||
tmp = _mm_aesenclast_si128 (tmp,((__m128i*)key)[j]);
|
||||
_mm_storeu_si128 (&((__m128i*)out)[i],tmp);
|
||||
}
|
||||
}
|
||||
|
||||
#if 0
|
||||
void AES_ECB_decrypt(const unsigned char *in, //pointer to the CIPHERTEXT
|
||||
unsigned char *out, //pointer to the DECRYPTED TEXT buffer
|
||||
unsigned long length, //text length in bytes
|
||||
const char *key, //pointer to the expanded key schedule
|
||||
int number_of_rounds) //number of AES rounds 10,12 or 14
|
||||
{
|
||||
__m128i tmp;
|
||||
unsigned long i;
|
||||
int j;
|
||||
if(length%16)
|
||||
length = length/16+1;
|
||||
else
|
||||
length = length/16;
|
||||
for(i = 0; i < length; i++) {
|
||||
tmp = _mm_loadu_si128 (&((__m128i*)in)[i]);
|
||||
tmp = _mm_xor_si128 (tmp,((__m128i*)key)[0]);
|
||||
for(j = 1; j < number_of_rounds; j++) {
|
||||
tmp = _mm_aesdec_si128 (tmp,((__m128i*)key)[j]);
|
||||
}
|
||||
tmp = _mm_aesdeclast_si128 (tmp,((__m128i*)key)[j]);
|
||||
_mm_storeu_si128 (&((__m128i*)out)[i],tmp);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
#endif // AESNIENCECB_H
|
199
aesni/aesni-key-exp.h
Normal file
199
aesni/aesni-key-exp.h
Normal file
@ -0,0 +1,199 @@
|
||||
#ifndef AESNIKEYEXP_H
|
||||
#define AESNIKEYEXP_H
|
||||
|
||||
#include <wmmintrin.h>
|
||||
|
||||
#define cpuid(func, ax, bx, cx, dx)\
|
||||
__asm__ __volatile__("cpuid": "=a" (ax), "=b" (bx), "=c" (cx), "=d" (dx) : "a" (func));
|
||||
|
||||
namespace {
|
||||
|
||||
bool check_aesni_support()
|
||||
{
|
||||
unsigned int a,b,c,d;
|
||||
cpuid(1, a,b,c,d);
|
||||
return (c & 0x2000000);
|
||||
}
|
||||
|
||||
__m128i AES_128_ASSIST (__m128i temp1, __m128i temp2)
|
||||
{
|
||||
__m128i temp3;
|
||||
temp2 = _mm_shuffle_epi32 (temp2 ,0xff);
|
||||
temp3 = _mm_slli_si128 (temp1, 0x4);
|
||||
temp1 = _mm_xor_si128 (temp1, temp3);
|
||||
temp3 = _mm_slli_si128 (temp3, 0x4);
|
||||
temp1 = _mm_xor_si128 (temp1, temp3);
|
||||
temp3 = _mm_slli_si128 (temp3, 0x4);
|
||||
temp1 = _mm_xor_si128 (temp1, temp3);
|
||||
temp1 = _mm_xor_si128 (temp1, temp2);
|
||||
return temp1;
|
||||
}
|
||||
|
||||
void AES_128_Key_Expansion (const unsigned char *userkey,
|
||||
unsigned char *key)
|
||||
{
|
||||
__m128i temp1, temp2;
|
||||
__m128i *Key_Schedule = (__m128i*)key;
|
||||
temp1 = _mm_loadu_si128((__m128i*)userkey);
|
||||
Key_Schedule[0] = temp1;
|
||||
temp2 = _mm_aeskeygenassist_si128 (temp1 ,0x1);
|
||||
temp1 = AES_128_ASSIST(temp1, temp2);
|
||||
Key_Schedule[1] = temp1;
|
||||
temp2 = _mm_aeskeygenassist_si128 (temp1,0x2);
|
||||
temp1 = AES_128_ASSIST(temp1, temp2);
|
||||
Key_Schedule[2] = temp1;
|
||||
temp2 = _mm_aeskeygenassist_si128 (temp1,0x4);
|
||||
temp1 = AES_128_ASSIST(temp1, temp2);
|
||||
Key_Schedule[3] = temp1;
|
||||
temp2 = _mm_aeskeygenassist_si128 (temp1,0x8);
|
||||
temp1 = AES_128_ASSIST(temp1, temp2);
|
||||
Key_Schedule[4] = temp1;
|
||||
temp2 = _mm_aeskeygenassist_si128 (temp1,0x10);
|
||||
temp1 = AES_128_ASSIST(temp1, temp2);
|
||||
Key_Schedule[5] = temp1;
|
||||
temp2 = _mm_aeskeygenassist_si128 (temp1,0x20);
|
||||
temp1 = AES_128_ASSIST(temp1, temp2);
|
||||
Key_Schedule[6] = temp1;
|
||||
temp2 = _mm_aeskeygenassist_si128 (temp1,0x40);
|
||||
temp1 = AES_128_ASSIST(temp1, temp2);
|
||||
Key_Schedule[7] = temp1;
|
||||
temp2 = _mm_aeskeygenassist_si128 (temp1,0x80);
|
||||
temp1 = AES_128_ASSIST(temp1, temp2);
|
||||
Key_Schedule[8] = temp1;
|
||||
temp2 = _mm_aeskeygenassist_si128 (temp1,0x1b);
|
||||
temp1 = AES_128_ASSIST(temp1, temp2);
|
||||
Key_Schedule[9] = temp1;
|
||||
temp2 = _mm_aeskeygenassist_si128 (temp1,0x36);
|
||||
temp1 = AES_128_ASSIST(temp1, temp2);
|
||||
Key_Schedule[10] = temp1;
|
||||
}
|
||||
|
||||
void KEY_192_ASSIST(__m128i* temp1, __m128i * temp2, __m128i * temp3)
|
||||
{
|
||||
__m128i temp4;
|
||||
*temp2 = _mm_shuffle_epi32 (*temp2, 0x55);
|
||||
temp4 = _mm_slli_si128 (*temp1, 0x4);
|
||||
*temp1 = _mm_xor_si128 (*temp1, temp4);
|
||||
temp4 = _mm_slli_si128 (temp4, 0x4);
|
||||
*temp1 = _mm_xor_si128 (*temp1, temp4);
|
||||
temp4 = _mm_slli_si128 (temp4, 0x4);
|
||||
*temp1 = _mm_xor_si128 (*temp1, temp4);
|
||||
*temp1 = _mm_xor_si128 (*temp1, *temp2);
|
||||
*temp2 = _mm_shuffle_epi32(*temp1, 0xff);
|
||||
temp4 = _mm_slli_si128 (*temp3, 0x4);
|
||||
*temp3 = _mm_xor_si128 (*temp3, temp4);
|
||||
*temp3 = _mm_xor_si128 (*temp3, *temp2);
|
||||
}
|
||||
|
||||
void AES_192_Key_Expansion (const unsigned char *userkey, unsigned char *key)
|
||||
{
|
||||
__m128i temp1, temp2, temp3;
|
||||
__m128i *Key_Schedule = (__m128i*)key;
|
||||
temp1 = _mm_loadu_si128((__m128i*)userkey);
|
||||
temp3 = _mm_loadu_si128((__m128i*)(userkey+16));
|
||||
Key_Schedule[0]=temp1; Key_Schedule[1]=temp3;
|
||||
temp2=_mm_aeskeygenassist_si128 (temp3,0x1);
|
||||
KEY_192_ASSIST(&temp1, &temp2, &temp3);
|
||||
Key_Schedule[1] = (__m128i)_mm_shuffle_pd((__m128d)Key_Schedule[1], (__m128d)temp1,0);
|
||||
Key_Schedule[2] = (__m128i)_mm_shuffle_pd((__m128d)temp1,(__m128d)temp3,1);
|
||||
temp2=_mm_aeskeygenassist_si128 (temp3,0x2);
|
||||
KEY_192_ASSIST(&temp1, &temp2, &temp3);
|
||||
Key_Schedule[3]=temp1;
|
||||
Key_Schedule[4]=temp3;
|
||||
temp2=_mm_aeskeygenassist_si128 (temp3,0x4);
|
||||
KEY_192_ASSIST(&temp1, &temp2, &temp3);
|
||||
Key_Schedule[4] = (__m128i)_mm_shuffle_pd((__m128d)Key_Schedule[4], (__m128d)temp1,0);
|
||||
Key_Schedule[5] = (__m128i)_mm_shuffle_pd((__m128d)temp1,(__m128d)temp3,1);
|
||||
temp2=_mm_aeskeygenassist_si128 (temp3,0x8);
|
||||
KEY_192_ASSIST(&temp1, &temp2, &temp3);
|
||||
Key_Schedule[6]=temp1;
|
||||
Key_Schedule[7]=temp3;
|
||||
temp2=_mm_aeskeygenassist_si128 (temp3,0x10);
|
||||
KEY_192_ASSIST(&temp1, &temp2, &temp3);
|
||||
Key_Schedule[7] = (__m128i)_mm_shuffle_pd((__m128d)Key_Schedule[7], (__m128d)temp1,0);
|
||||
Key_Schedule[8] = (__m128i)_mm_shuffle_pd((__m128d)temp1,(__m128d)temp3,1);
|
||||
temp2=_mm_aeskeygenassist_si128 (temp3,0x20);
|
||||
KEY_192_ASSIST(&temp1, &temp2, &temp3);
|
||||
Key_Schedule[9]=temp1;
|
||||
Key_Schedule[10]=temp3;
|
||||
temp2=_mm_aeskeygenassist_si128 (temp3,0x40);
|
||||
KEY_192_ASSIST(&temp1, &temp2, &temp3);
|
||||
Key_Schedule[10] = (__m128i)_mm_shuffle_pd((__m128d)Key_Schedule[10], (__m128d)temp1,0);
|
||||
Key_Schedule[11] = (__m128i)_mm_shuffle_pd((__m128d)temp1,(__m128d)temp3,1);
|
||||
temp2=_mm_aeskeygenassist_si128 (temp3,0x80);
|
||||
KEY_192_ASSIST(&temp1, &temp2, &temp3);
|
||||
Key_Schedule[12]=temp1;
|
||||
}
|
||||
|
||||
void KEY_256_ASSIST_1(__m128i* temp1, __m128i * temp2)
|
||||
{
|
||||
__m128i temp4;
|
||||
*temp2 = _mm_shuffle_epi32(*temp2, 0xff);
|
||||
temp4 = _mm_slli_si128 (*temp1, 0x4);
|
||||
*temp1 = _mm_xor_si128 (*temp1, temp4);
|
||||
temp4 = _mm_slli_si128 (temp4, 0x4);
|
||||
*temp1 = _mm_xor_si128 (*temp1, temp4);
|
||||
temp4 = _mm_slli_si128 (temp4, 0x4);
|
||||
*temp1 = _mm_xor_si128 (*temp1, temp4);
|
||||
*temp1 = _mm_xor_si128 (*temp1, *temp2);
|
||||
}
|
||||
|
||||
void KEY_256_ASSIST_2(__m128i* temp1, __m128i * temp3)
|
||||
{
|
||||
__m128i temp2,temp4;
|
||||
temp4 = _mm_aeskeygenassist_si128 (*temp1, 0x0);
|
||||
temp2 = _mm_shuffle_epi32(temp4, 0xaa);
|
||||
temp4 = _mm_slli_si128 (*temp3, 0x4);
|
||||
*temp3 = _mm_xor_si128 (*temp3, temp4);
|
||||
temp4 = _mm_slli_si128 (temp4, 0x4);
|
||||
*temp3 = _mm_xor_si128 (*temp3, temp4);
|
||||
temp4 = _mm_slli_si128 (temp4, 0x4);
|
||||
*temp3 = _mm_xor_si128 (*temp3, temp4);
|
||||
*temp3 = _mm_xor_si128 (*temp3, temp2);
|
||||
}
|
||||
|
||||
void AES_256_Key_Expansion (const unsigned char *userkey, unsigned char *key)
|
||||
{
|
||||
__m128i temp1, temp2, temp3;
|
||||
__m128i *Key_Schedule = (__m128i*)key;
|
||||
temp1 = _mm_loadu_si128((__m128i*)userkey);
|
||||
temp3 = _mm_loadu_si128((__m128i*)(userkey+16));
|
||||
Key_Schedule[0] = temp1; Key_Schedule[1] = temp3;
|
||||
temp2 = _mm_aeskeygenassist_si128 (temp3,0x01);
|
||||
KEY_256_ASSIST_1(&temp1, &temp2);
|
||||
Key_Schedule[2]=temp1;
|
||||
KEY_256_ASSIST_2(&temp1, &temp3);
|
||||
Key_Schedule[3]=temp3;
|
||||
temp2 = _mm_aeskeygenassist_si128 (temp3,0x02);
|
||||
KEY_256_ASSIST_1(&temp1, &temp2);
|
||||
Key_Schedule[4]=temp1;
|
||||
KEY_256_ASSIST_2(&temp1, &temp3);
|
||||
Key_Schedule[5]=temp3;
|
||||
temp2 = _mm_aeskeygenassist_si128 (temp3,0x04);
|
||||
KEY_256_ASSIST_1(&temp1, &temp2);
|
||||
Key_Schedule[6]=temp1;
|
||||
KEY_256_ASSIST_2(&temp1, &temp3);
|
||||
Key_Schedule[7]=temp3;
|
||||
temp2 = _mm_aeskeygenassist_si128 (temp3,0x08);
|
||||
KEY_256_ASSIST_1(&temp1, &temp2);
|
||||
Key_Schedule[8]=temp1;
|
||||
KEY_256_ASSIST_2(&temp1, &temp3);
|
||||
Key_Schedule[9]=temp3;
|
||||
temp2 = _mm_aeskeygenassist_si128 (temp3,0x10);
|
||||
KEY_256_ASSIST_1(&temp1, &temp2);
|
||||
Key_Schedule[10]=temp1;
|
||||
KEY_256_ASSIST_2(&temp1, &temp3);
|
||||
Key_Schedule[11]=temp3;
|
||||
temp2 = _mm_aeskeygenassist_si128 (temp3,0x20);
|
||||
KEY_256_ASSIST_1(&temp1, &temp2);
|
||||
Key_Schedule[12]=temp1;
|
||||
KEY_256_ASSIST_2(&temp1, &temp3);
|
||||
Key_Schedule[13]=temp3;
|
||||
temp2 = _mm_aeskeygenassist_si128 (temp3,0x40);
|
||||
KEY_256_ASSIST_1(&temp1, &temp2);
|
||||
Key_Schedule[14]=temp1;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endif // AESNIKEYEXP_H
|
4
main.cpp
4
main.cpp
@ -1,11 +1,13 @@
|
||||
#include <QCoreApplication>
|
||||
#include <QTest>
|
||||
|
||||
#ifdef __cplusplus
|
||||
#include "unit_test/aestest.h"
|
||||
#endif
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
QCoreApplication a(argc, argv);
|
||||
|
||||
AesTest test1;
|
||||
QTest::qExec(&test1);
|
||||
return 0;
|
||||
|
@ -1,4 +1,12 @@
|
||||
#include "qaesencryption.h"
|
||||
#include <QDebug>
|
||||
#include <QVector>
|
||||
|
||||
#ifdef USE_INTEL_AES_IF_AVAILABLE
|
||||
#include "aesni/aesni-key-exp.h"
|
||||
#include "aesni/aesni-enc-ecb.h"
|
||||
#include "aesni/aesni-enc-cbc.h"
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Static Functions
|
||||
@ -34,7 +42,11 @@ QByteArray QAESEncryption::RemovePadding(const QByteArray &rawText, QAESEncrypti
|
||||
ret.remove(ret.length()-1, 1);
|
||||
break;
|
||||
case Padding::PKCS7:
|
||||
ret.remove(ret.length() - *ret.rbegin(), *ret.rbegin());
|
||||
#if QT_VERSION >= QT_VERSION_CHECK(5, 10, 0)
|
||||
ret.remove(ret.length() - ret.back(), ret.back());
|
||||
#else
|
||||
ret.remove(ret.length() - ret.at(ret.length() - 1), ret.at(ret.length() - 1));
|
||||
#endif
|
||||
break;
|
||||
case Padding::ISO:
|
||||
{
|
||||
@ -49,7 +61,7 @@ QByteArray QAESEncryption::RemovePadding(const QByteArray &rawText, QAESEncrypti
|
||||
}
|
||||
|
||||
// And check if it's the byte for marking padding
|
||||
if (ret.at(marker_index) == static_cast<char>(0x80))
|
||||
if (ret.at(marker_index) == '\x80')
|
||||
{
|
||||
ret.truncate(marker_index);
|
||||
}
|
||||
@ -66,28 +78,36 @@ QByteArray QAESEncryption::RemovePadding(const QByteArray &rawText, QAESEncrypti
|
||||
* */
|
||||
|
||||
/*
|
||||
* Inline Functions
|
||||
* Local Functions
|
||||
* */
|
||||
|
||||
inline quint8 xTime(quint8 x){
|
||||
return ((x<<1) ^ (((x>>7) & 1) * 0x1b));
|
||||
namespace {
|
||||
|
||||
quint8 xTime(quint8 x)
|
||||
{
|
||||
return ((x<<1) ^ (((x>>7) & 1) * 0x1b));
|
||||
}
|
||||
|
||||
inline quint8 multiply(quint8 x, quint8 y){
|
||||
return (((y & 1) * x) ^ ((y>>1 & 1) * xTime(x)) ^ ((y>>2 & 1) * xTime(xTime(x))) ^ ((y>>3 & 1)
|
||||
quint8 multiply(quint8 x, quint8 y)
|
||||
{
|
||||
return (((y & 1) * x) ^ ((y>>1 & 1) * xTime(x)) ^ ((y>>2 & 1) * xTime(xTime(x))) ^ ((y>>3 & 1)
|
||||
* xTime(xTime(xTime(x)))) ^ ((y>>4 & 1) * xTime(xTime(xTime(xTime(x))))));
|
||||
}
|
||||
|
||||
/*
|
||||
* End Inline functions
|
||||
* */
|
||||
}
|
||||
|
||||
/*
|
||||
* End Local functions
|
||||
* */
|
||||
|
||||
QAESEncryption::QAESEncryption(Aes level, Mode mode,
|
||||
Padding padding)
|
||||
: m_nb(4), m_blocklen(16), m_level(level), m_mode(mode), m_padding(padding)
|
||||
, m_aesNIAvailable(false), m_state(nullptr)
|
||||
{
|
||||
m_state = NULL;
|
||||
#ifdef USE_INTEL_AES_IF_AVAILABLE
|
||||
m_aesNIAvailable = check_aesni_support();
|
||||
#endif
|
||||
|
||||
switch (level)
|
||||
{
|
||||
@ -141,7 +161,7 @@ QByteArray QAESEncryption::getPadding(int currSize, int alignment)
|
||||
break;
|
||||
case Padding::ISO:
|
||||
if (size > 0)
|
||||
return QByteArray (size - 1, 0x00).prepend(0x80);
|
||||
return QByteArray (size - 1, 0x00).prepend('\x80');
|
||||
break;
|
||||
default:
|
||||
return QByteArray(size, 0x00);
|
||||
@ -152,61 +172,104 @@ QByteArray QAESEncryption::getPadding(int currSize, int alignment)
|
||||
|
||||
QByteArray QAESEncryption::expandKey(const QByteArray &key)
|
||||
{
|
||||
int i, k;
|
||||
quint8 tempa[4]; // Used for the column/row operations
|
||||
QByteArray roundKey(key);
|
||||
|
||||
// The first round key is the key itself.
|
||||
// ...
|
||||
#ifdef USE_INTEL_AES_IF_AVAILABLE
|
||||
if (true){
|
||||
switch(m_level) {
|
||||
case AES_128: {
|
||||
AES128 aes128;
|
||||
quint8 ret[aes128.expandedKey];
|
||||
memset(ret, 0x00, sizeof(ret));
|
||||
quint8 uchar_key[key.size()];
|
||||
memcpy(uchar_key, key.data(), key.size());
|
||||
AES_128_Key_Expansion(uchar_key, ret);
|
||||
return QByteArray((char*) ret, aes128.expandedKey);
|
||||
}
|
||||
break;
|
||||
case AES_192: {
|
||||
AES192 aes192;
|
||||
quint8 ret[aes192.expandedKey];
|
||||
memset(ret, 0x00, sizeof(ret));
|
||||
quint8 uchar_key[key.size()];
|
||||
memcpy(uchar_key, key.data(), key.size());
|
||||
|
||||
// All other round keys are found from the previous round keys.
|
||||
//i == Nk
|
||||
for(i = m_nk; i < m_nb * (m_nr + 1); i++)
|
||||
AES_192_Key_Expansion(uchar_key, ret);
|
||||
return QByteArray((char*) ret, aes192.expandedKey);
|
||||
}
|
||||
break;
|
||||
case AES_256: {
|
||||
AES256 aes256;
|
||||
quint8 ret[aes256.expandedKey];
|
||||
memset(ret, 0x00, sizeof(ret));
|
||||
quint8 uchar_key[key.size()];
|
||||
memcpy(uchar_key, key.data(), key.size());
|
||||
|
||||
AES_256_Key_Expansion(uchar_key, ret);
|
||||
return QByteArray((char*) ret, aes256.expandedKey);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
return QByteArray();
|
||||
break;
|
||||
}
|
||||
} else
|
||||
#endif
|
||||
{
|
||||
tempa[0] = (quint8) roundKey.at((i-1) * 4 + 0);
|
||||
tempa[1] = (quint8) roundKey.at((i-1) * 4 + 1);
|
||||
tempa[2] = (quint8) roundKey.at((i-1) * 4 + 2);
|
||||
tempa[3] = (quint8) roundKey.at((i-1) * 4 + 3);
|
||||
|
||||
if (i % m_nk == 0)
|
||||
{
|
||||
// This function shifts the 4 bytes in a word to the left once.
|
||||
// [a0,a1,a2,a3] becomes [a1,a2,a3,a0]
|
||||
int i, k;
|
||||
quint8 tempa[4]; // Used for the column/row operations
|
||||
QByteArray roundKey(key); // The first round key is the key itself.
|
||||
|
||||
// Function RotWord()
|
||||
k = tempa[0];
|
||||
tempa[0] = tempa[1];
|
||||
tempa[1] = tempa[2];
|
||||
tempa[2] = tempa[3];
|
||||
tempa[3] = k;
|
||||
// All other round keys are found from the previous round keys.
|
||||
//i == Nk
|
||||
for(i = m_nk; i < m_nb * (m_nr + 1); i++)
|
||||
{
|
||||
tempa[0] = (quint8) roundKey.at((i-1) * 4 + 0);
|
||||
tempa[1] = (quint8) roundKey.at((i-1) * 4 + 1);
|
||||
tempa[2] = (quint8) roundKey.at((i-1) * 4 + 2);
|
||||
tempa[3] = (quint8) roundKey.at((i-1) * 4 + 3);
|
||||
|
||||
// Function Subword()
|
||||
tempa[0] = getSBoxValue(tempa[0]);
|
||||
tempa[1] = getSBoxValue(tempa[1]);
|
||||
tempa[2] = getSBoxValue(tempa[2]);
|
||||
tempa[3] = getSBoxValue(tempa[3]);
|
||||
if (i % m_nk == 0)
|
||||
{
|
||||
// This function shifts the 4 bytes in a word to the left once.
|
||||
// [a0,a1,a2,a3] becomes [a1,a2,a3,a0]
|
||||
|
||||
tempa[0] = tempa[0] ^ Rcon[i/m_nk];
|
||||
}
|
||||
if (m_level == AES_256 && i % m_nk == 4)
|
||||
{
|
||||
// Function Subword()
|
||||
tempa[0] = getSBoxValue(tempa[0]);
|
||||
tempa[1] = getSBoxValue(tempa[1]);
|
||||
tempa[2] = getSBoxValue(tempa[2]);
|
||||
tempa[3] = getSBoxValue(tempa[3]);
|
||||
}
|
||||
roundKey.insert(i * 4 + 0, (quint8) roundKey.at((i - m_nk) * 4 + 0) ^ tempa[0]);
|
||||
roundKey.insert(i * 4 + 1, (quint8) roundKey.at((i - m_nk) * 4 + 1) ^ tempa[1]);
|
||||
roundKey.insert(i * 4 + 2, (quint8) roundKey.at((i - m_nk) * 4 + 2) ^ tempa[2]);
|
||||
roundKey.insert(i * 4 + 3, (quint8) roundKey.at((i - m_nk) * 4 + 3) ^ tempa[3]);
|
||||
// Function RotWord()
|
||||
k = tempa[0];
|
||||
tempa[0] = tempa[1];
|
||||
tempa[1] = tempa[2];
|
||||
tempa[2] = tempa[3];
|
||||
tempa[3] = k;
|
||||
|
||||
// Function Subword()
|
||||
tempa[0] = getSBoxValue(tempa[0]);
|
||||
tempa[1] = getSBoxValue(tempa[1]);
|
||||
tempa[2] = getSBoxValue(tempa[2]);
|
||||
tempa[3] = getSBoxValue(tempa[3]);
|
||||
|
||||
tempa[0] = tempa[0] ^ Rcon[i/m_nk];
|
||||
}
|
||||
|
||||
if (m_level == AES_256 && i % m_nk == 4)
|
||||
{
|
||||
// Function Subword()
|
||||
tempa[0] = getSBoxValue(tempa[0]);
|
||||
tempa[1] = getSBoxValue(tempa[1]);
|
||||
tempa[2] = getSBoxValue(tempa[2]);
|
||||
tempa[3] = getSBoxValue(tempa[3]);
|
||||
}
|
||||
roundKey.insert(i * 4 + 0, (quint8) roundKey.at((i - m_nk) * 4 + 0) ^ tempa[0]);
|
||||
roundKey.insert(i * 4 + 1, (quint8) roundKey.at((i - m_nk) * 4 + 1) ^ tempa[1]);
|
||||
roundKey.insert(i * 4 + 2, (quint8) roundKey.at((i - m_nk) * 4 + 2) ^ tempa[2]);
|
||||
roundKey.insert(i * 4 + 3, (quint8) roundKey.at((i - m_nk) * 4 + 3) ^ tempa[3]);
|
||||
}
|
||||
return roundKey;
|
||||
}
|
||||
return roundKey;
|
||||
}
|
||||
|
||||
// This function adds the round key to state.
|
||||
// The round key is added to the state by an XOR function.
|
||||
void QAESEncryption::addRoundKey(const quint8 round, const QByteArray expKey)
|
||||
void QAESEncryption::addRoundKey(const quint8 round, const QByteArray &expKey)
|
||||
{
|
||||
QByteArray::iterator it = m_state->begin();
|
||||
for(int i=0; i < 16; ++i)
|
||||
@ -331,11 +394,11 @@ void QAESEncryption::invShiftRows()
|
||||
it[6] = (quint8)temp;
|
||||
|
||||
//Shift 3
|
||||
temp = (quint8)it[15];
|
||||
it[15] = (quint8)it[3];
|
||||
it[3] = (quint8)it[7];
|
||||
temp = (quint8)it[7];
|
||||
it[7] = (quint8)it[11];
|
||||
it[11] = (quint8)temp;
|
||||
it[11] = (quint8)it[15];
|
||||
it[15] = (quint8)it[3];
|
||||
it[3] = (quint8)temp;
|
||||
}
|
||||
|
||||
QByteArray QAESEncryption::byteXor(const QByteArray &a, const QByteArray &b)
|
||||
@ -409,12 +472,20 @@ QByteArray QAESEncryption::invCipher(const QByteArray &expKey, const QByteArray
|
||||
return output;
|
||||
}
|
||||
|
||||
QByteArray QAESEncryption::printArray(uchar* arr, int size)
|
||||
{
|
||||
QByteArray print("");
|
||||
for(int i=0; i<size; i++)
|
||||
print.append(arr[i]);
|
||||
|
||||
return print.toHex();
|
||||
}
|
||||
|
||||
QByteArray QAESEncryption::encode(const QByteArray &rawText, const QByteArray &key, const QByteArray &iv)
|
||||
{
|
||||
if (m_mode >= CBC && (iv.isNull() || iv.size() != m_blocklen))
|
||||
if (m_mode >= CBC && (iv.isEmpty() || iv.size() != m_blocklen))
|
||||
return QByteArray();
|
||||
|
||||
QByteArray ret;
|
||||
QByteArray expandedKey = expandKey(key);
|
||||
QByteArray alignedText(rawText);
|
||||
|
||||
@ -423,45 +494,86 @@ QByteArray QAESEncryption::encode(const QByteArray &rawText, const QByteArray &k
|
||||
|
||||
switch(m_mode)
|
||||
{
|
||||
case ECB:
|
||||
case ECB: {
|
||||
#ifdef USE_INTEL_AES_IF_AVAILABLE
|
||||
if (m_aesNIAvailable){
|
||||
unsigned char in[alignedText.size()];
|
||||
memcpy(in, alignedText.data(), alignedText.size());
|
||||
unsigned char out[alignedText.size()];
|
||||
memcpy(out, alignedText.data(), alignedText.size());
|
||||
char expKey[expandedKey.size()];
|
||||
memcpy(expKey, expandedKey.data(), expandedKey.size());
|
||||
AES_ECB_encrypt(in, out, alignedText.size(),
|
||||
expKey, m_nr);
|
||||
return QByteArray((char*)out, alignedText.size());
|
||||
}
|
||||
#endif
|
||||
QByteArray ret;
|
||||
for(int i=0; i < alignedText.size(); i+= m_blocklen)
|
||||
ret.append(cipher(expandedKey, alignedText.mid(i, m_blocklen)));
|
||||
break;
|
||||
return ret;
|
||||
}
|
||||
break;
|
||||
case CBC: {
|
||||
QByteArray ivTemp(iv);
|
||||
for(int i=0; i < alignedText.size(); i+= m_blocklen) {
|
||||
alignedText.replace(i, m_blocklen, byteXor(alignedText.mid(i, m_blocklen),ivTemp));
|
||||
ret.append(cipher(expandedKey, alignedText.mid(i, m_blocklen)));
|
||||
ivTemp = ret.mid(i, m_blocklen);
|
||||
}
|
||||
#ifdef USE_INTEL_AES_IF_AVAILABLE
|
||||
if (m_aesNIAvailable){
|
||||
quint8 in[alignedText.size()];
|
||||
memcpy(in, alignedText.constData(), alignedText.size());
|
||||
quint8 ivec[iv.size()];
|
||||
memcpy(ivec, iv.data(), iv.size());
|
||||
char out[alignedText.size()];
|
||||
memset(out, 0x00, alignedText.size());
|
||||
char expKey[expandedKey.size()];
|
||||
memcpy(expKey, expandedKey.data(), expandedKey.size());
|
||||
AES_CBC_encrypt(in,
|
||||
(unsigned char*) out,
|
||||
ivec,
|
||||
alignedText.size(),
|
||||
expKey,
|
||||
m_nr);
|
||||
return QByteArray(out, alignedText.size());
|
||||
}
|
||||
break;
|
||||
#endif
|
||||
QByteArray ret;
|
||||
QByteArray ivTemp(iv);
|
||||
for(int i=0; i < alignedText.size(); i+= m_blocklen) {
|
||||
alignedText.replace(i, m_blocklen, byteXor(alignedText.mid(i, m_blocklen),ivTemp));
|
||||
ret.append(cipher(expandedKey, alignedText.mid(i, m_blocklen)));
|
||||
ivTemp = ret.mid(i, m_blocklen);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
break;
|
||||
case CFB: {
|
||||
ret.append(byteXor(alignedText.left(m_blocklen), cipher(expandedKey, iv)));
|
||||
for(int i=0; i < alignedText.size(); i+= m_blocklen) {
|
||||
if (i+m_blocklen < alignedText.size())
|
||||
ret.append(byteXor(alignedText.mid(i+m_blocklen, m_blocklen),
|
||||
cipher(expandedKey, ret.mid(i, m_blocklen))));
|
||||
}
|
||||
QByteArray ret;
|
||||
ret.append(byteXor(alignedText.left(m_blocklen), cipher(expandedKey, iv)));
|
||||
for(int i=0; i < alignedText.size(); i+= m_blocklen) {
|
||||
if (i+m_blocklen < alignedText.size())
|
||||
ret.append(byteXor(alignedText.mid(i+m_blocklen, m_blocklen),
|
||||
cipher(expandedKey, ret.mid(i, m_blocklen))));
|
||||
}
|
||||
break;
|
||||
return ret;
|
||||
}
|
||||
break;
|
||||
case OFB: {
|
||||
QByteArray ofbTemp;
|
||||
ofbTemp.append(cipher(expandedKey, iv));
|
||||
for (int i=m_blocklen; i < alignedText.size(); i += m_blocklen){
|
||||
ofbTemp.append(cipher(expandedKey, ofbTemp.right(m_blocklen)));
|
||||
}
|
||||
ret.append(byteXor(alignedText, ofbTemp));
|
||||
QByteArray ret;
|
||||
QByteArray ofbTemp;
|
||||
ofbTemp.append(cipher(expandedKey, iv));
|
||||
for (int i=m_blocklen; i < alignedText.size(); i += m_blocklen){
|
||||
ofbTemp.append(cipher(expandedKey, ofbTemp.right(m_blocklen)));
|
||||
}
|
||||
break;
|
||||
ret.append(byteXor(alignedText, ofbTemp));
|
||||
return ret;
|
||||
}
|
||||
break;
|
||||
default: break;
|
||||
}
|
||||
return ret;
|
||||
return QByteArray();
|
||||
}
|
||||
|
||||
QByteArray QAESEncryption::decode(const QByteArray &rawText, const QByteArray &key, const QByteArray &iv)
|
||||
{
|
||||
if (m_mode >= CBC && (iv.isNull() || iv.size() != m_blocklen))
|
||||
if (m_mode >= CBC && (iv.isEmpty() || iv.size() != m_blocklen))
|
||||
return QByteArray();
|
||||
|
||||
QByteArray ret;
|
||||
|
@ -4,6 +4,12 @@
|
||||
#include <QObject>
|
||||
#include <QByteArray>
|
||||
|
||||
#ifdef __linux__
|
||||
#ifndef __LP64__
|
||||
#define do_rdtsc _do_rdtsc
|
||||
#endif
|
||||
#endif
|
||||
|
||||
class Q_DECL_EXPORT QAESEncryption : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
@ -28,20 +34,21 @@ public:
|
||||
};
|
||||
|
||||
static QByteArray Crypt(QAESEncryption::Aes level, QAESEncryption::Mode mode, const QByteArray &rawText, const QByteArray &key,
|
||||
const QByteArray &iv = NULL, QAESEncryption::Padding padding = QAESEncryption::ISO);
|
||||
const QByteArray &iv = QByteArray(), QAESEncryption::Padding padding = QAESEncryption::ISO);
|
||||
static QByteArray Decrypt(QAESEncryption::Aes level, QAESEncryption::Mode mode, const QByteArray &rawText, const QByteArray &key,
|
||||
const QByteArray &iv = NULL, QAESEncryption::Padding padding = QAESEncryption::ISO);
|
||||
const QByteArray &iv = QByteArray(), QAESEncryption::Padding padding = QAESEncryption::ISO);
|
||||
static QByteArray ExpandKey(QAESEncryption::Aes level, QAESEncryption::Mode mode, const QByteArray &key);
|
||||
static QByteArray RemovePadding(const QByteArray &rawText, QAESEncryption::Padding padding);
|
||||
static QByteArray RemovePadding(const QByteArray &rawText, QAESEncryption::Padding padding = QAESEncryption::ISO);
|
||||
|
||||
QAESEncryption(QAESEncryption::Aes level, QAESEncryption::Mode mode,
|
||||
QAESEncryption::Padding padding = QAESEncryption::ISO);
|
||||
|
||||
QByteArray encode(const QByteArray &rawText, const QByteArray &key, const QByteArray &iv = NULL);
|
||||
QByteArray decode(const QByteArray &rawText, const QByteArray &key, const QByteArray &iv = NULL);
|
||||
QByteArray encode(const QByteArray &rawText, const QByteArray &key, const QByteArray &iv = QByteArray());
|
||||
QByteArray decode(const QByteArray &rawText, const QByteArray &key, const QByteArray &iv = QByteArray());
|
||||
QByteArray removePadding(const QByteArray &rawText);
|
||||
QByteArray expandKey(const QByteArray &key);
|
||||
|
||||
QByteArray printArray(uchar *arr, int size);
|
||||
signals:
|
||||
|
||||
public slots:
|
||||
@ -56,6 +63,7 @@ private:
|
||||
int m_nr;
|
||||
int m_expandedKey;
|
||||
int m_padding;
|
||||
bool m_aesNIAvailable;
|
||||
QByteArray* m_state;
|
||||
|
||||
struct AES256{
|
||||
@ -82,7 +90,7 @@ private:
|
||||
quint8 getSBoxValue(quint8 num){return sbox[num];}
|
||||
quint8 getSBoxInvert(quint8 num){return rsbox[num];}
|
||||
|
||||
void addRoundKey(const quint8 round, const QByteArray expKey);
|
||||
void addRoundKey(const quint8 round, const QByteArray &expKey);
|
||||
void subBytes();
|
||||
void shiftRows();
|
||||
void mixColumns();
|
||||
@ -90,9 +98,9 @@ private:
|
||||
void invSubBytes();
|
||||
void invShiftRows();
|
||||
QByteArray getPadding(int currSize, int alignment);
|
||||
QByteArray cipher(const QByteArray &expKey, const QByteArray &plainText);
|
||||
QByteArray invCipher(const QByteArray &expKey, const QByteArray &plainText);
|
||||
QByteArray byteXor(const QByteArray &in, const QByteArray &iv);
|
||||
QByteArray cipher(const QByteArray &expKey, const QByteArray &in);
|
||||
QByteArray invCipher(const QByteArray &expKey, const QByteArray &in);
|
||||
QByteArray byteXor(const QByteArray &a, const QByteArray &b);
|
||||
|
||||
const quint8 sbox[256] = {
|
||||
//0 1 2 3 4 5 6 7 8 9 A B C D E F
|
||||
|
@ -9,16 +9,15 @@ CONFIG -= app_bundle
|
||||
|
||||
TEMPLATE = app
|
||||
|
||||
SOURCES += main.cpp \
|
||||
qaesencryption.cpp \
|
||||
unit_test/aestest.cpp
|
||||
|
||||
# The following define makes your compiler emit warnings if you use
|
||||
# any feature of Qt which as been marked deprecated (the exact warnings
|
||||
# depend on your compiler). Please consult the documentation of the
|
||||
# deprecated API in order to know how to port your code away from it.
|
||||
DEFINES += QT_DEPRECATED_WARNINGS
|
||||
|
||||
DEFINES += USE_INTEL_AES_IF_AVAILABLE
|
||||
QMAKE_CXXFLAGS += -maes
|
||||
|
||||
CONFIG(release, debug|release): {
|
||||
DESTDIR="$$PWD/build/release"
|
||||
} else {
|
||||
@ -32,8 +31,15 @@ CONFIG(release, debug|release): {
|
||||
|
||||
HEADERS += \
|
||||
qaesencryption.h \
|
||||
aesni/aesni-key-exp.h \
|
||||
aesni/aesni-enc-ecb.h \
|
||||
aesni/aesni-enc-cbc.h \
|
||||
unit_test/aestest.h
|
||||
|
||||
SOURCES += main.cpp \
|
||||
qaesencryption.cpp \
|
||||
unit_test/aestest.cpp
|
||||
|
||||
DISTFILES += \
|
||||
unit_test/longText.txt
|
||||
|
||||
|
@ -8,6 +8,9 @@
|
||||
|
||||
void AesTest::initTestCase()
|
||||
{
|
||||
#ifdef USE_INTEL_AES_IF_AVAILABLE
|
||||
qDebug() << "AESNI Enabled";
|
||||
#endif
|
||||
quint8 key_16[16] = {0x2b, 0x7e, 0x15, 0x16, 0x28, 0xae, 0xd2, 0xa6, 0xab, 0xf7, 0x15, 0x88, 0x09, 0xcf, 0x4f, 0x3c};
|
||||
for (int i=0; i<16; i++)
|
||||
key16.append(key_16[i]);
|
||||
@ -54,6 +57,7 @@ void AesTest::initTestCase()
|
||||
inCBC128.append(text_cbc[i]);
|
||||
outCBC128.append(output_cbc[i]);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user