File indexing completed on 2024-05-12 04:58:25
0001 /* ============================================================ 0002 * Falkon - Qt web browser 0003 * Copyright (C) 2013-2014 S. Razi Alavizadeh <s.r.alavizadeh@gmail.com> 0004 * Copyright (C) 2013-2017 David Rosca <nowrep@gmail.com> 0005 * 0006 * This is based on a work by Saju Pillai <saju.pillai@gmail.com> 0007 * 0008 * This program is free software: you can redistribute it and/or modify 0009 * it under the terms of the GNU General Public License as published by 0010 * the Free Software Foundation, either version 3 of the License, or 0011 * (at your option) any later version. 0012 * 0013 * This program is distributed in the hope that it will be useful, 0014 * but WITHOUT ANY WARRANTY; without even the implied warranty of 0015 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 0016 * GNU General Public License for more details. 0017 * 0018 * You should have received a copy of the GNU General Public License 0019 * along with this program. If not, see <http://www.gnu.org/licenses/>. 0020 * ============================================================ */ 0021 0022 #include "aesinterface.h" 0023 0024 #include <openssl/aes.h> 0025 #include <openssl/rand.h> 0026 #include <openssl/sha.h> 0027 0028 #include <QCryptographicHash> 0029 #include <QByteArray> 0030 #include <QMessageBox> 0031 0032 ////////////////////////////////////////////// 0033 /// Version 1: 0034 /// init(): n=5, EVP_CIPHER=EVP_aes_256_cbc(), EVP_MD=EVP_sha256(), Random IV 0035 /// Encrypted data structure: Version$InitializationVector_base64$EncryptedData_base64 0036 const int AesInterface::VERSION = 1; 0037 0038 AesInterface::AesInterface(QObject* parent) 0039 : QObject(parent) 0040 { 0041 m_encodeCTX = EVP_CIPHER_CTX_new(); 0042 m_decodeCTX = EVP_CIPHER_CTX_new(); 0043 EVP_CIPHER_CTX_init(m_encodeCTX); 0044 EVP_CIPHER_CTX_init(m_decodeCTX); 0045 } 0046 0047 AesInterface::~AesInterface() 0048 { 0049 EVP_CIPHER_CTX_cleanup(m_encodeCTX); 0050 EVP_CIPHER_CTX_cleanup(m_decodeCTX); 0051 EVP_CIPHER_CTX_free(m_encodeCTX); 0052 EVP_CIPHER_CTX_free(m_decodeCTX); 0053 } 0054 0055 bool AesInterface::isOk() const 0056 { 0057 return m_ok; 0058 } 0059 0060 // Create an 256 bit 'key' using the supplied password, and creates a random 'iv'. 0061 // saltArray is an array of 8 bytes can be added for taste. 0062 // Fills in the encryption and decryption ctx objects and returns true on success 0063 bool AesInterface::init(int evpMode, const QByteArray &password, const QByteArray &iVector) 0064 { 0065 m_iVector.clear(); 0066 0067 int i; 0068 const int nrounds = 5; 0069 uchar key[EVP_MAX_KEY_LENGTH]; 0070 0071 // Gen "key" for AES 256 CBC mode. A SHA1 digest is used to hash the supplied 0072 // key material. nrounds is the number of times that we hash the material. 0073 // More rounds are more secure but slower. 0074 i = EVP_BytesToKey(EVP_aes_256_cbc(), EVP_sha256(), nullptr, (uchar*)password.data(), password.size(), nrounds, key, nullptr); 0075 0076 if (i != 32) { 0077 qWarning("Key size is %d bits - should be 256 bits", i * 8); 0078 return false; 0079 } 0080 0081 int result = 0; 0082 if (evpMode == EVP_PKEY_MO_ENCRYPT) { 0083 m_iVector = createRandomData(EVP_MAX_IV_LENGTH); 0084 result = EVP_EncryptInit_ex(m_encodeCTX, EVP_aes_256_cbc(), NULL, key, (uchar*)m_iVector.constData()); 0085 } 0086 else if (evpMode == EVP_PKEY_MO_DECRYPT) { 0087 result = EVP_DecryptInit_ex(m_decodeCTX, EVP_aes_256_cbc(), NULL, key, (uchar*)iVector.constData()); 0088 } 0089 0090 if (result == 0) { 0091 qWarning("EVP is not initialized!"); 0092 return false; 0093 } 0094 0095 return true; 0096 } 0097 0098 QByteArray AesInterface::encrypt(const QByteArray &plainData, const QByteArray &password) 0099 { 0100 if (!init(EVP_PKEY_MO_ENCRYPT, password)) { 0101 m_ok = false; 0102 return plainData; 0103 } 0104 0105 // max ciphertext len for a n bytes of plaintext is n + AES_BLOCK_SIZE -1 bytes 0106 int dataLength = plainData.size(); 0107 int cipherlength = dataLength + AES_BLOCK_SIZE; 0108 int finalLength = 0; 0109 auto* ciphertext = (uchar*)malloc(cipherlength); 0110 0111 // allows reusing of 'm_encodeCTX' for multiple encryption cycles 0112 EVP_EncryptInit_ex(m_encodeCTX, NULL, NULL, NULL, NULL); 0113 0114 // update ciphertext, c_len is filled with the length of ciphertext generated, 0115 // dataLength is the size of plaintext in bytes 0116 EVP_EncryptUpdate(m_encodeCTX, ciphertext, &cipherlength, (uchar*)plainData.data(), dataLength); 0117 0118 // update ciphertext with the final remaining bytes 0119 EVP_EncryptFinal_ex(m_encodeCTX, ciphertext + cipherlength, &finalLength); 0120 0121 dataLength = cipherlength + finalLength; 0122 QByteArray out((char*)ciphertext, dataLength); 0123 out = QByteArray::number(AesInterface::VERSION) + '$' + m_iVector.toBase64() + '$' + out.toBase64(); 0124 free(ciphertext); 0125 0126 m_ok = true; 0127 return out; 0128 } 0129 0130 QByteArray AesInterface::decrypt(const QByteArray &cipherData, const QByteArray &password) 0131 { 0132 m_ok = false; 0133 0134 if (cipherData.isEmpty()) { 0135 m_ok = true; 0136 return {}; 0137 } 0138 0139 QList<QByteArray> cipherSections(cipherData.split('$')); 0140 if (cipherSections.size() != 3) { 0141 qWarning() << "Decrypt error: It seems data is corrupted"; 0142 return {}; 0143 } 0144 0145 if (cipherSections.at(0).toInt() > AesInterface::VERSION) { 0146 QMessageBox::information(nullptr, tr("Warning!"), tr("Data has been encrypted with a newer version of Falkon." 0147 "\nPlease install latest version of Falkon.")); 0148 return {}; 0149 } 0150 0151 if (cipherSections.at(0).toInt() != 1) { 0152 qWarning() << Q_FUNC_INFO << "There is just version 1 of decoder, yet ;-)"; 0153 return {}; 0154 } 0155 0156 if (!init(EVP_PKEY_MO_DECRYPT, password, QByteArray::fromBase64(cipherSections.at(1)))) { 0157 return {}; 0158 } 0159 0160 QByteArray cipherArray = QByteArray::fromBase64(cipherSections.at(2)); 0161 int cipherLength = cipherArray.size(); 0162 int plainTextLength = cipherLength; 0163 int finalLength = 0; 0164 0165 auto* cipherText = (uchar*)cipherArray.data(); 0166 // because we have padding ON, we must allocate an extra cipher block size of memory 0167 auto* plainText = (uchar*)malloc(plainTextLength + AES_BLOCK_SIZE); 0168 0169 EVP_DecryptInit_ex(m_decodeCTX, NULL, NULL, NULL, NULL); 0170 EVP_DecryptUpdate(m_decodeCTX, plainText, &plainTextLength, cipherText, cipherLength); 0171 int success = EVP_DecryptFinal_ex(m_decodeCTX, plainText + plainTextLength, &finalLength); 0172 0173 cipherLength = plainTextLength + finalLength; 0174 0175 QByteArray result((char*)plainText, cipherLength); 0176 free(plainText); 0177 0178 if (success != 1) { 0179 return {}; 0180 } 0181 0182 m_ok = true; 0183 return result; 0184 } 0185 0186 QByteArray AesInterface::passwordToHash(const QString &masterPassword) 0187 { 0188 if (!masterPassword.isEmpty()) { 0189 QByteArray result = masterPassword.toUtf8(); 0190 result = QCryptographicHash::hash(result, QCryptographicHash::Sha1) + result; 0191 result = QCryptographicHash::hash(result, QCryptographicHash::Sha1); 0192 return result.toBase64(); 0193 } 0194 else { 0195 return {}; 0196 } 0197 } 0198 0199 QByteArray AesInterface::createRandomData(int length) 0200 { 0201 auto* randomData = (uchar*)malloc(length); 0202 0203 RAND_bytes(randomData, length); 0204 QByteArray data((char*)randomData, length); 0205 free(randomData); 0206 0207 return data; 0208 }