Subversion Repositories tpanel

Rev

Rev 476 | Go to most recent revision | Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
475 andreas 1
/*
2
 * Copyright (C) 2024 by Andreas Theofilu <andreas@theosys.at>
3
 *
4
 * This program is free software; you can redistribute it and/or modify
5
 * it under the terms of the GNU General Public License as published by
6
 * the Free Software Foundation; either version 3 of the License, or
7
 * (at your option) any later version.
8
 *
9
 * This program is distributed in the hope that it will be useful,
10
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12
 * GNU General Public License for more details.
13
 *
14
 * You should have received a copy of the GNU General Public License
15
 * along with this program; if not, write to the Free Software Foundation,
16
 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301  USA
17
 */
18
 
19
#include <iostream>
20
#include <fstream>
21
#include <cstring>
22
 
23
#include <openssl/err.h>
24
#include <openssl/evp.h>
25
 
26
#include "tscramble.h"
27
#include "terror.h"
28
 
29
using std::string;
30
using std::ifstream;
31
using std::ios_base;
32
using std::ios;
33
using std::exception;
34
using std::min;
35
using std::cout;
36
using std::cerr;
37
using std::endl;
38
 
39
#define CHUNK_SIZE          1024
40
#define OSSL_SUCCESS        1
41
#define OSSL_ERROR          0
42
static unsigned long ssl_errno;
43
 
44
void _print_ssl_error(unsigned long eno)
45
{
46
    char msg[1024];
47
 
48
    ERR_error_string_n(eno, msg, sizeof(msg));
49
    MSG_ERROR(msg);
50
}
51
 
52
string _get_ssl_error()
53
{
54
    char msg[1024];
55
 
56
    ERR_error_string_n(ssl_errno, msg, sizeof(msg));
57
    return string(msg);
58
}
59
 
60
TScramble::TScramble()
61
{
62
    DECL_TRACER("TScramble::TScramble()");
63
 
64
    mCtx = EVP_CIPHER_CTX_new();
65
 
66
    if (!mCtx)
67
        MSG_ERROR("Error getting new context!");
68
}
69
 
70
TScramble::~TScramble()
71
{
72
    DECL_TRACER("TScramble::~TScramble()");
73
 
74
    if (mCtx)
75
    {
76
        EVP_CIPHER_CTX_cleanup(mCtx);
77
        EVP_CIPHER_CTX_free(mCtx);
78
    }
79
}
80
 
81
bool TScramble::aesInit(const string& key, const string& salt, bool encrypt)
82
{
83
    DECL_TRACER("TScramble::aesInit(const string& key, const string& salt, bool encrypt)");
84
 
85
    if (mAesInitialized)
86
        return true;
87
 
88
    if (!mCtx)
89
    {
90
        MSG_ERROR("ERROR: No context available! Initialisation failed!");
91
        return false;
92
    }
93
 
94
    int keySize;
95
    int count = 5;      // Number iterations
96
 
97
    const EVP_MD *md = EVP_sha1();
98
    const EVP_CIPHER *pCipher = EVP_aes_128_cbc();
99
 
100
    if (!md)
101
    {
102
        MSG_ERROR("Error getting SHA1 hash function!");
103
        return false;
104
    }
105
 
106
    if (!pCipher)
107
    {
108
        MSG_ERROR("Error getting the AES128-CBC cipher algorithm!");
109
        return false;
110
    }
111
 
112
    // If the given salt is less then AES128_SALT_SIZE bytes, we first initialize
113
    // the buffer with 0 bytes. Then the salt is copied into the buffer. This
114
    // guaranties that we have a padding.
115
    memset(mAesSalt, 0, AES128_SALT_SIZE);
116
    memcpy(mAesSalt, salt.c_str(), min((size_t)AES128_SALT_SIZE, salt.length()));
117
    // Initialize the key and IV with 0
118
    memset(mAesKey, 0, AES128_KEY_SIZE);
119
    memset(mAesIV, 0, AES128_KEY_SIZE);
120
 
121
    keySize = EVP_BytesToKey(pCipher, md, mAesSalt, (unsigned char *)key.c_str(), key.length(), count, mAesKey, mAesIV);
122
 
123
    if (keySize == AES128_KEY_SIZE)
124
    {
125
        EVP_CIPHER_CTX_init(mCtx);
126
 
127
        if (encrypt)
128
        {
129
            if ((ssl_errno = EVP_EncryptInit_ex(mCtx, pCipher, nullptr, mAesKey, mAesIV)) != OSSL_SUCCESS)
130
            {
131
                MSG_ERROR("Error initializing: " << _get_ssl_error());
132
                return false;
133
            }
134
        }
135
        else
136
        {
137
            if ((ssl_errno = EVP_DecryptInit_ex(mCtx, pCipher, nullptr, mAesKey, mAesIV)) != OSSL_SUCCESS)
138
            {
139
                MSG_ERROR("Error initializing: " << _get_ssl_error());
140
                return false;
141
            }
142
        }
143
 
144
        EVP_CIPHER_CTX_set_key_length(mCtx, AES128_KEY_SIZE);
145
    }
146
    else
147
    {
148
        MSG_ERROR("Key size is " << (keySize * 8) << " bits - should be 128 bits");
149
        return false;
150
    }
151
 
152
    mAesInitialized = true;
153
    return mAesInitialized;
154
}
155
 
