123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492 |
- #include "QAESEncryption.h"
- /*
- * Static Functions
- * */
- QByteArray QAESEncryption::Crypt(QAESEncryption::AES level, QAESEncryption::MODE mode, const QByteArray &rawText,
- const QByteArray &key, const QByteArray &iv, QAESEncryption::PADDING padding)
- {
- return QAESEncryption(level, mode, padding).encode(rawText, key, iv);
- }
- QByteArray QAESEncryption::Decrypt(QAESEncryption::AES level, QAESEncryption::MODE mode, const QByteArray &rawText,
- const QByteArray &key, const QByteArray &iv, QAESEncryption::PADDING padding)
- {
- return QAESEncryption(level, mode, padding).decode(rawText, key, iv);
- }
- QByteArray QAESEncryption::ExpandKey(QAESEncryption::AES level, QAESEncryption::MODE mode, const QByteArray &key)
- {
- return QAESEncryption(level, mode).expandKey(key);
- }
- QByteArray QAESEncryption::RemovePadding(const QByteArray &rawText, QAESEncryption::PADDING padding)
- {
- QByteArray ret(rawText);
- switch (padding)
- {
- case PADDING::ZERO:
- //Works only if the last byte of the decoded array is not zero
- while (ret.at(ret.length()-1) == 0x00)
- ret.remove(ret.length()-1, 1);
- break;
- case PADDING::PKCS7:
- ret.remove(ret.length() - ret.at(ret.length()-1), ret.at(ret.length()-1));
- break;
- case PADDING::ISO:
- ret.truncate(ret.lastIndexOf(0x80u));
- break;
- default:
- //do nothing
- break;
- }
- return ret;
- }
- /*
- * End Static function declarations
- * */
- /*
- * Inline Functions
- * */
- inline 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)
- * xTime(xTime(xTime(x)))) ^ ((y>>4 & 1) * xTime(xTime(xTime(xTime(x))))));
- }
- /*
- * End Inline functions
- * */
- QAESEncryption::QAESEncryption(QAESEncryption::AES level, QAESEncryption::MODE mode, PADDING padding)
- : m_nb(4), m_blocklen(16), m_level(level), m_mode(mode), m_padding(padding)
- {
- m_state = NULL;
- switch (level)
- {
- case AES_128: {
- AES128 aes;
- m_nk = aes.nk;
- m_keyLen = aes.keylen;
- m_nr = aes.nr;
- m_expandedKey = aes.expandedKey;
- }
- break;
- case AES_192: {
- AES192 aes;
- m_nk = aes.nk;
- m_keyLen = aes.keylen;
- m_nr = aes.nr;
- m_expandedKey = aes.expandedKey;
- }
- break;
- case AES_256: {
- AES256 aes;
- m_nk = aes.nk;
- m_keyLen = aes.keylen;
- m_nr = aes.nr;
- m_expandedKey = aes.expandedKey;
- }
- break;
- default: {
- AES128 aes;
- m_nk = aes.nk;
- m_keyLen = aes.keylen;
- m_nr = aes.nr;
- m_expandedKey = aes.expandedKey;
- }
- break;
- }
- }
- QByteArray QAESEncryption::getPadding(int currSize, int alignment)
- {
- QByteArray ret(0);
- int size = (alignment - currSize % alignment) % alignment;
- if (size == 0) return ret;
- switch(m_padding)
- {
- case PADDING::ZERO:
- ret.insert(0, size, 0x00);
- break;
- case PADDING::PKCS7:
- ret.insert(0, size, size);
- break;
- case PADDING::ISO:
- ret.insert(0, 0x80u);
- ret.insert(1, size, 0x00);
- break;
- default:
- ret.insert(0, size, 0x00);
- break;
- }
- return ret;
- }
- 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.
- // ...
- // 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);
- 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]
- // 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;
- }
- // 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)
- {
- QByteArray::iterator it = m_state->begin();
- for(int i=0; i < 16; ++i)
- it[i] = (quint8) it[i] ^ (quint8) expKey.at(round * m_nb * 4 + (i/4) * m_nb + (i%4));
- }
- // The SubBytes Function Substitutes the values in the
- // state matrix with values in an S-box.
- void QAESEncryption::subBytes()
- {
- QByteArray::iterator it = m_state->begin();
- for(int i = 0; i < 16; i++)
- it[i] = getSBoxValue((quint8) it[i]);
- }
- // The ShiftRows() function shifts the rows in the state to the left.
- // Each row is shifted with different offset.
- // Offset = Row number. So the first row is not shifted.
- void QAESEncryption::shiftRows()
- {
- QByteArray::iterator it = m_state->begin();
- quint8 temp;
- //Keep in mind that QByteArray is column-driven!!
- //Shift 1 to left
- temp = (quint8)it[1];
- it[1] = (quint8)it[5];
- it[5] = (quint8)it[9];
- it[9] = (quint8)it[13];
- it[13] = (quint8)temp;
- //Shift 2 to left
- temp = (quint8)it[2];
- it[2] = (quint8)it[10];
- it[10] = (quint8)temp;
- temp = (quint8)it[6];
- it[6] = (quint8)it[14];
- it[14] = (quint8)temp;
- //Shift 3 to left
- temp = (quint8)it[3];
- it[3] = (quint8)it[15];
- it[15] = (quint8)it[11];
- it[11] = (quint8)it[7];
- it[7] = (quint8)temp;
- }
- // MixColumns function mixes the columns of the state matrix
- //optimized!!
- void QAESEncryption::mixColumns()
- {
- QByteArray::iterator it = m_state->begin();
- quint8 tmp, tm, t;
- for(int i = 0; i < 16; i += 4){
- t = (quint8)it[i];
- tmp = (quint8)it[i] ^ (quint8)it[i+1] ^ (quint8)it[i+2] ^ (quint8)it[i+3] ;
- tm = xTime( (quint8)it[i] ^ (quint8)it[i+1] );
- it[i] = (quint8)it[i] ^ (quint8)tm ^ (quint8)tmp;
- tm = xTime( (quint8)it[i+1] ^ (quint8)it[i+2]);
- it[i+1] = (quint8)it[i+1] ^ (quint8)tm ^ (quint8)tmp;
- tm = xTime( (quint8)it[i+2] ^ (quint8)it[i+3]);
- it[i+2] =(quint8)it[i+2] ^ (quint8)tm ^ (quint8)tmp;
- tm = xTime((quint8)it[i+3] ^ (quint8)t);
- it[i+3] =(quint8)it[i+3] ^ (quint8)tm ^ (quint8)tmp;
- }
- }
- // MixColumns function mixes the columns of the state matrix.
- // The method used to multiply may be difficult to understand for the inexperienced.
- // Please use the references to gain more information.
- void QAESEncryption::invMixColumns()
- {
- QByteArray::iterator it = m_state->begin();
- quint8 a,b,c,d;
- for(int i = 0; i < 16; i+=4){
- a = (quint8) it[i];
- b = (quint8) it[i+1];
- c = (quint8) it[i+2];
- d = (quint8) it[i+3];
- it[i] = (quint8) (multiply(a, 0x0e) ^ multiply(b, 0x0b) ^ multiply(c, 0x0d) ^ multiply(d, 0x09));
- it[i+1] = (quint8) (multiply(a, 0x09) ^ multiply(b, 0x0e) ^ multiply(c, 0x0b) ^ multiply(d, 0x0d));
- it[i+2] = (quint8) (multiply(a, 0x0d) ^ multiply(b, 0x09) ^ multiply(c, 0x0e) ^ multiply(d, 0x0b));
- it[i+3] = (quint8) (multiply(a, 0x0b) ^ multiply(b, 0x0d) ^ multiply(c, 0x09) ^ multiply(d, 0x0e));
- }
- }
- // The SubBytes Function Substitutes the values in the
- // state matrix with values in an S-box.
- void QAESEncryption::invSubBytes()
- {
- QByteArray::iterator it = m_state->begin();
- for(int i = 0; i < 16; ++i)
- it[i] = getSBoxInvert((quint8) it[i]);
- }
- void QAESEncryption::invShiftRows()
- {
- QByteArray::iterator it = m_state->begin();
- uint8_t temp;
- //Keep in mind that QByteArray is column-driven!!
- //Shift 1 to right
- temp = (quint8)it[13];
- it[13] = (quint8)it[9];
- it[9] = (quint8)it[5];
- it[5] = (quint8)it[1];
- it[1] = (quint8)temp;
- //Shift 2
- temp = (quint8)it[10];
- it[10] = (quint8)it[2];
- it[2] = (quint8)temp;
- temp = (quint8)it[14];
- it[14] = (quint8)it[6];
- it[6] = (quint8)temp;
- //Shift 3
- temp = (quint8)it[15];
- it[15] = (quint8)it[3];
- it[3] = (quint8)it[7];
- it[7] = (quint8)it[11];
- it[11] = (quint8)temp;
- }
- QByteArray QAESEncryption::byteXor(const QByteArray &a, const QByteArray &b)
- {
- QByteArray::const_iterator it_a = a.begin();
- QByteArray::const_iterator it_b = b.begin();
- QByteArray ret;
- for(int i = 0; i < m_blocklen; i++)
- ret.insert(i,it_a[i] ^ it_b[i]);
- return ret;
- }
- // Cipher is the main function that encrypts the PlainText.
- QByteArray QAESEncryption::cipher(const QByteArray &expKey, const QByteArray &in)
- {
- //m_state is the input buffer...
- QByteArray output(in);
- m_state = &output;
- // Add the First round key to the state before starting the rounds.
- addRoundKey(0, expKey);
- // There will be Nr rounds.
- // The first Nr-1 rounds are identical.
- // These Nr-1 rounds are executed in the loop below.
- for(quint8 round = 1; round < m_nr; ++round){
- subBytes();
- shiftRows();
- mixColumns();
- addRoundKey(round, expKey);
- }
- // The last round is given below.
- // The MixColumns function is not here in the last round.
- subBytes();
- shiftRows();
- addRoundKey(m_nr, expKey);
- return output;
- }
- QByteArray QAESEncryption::invCipher(const QByteArray &expKey, const QByteArray &in)
- {
- //m_state is the input buffer.... handle it!
- QByteArray output(in);
- m_state = &output;
- // Add the First round key to the state before starting the rounds.
- addRoundKey(m_nr, expKey);
- // There will be Nr rounds.
- // The first Nr-1 rounds are identical.
- // These Nr-1 rounds are executed in the loop below.
- for(quint8 round=m_nr-1; round>0 ; round--){
- invShiftRows();
- invSubBytes();
- addRoundKey(round, expKey);
- invMixColumns();
- }
- // The last round is given below.
- // The MixColumns function is not here in the last round.
- invShiftRows();
- invSubBytes();
- addRoundKey(0, expKey);
- return output;
- }
- QByteArray QAESEncryption::encode(const QByteArray &rawText, const QByteArray &key, const QByteArray &iv)
- {
- if (m_mode >= CBC && (iv.isNull() || iv.size() != m_blocklen))
- return QByteArray();
- QByteArray ret;
- QByteArray expandedKey = expandKey(key);
- QByteArray alignedText(rawText);
- QByteArray ivTemp(iv);
- //Fill array with padding
- alignedText.append(getPadding(rawText.size(), m_blocklen));
- //Preparation for CFB
- if (m_mode == CFB)
- ret.append(byteXor(alignedText.mid(0, m_blocklen), cipher(expandedKey, iv)));
- //Looping thru all blocks
- for(int i=0; i < alignedText.size(); i+= m_blocklen){
- switch(m_mode)
- {
- case ECB:
- ret.append(cipher(expandedKey, alignedText.mid(i, m_blocklen)));
- break;
- case CBC:
- 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);
- break;
- case CFB:
- if (i+m_blocklen < alignedText.size())
- ret.append(byteXor(alignedText.mid(i+m_blocklen, m_blocklen),
- cipher(expandedKey, ret.mid(i, m_blocklen))));
- break;
- default:
- //do nothing
- break;
- }
- }
- return ret;
- }
- QByteArray QAESEncryption::decode(const QByteArray &rawText, const QByteArray &key, const QByteArray &iv)
- {
- if (m_mode >= CBC && (iv.isNull() || iv.size() != m_blocklen))
- return QByteArray();
- QByteArray ret;
- QByteArray expandedKey = expandKey(key);
- QByteArray ivTemp(iv);
- //Preparation for CFB
- if (m_mode == CFB)
- ret.append(byteXor(rawText.mid(0, m_blocklen), cipher(expandedKey, iv)));
- for(int i=0; i < rawText.size(); i+= m_blocklen){
- switch(m_mode)
- {
- case ECB:
- ret.append(invCipher(expandedKey, rawText.mid(i, m_blocklen)));
- break;
- case CBC:
- ret.append(invCipher(expandedKey, rawText.mid(i, m_blocklen)));
- ret.replace(i, m_blocklen, byteXor(ret.mid(i, m_blocklen),ivTemp));
- ivTemp = rawText.mid(i, m_blocklen);
- break;
- case CFB:
- if (i+m_blocklen < rawText.size()){
- ret.append(byteXor(rawText.mid(i+m_blocklen, m_blocklen),
- cipher(expandedKey, rawText.mid(i, m_blocklen))));
- }
- break;
- default:
- //do nothing
- break;
- }
- }
- return ret;
- }
- QByteArray QAESEncryption::removePadding(const QByteArray &rawText)
- {
- QByteArray ret(rawText);
- switch (m_padding)
- {
- case PADDING::ZERO:
- //Works only if the last byte of the decoded array is not zero
- while (ret.at(ret.length()-1) == 0x00)
- ret.remove(ret.length()-1, 1);
- break;
- case PADDING::PKCS7:
- ret.remove(ret.length() - ret.at(ret.length()-1), ret.at(ret.length()-1));
- break;
- case PADDING::ISO:
- ret.truncate(ret.lastIndexOf(0x80u));
- break;
- default:
- //do nothing
- break;
- }
- return ret;
- }
|