Libgourou

Libgourou Git Source Tree

Root/utils/drmprocessorclientimpl.cpp

1/*
2 Copyright (c) 2021, Grégory Soutadé
3
4 All rights reserved.
5 Redistribution and use in source and binary forms, with or without
6 modification, are permitted provided that the following conditions are met:
7
8 * Redistributions of source code must retain the above copyright
9 notice, this list of conditions and the following disclaimer.
10 * Redistributions in binary form must reproduce the above copyright
11 notice, this list of conditions and the following disclaimer in the
12 documentation and/or other materials provided with the distribution.
13 * Neither the name of the copyright holder nor the
14 names of its contributors may be used to endorse or promote products
15 derived from this software without specific prior written permission.
16
17 THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY
18 EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
19 WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
20 DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS BE LIABLE FOR ANY
21 DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
22 (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
23 LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
24 ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
26 SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27*/
28
29#include <openssl/rand.h>
30#include <openssl/pkcs12.h>
31#include <openssl/evp.h>
32#include <openssl/err.h>
33
34#include <QCoreApplication>
35#include <QNetworkReply>
36#include <QNetworkRequest>
37#include <QNetworkAccessManager>
38#include <QFile>
39
40#include <zip.h>
41#include <zlib.h>
42
43#include <libgourou_common.h>
44#include <libgourou_log.h>
45#include "drmprocessorclientimpl.h"
46
47/* Digest interface */
48void* DRMProcessorClientImpl::createDigest(const std::string& digestName)
49{
50 EVP_MD_CTX *sha_ctx = EVP_MD_CTX_new();
51 const EVP_MD* md = EVP_get_digestbyname(digestName.c_str());
52 EVP_DigestInit(sha_ctx, md);
53
54 return sha_ctx;
55}
56
57int DRMProcessorClientImpl::digestUpdate(void* handler, unsigned char* data, unsigned int length)
58{
59 return EVP_DigestUpdate((EVP_MD_CTX *)handler, data, length);
60}
61
62int DRMProcessorClientImpl::digestFinalize(void* handler, unsigned char* digestOut)
63{
64 int res = EVP_DigestFinal((EVP_MD_CTX *)handler, digestOut, NULL);
65 EVP_MD_CTX_free((EVP_MD_CTX *)handler);
66 return res;
67}
68
69int DRMProcessorClientImpl::digest(const std::string& digestName, unsigned char* data, unsigned int length, unsigned char* digestOut)
70{
71 void* handler = createDigest(digestName);
72 if (!handler)
73return -1;
74 if (digestUpdate(handler, data, length))
75return -1;
76 return digestFinalize(handler, digestOut);
77}
78
79/* Random interface */
80void DRMProcessorClientImpl::randBytes(unsigned char* bytesOut, unsigned int length)
81{
82 RAND_bytes(bytesOut, length);
83}
84
85/* HTTP interface */
86std::string DRMProcessorClientImpl::sendHTTPRequest(const std::string& URL, const std::string& POSTData, const std::string& contentType, std::map<std::string, std::string>* responseHeaders)
87{
88 QNetworkRequest request(QUrl(URL.c_str()));
89 QNetworkAccessManager networkManager;
90 QByteArray replyData;
91
92 GOUROU_LOG(gourou::INFO, "Send request to " << URL);
93 if (POSTData.size())
94 {
95GOUROU_LOG(gourou::DEBUG, "<<< " << std::endl << POSTData);
96 }
97
98 request.setRawHeader("Accept", "*/*");
99 request.setRawHeader("User-Agent", "book2png");
100 if (contentType.size())
101request.setRawHeader("Content-Type", contentType.c_str());
102
103 QNetworkReply* reply;
104
105 if (POSTData.size())
106reply = networkManager.post(request, POSTData.c_str());
107 else
108reply = networkManager.get(request);
109
110 QCoreApplication* app = QCoreApplication::instance();
111 networkManager.moveToThread(app->thread());
112 while (!reply->isFinished())
113app->processEvents();
114
115 QByteArray location = reply->rawHeader("Location");
116 if (location.size() != 0)
117 {
118GOUROU_LOG(gourou::DEBUG, "New location");
119return sendHTTPRequest(location.constData(), POSTData, contentType);
120 }
121
122 if (reply->error() != QNetworkReply::NoError)
123EXCEPTION(gourou::CLIENT_NETWORK_ERROR, "Error " << reply->errorString().toStdString());
124
125 QList<QByteArray> headers = reply->rawHeaderList();
126 for (int i = 0; i < headers.size(); ++i) {
127if (gourou::logLevel >= gourou::DEBUG)
128 std::cout << headers[i].constData() << " : " << reply->rawHeader(headers[i]).constData() << std::endl;
129if (responseHeaders)
130 (*responseHeaders)[headers[i].constData()] = reply->rawHeader(headers[i]).constData();
131 }
132
133 replyData = reply->readAll();
134 if (reply->rawHeader("Content-Type") == "application/vnd.adobe.adept+xml")
135 {
136GOUROU_LOG(gourou::DEBUG, ">>> " << std::endl << replyData.data());
137 }
138
139 return std::string(replyData.data(), replyData.length());
140}
141
142void DRMProcessorClientImpl::RSAPrivateEncrypt(const unsigned char* RSAKey, unsigned int RSAKeyLength,
143 const RSA_KEY_TYPE keyType, const std::string& password,
144 const unsigned char* data, unsigned dataLength,
145 unsigned char* res)
146{
147 PKCS12 * pkcs12;
148 EVP_PKEY* pkey;
149 X509* cert;
150 STACK_OF(X509)* ca;
151 RSA * rsa;
152
153 pkcs12 = d2i_PKCS12(NULL, &RSAKey, RSAKeyLength);
154 if (!pkcs12)
155EXCEPTION(gourou::CLIENT_INVALID_PKCS12, ERR_error_string(ERR_get_error(), NULL));
156 PKCS12_parse(pkcs12, password.c_str(), &pkey, &cert, &ca);
157 rsa = EVP_PKEY_get1_RSA(pkey);
158
159 int ret = RSA_private_encrypt(dataLength, data, res, rsa, RSA_PKCS1_PADDING);
160
161 if (ret < 0)
162EXCEPTION(gourou::CLIENT_RSA_ERROR, ERR_error_string(ERR_get_error(), NULL));
163
164 if (gourou::logLevel >= gourou::DEBUG)
165 {
166printf("Sig : ");
167for(int i=0; i<(int)sizeof(res); i++)
168 printf("%02x ", res[i]);
169printf("\n");
170 }
171}
172
173void DRMProcessorClientImpl::RSAPublicEncrypt(const unsigned char* RSAKey, unsigned int RSAKeyLength,
174 const RSA_KEY_TYPE keyType,
175 const unsigned char* data, unsigned dataLength,
176 unsigned char* res)
177{
178 X509 * x509 = d2i_X509(0, &RSAKey, RSAKeyLength);
179 if (!x509)
180EXCEPTION(gourou::CLIENT_INVALID_CERTIFICATE, "Invalid certificate");
181
182 EVP_PKEY * evpKey = X509_get_pubkey(x509);
183 RSA* rsa = EVP_PKEY_get1_RSA(evpKey);
184 EVP_PKEY_free(evpKey);
185
186 if (!rsa)
187EXCEPTION(gourou::CLIENT_NO_PRIV_KEY, "No private key in certificate");
188
189 int ret = RSA_public_encrypt(dataLength, data, res, rsa, RSA_PKCS1_PADDING);
190 if (ret < 0)
191EXCEPTION(gourou::CLIENT_RSA_ERROR, ERR_error_string(ERR_get_error(), NULL));
192}
193
194void* DRMProcessorClientImpl::generateRSAKey(int keyLengthBits)
195{
196 BIGNUM * bn = BN_new();
197 RSA * rsa = RSA_new();
198 BN_set_word(bn, 0x10001);
199 RSA_generate_key_ex(rsa, keyLengthBits, bn, 0);
200 BN_free(bn);
201
202 return rsa;
203}
204
205void DRMProcessorClientImpl::destroyRSAHandler(void* handler)
206{
207 RSA_free((RSA*)handler);
208}
209
210void DRMProcessorClientImpl::extractRSAPublicKey(void* handler, unsigned char** keyOut, unsigned int* keyOutLength)
211{
212 EVP_PKEY * evpKey = EVP_PKEY_new();
213 EVP_PKEY_set1_RSA(evpKey, (RSA*)handler);
214 X509_PUBKEY *x509_pubkey = 0;
215 X509_PUBKEY_set(&x509_pubkey, evpKey);
216
217 *keyOutLength = i2d_X509_PUBKEY(x509_pubkey, keyOut);
218
219 X509_PUBKEY_free(x509_pubkey);
220 EVP_PKEY_free(evpKey);
221}
222
223void DRMProcessorClientImpl::extractRSAPrivateKey(void* handler, unsigned char** keyOut, unsigned int* keyOutLength)
224{
225 EVP_PKEY * evpKey = EVP_PKEY_new();
226 EVP_PKEY_set1_RSA(evpKey, (RSA*)handler);
227 PKCS8_PRIV_KEY_INFO * privKey = EVP_PKEY2PKCS8(evpKey);
228
229 *keyOutLength = i2d_PKCS8_PRIV_KEY_INFO(privKey, keyOut);
230
231 PKCS8_PRIV_KEY_INFO_free(privKey);
232 EVP_PKEY_free(evpKey);
233}
234
235void DRMProcessorClientImpl::extractCertificate(const unsigned char* RSAKey, unsigned int RSAKeyLength,
236const RSA_KEY_TYPE keyType, const std::string& password,
237unsigned char** certOut, unsigned int* certOutLength)
238{
239 PKCS12 * pkcs12;
240 EVP_PKEY* pkey = 0;
241 X509* cert = 0;
242 STACK_OF(X509)* ca;
243
244 pkcs12 = d2i_PKCS12(NULL, &RSAKey, RSAKeyLength);
245 if (!pkcs12)
246EXCEPTION(gourou::CLIENT_INVALID_PKCS12, ERR_error_string(ERR_get_error(), NULL));
247 PKCS12_parse(pkcs12, password.c_str(), &pkey, &cert, &ca);
248
249 *certOutLength = i2d_X509(cert, certOut);
250
251 EVP_PKEY_free(pkey);
252}
253
254/* Crypto interface */
255void DRMProcessorClientImpl::AESEncrypt(CHAINING_MODE chaining,
256const unsigned char* key, unsigned int keyLength,
257const unsigned char* iv, unsigned int ivLength,
258const unsigned char* dataIn, unsigned int dataInLength,
259unsigned char* dataOut, unsigned int* dataOutLength)
260{
261 void* handler = AESEncryptInit(chaining, key, keyLength, iv, ivLength);
262 AESEncryptUpdate(handler, dataIn, dataInLength, dataOut, dataOutLength);
263 AESEncryptFinalize(handler, dataOut+*dataOutLength, dataOutLength);
264}
265
266void* DRMProcessorClientImpl::AESEncryptInit(CHAINING_MODE chaining,
267 const unsigned char* key, unsigned int keyLength,
268 const unsigned char* iv, unsigned int ivLength)
269{
270 EVP_CIPHER_CTX *ctx = EVP_CIPHER_CTX_new();
271
272 switch(keyLength)
273 {
274 case 16:
275switch(chaining)
276{
277case CHAIN_ECB:
278 EVP_EncryptInit_ex(ctx, EVP_aes_128_ecb(), NULL, key, iv);
279 break;
280case CHAIN_CBC:
281 EVP_EncryptInit_ex(ctx, EVP_aes_128_cbc(), NULL, key, iv);
282 break;
283default:
284 EXCEPTION(gourou::CLIENT_BAD_CHAINING, "Unknown chaining mode " << chaining);
285}
286break;
287 default:
288EVP_CIPHER_CTX_free(ctx);
289EXCEPTION(gourou::CLIENT_BAD_KEY_SIZE, "Invalid key size " << keyLength);
290 }
291
292 return ctx;
293}
294
295void* DRMProcessorClientImpl::AESDecryptInit(CHAINING_MODE chaining,
296 const unsigned char* key, unsigned int keyLength,
297 const unsigned char* iv, unsigned int ivLength)
298{
299 EVP_CIPHER_CTX *ctx = EVP_CIPHER_CTX_new();
300
301 switch(keyLength)
302 {
303 case 16:
304switch(chaining)
305{
306case CHAIN_ECB:
307 EVP_DecryptInit_ex(ctx, EVP_aes_128_ecb(), NULL, key, iv);
308 break;
309case CHAIN_CBC:
310 EVP_DecryptInit_ex(ctx, EVP_aes_128_cbc(), NULL, key, iv);
311 break;
312default:
313 EXCEPTION(gourou::CLIENT_BAD_CHAINING, "Unknown chaining mode " << chaining);
314}
315break;
316 default:
317EVP_CIPHER_CTX_free(ctx);
318EXCEPTION(gourou::CLIENT_BAD_KEY_SIZE, "Invalid key size " << keyLength);
319 }
320
321 return ctx;
322}
323
324void DRMProcessorClientImpl::AESEncryptUpdate(void* handler, const unsigned char* dataIn, unsigned int dataInLength,
325 unsigned char* dataOut, unsigned int* dataOutLength)
326{
327 EVP_EncryptUpdate((EVP_CIPHER_CTX*)handler, dataOut, (int*)dataOutLength, dataIn, dataInLength);
328}
329
330void DRMProcessorClientImpl::AESEncryptFinalize(void* handler,
331unsigned char* dataOut, unsigned int* dataOutLength)
332{
333 int len;
334 EVP_EncryptFinal_ex((EVP_CIPHER_CTX*)handler, dataOut, &len);
335 *dataOutLength += len;
336 EVP_CIPHER_CTX_free((EVP_CIPHER_CTX*)handler);
337}
338
339void DRMProcessorClientImpl::AESDecrypt(CHAINING_MODE chaining,
340const unsigned char* key, unsigned int keyLength,
341const unsigned char* iv, unsigned int ivLength,
342const unsigned char* dataIn, unsigned int dataInLength,
343unsigned char* dataOut, unsigned int* dataOutLength)
344{
345 void* handler = AESDecryptInit(chaining, key, keyLength, iv, ivLength);
346 AESDecryptUpdate(handler, dataIn, dataInLength, dataOut, dataOutLength);
347 AESDecryptFinalize(handler, dataOut+*dataOutLength, dataOutLength);
348}
349
350void DRMProcessorClientImpl::AESDecryptUpdate(void* handler, const unsigned char* dataIn, unsigned int dataInLength,
351 unsigned char* dataOut, unsigned int* dataOutLength)
352{
353 EVP_DecryptUpdate((EVP_CIPHER_CTX*)handler, dataOut, (int*)dataOutLength, dataIn, dataInLength);
354}
355
356void DRMProcessorClientImpl::AESDecryptFinalize(void* handler, unsigned char* dataOut, unsigned int* dataOutLength)
357{
358 int len;
359 EVP_DecryptFinal_ex((EVP_CIPHER_CTX*)handler, dataOut, &len);
360 *dataOutLength += len;
361 EVP_CIPHER_CTX_free((EVP_CIPHER_CTX*)handler);
362}
363
364void* DRMProcessorClientImpl::zipOpen(const std::string& path)
365{
366 zip_t* handler = zip_open(path.c_str(), 0, 0);
367
368 if (!handler)
369EXCEPTION(gourou::CLIENT_BAD_ZIP_FILE, "Invalid zip file " << path);
370
371 return handler;
372}
373
374std::string DRMProcessorClientImpl::zipReadFile(void* handler, const std::string& path)
375{
376 std::string res;
377 unsigned char* buffer;
378 zip_stat_t sb;
379
380 if (zip_stat((zip_t *)handler, path.c_str(), 0, &sb) < 0)
381EXCEPTION(gourou::CLIENT_ZIP_ERROR, "Zip error " << zip_strerror((zip_t *)handler));
382
383 if (!(sb.valid & (ZIP_STAT_INDEX|ZIP_STAT_SIZE)))
384EXCEPTION(gourou::CLIENT_ZIP_ERROR, "Required fields missing");
385
386 buffer = new unsigned char[sb.size];
387
388 zip_file_t *f = zip_fopen_index((zip_t *)handler, sb.index, ZIP_FL_COMPRESSED);
389
390 zip_fread(f, buffer, sb.size);
391 zip_fclose(f);
392
393 res = std::string((char*)buffer, sb.size);
394 delete[] buffer;
395
396 return res;
397}
398
399void DRMProcessorClientImpl::zipWriteFile(void* handler, const std::string& path, const std::string& content)
400{
401 zip_source_t* s = zip_source_buffer((zip_t*)handler, content.c_str(), content.length(), 0);
402 if (zip_file_add((zip_t*)handler, path.c_str(), s, ZIP_FL_OVERWRITE|ZIP_FL_ENC_UTF_8) < 0)
403 {
404zip_source_free(s);
405EXCEPTION(gourou::CLIENT_ZIP_ERROR, "Zip error " << zip_strerror((zip_t *)handler));
406 }
407}
408
409void DRMProcessorClientImpl::zipDeleteFile(void* handler, const std::string& path)
410{
411 zip_int64_t idx = zip_name_locate((zip_t*)handler, path.c_str(), 0);
412
413 if (idx < 0)
414EXCEPTION(gourou::CLIENT_ZIP_ERROR, "No such file " << path.c_str());
415
416 if (zip_delete((zip_t*)handler, idx))
417EXCEPTION(gourou::CLIENT_ZIP_ERROR, "Zip error " << zip_strerror((zip_t *)handler));
418}
419
420void DRMProcessorClientImpl::zipClose(void* handler)
421{
422 zip_close((zip_t*)handler);
423}
424
425void DRMProcessorClientImpl::inflate(std::string data, gourou::ByteArray& result,
426 int wbits)
427{
428 unsigned int dataSize = data.size()*2;
429 unsigned char* buffer = new unsigned char[dataSize];
430
431 z_stream infstream;
432
433 infstream.zalloc = Z_NULL;
434 infstream.zfree = Z_NULL;
435 infstream.opaque = Z_NULL;
436
437 infstream.avail_in = (uInt)data.size();
438 infstream.next_in = (Bytef *)data.c_str(); // input char array
439 infstream.avail_out = (uInt)dataSize; // size of output
440 infstream.next_out = (Bytef *)buffer; // output char array
441
442 int ret = inflateInit2(&infstream, wbits);
443
444 ret = ::inflate(&infstream, Z_SYNC_FLUSH);
445 while (ret == Z_OK || ret == Z_STREAM_END)
446 {
447result.append(buffer, dataSize-infstream.avail_out);
448if (ret == Z_STREAM_END) break;
449infstream.avail_out = (uInt)dataSize; // size of output
450infstream.next_out = (Bytef *)buffer; // output char array
451ret = ::inflate(&infstream, Z_SYNC_FLUSH);
452 }
453
454 inflateEnd(&infstream);
455
456 delete[] buffer;
457
458 if (ret != Z_OK && ret != Z_STREAM_END && ret != Z_BUF_ERROR)
459EXCEPTION(gourou::CLIENT_ZIP_ERROR, zError(ret));
460}
461
462void DRMProcessorClientImpl::deflate(std::string data, gourou::ByteArray& result,
463 int wbits, int compressionLevel)
464{
465 unsigned int dataSize = data.size();
466 unsigned char* buffer = new unsigned char[dataSize];
467
468 z_stream defstream;
469
470 defstream.zalloc = Z_NULL;
471 defstream.zfree = Z_NULL;
472 defstream.opaque = Z_NULL;
473
474 defstream.avail_in = (uInt)data.size();
475 defstream.next_in = (Bytef *)data.c_str(); // input char array
476 defstream.avail_out = (uInt)dataSize; // size of output
477 defstream.next_out = (Bytef *)buffer; // output char array
478
479 int ret = deflateInit2(&defstream, Z_DEFAULT_COMPRESSION, Z_DEFLATED, wbits,
480 compressionLevel, Z_DEFAULT_STRATEGY);
481
482 ret = ::deflate(&defstream, Z_SYNC_FLUSH);
483 while (ret == Z_OK || ret == Z_STREAM_END)
484 {
485result.append(buffer, dataSize-defstream.avail_out);
486if (ret == Z_STREAM_END) break;
487defstream.avail_out = (uInt)dataSize; // size of output
488defstream.next_out = (Bytef *)buffer; // output char array
489ret = ::deflate(&defstream, Z_SYNC_FLUSH);
490 }
491
492 deflateEnd(&defstream);
493
494 delete[] buffer;
495
496 if (ret != Z_OK && ret != Z_STREAM_END && ret != Z_BUF_ERROR)
497EXCEPTION(gourou::CLIENT_ZIP_ERROR, zError(ret));
498}

Archive Download this file