From 57b0cdf743c46f10fb5fbf3b822dd4a327add64b Mon Sep 17 00:00:00 2001 From: Marc Muller Date: Fri, 28 Jun 2019 11:40:31 +0200 Subject: [PATCH 1/5] adding qt version check to keep retrocomp with qt pre 5.10 qbytearray --- qaesencryption.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/qaesencryption.cpp b/qaesencryption.cpp index a37b3c4..3566862 100644 --- a/qaesencryption.cpp +++ b/qaesencryption.cpp @@ -34,7 +34,11 @@ QByteArray QAESEncryption::RemovePadding(const QByteArray &rawText, QAESEncrypti ret.remove(ret.length()-1, 1); break; case Padding::PKCS7: +#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: { From 78efdb4f3ff136775cd3c27d27f23d36605e0d50 Mon Sep 17 00:00:00 2001 From: Matteo B Date: Fri, 15 May 2020 16:45:35 -0700 Subject: [PATCH 2/5] Adding ECB and CBC modes via AES-NI (#32) Added ECB and CBC modes via AES-NI, only is enabled and supported --- aesni/aesni-enc-cbc.c | 60 +++++++++++ aesni/aesni-enc-ecb.c | 58 ++++++++++ aesni/aesni-key-exp.c | 196 ++++++++++++++++++++++++++++++++++ main.cpp | 4 +- qaesencryption.cpp | 239 ++++++++++++++++++++++++++++++------------ qaesencryption.h | 8 ++ qaesencryption.pro | 16 ++- unit_test/aestest.cpp | 4 + 8 files changed, 512 insertions(+), 73 deletions(-) create mode 100755 aesni/aesni-enc-cbc.c create mode 100755 aesni/aesni-enc-ecb.c create mode 100755 aesni/aesni-key-exp.c diff --git a/aesni/aesni-enc-cbc.c b/aesni/aesni-enc-cbc.c new file mode 100755 index 0000000..5efceb1 --- /dev/null +++ b/aesni/aesni-enc-cbc.c @@ -0,0 +1,60 @@ +#include + +#ifdef __cplusplus +extern "C" { +#endif + +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 + +#ifdef __cplusplus +extern "C" { +#endif + +/* 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 + +#ifdef __cplusplus +extern "C" { +#endif + +#define cpuid(func, ax, bx, cx, dx)\ + __asm__ __volatile__("cpuid": "=a" (ax), "=b" (bx), "=c" (cx), "=d" (dx) : "a" (func)); + +inline bool check_aesni_support() +{ + unsigned int a,b,c,d; + cpuid(1, a,b,c,d); + return (c & 0x2000000); +} +inline __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; +} + +inline 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; +} + +inline 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); +} + +inline 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; +} +#ifdef __cplusplus +} +#endif diff --git a/main.cpp b/main.cpp index 40e661c..ef3b7c2 100644 --- a/main.cpp +++ b/main.cpp @@ -1,11 +1,13 @@ #include #include + +#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; diff --git a/qaesencryption.cpp b/qaesencryption.cpp index 3566862..6461dd1 100644 --- a/qaesencryption.cpp +++ b/qaesencryption.cpp @@ -1,4 +1,12 @@ #include "qaesencryption.h" +#include +#include + +#ifdef USE_INTEL_AES_IF_AVAILABLE +#include "aesni/aesni-key-exp.c" +#include "aesni/aesni-enc-ecb.c" +#include "aesni/aesni-enc-cbc.c" +#endif /* * Static Functions @@ -90,9 +98,14 @@ inline quint8 multiply(quint8 x, quint8 y){ 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 = NULL; +#ifdef USE_INTEL_AES_IF_AVAILABLE + m_aesNIAvailable = check_aesni_support(); +#endif + switch (level) { case AES_128: { @@ -156,56 +169,99 @@ 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. @@ -413,12 +469,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= CBC && (iv.isNull() || iv.size() != m_blocklen)) return QByteArray(); - QByteArray ret; QByteArray expandedKey = expandKey(key); QByteArray alignedText(rawText); @@ -427,40 +491,81 @@ 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) diff --git a/qaesencryption.h b/qaesencryption.h index 90e54bd..4f3165e 100644 --- a/qaesencryption.h +++ b/qaesencryption.h @@ -4,6 +4,12 @@ #include #include +#ifdef __linux__ +#ifndef __LP64__ +#define do_rdtsc _do_rdtsc +#endif +#endif + class QAESEncryption : public QObject { Q_OBJECT @@ -42,6 +48,7 @@ public: 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{ diff --git a/qaesencryption.pro b/qaesencryption.pro index 1e728c1..d5d2ed1 100644 --- a/qaesencryption.pro +++ b/qaesencryption.pro @@ -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 + # You can also make your code fail to compile if you use deprecated APIs. # In order to do so, uncomment the following line. # You can also select to disable deprecated APIs only up to a certain version of Qt. @@ -26,7 +25,14 @@ DEFINES += QT_DEPRECATED_WARNINGS HEADERS += \ qaesencryption.h \ - unit_test/aestest.h + unit_test/aestest.h \ + +SOURCES += main.cpp \ + qaesencryption.cpp \ + unit_test/aestest.cpp \ + aesni/aesni-key-exp.c \ + aesni/aesni-enc-ecb.c \ + aesni/aesni-enc-cbc.c DISTFILES += \ unit_test/longText.txt diff --git a/unit_test/aestest.cpp b/unit_test/aestest.cpp index 39080ca..e083e00 100644 --- a/unit_test/aestest.cpp +++ b/unit_test/aestest.cpp @@ -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]); } + } From 74643b2570702f7264bdffa73cf55547b3fc1115 Mon Sep 17 00:00:00 2001 From: Matteo Brichese Date: Fri, 15 May 2020 16:58:38 -0700 Subject: [PATCH 3/5] updated readme after aesni merge --- README.md | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 1e24099..799114c 100644 --- a/README.md +++ b/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 @@ -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) From a22e7bd5f903c4e67669f6e5b71d65d1841a1e43 Mon Sep 17 00:00:00 2001 From: Ilya Chesalin Date: Sat, 16 May 2020 03:28:30 +0300 Subject: [PATCH 4/5] Fixed invShiftRows in Shift 3 (#30) This must be broken. The indices of iterable inside shift 3 seem random and do not correspond to the AES algorighm. More than that, it should be reversed from shiftRows methods, and shifts 1 and 2 seem normal. --- qaesencryption.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/qaesencryption.cpp b/qaesencryption.cpp index 6461dd1..4a3cd56 100644 --- a/qaesencryption.cpp +++ b/qaesencryption.cpp @@ -391,11 +391,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) From 0ddf76d59a415f2d65263296e48cefe4a6694383 Mon Sep 17 00:00:00 2001 From: Oleg Derevenetz Date: Wed, 9 Sep 2020 22:39:11 +0300 Subject: [PATCH 5/5] Minor improvements (#33) * Pass expKey parameter of addRoundKey() by const reference to avoid unnecessary copy. * Use C++11 nullptr instead of NULL, make it clear that default value of iv parameter in encode() and decode() is empty QByteArray instead of implicit conversion from null pointer via QByteArray(const char *, int = -1) constructor. * Change parameter names in declarations of cipher(), invCipher() and byteXor() to match definitions. * Convert AES-NI-related files to headers, place functions with internal linkage to anonymous namespace to avoid exporting them, don't use inline specifier (inline keyword have different meaning in C++ rather than in C). * Use char literals instead of implementation-defined int-to-signed-char conversions where possible. * Set default value for padding argument in static RemovePadding() to match sample in README. --- README.md | 4 +- aesni/{aesni-enc-cbc.c => aesni-enc-cbc.h} | 123 +++---- aesni/{aesni-enc-ecb.c => aesni-enc-ecb.h} | 119 ++++--- aesni/{aesni-key-exp.c => aesni-key-exp.h} | 395 +++++++++++---------- qaesencryption.cpp | 41 ++- qaesencryption.h | 18 +- qaesencryption.pro | 11 +- 7 files changed, 361 insertions(+), 350 deletions(-) rename aesni/{aesni-enc-cbc.c => aesni-enc-cbc.h} (93%) mode change 100755 => 100644 rename aesni/{aesni-enc-ecb.c => aesni-enc-ecb.h} (94%) mode change 100755 => 100644 rename aesni/{aesni-key-exp.c => aesni-key-exp.h} (92%) mode change 100755 => 100644 diff --git a/README.md b/README.md index 799114c..0a6d05a 100644 --- a/README.md +++ b/README.md @@ -10,12 +10,12 @@ AES-NI support for all key sizes - ECB, CBC 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 diff --git a/aesni/aesni-enc-cbc.c b/aesni/aesni-enc-cbc.h old mode 100755 new mode 100644 similarity index 93% rename from aesni/aesni-enc-cbc.c rename to aesni/aesni-enc-cbc.h index 5efceb1..4328c66 --- a/aesni/aesni-enc-cbc.c +++ b/aesni/aesni-enc-cbc.h @@ -1,60 +1,63 @@ -#include - -#ifdef __cplusplus -extern "C" { -#endif - -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 + +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 - -#ifdef __cplusplus -extern "C" { -#endif - -/* 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 + +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 - -#ifdef __cplusplus -extern "C" { -#endif - -#define cpuid(func, ax, bx, cx, dx)\ - __asm__ __volatile__("cpuid": "=a" (ax), "=b" (bx), "=c" (cx), "=d" (dx) : "a" (func)); - -inline bool check_aesni_support() -{ - unsigned int a,b,c,d; - cpuid(1, a,b,c,d); - return (c & 0x2000000); -} -inline __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; -} - -inline 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; -} - -inline 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); -} - -inline 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; -} -#ifdef __cplusplus -} -#endif +#ifndef AESNIKEYEXP_H +#define AESNIKEYEXP_H + +#include + +#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 diff --git a/qaesencryption.cpp b/qaesencryption.cpp index 4a3cd56..9103fb8 100644 --- a/qaesencryption.cpp +++ b/qaesencryption.cpp @@ -3,9 +3,9 @@ #include #ifdef USE_INTEL_AES_IF_AVAILABLE -#include "aesni/aesni-key-exp.c" -#include "aesni/aesni-enc-ecb.c" -#include "aesni/aesni-enc-cbc.c" +#include "aesni/aesni-key-exp.h" +#include "aesni/aesni-enc-ecb.h" +#include "aesni/aesni-enc-cbc.h" #endif /* @@ -61,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(0x80)) + if (ret.at(marker_index) == '\x80') { ret.truncate(marker_index); } @@ -78,30 +78,33 @@ 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_aesNIAvailable(false), m_state(nullptr) { - m_state = NULL; - #ifdef USE_INTEL_AES_IF_AVAILABLE m_aesNIAvailable = check_aesni_support(); #endif @@ -158,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); @@ -266,7 +269,7 @@ QByteArray QAESEncryption::expandKey(const QByteArray &key) // 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) @@ -480,7 +483,7 @@ QByteArray QAESEncryption::printArray(uchar* arr, int size) 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 expandedKey = expandKey(key); @@ -570,7 +573,7 @@ QByteArray QAESEncryption::encode(const QByteArray &rawText, const QByteArray &k 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; diff --git a/qaesencryption.h b/qaesencryption.h index 4f3165e..45ba570 100644 --- a/qaesencryption.h +++ b/qaesencryption.h @@ -34,17 +34,17 @@ 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); @@ -90,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(); @@ -98,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 diff --git a/qaesencryption.pro b/qaesencryption.pro index d5d2ed1..16a1151 100644 --- a/qaesencryption.pro +++ b/qaesencryption.pro @@ -25,18 +25,17 @@ QMAKE_CXXFLAGS += -maes HEADERS += \ qaesencryption.h \ - unit_test/aestest.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 \ - aesni/aesni-key-exp.c \ - aesni/aesni-enc-ecb.c \ - aesni/aesni-enc-cbc.c + unit_test/aestest.cpp DISTFILES += \ unit_test/longText.txt RESOURCES += \ res.qrc -