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#include <bytearray.h>
29
30#include <algorithm>
31#include <cctype>
32#include <locale>
33
34#define OPENSSL_NO_DEPRECATED 1
35
36#include <openssl/rand.h>
37#include <openssl/pkcs12.h>
38#include <openssl/evp.h>
39#include <openssl/err.h>
40#include <openssl/rsa.h>
41#include <openssl/bn.h>
42
43#include <curl/curl.h>
44
45#include <zlib.h>
46#include <zip.h>
47
48#include <libgourou_common.h>
49#include "drmprocessorclientimpl.h"
50
51DRMProcessorClientImpl::DRMProcessorClientImpl():
52 legacy(0), deflt(0)
53{
54#if OPENSSL_VERSION_MAJOR >= 3
55 legacy = OSSL_PROVIDER_load(NULL, "legacy");
56 if (!legacy)
57EXCEPTION(gourou::CLIENT_OSSL_ERROR, "Error, OpenSSL legacy provider not available");
58
59 deflt = OSSL_PROVIDER_load(NULL, "default");
60 if (!deflt)
61EXCEPTION(gourou::CLIENT_OSSL_ERROR, "Error, OpenSSL default provider not available");
62#endif
63}
64
65DRMProcessorClientImpl::~DRMProcessorClientImpl()
66{
67#if OPENSSL_VERSION_MAJOR >= 3
68 if (legacy)
69OSSL_PROVIDER_unload(legacy);
70
71 if (deflt)
72OSSL_PROVIDER_unload(deflt);
73#endif
74}
75
76/* Digest interface */
77void* DRMProcessorClientImpl::createDigest(const std::string& digestName)
78{
79 EVP_MD_CTX *md_ctx = EVP_MD_CTX_new();
80 const EVP_MD* md = EVP_get_digestbyname(digestName.c_str());
81
82 if (EVP_DigestInit(md_ctx, md) != 1)
83 {
84EVP_MD_CTX_free(md_ctx);
85EXCEPTION(gourou::CLIENT_DIGEST_ERROR, ERR_error_string(ERR_get_error(), NULL));
86 }
87
88 return md_ctx;
89}
90
91void DRMProcessorClientImpl::digestUpdate(void* handler, unsigned char* data, unsigned int length)
92{
93 if (EVP_DigestUpdate((EVP_MD_CTX *)handler, data, length) != 1)
94EXCEPTION(gourou::CLIENT_DIGEST_ERROR, ERR_error_string(ERR_get_error(), NULL));
95}
96
97void DRMProcessorClientImpl::digestFinalize(void* handler, unsigned char* digestOut)
98{
99 int res = EVP_DigestFinal((EVP_MD_CTX *)handler, digestOut, NULL);
100 EVP_MD_CTX_free((EVP_MD_CTX *)handler);
101
102 if (res <= 0)
103EXCEPTION(gourou::CLIENT_DIGEST_ERROR, ERR_error_string(ERR_get_error(), NULL));
104}
105
106void DRMProcessorClientImpl::digest(const std::string& digestName, unsigned char* data, unsigned int length, unsigned char* digestOut)
107{
108 void* handler = createDigest(digestName);
109 digestUpdate(handler, data, length);
110 digestFinalize(handler, digestOut);
111}
112
113/* Random interface */
114void DRMProcessorClientImpl::randBytes(unsigned char* bytesOut, unsigned int length)
115{
116 RAND_bytes(bytesOut, length);
117}
118
119/* HTTP interface */
120#define HTTP_REQ_MAX_RETRY 5
121#define DISPLAY_THRESHOLD 10*1024 // Threshold to display download progression
122static unsigned downloadedBytes;
123
124static int downloadProgress(void *clientp, curl_off_t dltotal, curl_off_t dlnow,
125 curl_off_t ultotal, curl_off_t ulnow)
126{
127// For "big" files only
128 if (dltotal >= DISPLAY_THRESHOLD && gourou::logLevel >= gourou::LG_LOG_WARN)
129 {
130int percent = 0;
131if (dltotal)
132 percent = (dlnow * 100) / dltotal;
133
134std::cout << "\rDownload " << percent << "%" << std::flush;
135 }
136
137 return 0;
138}
139
140static size_t curlRead(void *data, size_t size, size_t nmemb, void *userp)
141{
142 gourou::ByteArray* replyData = (gourou::ByteArray*) userp;
143
144 replyData->append((unsigned char*)data, size*nmemb);
145
146 return size*nmemb;
147}
148
149static size_t curlReadFd(void *data, size_t size, size_t nmemb, void *userp)
150{
151 int fd = *(int*) userp;
152
153 size_t res = write(fd, data, size*nmemb);
154
155 downloadedBytes += res;
156
157 return res;
158}
159
160static size_t curlHeaders(char *buffer, size_t size, size_t nitems, void *userdata)
161{
162 std::map<std::string, std::string>* responseHeaders = (std::map<std::string, std::string>*)userdata;
163 std::string::size_type pos = 0;
164 std::string buf(buffer, size*nitems);
165
166 pos = buf.find(":", pos);
167
168 if (pos != std::string::npos)
169 {
170std::string key = std::string(buffer, pos);
171std::string value = std::string(&buffer[pos+1], (size*nitems)-(pos+1));
172
173key = gourou::trim(key);
174value = gourou::trim(value);
175
176(*responseHeaders)[key] = value;
177
178if (gourou::logLevel >= gourou::LG_LOG_DEBUG)
179 std::cout << key << " : " << value << std::endl;
180 }
181
182 return size*nitems;
183}
184
185std::string DRMProcessorClientImpl::sendHTTPRequest(const std::string& URL, const std::string& POSTData, const std::string& contentType, std::map<std::string, std::string>* responseHeaders, int fd, bool resume)
186{
187 gourou::ByteArray replyData;
188 std::map<std::string, std::string> localHeaders;
189
190 if (!responseHeaders)
191responseHeaders = &localHeaders;
192
193 GOUROU_LOG(INFO, "Send request to " << URL);
194 if (POSTData.size())
195 {
196GOUROU_LOG(DEBUG, "<<< " << std::endl << POSTData);
197 }
198
199 unsigned prevDownloadedBytes;
200 downloadedBytes = 0;
201 if (fd && resume)
202 {
203struct stat _stat;
204if (!fstat(fd, &_stat))
205{
206 GOUROU_LOG(WARN, "Resume download @ " << _stat.st_size << " bytes");
207 downloadedBytes = _stat.st_size;
208}
209else
210 GOUROU_LOG(WARN, "Want to resume, but fstat failed");
211 }
212
213 CURL *curl = curl_easy_init();
214 CURLcode res;
215 curl_easy_setopt(curl, CURLOPT_URL, URL.c_str());
216 curl_easy_setopt(curl, CURLOPT_USERAGENT, "book2png");
217 curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1);
218
219
220 struct curl_slist *list = NULL;
221 list = curl_slist_append(list, "Accept: */*");
222 std::string _contentType;
223 if (contentType.size())
224 {
225_contentType = "Content-Type: " + contentType;
226list = curl_slist_append(list, _contentType.c_str());
227 }
228
229 curl_easy_setopt(curl, CURLOPT_HTTPHEADER, list);
230
231 if (POSTData.size())
232 {
233curl_easy_setopt(curl, CURLOPT_POST, 1L);
234curl_easy_setopt(curl, CURLOPT_POSTFIELDSIZE, POSTData.size());
235curl_easy_setopt(curl, CURLOPT_POSTFIELDS, POSTData.data());
236 }
237
238 if (fd)
239 {
240curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, curlReadFd);
241curl_easy_setopt(curl, CURLOPT_WRITEDATA, (void*)&fd);
242 }
243 else
244 {
245curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, curlRead);
246curl_easy_setopt(curl, CURLOPT_WRITEDATA, (void*)&replyData);
247 }
248
249 curl_easy_setopt(curl, CURLOPT_HEADERFUNCTION, curlHeaders);
250 curl_easy_setopt(curl, CURLOPT_HEADERDATA, (void*)responseHeaders);
251
252 curl_easy_setopt(curl, CURLOPT_XFERINFOFUNCTION, downloadProgress);
253 curl_easy_setopt(curl, CURLOPT_NOPROGRESS, 0);
254
255 for (int i=0; i<HTTP_REQ_MAX_RETRY; i++)
256 {
257prevDownloadedBytes = downloadedBytes;
258if (downloadedBytes)
259 curl_easy_setopt(curl, CURLOPT_RESUME_FROM, downloadedBytes);
260
261res = curl_easy_perform(curl);
262
263// Connexion failed, wait & retry
264if (res == CURLE_COULDNT_CONNECT)
265{
266 GOUROU_LOG(WARN, "\nConnection failed, attempt " << (i+1) << "/" << HTTP_REQ_MAX_RETRY);
267}
268// Transfer failed but some data has been received
269// --> try again without incrementing tries
270else if (res == CURLE_RECV_ERROR)
271{
272 if (prevDownloadedBytes != downloadedBytes)
273 {
274GOUROU_LOG(WARN, "\nConnection broken, but data received, try again");
275i--;
276 }
277 else
278GOUROU_LOG(WARN, "\nConnection broken and no data received, attempt " << (i+1) << "/" << HTTP_REQ_MAX_RETRY);
279}
280// Other error --> fail
281else
282 break;
283
284// Wait a little bit (250ms * i)
285usleep((250 * 1000) * (i+1));
286 }
287
288 curl_slist_free_all(list);
289 curl_easy_cleanup(curl);
290
291 if (res != CURLE_OK)
292EXCEPTION(gourou::CLIENT_NETWORK_ERROR, "Error " << curl_easy_strerror(res));
293
294 if ((downloadedBytes >= DISPLAY_THRESHOLD || replyData.size() >= DISPLAY_THRESHOLD) &&
295gourou::logLevel >= gourou::LG_LOG_WARN)
296std::cout << std::endl;
297
298 if ((*responseHeaders)["Content-Type"] == "application/vnd.adobe.adept+xml")
299 {
300GOUROU_LOG(DEBUG, ">>> " << std::endl << replyData.data());
301 }
302
303 return std::string((char*)replyData.data(), replyData.length());
304}
305
306void DRMProcessorClientImpl::padWithPKCS1(unsigned char* out, unsigned int outLength,
307 const unsigned char* in, unsigned int inLength)
308{
309 if (outLength < (inLength + 3))
310EXCEPTION(gourou::CLIENT_RSA_ERROR, "Not enough space for PKCS1 padding");
311
312 /*
313 PKCS1v5 Padding is :
314 0x00 0x01 0xff * n 0x00 dataIn
315 */
316
317 memset(out, 0xFF, outLength);
318
319 out[0] = 0x0;
320 out[1] = 0x1;
321 out[outLength - inLength - 1] = 0x00;
322 memcpy(&out[outLength - inLength], in, inLength);
323}
324
325
326void DRMProcessorClientImpl::RSAPrivateEncrypt(const unsigned char* RSAKey, unsigned int RSAKeyLength,
327 const RSA_KEY_TYPE keyType, const std::string& password,
328 const unsigned char* data, unsigned dataLength,
329 unsigned char* res)
330{
331 PKCS12 * pkcs12;
332 EVP_PKEY_CTX *ctx;
333 EVP_PKEY* pkey = NULL;
334 size_t outlen;
335 unsigned char* tmp;
336 int ret;
337
338 pkcs12 = d2i_PKCS12(NULL, &RSAKey, RSAKeyLength);
339 if (!pkcs12)
340EXCEPTION(gourou::CLIENT_INVALID_PKCS12, ERR_error_string(ERR_get_error(), NULL));
341
342 if (PKCS12_parse(pkcs12, password.c_str(), &pkey, NULL, NULL) <= 0)
343EXCEPTION(gourou::CLIENT_INVALID_PKCS12, ERR_error_string(ERR_get_error(), NULL));
344
345 outlen = EVP_PKEY_get_size(pkey);
346
347 ctx = EVP_PKEY_CTX_new(pkey, NULL);
348
349 /* Use RSA private key */
350 if (EVP_PKEY_decrypt_init(ctx) <= 0)
351EXCEPTION(gourou::CLIENT_RSA_ERROR, ERR_error_string(ERR_get_error(), NULL));
352
353 if (EVP_PKEY_CTX_set_rsa_padding(ctx, RSA_NO_PADDING) <= 0)
354EXCEPTION(gourou::CLIENT_RSA_ERROR, ERR_error_string(ERR_get_error(), NULL));
355
356 tmp = (unsigned char*)malloc(outlen);
357
358 /* PKCS1 functions are no more exported */
359 padWithPKCS1(tmp, outlen, data, dataLength);
360
361 ret = EVP_PKEY_decrypt(ctx, res, &outlen, tmp, outlen);
362
363 EVP_PKEY_CTX_free(ctx);
364 free(tmp);
365
366 if (ret <= 0)
367EXCEPTION(gourou::CLIENT_RSA_ERROR, ERR_error_string(ERR_get_error(), NULL));
368}
369
370void DRMProcessorClientImpl::RSAPrivateDecrypt(const unsigned char* RSAKey, unsigned int RSAKeyLength,
371 const RSA_KEY_TYPE keyType, const std::string& password,
372 const unsigned char* data, unsigned dataLength,
373 unsigned char* res)
374{
375 BIO* mem = BIO_new_mem_buf(RSAKey, RSAKeyLength);
376 PKCS8_PRIV_KEY_INFO* p8inf = d2i_PKCS8_PRIV_KEY_INFO_bio(mem, NULL);
377
378 if (!p8inf)
379EXCEPTION(gourou::CLIENT_INVALID_PKCS8, ERR_error_string(ERR_get_error(), NULL));
380
381 EVP_PKEY_CTX *ctx;
382 EVP_PKEY* pkey = EVP_PKCS82PKEY(p8inf);
383 size_t outlen = dataLength;
384 int ret;
385
386 if (!pkey)
387EXCEPTION(gourou::CLIENT_INVALID_PKCS8, ERR_error_string(ERR_get_error(), NULL));
388
389 ctx = EVP_PKEY_CTX_new(pkey, NULL);
390
391 if (EVP_PKEY_decrypt_init(ctx) <= 0)
392EXCEPTION(gourou::CLIENT_RSA_ERROR, ERR_error_string(ERR_get_error(), NULL));
393
394 if (EVP_PKEY_CTX_set_rsa_padding(ctx, RSA_NO_PADDING) <= 0)
395EXCEPTION(gourou::CLIENT_RSA_ERROR, ERR_error_string(ERR_get_error(), NULL));
396
397 ret = EVP_PKEY_decrypt(ctx, res, &outlen, data, dataLength);
398
399 PKCS8_PRIV_KEY_INFO_free(p8inf);
400 EVP_PKEY_CTX_free(ctx);
401 BIO_free(mem);
402
403 if (ret <= 0)
404EXCEPTION(gourou::CLIENT_RSA_ERROR, ERR_error_string(ERR_get_error(), NULL));
405}
406
407void DRMProcessorClientImpl::RSAPublicEncrypt(const unsigned char* RSAKey, unsigned int RSAKeyLength,
408 const RSA_KEY_TYPE keyType,
409 const unsigned char* data, unsigned dataLength,
410 unsigned char* res)
411{
412 size_t outlen;
413
414 X509 * x509 = d2i_X509(0, &RSAKey, RSAKeyLength);
415 if (!x509)
416EXCEPTION(gourou::CLIENT_INVALID_CERTIFICATE, "Invalid certificate");
417
418 EVP_PKEY_CTX *ctx;
419 EVP_PKEY * evpKey = X509_get_pubkey(x509);
420
421 if (!evpKey)
422EXCEPTION(gourou::CLIENT_NO_PUB_KEY, "No public key in certificate");
423
424 ctx = EVP_PKEY_CTX_new(evpKey, NULL);
425
426 if (EVP_PKEY_encrypt_init(ctx) <= 0)
427EXCEPTION(gourou::CLIENT_RSA_ERROR, ERR_error_string(ERR_get_error(), NULL));
428
429 if (EVP_PKEY_CTX_set_rsa_padding(ctx, RSA_PKCS1_PADDING) <= 0)
430EXCEPTION(gourou::CLIENT_RSA_ERROR, ERR_error_string(ERR_get_error(), NULL));
431
432 int ret = EVP_PKEY_encrypt(ctx, res, &outlen, data, dataLength);
433
434 EVP_PKEY_CTX_free(ctx);
435
436 if (ret < 0)
437EXCEPTION(gourou::CLIENT_RSA_ERROR, ERR_error_string(ERR_get_error(), NULL));
438
439 EVP_PKEY_free(evpKey);
440}
441
442void* DRMProcessorClientImpl::generateRSAKey(int keyLengthBits)
443{
444 BIGNUM * bn = BN_new();
445 EVP_PKEY_CTX* ctx = EVP_PKEY_CTX_new_id(EVP_PKEY_RSA, NULL);
446 EVP_PKEY *key = NULL;
447
448 BN_set_word(bn, 0x10001);
449
450 EVP_PKEY_keygen_init(ctx);
451
452 EVP_PKEY_CTX_set_rsa_keygen_bits(ctx, keyLengthBits);
453 EVP_PKEY_CTX_set_rsa_padding(ctx, RSA_PKCS1_PADDING);
454 EVP_PKEY_CTX_set1_rsa_keygen_pubexp(ctx, bn);
455 EVP_PKEY_keygen(ctx, &key);
456
457 EVP_PKEY_CTX_free(ctx);
458 BN_free(bn);
459
460 return key;
461}
462
463void DRMProcessorClientImpl::destroyRSAHandler(void* handler)
464{
465 free(handler);
466}
467
468void DRMProcessorClientImpl::extractRSAPublicKey(void* handler, unsigned char** keyOut, unsigned int* keyOutLength)
469{
470 X509_PUBKEY *x509_pubkey = 0;
471 X509_PUBKEY_set(&x509_pubkey, (EVP_PKEY*)handler);
472
473 *keyOutLength = i2d_X509_PUBKEY(x509_pubkey, keyOut);
474
475 X509_PUBKEY_free(x509_pubkey);
476}
477
478void DRMProcessorClientImpl::extractRSAPrivateKey(void* handler, unsigned char** keyOut, unsigned int* keyOutLength)
479{
480 PKCS8_PRIV_KEY_INFO * privKey = EVP_PKEY2PKCS8((EVP_PKEY*)handler);
481
482 *keyOutLength = i2d_PKCS8_PRIV_KEY_INFO(privKey, keyOut);
483
484 PKCS8_PRIV_KEY_INFO_free(privKey);
485}
486
487void DRMProcessorClientImpl::extractCertificate(const unsigned char* RSAKey, unsigned int RSAKeyLength,
488const RSA_KEY_TYPE keyType, const std::string& password,
489unsigned char** certOut, unsigned int* certOutLength)
490{
491 PKCS12 * pkcs12;
492 EVP_PKEY* pkey = 0;
493 X509* cert = 0;
494
495 pkcs12 = d2i_PKCS12(NULL, &RSAKey, RSAKeyLength);
496 if (!pkcs12)
497EXCEPTION(gourou::CLIENT_INVALID_PKCS12, ERR_error_string(ERR_get_error(), NULL));
498 PKCS12_parse(pkcs12, password.c_str(), &pkey, &cert, NULL);
499
500 if (!cert)
501EXCEPTION(gourou::CLIENT_INVALID_PKCS12, ERR_error_string(ERR_get_error(), NULL));
502
503 *certOutLength = i2d_X509(cert, certOut);
504
505 EVP_PKEY_free(pkey);
506}
507
508/* Crypto interface */
509void DRMProcessorClientImpl::encrypt(CRYPTO_ALGO algo, CHAINING_MODE chaining,
510 const unsigned char* key, unsigned int keyLength,
511 const unsigned char* iv, unsigned int ivLength,
512 const unsigned char* dataIn, unsigned int dataInLength,
513 unsigned char* dataOut, unsigned int* dataOutLength)
514{
515 void* handler = encryptInit(algo, chaining, key, keyLength, iv, ivLength);
516 encryptUpdate(handler, dataIn, dataInLength, dataOut, dataOutLength);
517 encryptFinalize(handler, dataOut+*dataOutLength, dataOutLength);
518}
519
520void* DRMProcessorClientImpl::encryptInit(CRYPTO_ALGO algo, CHAINING_MODE chaining,
521 const unsigned char* key, unsigned int keyLength,
522 const unsigned char* iv, unsigned int ivLength)
523{
524 EVP_CIPHER_CTX *ctx = EVP_CIPHER_CTX_new();
525 int ret = 0;
526
527 switch (algo)
528 {
529 case ALGO_AES:
530 {
531switch(keyLength)
532{
533case 16:
534 switch(chaining)
535 {
536 case CHAIN_ECB:
537ret = EVP_EncryptInit(ctx, EVP_aes_128_ecb(), key, iv);
538break;
539 case CHAIN_CBC:
540ret = EVP_EncryptInit(ctx, EVP_aes_128_cbc(), key, iv);
541break;
542 default:
543EXCEPTION(gourou::CLIENT_BAD_CHAINING, "Unknown chaining mode " << chaining);
544 }
545 break;
546default:
547 EVP_CIPHER_CTX_free(ctx);
548 EXCEPTION(gourou::CLIENT_BAD_KEY_SIZE, "Invalid key size " << keyLength);
549}
550break;
551 }
552 case ALGO_RC4:
553 {
554if (keyLength != 16)
555{
556 EVP_CIPHER_CTX_free(ctx);
557 EXCEPTION(gourou::CLIENT_BAD_KEY_SIZE, "Invalid key size " << keyLength);
558}
559ret = EVP_DecryptInit(ctx, EVP_rc4(), key, iv);
560break;
561 }
562 }
563
564 if (ret <= 0)
565 {
566EVP_CIPHER_CTX_free(ctx);
567EXCEPTION(gourou::CLIENT_CRYPT_ERROR, ERR_error_string(ERR_get_error(), NULL));
568 }
569
570 return ctx;
571}
572
573void* DRMProcessorClientImpl::decryptInit(CRYPTO_ALGO algo, CHAINING_MODE chaining,
574 const unsigned char* key, unsigned int keyLength,
575 const unsigned char* iv, unsigned int ivLength)
576{
577 EVP_CIPHER_CTX *ctx = EVP_CIPHER_CTX_new();
578 int ret = 0;
579
580 switch(algo)
581 {
582 case ALGO_AES:
583 {
584switch(keyLength)
585{
586case 16:
587 switch(chaining)
588 {
589 case CHAIN_ECB:
590ret = EVP_DecryptInit(ctx, EVP_aes_128_ecb(), key, iv);
591break;
592 case CHAIN_CBC:
593ret = EVP_DecryptInit(ctx, EVP_aes_128_cbc(), key, iv);
594break;
595 default:
596EXCEPTION(gourou::CLIENT_BAD_CHAINING, "Unknown chaining mode " << chaining);
597 }
598 break;
599default:
600 EVP_CIPHER_CTX_free(ctx);
601 EXCEPTION(gourou::CLIENT_BAD_KEY_SIZE, "Invalid key size " << keyLength);
602}
603break;
604 }
605 case ALGO_RC4:
606 {
607if (keyLength != 16)
608{
609 EVP_CIPHER_CTX_free(ctx);
610 EXCEPTION(gourou::CLIENT_BAD_KEY_SIZE, "Invalid key size " << keyLength);
611}
612ret = EVP_DecryptInit(ctx, EVP_rc4(), key, iv);
613break;
614 }
615 }
616
617 if (ret <= 0)
618 {
619EVP_CIPHER_CTX_free(ctx);
620EXCEPTION(gourou::CLIENT_CRYPT_ERROR, ERR_error_string(ERR_get_error(), NULL));
621 }
622
623 return ctx;
624}
625
626void DRMProcessorClientImpl::encryptUpdate(void* handler, const unsigned char* dataIn, unsigned int dataInLength,
627 unsigned char* dataOut, unsigned int* dataOutLength)
628{
629 int ret = EVP_EncryptUpdate((EVP_CIPHER_CTX*)handler, dataOut, (int*)dataOutLength, dataIn, dataInLength);
630
631 if (ret <= 0)
632 EXCEPTION(gourou::CLIENT_CRYPT_ERROR, ERR_error_string(ERR_get_error(), NULL));
633}
634
635void DRMProcessorClientImpl::encryptFinalize(void* handler,
636 unsigned char* dataOut, unsigned int* dataOutLength)
637{
638 int len, ret;
639
640 ret = EVP_EncryptFinal_ex((EVP_CIPHER_CTX*)handler, dataOut, &len);
641 *dataOutLength += len;
642 EVP_CIPHER_CTX_free((EVP_CIPHER_CTX*)handler);
643
644 if (ret <= 0)
645 EXCEPTION(gourou::CLIENT_CRYPT_ERROR, ERR_error_string(ERR_get_error(), NULL));
646}
647
648void DRMProcessorClientImpl::decrypt(CRYPTO_ALGO algo, CHAINING_MODE chaining,
649 const unsigned char* key, unsigned int keyLength,
650 const unsigned char* iv, unsigned int ivLength,
651 const unsigned char* dataIn, unsigned int dataInLength,
652 unsigned char* dataOut, unsigned int* dataOutLength)
653{
654 void* handler = decryptInit(algo, chaining, key, keyLength, iv, ivLength);
655 decryptUpdate(handler, dataIn, dataInLength, dataOut, dataOutLength);
656 decryptFinalize(handler, dataOut+*dataOutLength, dataOutLength);
657}
658
659void DRMProcessorClientImpl::decryptUpdate(void* handler, const unsigned char* dataIn, unsigned int dataInLength,
660 unsigned char* dataOut, unsigned int* dataOutLength)
661{
662 int ret = EVP_DecryptUpdate((EVP_CIPHER_CTX*)handler, dataOut, (int*)dataOutLength, dataIn, dataInLength);
663
664 if (ret <= 0)
665 EXCEPTION(gourou::CLIENT_CRYPT_ERROR, ERR_error_string(ERR_get_error(), NULL));
666}
667
668void DRMProcessorClientImpl::decryptFinalize(void* handler, unsigned char* dataOut, unsigned int* dataOutLength)
669{
670 int len, ret;
671
672 ret = EVP_DecryptFinal_ex((EVP_CIPHER_CTX*)handler, dataOut, &len);
673 *dataOutLength += len;
674 EVP_CIPHER_CTX_free((EVP_CIPHER_CTX*)handler);
675
676 if (ret <= 0)
677 EXCEPTION(gourou::CLIENT_CRYPT_ERROR, ERR_error_string(ERR_get_error(), NULL));
678}
679
680void* DRMProcessorClientImpl::zipOpen(const std::string& path)
681{
682 zip_t* handler = zip_open(path.c_str(), 0, 0);
683
684 if (!handler)
685EXCEPTION(gourou::CLIENT_BAD_ZIP_FILE, "Invalid zip file " << path);
686
687 return handler;
688}
689
690void DRMProcessorClientImpl::zipReadFile(void* handler, const std::string& path, gourou::ByteArray& result, bool decompress)
691{
692 std::string res;
693 zip_stat_t sb;
694
695 if (zip_stat((zip_t *)handler, path.c_str(), 0, &sb) < 0)
696EXCEPTION(gourou::CLIENT_ZIP_ERROR, "Zip error, no file " << path << ", " << zip_strerror((zip_t *)handler));
697
698 if (!(sb.valid & (ZIP_STAT_INDEX|ZIP_STAT_SIZE)))
699EXCEPTION(gourou::CLIENT_ZIP_ERROR, "Required fields missing");
700
701 result.resize(sb.size);
702
703 zip_file_t *f = zip_fopen_index((zip_t *)handler, sb.index, (decompress)?0:ZIP_FL_COMPRESSED);
704 zip_fread(f, result.data(), sb.size);
705 zip_fclose(f);
706}
707
708void DRMProcessorClientImpl::zipWriteFile(void* handler, const std::string& path, gourou::ByteArray& content)
709{
710 zip_int64_t ret;
711
712 zip_source_t* s = zip_source_buffer((zip_t*)handler, content.takeShadowData(), content.length(), 1);
713
714 zip_int64_t idx = zip_name_locate((zip_t*)handler, path.c_str(), 0);
715
716 // File doesn't exists
717 if (idx == -1)
718ret = zip_file_add((zip_t*)handler, path.c_str(), s, 0);
719 else
720ret = zip_file_replace((zip_t*)handler, idx, s, ZIP_FL_OVERWRITE);
721
722 if (ret < 0)
723 {
724zip_source_free(s);
725EXCEPTION(gourou::CLIENT_ZIP_ERROR, "Zip error " << zip_strerror((zip_t *)handler));
726 }
727}
728
729void DRMProcessorClientImpl::zipDeleteFile(void* handler, const std::string& path)
730{
731 zip_int64_t idx = zip_name_locate((zip_t*)handler, path.c_str(), 0);
732
733 if (idx < 0)
734EXCEPTION(gourou::CLIENT_ZIP_ERROR, "No such file " << path.c_str());
735
736 if (zip_delete((zip_t*)handler, idx))
737EXCEPTION(gourou::CLIENT_ZIP_ERROR, "Zip error " << zip_strerror((zip_t *)handler));
738}
739
740void DRMProcessorClientImpl::zipClose(void* handler)
741{
742 zip_close((zip_t*)handler);
743}
744
745void DRMProcessorClientImpl::inflate(gourou::ByteArray& data, gourou::ByteArray& result,
746 int wbits)
747{
748 unsigned int dataSize = data.size()*2;
749 unsigned char* buffer = new unsigned char[dataSize];
750
751 z_stream infstream;
752
753 infstream.zalloc = Z_NULL;
754 infstream.zfree = Z_NULL;
755 infstream.opaque = Z_NULL;
756
757 infstream.avail_in = (uInt)data.size();
758 infstream.next_in = (Bytef *)data.data(); // input char array
759 infstream.avail_out = (uInt)dataSize; // size of output
760 infstream.next_out = (Bytef *)buffer; // output char array
761
762 int ret = inflateInit2(&infstream, wbits);
763
764 if (ret != Z_OK)
765EXCEPTION(gourou::CLIENT_ZIP_ERROR, "Inflate error, code " << zError(ret) << ", msg " << infstream.msg);
766
767 ret = ::inflate(&infstream, Z_FINISH);
768 while (ret == Z_OK || ret == Z_STREAM_END || ret == Z_BUF_ERROR)
769 {
770// Real error
771if (ret == Z_BUF_ERROR && infstream.avail_out == (uInt)dataSize)
772 break;
773
774result.append(buffer, dataSize-infstream.avail_out);
775
776if ((ret == Z_OK && infstream.avail_out != 0) || ret == Z_STREAM_END)
777 break;
778infstream.avail_out = (uInt)dataSize; // size of output
779infstream.next_out = (Bytef *)buffer; // output char array
780ret = ::inflate(&infstream, Z_FINISH);
781 }
782
783 if (ret == Z_STREAM_END)
784ret = inflateEnd(&infstream);
785
786 delete[] buffer;
787
788 if (ret != Z_OK && ret != Z_STREAM_END)
789EXCEPTION(gourou::CLIENT_ZIP_ERROR, "Inflate error, code " << zError(ret) << ", msg " << infstream.msg);
790}
791
792void DRMProcessorClientImpl::deflate(gourou::ByteArray& data, gourou::ByteArray& result,
793 int wbits, int compressionLevel)
794{
795 unsigned int dataSize = data.size();
796 unsigned char* buffer = new unsigned char[dataSize];
797
798 z_stream defstream;
799
800 defstream.zalloc = Z_NULL;
801 defstream.zfree = Z_NULL;
802 defstream.opaque = Z_NULL;
803
804 defstream.avail_in = (uInt)dataSize;
805 defstream.next_in = (Bytef *)data.data(); // input char array
806 defstream.avail_out = (uInt)dataSize; // size of output
807 defstream.next_out = (Bytef *)buffer; // output char array
808
809 int ret = deflateInit2(&defstream, Z_DEFAULT_COMPRESSION, Z_DEFLATED, wbits,
810 compressionLevel, Z_DEFAULT_STRATEGY);
811
812 if (ret != Z_OK)
813EXCEPTION(gourou::CLIENT_ZIP_ERROR, "Deflate error, code " << zError(ret) << ", msg " << defstream.msg);
814
815 ret = ::deflate(&defstream, Z_FINISH);
816 while (ret == Z_OK || ret == Z_STREAM_END)
817 {
818result.append(buffer, dataSize-defstream.avail_out);
819if ((ret == Z_OK && defstream.avail_out != 0) || ret == Z_STREAM_END)
820 break;
821defstream.avail_out = (uInt)dataSize; // size of output
822defstream.next_out = (Bytef *)buffer; // output char array
823ret = ::deflate(&defstream, Z_FINISH);
824 }
825
826 if (ret == Z_STREAM_END)
827ret = deflateEnd(&defstream);
828
829 delete[] buffer;
830
831 if (ret != Z_OK && ret != Z_STREAM_END)
832EXCEPTION(gourou::CLIENT_ZIP_ERROR, "Deflate error, code " << zError(ret) << ", msg " << defstream.msg);
833}

Archive Download this file