156
bool TScramble::aesDecodeFile(const string& fname)
157
{
158
    DECL_TRACER("TScramble::aesDecodeFile(const string& fname)");
159
 
160
    if (fname.empty())
161
    {
162
        MSG_ERROR("Got no file name to open a file!");
163
        return false;
164
    }
165
 
166
    ifstream ifile;
167
 
168
    try
169
    {
170
        ifile.open(fname, ios::binary);
171
        bool state = aesDecodeFile(ifile);
172
        ifile.close();
173
        return state;
174
    }
175
    catch(exception& e)
176
    {
177
        MSG_ERROR("Error opening file \"" << fname << "\": " << e.what());
178
 
179
        if (ifile.is_open())
180
            ifile.close();
181
    }
182
 
183
    return false;
184
}
185
 
186
bool TScramble::aesDecodeFile(ifstream& is)
187
{
188
    DECL_TRACER("TScramble::aesDecodeFile(ifstream& is)");
189
 
190
    if (!is.is_open())
191
    {
192
        MSG_ERROR("No open file!");
193
        return false;
194
    }
195
 
196
    if (!mAesInitialized || !mCtx)
197
    {
198
        MSG_ERROR("Class was not initialized!");
199
        return false;
200
    }
201
 
202
    mDecrypted.clear();
203
    // Find file size
204
    is.seekg(0, ios_base::end);         // Seek to end of file
205
    size_t fileSize = is.tellg();       // Get current position (file size)
206
    is.seekg(0);                        // Seek to first byte of file
207
    size_t pos = 0;                     // Position (offset) in input and output buffer
208
    // Allocate space for input and output buffers
209
    unsigned char *buffer = new unsigned char[fileSize];
210
    unsigned char *outBuffer = new unsigned char[fileSize];
211
    unsigned char decBuffer[CHUNK_SIZE];    // Buffer for decoding a chunk.
212
    unsigned char encBuffer[CHUNK_SIZE];    // Buffer for decoding a chunk.
213
    int len = 0;
214
    // Not really necessary, but initialize output buffer with zeros
215
    memset(outBuffer, 0, fileSize);
216
    // Read whole file
217
    is.read(reinterpret_cast<char *>(buffer), fileSize);
218
    // decode
219
    if (fileSize > CHUNK_SIZE)     // Is the file size greater then a chunk?
220
    {                               // Yes, then start reading the file in chunks
221
        size_t numBlocks = fileSize / CHUNK_SIZE;
222
 
223
        for (size_t i = 0; i < numBlocks; ++i)
224
        {
225
            memcpy(encBuffer, buffer + i * CHUNK_SIZE, CHUNK_SIZE);
226
 
227
            if ((ssl_errno = EVP_DecryptUpdate(mCtx, decBuffer, &len, encBuffer, CHUNK_SIZE)) != OSSL_SUCCESS)
228
            {
229
                MSG_ERROR("Loop " << i << ": Error updating");
230
                _print_ssl_error(ssl_errno);
231
                delete[] buffer;
232
                delete[] outBuffer;
233
                return false;
234
            }
235
 
236
            memcpy(outBuffer+pos, decBuffer, len);
237
            pos += len;
238
        }
239
 
240
        int size2 = fileSize - (numBlocks * CHUNK_SIZE);
241
 
242
        if (size2 > 0)      // Is there something left of the file less then CHUNK_SIZE?
243
        {                   // Yes, then decrypt it
244
            memcpy(encBuffer, buffer + numBlocks * CHUNK_SIZE, size2);
245
 
246
            if ((ssl_errno = EVP_DecryptUpdate(mCtx, decBuffer, &len, encBuffer, size2)) != OSSL_SUCCESS)
247
            {
248
                MSG_ERROR("Error updating");
249
                _print_ssl_error(ssl_errno);
250
                delete[] buffer;
251
                delete[] outBuffer;
252
                return false;
253
            }
254
 
255
            memcpy(outBuffer+pos, decBuffer, len);
256
            pos += len;
257
        }
258
    }
259
    else
260
    {
261
        if ((ssl_errno = EVP_DecryptUpdate(mCtx, outBuffer, &len, buffer, fileSize)) != OSSL_SUCCESS)
262
        {
263
            _print_ssl_error(ssl_errno);
264
            delete[] buffer;
265
            delete[] outBuffer;
266
            return false;
267
        }
268
 
269
        pos = len;
270
    }
271
 
272
    if ((ssl_errno = EVP_DecryptFinal_ex(mCtx, outBuffer + pos, &len)) != OSSL_SUCCESS)
273
    {
274
        MSG_ERROR("Error finalizing: " << _get_ssl_error());
275
        delete[] buffer;
276
        delete[] outBuffer;
277
        return false;
278
    }
279
 
280
    pos += len;
281
    mDecrypted.assign(reinterpret_cast<char *>(outBuffer), pos);
282
    delete[] buffer;
283
    delete[] outBuffer;
284
 
285
    return true;
286
}