33#include < QDebug>
44#include < openssl/rand.h>
55#include < openssl/evp.h>
6- #include < sodium.h> // Ensure Sodium library is included
6+ #include < sodium.h>
77
88bool EncryptionEngine::cryptOperation (const QString& inputPath, const QString& outputPath, const QString& password, const QString& algorithm, bool encrypt, const QString& kdf, int iterations, bool useHMAC, const QString& customHeader, const QStringList& keyfilePaths) {
9+ qDebug () << " Starting cryptOperation..." ;
10+ qDebug () << " Encrypt mode:" << encrypt;
11+ qDebug () << " Input file:" << inputPath;
12+ qDebug () << " Output file:" << outputPath;
13+ qDebug () << " Algorithm:" << algorithm;
14+ qDebug () << " KDF:" << kdf;
15+ qDebug () << " Iterations:" << iterations;
16+ qDebug () << " Use HMAC:" << useHMAC;
17+
918 QFile inputFile (inputPath);
1019 QFile outputFile (outputPath);
1120
1221 if (!inputFile.open (QIODevice::ReadOnly)) {
13- qDebug () << " Failed to open input file" ;
22+ qDebug () << " Failed to open input file: " << inputPath ;
1423 return false ;
1524 }
1625
1726 if (!outputFile.open (QIODevice::WriteOnly)) {
18- qDebug () << " Failed to open output file" ;
27+ qDebug () << " Failed to open output file: " << outputPath ;
1928 return false ;
2029 }
2130
2231 const EVP_CIPHER* cipher = getCipher (algorithm);
2332 if (!cipher) {
24- qDebug () << " Invalid algorithm" ;
33+ qDebug () << " Invalid algorithm: " << algorithm ;
2534 return false ;
2635 }
2736
2837 int ivLength = EVP_CIPHER_iv_length (cipher);
2938 QByteArray iv (ivLength, 0 );
30- QByteArray salt (16 , 0 );
39+ QByteArray salt (32 , 0 );
3140
3241 if (encrypt) {
33- RAND_bytes (reinterpret_cast <unsigned char *>(iv.data ()), ivLength);
3442 RAND_bytes (reinterpret_cast <unsigned char *>(salt.data ()), salt.size ());
35- outputFile.write (customHeader.toUtf8 ());
36- outputFile.write (salt);
37- outputFile.write (iv);
38- lastIv = iv; // Store the last used IV
43+ RAND_bytes (reinterpret_cast <unsigned char *>(iv.data ()), ivLength);
3944 } else {
40- QByteArray header (customHeader.size (), 0 );
41- if (inputFile.read (header.data (), customHeader.size ()) != customHeader.size () || header != customHeader.toUtf8 ()) {
42- qDebug () << " Failed to read or validate custom header" ;
45+ inputFile.seek (customHeader.size ()); // Skip the custom header
46+ if (inputFile.read (salt.data (), salt.size ()) != salt.size ()) {
47+ qDebug () << " Failed to read salt from input file" ;
48+ inputFile.close ();
4349 return false ;
4450 }
45- inputFile.read (salt.data (), salt.size ());
46- inputFile.read (iv.data (), iv.size ());
47- lastIv = iv; // Store the last used IV
4851 }
4952
53+ qDebug () << " Deriving key..." ;
5054 QByteArray key = deriveKey (password, salt, keyfilePaths, kdf, iterations);
5155
5256 if (key.isEmpty ()) {
57+ qDebug () << " Key derivation failed." ;
5358 return false ;
5459 }
5560
@@ -66,14 +71,29 @@ bool EncryptionEngine::cryptOperation(const QString& inputPath, const QString& o
6671 }
6772
6873 bool success = false ;
74+
6975 if (encrypt) {
76+ outputFile.write (customHeader.toUtf8 ());
77+ outputFile.write (salt);
78+ outputFile.write (iv);
7079 success = useHMAC ? performAuthenticatedEncryption (ctx, cipher, key, iv, inputFile, outputFile)
7180 : performStandardEncryption (ctx, cipher, key, iv, inputFile, outputFile);
7281 } else {
82+ QByteArray header (customHeader.size (), 0 );
83+ if (inputFile.read (header.data (), customHeader.size ()) != customHeader.size () || header != customHeader.toUtf8 ()) {
84+ qDebug () << " Failed to read or validate custom header" ;
85+ return false ;
86+ }
87+ inputFile.seek (customHeader.size () + salt.size ()); // Skip header and salt
88+ inputFile.read (iv.data (), iv.size ());
7389 success = useHMAC ? performAuthenticatedDecryption (ctx, cipher, key, iv, inputFile, outputFile)
7490 : performStandardDecryption (ctx, cipher, key, iv, inputFile, outputFile);
7591 }
7692
93+ if (!success) {
94+ qDebug () << " Encryption/Decryption process failed." ;
95+ }
96+
7797 EVP_CIPHER_CTX_free (ctx);
7898 inputFile.close ();
7999 outputFile.close ();
@@ -87,34 +107,41 @@ bool EncryptionEngine::cryptOperation(const QString& inputPath, const QString& o
87107}
88108
89109bool EncryptionEngine::performStandardEncryption (EVP_CIPHER_CTX* ctx, const EVP_CIPHER* cipher, const QByteArray& key, const QByteArray& iv, QFile& inputFile, QFile& outputFile) {
90- if (!EVP_EncryptInit_ex (ctx, cipher, nullptr , reinterpret_cast <const unsigned char *>(key.data ()), reinterpret_cast <const unsigned char *>(iv.data ()))) {
110+ // Initialize encryption operation
111+ if (1 != EVP_EncryptInit_ex (ctx, cipher, nullptr , reinterpret_cast <const unsigned char *>(key.data ()), reinterpret_cast <const unsigned char *>(iv.data ()))) {
91112 qDebug () << " EVP_EncryptInit_ex failed" ;
92113 return false ;
93114 }
94115
95116 QByteArray buffer (4096 , 0 );
96- QByteArray outputBuffer (4096 + EVP_CIPHER_block_size (cipher), 0 );
97- int outLen;
98-
117+ QByteArray outBuf (4096 + EVP_CIPHER_block_size (cipher), 0 );
118+ int outLen = 0 ;
119+
99120 while (!inputFile.atEnd ()) {
100121 int inLen = inputFile.read (buffer.data (), buffer.size ());
101- if (! EVP_EncryptUpdate (ctx, reinterpret_cast <unsigned char *>(outputBuffer .data ()), &outLen, reinterpret_cast <unsigned char *>(buffer.data ()), inLen)) {
122+ if (1 != EVP_EncryptUpdate (ctx, reinterpret_cast <unsigned char *>(outBuf .data ()), &outLen, reinterpret_cast <const unsigned char *>(buffer.data ()), inLen)) {
102123 qDebug () << " EVP_EncryptUpdate failed" ;
103124 return false ;
104125 }
105- outputFile.write (outputBuffer .data (), outLen);
126+ outputFile.write (outBuf .data (), outLen);
106127 }
107128
108- if (!EVP_EncryptFinal_ex (ctx, reinterpret_cast <unsigned char *>(outputBuffer.data ()), &outLen)) {
129+ // Finalize encryption
130+ if (1 != EVP_EncryptFinal_ex (ctx, reinterpret_cast <unsigned char *>(outBuf.data ()), &outLen)) {
109131 qDebug () << " EVP_EncryptFinal_ex failed" ;
110132 return false ;
111133 }
112- outputFile.write (outputBuffer .data (), outLen);
134+ outputFile.write (outBuf .data (), outLen);
113135
114136 return true ;
115137}
116138
117139bool EncryptionEngine::performStandardDecryption (EVP_CIPHER_CTX* ctx, const EVP_CIPHER* cipher, const QByteArray& key, const QByteArray& iv, QFile& inputFile, QFile& outputFile) {
140+ qDebug () << " Starting decryption process..." ;
141+ qDebug () << " Key (Hex):" << key.toHex ();
142+ qDebug () << " IV (Hex):" << iv.toHex ();
143+
144+ // Initialize the decryption operation
118145 if (!EVP_DecryptInit_ex (ctx, cipher, nullptr , reinterpret_cast <const unsigned char *>(key.data ()), reinterpret_cast <const unsigned char *>(iv.data ()))) {
119146 qDebug () << " EVP_DecryptInit_ex failed" ;
120147 return false ;
@@ -143,74 +170,106 @@ bool EncryptionEngine::performStandardDecryption(EVP_CIPHER_CTX* ctx, const EVP_
143170}
144171
145172bool EncryptionEngine::performAuthenticatedEncryption (EVP_CIPHER_CTX* ctx, const EVP_CIPHER* cipher, const QByteArray& key, const QByteArray& iv, QFile& inputFile, QFile& outputFile) {
146- QByteArray tag (16 , 0 );
173+ QByteArray tag (16 , 0 ); // GCM mode requires a 16-byte tag
174+
175+ // Initialize encryption operation
147176 if (!EVP_EncryptInit_ex (ctx, cipher, nullptr , reinterpret_cast <const unsigned char *>(key.data ()), reinterpret_cast <const unsigned char *>(iv.data ()))) {
148177 qDebug () << " EVP_EncryptInit_ex failed" ;
149178 return false ;
150179 }
151180
152- QByteArray buffer (4096 , 0 );
153- QByteArray outputBuffer (4096 + EVP_CIPHER_block_size (cipher), 0 );
154- int outLen;
181+ QByteArray buffer (4096 , 0 ); // Input buffer
182+ QByteArray outputBuffer; // Output buffer
155183
184+ // Encrypt the data in chunks
156185 while (!inputFile.atEnd ()) {
157- int inLen = inputFile.read (buffer.data (), buffer.size ());
158- if (!EVP_EncryptUpdate (ctx, reinterpret_cast <unsigned char *>(outputBuffer.data ()), &outLen, reinterpret_cast <unsigned char *>(buffer.data ()), inLen)) {
186+ qint64 bytesRead = inputFile.read (buffer.data (), buffer.size ());
187+ if (bytesRead <= 0 ) break ;
188+
189+ outputBuffer.resize (bytesRead + EVP_CIPHER_block_size (cipher));
190+ int outLen;
191+
192+ if (!EVP_EncryptUpdate (ctx, reinterpret_cast <unsigned char *>(outputBuffer.data ()), &outLen,
193+ reinterpret_cast <const unsigned char *>(buffer.constData ()), bytesRead)) {
159194 qDebug () << " EVP_EncryptUpdate failed" ;
160195 return false ;
161196 }
162- outputFile.write (outputBuffer.data (), outLen);
197+
198+ outputFile.write (outputBuffer.constData (), outLen);
163199 }
164200
201+ // Finalize the encryption
202+ outputBuffer.resize (EVP_CIPHER_block_size (cipher));
203+ int outLen;
165204 if (!EVP_EncryptFinal_ex (ctx, reinterpret_cast <unsigned char *>(outputBuffer.data ()), &outLen)) {
166205 qDebug () << " EVP_EncryptFinal_ex failed" ;
167206 return false ;
168207 }
169- outputFile.write (outputBuffer.data (), outLen);
170208
209+ if (outLen > 0 ) {
210+ outputFile.write (outputBuffer.constData (), outLen);
211+ }
212+
213+ // Get the tag
171214 if (!EVP_CIPHER_CTX_ctrl (ctx, EVP_CTRL_GCM_GET_TAG, tag.size (), tag.data ())) {
172215 qDebug () << " EVP_CIPHER_CTX_ctrl(EVP_CTRL_GCM_GET_TAG) failed" ;
173216 return false ;
174217 }
218+
219+ // Append the tag to the end of the file
175220 outputFile.write (tag);
176221
177222 return true ;
178223}
179224
180225bool EncryptionEngine::performAuthenticatedDecryption (EVP_CIPHER_CTX* ctx, const EVP_CIPHER* cipher, const QByteArray& key, const QByteArray& iv, QFile& inputFile, QFile& outputFile) {
181- QByteArray tag (16 , 0 );
182- inputFile.seek (inputFile.size () - tag.size ());
183- inputFile.read (tag.data (), tag.size ());
184- inputFile.seek (0 );
226+ QByteArray tag (16 , 0 ); // GCM mode requires a 16-byte tag
227+
228+ // Read the entire encrypted content
229+ QByteArray encryptedContent = inputFile.readAll ();
230+
231+ // The last 16 bytes should be the tag
232+ if (encryptedContent.size () < 16 ) {
233+ qDebug () << " Encrypted content is too short" ;
234+ return false ;
235+ }
185236
237+ tag = encryptedContent.right (16 );
238+ encryptedContent.chop (16 ); // Remove the tag from the encrypted content
239+
240+ qDebug () << " Tag read for decryption (Hex):" << tag.toHex ();
241+
242+ // Initialize decryption operation
186243 if (!EVP_DecryptInit_ex (ctx, cipher, nullptr , reinterpret_cast <const unsigned char *>(key.data ()), reinterpret_cast <const unsigned char *>(iv.data ()))) {
187244 qDebug () << " EVP_DecryptInit_ex failed" ;
188245 return false ;
189246 }
190247
191- QByteArray buffer (4096 , 0 );
192- QByteArray outputBuffer (4096 + EVP_CIPHER_block_size (cipher), 0 );
248+ QByteArray outputBuffer (encryptedContent.size () + EVP_CIPHER_block_size (cipher), 0 );
193249 int outLen;
194250
195- while (inputFile.pos () < inputFile.size () - tag.size ()) {
196- int inLen = inputFile.read (buffer.data (), buffer.size ());
197- if (!EVP_DecryptUpdate (ctx, reinterpret_cast <unsigned char *>(outputBuffer.data ()), &outLen, reinterpret_cast <unsigned char *>(buffer.data ()), inLen)) {
198- qDebug () << " EVP_DecryptUpdate failed" ;
199- return false ;
200- }
201- outputFile.write (outputBuffer.data (), outLen);
251+ // Decrypt the data
252+ if (!EVP_DecryptUpdate (ctx, reinterpret_cast <unsigned char *>(outputBuffer.data ()), &outLen,
253+ reinterpret_cast <const unsigned char *>(encryptedContent.constData ()), encryptedContent.size ())) {
254+ qDebug () << " EVP_DecryptUpdate failed" ;
255+ return false ;
202256 }
203257
258+ // Set the expected tag
204259 if (!EVP_CIPHER_CTX_ctrl (ctx, EVP_CTRL_GCM_SET_TAG, tag.size (), tag.data ())) {
205260 qDebug () << " EVP_CIPHER_CTX_ctrl(EVP_CTRL_GCM_SET_TAG) failed" ;
206261 return false ;
207262 }
208263
209- if (!EVP_DecryptFinal_ex (ctx, reinterpret_cast <unsigned char *>(outputBuffer.data ()), &outLen)) {
210- qDebug () << " EVP_DecryptFinal_ex failed" ;
264+ int tmpLen;
265+ // Finalize the decryption and check the tag
266+ if (!EVP_DecryptFinal_ex (ctx, reinterpret_cast <unsigned char *>(outputBuffer.data ()) + outLen, &tmpLen)) {
267+ qDebug () << " EVP_DecryptFinal_ex failed - authentication failure" ;
211268 return false ;
212269 }
213- outputFile.write (outputBuffer.data (), outLen);
270+
271+ outLen += tmpLen;
272+ outputFile.write (outputBuffer.constData (), outLen);
214273
215274 return true ;
216275}
0 commit comments