mirror of
https://forge.soutade.fr/soutade/libgourou.git
synced 2026-03-27 01:36:58 +00:00
Compare commits
28 commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d7bd98e719 | ||
|
|
72cb22ad2a | ||
|
|
b44b988966 | ||
|
|
76cab18667 | ||
|
|
2387dff2cb | ||
|
|
a7cfd3ef89 | ||
|
|
772abdd2f9 | ||
|
|
1605656c73 | ||
|
|
8f0341d0bd | ||
|
|
8061681705 | ||
|
|
724961566c | ||
|
|
98c511d0ca | ||
|
|
db3e2179a9 | ||
|
|
28aefba6d6 | ||
|
|
e0e2bc7430 | ||
|
|
d3c90f03bb | ||
|
|
469d378f9a | ||
|
|
98b531a232 | ||
|
|
956bad3068 | ||
|
|
d9a920b062 | ||
|
|
204500117d | ||
|
|
ce2cf4192a | ||
|
|
68bf48df27 | ||
|
|
81faf1f9be | ||
|
|
f60abf04d8 | ||
|
|
0d77cf55e1 | ||
|
|
86a79cc381 | ||
|
|
68bf982b6f |
30 changed files with 4172 additions and 3987 deletions
13
Makefile
13
Makefile
|
|
@ -12,6 +12,8 @@ LDFLAGS = -lpugixml
|
||||||
|
|
||||||
VERSION := $(shell cat include/libgourou.h |grep LIBGOUROU_VERSION|cut -d '"' -f2)
|
VERSION := $(shell cat include/libgourou.h |grep LIBGOUROU_VERSION|cut -d '"' -f2)
|
||||||
|
|
||||||
|
UNAME := $(shell uname -s)
|
||||||
|
|
||||||
BUILD_STATIC ?= 0
|
BUILD_STATIC ?= 0
|
||||||
BUILD_SHARED ?= 1
|
BUILD_SHARED ?= 1
|
||||||
BUILD_UTILS ?= 1
|
BUILD_UTILS ?= 1
|
||||||
|
|
@ -27,8 +29,13 @@ ifneq ($(BUILD_STATIC), 0)
|
||||||
STATIC_UTILS=1
|
STATIC_UTILS=1
|
||||||
endif
|
endif
|
||||||
ifneq ($(BUILD_SHARED), 0)
|
ifneq ($(BUILD_SHARED), 0)
|
||||||
|
ifeq ($(UNAME), Darwin)
|
||||||
|
TARGETS += libgourou.dylib
|
||||||
|
TARGET_LIBRARIES += libgourou.dylib libgourou.dylib.$(VERSION)
|
||||||
|
else
|
||||||
TARGETS += libgourou.so
|
TARGETS += libgourou.so
|
||||||
TARGET_LIBRARIES += libgourou.so libgourou.so.$(VERSION)
|
TARGET_LIBRARIES += libgourou.so libgourou.so.$(VERSION)
|
||||||
|
endif
|
||||||
endif
|
endif
|
||||||
ifneq ($(BUILD_UTILS), 0)
|
ifneq ($(BUILD_UTILS), 0)
|
||||||
TARGETS += build_utils
|
TARGETS += build_utils
|
||||||
|
|
@ -82,6 +89,12 @@ libgourou.so.$(VERSION): $(OBJECTS) $(UPDFPARSERLIB)
|
||||||
libgourou.so: libgourou.so.$(VERSION)
|
libgourou.so: libgourou.so.$(VERSION)
|
||||||
ln -f -s $^ $@
|
ln -f -s $^ $@
|
||||||
|
|
||||||
|
libgourou.dylib.$(VERSION): $(OBJECTS) $(UPDFPARSERLIB)
|
||||||
|
$(CXX) $^ $(LDFLAGS) -o $@ -shared
|
||||||
|
|
||||||
|
libgourou.dylib: libgourou.dylib.$(VERSION)
|
||||||
|
ln -f -s $^ $@
|
||||||
|
|
||||||
build_utils: $(TARGET_LIBRARIES)
|
build_utils: $(TARGET_LIBRARIES)
|
||||||
$(MAKE) -C utils ROOT=$(PWD) CXX=$(CXX) AR=$(AR) DEBUG=$(DEBUG) STATIC_UTILS=$(STATIC_UTILS) DESTDIR=$(DESTDIR) PREFIX=$(PREFIX)
|
$(MAKE) -C utils ROOT=$(PWD) CXX=$(CXX) AR=$(AR) DEBUG=$(DEBUG) STATIC_UTILS=$(STATIC_UTILS) DESTDIR=$(DESTDIR) PREFIX=$(PREFIX)
|
||||||
|
|
||||||
|
|
|
||||||
63
README.md
63
README.md
|
|
@ -1,16 +1,16 @@
|
||||||
Introduction
|
Introduction
|
||||||
------------
|
------------
|
||||||
|
|
||||||
libgourou is a free implementation of Adobe's ADEPT protocol used to add DRM on ePub/PDF files. It overcome the lacks of Adobe support for Linux platforms.
|
libgourou is a free implementation of Adobe's ADEPT protocol used to add DRM on ePub/PDF files. It overcomes the lack of Adobe support for Linux platforms.
|
||||||
|
|
||||||
|
|
||||||
Architecture
|
Architecture
|
||||||
------------
|
------------
|
||||||
|
|
||||||
Like RMSDK, libgourou has a client/server scheme. All platform specific functions (crypto, network...) has to be implemented in a client class (that derives from DRMProcessorClient) while server implements ADEPT protocol.
|
Like RMSDK, libgourou has a client/server scheme. All platform specific functions (crypto, network...) have to be implemented in a client class (that derives from DRMProcessorClient) while server implements ADEPT protocol.
|
||||||
A reference implementation using cURL, OpenSSL and libzip is provided (in _utils_ directory).
|
A reference implementation using cURL, OpenSSL and libzip is provided (in _utils_ directory).
|
||||||
|
|
||||||
Main fucntions to use from gourou::DRMProcessor are :
|
Main functions to use from gourou::DRMProcessor are:
|
||||||
|
|
||||||
* Get an ePub from an ACSM file : _fulfill()_ and _download()_
|
* Get an ePub from an ACSM file : _fulfill()_ and _download()_
|
||||||
* Create a new device : _createDRMProcessor()_
|
* Create a new device : _createDRMProcessor()_
|
||||||
|
|
@ -18,41 +18,43 @@ Main fucntions to use from gourou::DRMProcessor are :
|
||||||
* Remove DRM : _removeDRM()_
|
* Remove DRM : _removeDRM()_
|
||||||
* Return loaned book : _returnLoan()_
|
* Return loaned book : _returnLoan()_
|
||||||
|
|
||||||
You can import configuration from (at least) :
|
You can import configuration from (at least):
|
||||||
|
|
||||||
* Kobo device : .adept/device.xml, .adept/devicesalt and .adept/activation.xml
|
* Kobo device : .adept/device.xml, .adept/devicesalt and .adept/activation.xml
|
||||||
* Bookeen device : .adobe-digital-editions/device.xml, root/devkey.bin and .adobe-digital-editions/activation.xml
|
* Bookeen device : .adobe-digital-editions/device.xml, root/devkey.bin and .adobe-digital-editions/activation.xml
|
||||||
|
|
||||||
Or create a new one. Be careful : there is a limited number of devices that can be created bye one account.
|
Or create a new one. Be careful: there is a limited number of devices that can be created by one account.
|
||||||
|
|
||||||
ePub are encrypted using a shared key : one account / multiple devices, so you can create and register a device into your computer and read downloaded (and encrypted) ePub file with your eReader configured using the same AdobeID account.
|
ePub are encrypted using a shared key: one account / multiple devices, so you can create and register a device into your computer and read downloaded (and encrypted) ePub file with your eReader configured using the same AdobeID account.
|
||||||
|
|
||||||
For those who wants to remove DRM without adept_remove, you can export your private key and import it within [Calibre](https://calibre-ebook.com/) an its DeDRM plugin.
|
For those who want to remove DRM without adept_remove, you can export your private key and import it within [Calibre](https://calibre-ebook.com/) an its DeDRM plugin.
|
||||||
|
|
||||||
|
|
||||||
Dependencies
|
Dependencies
|
||||||
------------
|
------------
|
||||||
|
|
||||||
For libgourou :
|
For libgourou:
|
||||||
|
|
||||||
_externals_ :
|
_externals_ :
|
||||||
|
|
||||||
* libpugixml
|
* libpugixml
|
||||||
|
|
||||||
_internals_ :
|
_internals_:
|
||||||
|
|
||||||
* uPDFParser
|
* uPDFParser
|
||||||
|
|
||||||
For utils :
|
For utils:
|
||||||
|
|
||||||
* libcurl
|
* libcurl
|
||||||
* OpenSSL
|
* openssl
|
||||||
* libzip
|
* libzip
|
||||||
* libpugixml
|
* libpugixml
|
||||||
|
|
||||||
|
|
||||||
Internal libraries are automatically fetched and statically compiled during the first run.
|
External & utils dependencies has to be installed by your package manager (_apt_ for example).
|
||||||
When you update libgourou's repository, **don't forget to update internal libraries** with :
|
Use _-dev_ flavours to get needed headers.
|
||||||
|
Internal libraries are automatically fetched and statically compiled during the first compilation.
|
||||||
|
When you update libgourou's repository, **don't forget to update internal libraries** with:
|
||||||
|
|
||||||
make update_lib
|
make update_lib
|
||||||
|
|
||||||
|
|
@ -92,31 +94,31 @@ You can optionaly specify your .adept directory
|
||||||
|
|
||||||
export ADEPT_DIR=/home/XXX
|
export ADEPT_DIR=/home/XXX
|
||||||
|
|
||||||
Then, use utils as following :
|
Then, use utils as following:
|
||||||
|
|
||||||
You can import configuration from your eReader or create a new one with _utils/adept\_activate_ :
|
You can import configuration from your eReader or create a new one with _utils/adept\_activate_:
|
||||||
|
|
||||||
./utils/adept_activate -u <AdobeID USERNAME>
|
./utils/adept_activate -u <AdobeID USERNAME>
|
||||||
|
|
||||||
Then a _/home/<user>/.config/adept_ directory is created with all configuration file
|
Then a _/home/<user>/.config/adept_ directory is created with all configuration file
|
||||||
|
|
||||||
To download an ePub/PDF :
|
To download an ePub/PDF:
|
||||||
|
|
||||||
./utils/acsmdownloader <ACSM_FILE>
|
./utils/acsmdownloader <ACSM_FILE>
|
||||||
|
|
||||||
To export your private key (for DeDRM software) :
|
To export your private key (for DeDRM software):
|
||||||
|
|
||||||
./utils/acsmdownloader --export-private-key [-o adobekey_1.der]
|
./utils/acsmdownloader --export-private-key [-o adobekey_1.der]
|
||||||
|
|
||||||
To remove ADEPT DRM :
|
To remove ADEPT DRM:
|
||||||
|
|
||||||
./utils/adept_remove <encryptedFile>
|
./utils/adept_remove <encryptedFile>
|
||||||
|
|
||||||
To list loaned books :
|
To list loaned books:
|
||||||
|
|
||||||
./utils/adept_loan_mgt [-l]
|
./utils/adept_loan_mgt [-l]
|
||||||
|
|
||||||
To return a loaned book :
|
To return a loaned book:
|
||||||
|
|
||||||
./utils/adept_loan_mgt -r <id>
|
./utils/adept_loan_mgt -r <id>
|
||||||
|
|
||||||
|
|
@ -124,6 +126,12 @@ To return a loaned book :
|
||||||
You can get utils full options description with -h or --help switch
|
You can get utils full options description with -h or --help switch
|
||||||
|
|
||||||
|
|
||||||
|
Binary packages
|
||||||
|
---------------
|
||||||
|
|
||||||
|
Compiled version (and AppImage) of libgourou and utils are available in [Release page](https://forge.soutade.fr/soutade/libgourou/releases)
|
||||||
|
|
||||||
|
|
||||||
Docker
|
Docker
|
||||||
------
|
------
|
||||||
|
|
||||||
|
|
@ -150,3 +158,18 @@ Special thanks
|
||||||
* _Jens_ for all test samples and utils testing
|
* _Jens_ for all test samples and utils testing
|
||||||
* _Milian_ for debug & code
|
* _Milian_ for debug & code
|
||||||
* _Berwyn H_ for all test samples, feedbacks, patches and kind donation
|
* _Berwyn H_ for all test samples, feedbacks, patches and kind donation
|
||||||
|
|
||||||
|
|
||||||
|
Donation
|
||||||
|
--------
|
||||||
|
|
||||||
|
https://www.paypal.com/donate/?hosted_button_id=JD3U6XMZCPHKN
|
||||||
|
|
||||||
|
|
||||||
|
Donators
|
||||||
|
--------
|
||||||
|
|
||||||
|
* _Berwyn H_
|
||||||
|
* _bwitt_
|
||||||
|
* _Ismail_
|
||||||
|
* _Radon_
|
||||||
|
|
|
||||||
|
|
@ -30,7 +30,7 @@
|
||||||
|
|
||||||
namespace macaron {
|
namespace macaron {
|
||||||
|
|
||||||
class Base64 {
|
class Base64 {
|
||||||
public:
|
public:
|
||||||
|
|
||||||
static std::string Encode(const std::string data) {
|
static std::string Encode(const std::string data) {
|
||||||
|
|
@ -126,7 +126,7 @@ class Base64 {
|
||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -37,7 +37,7 @@
|
||||||
#define ACS_SERVER "http://adeactivate.adobe.com/adept"
|
#define ACS_SERVER "http://adeactivate.adobe.com/adept"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#define LIBGOUROU_VERSION "0.8.4"
|
#define LIBGOUROU_VERSION "0.8.8"
|
||||||
|
|
||||||
namespace gourou
|
namespace gourou
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -44,7 +44,7 @@ namespace gourou
|
||||||
* Some common utilities
|
* Some common utilities
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#define ADOBE_ADEPT_NS "http://ns.adobe.com/adept"
|
#define ADOBE_ADEPT_NS "http://ns.adobe.com/adept"
|
||||||
|
|
||||||
static const int SHA1_LEN = 20;
|
static const int SHA1_LEN = 20;
|
||||||
static const int RSA_KEY_SIZE = 128;
|
static const int RSA_KEY_SIZE = 128;
|
||||||
|
|
@ -135,15 +135,15 @@ namespace gourou
|
||||||
DRM_INVALID_USER
|
DRM_INVALID_USER
|
||||||
};
|
};
|
||||||
|
|
||||||
#ifndef _NOEXCEPT
|
#ifndef _NOEXCEPT
|
||||||
#if __STDC_VERSION__ >= 201112L
|
#if __STDC_VERSION__ >= 201112L
|
||||||
# define _NOEXCEPT noexcept
|
# define _NOEXCEPT noexcept
|
||||||
# define _NOEXCEPT_(x) noexcept(x)
|
# define _NOEXCEPT_(x) noexcept(x)
|
||||||
#else
|
#else
|
||||||
# define _NOEXCEPT throw()
|
# define _NOEXCEPT throw()
|
||||||
# define _NOEXCEPT_(x)
|
# define _NOEXCEPT_(x)
|
||||||
#endif
|
#endif
|
||||||
#endif /* !_NOEXCEPT */
|
#endif /* !_NOEXCEPT */
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Generic exception class
|
* Generic exception class
|
||||||
|
|
@ -165,8 +165,8 @@ namespace gourou
|
||||||
Exception(const Exception& other)
|
Exception(const Exception& other)
|
||||||
{
|
{
|
||||||
this->code = other.code;
|
this->code = other.code;
|
||||||
this->line = line;
|
this->line = other.line;
|
||||||
this->file = file;
|
this->file = other.file;
|
||||||
this->fullmessage = strdup(other.fullmessage);
|
this->fullmessage = strdup(other.fullmessage);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -181,7 +181,7 @@ namespace gourou
|
||||||
|
|
||||||
private:
|
private:
|
||||||
int code, line;
|
int code, line;
|
||||||
const char* message, *file;
|
const char* file;
|
||||||
char* fullmessage;
|
char* fullmessage;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,7 @@
|
||||||
|
|
||||||
# uPDFParser
|
# uPDFParser
|
||||||
if [ ! -d lib/updfparser ] ; then
|
if [ ! -d lib/updfparser ] ; then
|
||||||
git clone git://soutade.fr/updfparser.git lib/updfparser
|
git clone https://forge.soutade.fr/soutade/uPDFParser.git lib/updfparser
|
||||||
pushd lib/updfparser
|
pushd lib/updfparser
|
||||||
make BUILD_STATIC=1 BUILD_SHARED=0
|
make BUILD_STATIC=1 BUILD_SHARED=0
|
||||||
popd
|
popd
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,7 @@
|
||||||
if [ ! -d lib/updfparser ] ; then
|
if [ ! -d lib/updfparser ] ; then
|
||||||
echo "Some libraries are missing"
|
echo "Some libraries are missing"
|
||||||
echo "You must run this script at the top of libgourou working direcotry."
|
echo "You must run this script at the top of libgourou working direcotry."
|
||||||
echo "./lib/setup.sh must be called first (make all)"
|
echo "./scripts/setup.sh must be called first (make all)"
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -202,7 +202,7 @@ namespace gourou
|
||||||
char* tmp = new char[_length*2+1];
|
char* tmp = new char[_length*2+1];
|
||||||
|
|
||||||
for(int i=0; i<(int)_length; i++)
|
for(int i=0; i<(int)_length; i++)
|
||||||
sprintf(&tmp[i*2], "%02x", _data[i]);
|
snprintf(&tmp[i*2], (_length-i)*2+1, "%02x", _data[i]);
|
||||||
|
|
||||||
tmp[_length*2] = 0;
|
tmp[_length*2] = 0;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -94,12 +94,12 @@ namespace gourou
|
||||||
std::string FulfillmentItem::getMetadata(std::string name)
|
std::string FulfillmentItem::getMetadata(std::string name)
|
||||||
{
|
{
|
||||||
// https://stackoverflow.com/questions/313970/how-to-convert-an-instance-of-stdstring-to-lower-case
|
// https://stackoverflow.com/questions/313970/how-to-convert-an-instance-of-stdstring-to-lower-case
|
||||||
#if __STDC_VERSION__ >= 201112L
|
#if __STDC_VERSION__ >= 201112L
|
||||||
std::transform(name.begin(), name.end(), name.begin(),
|
std::transform(name.begin(), name.end(), name.begin(),
|
||||||
[](unsigned char c){ return std::tolower(c); });
|
[](unsigned char c){ return std::tolower(c); });
|
||||||
#else
|
#else
|
||||||
std::transform(name.begin(), name.end(), name.begin(), tolower);
|
std::transform(name.begin(), name.end(), name.begin(), tolower);
|
||||||
#endif
|
#endif
|
||||||
name = std::string("dc:") + name;
|
name = std::string("dc:") + name;
|
||||||
pugi::xpath_node path = metadatas.select_node(name.c_str());
|
pugi::xpath_node path = metadatas.select_node(name.c_str());
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -21,6 +21,7 @@
|
||||||
#include <sys/time.h>
|
#include <sys/time.h>
|
||||||
#include <time.h>
|
#include <time.h>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
#include <ctime>
|
||||||
|
|
||||||
#include <uPDFParser.h>
|
#include <uPDFParser.h>
|
||||||
|
|
||||||
|
|
@ -70,6 +71,15 @@ namespace gourou
|
||||||
if (user) delete user;
|
if (user) delete user;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// function to parse a date or time string.
|
||||||
|
// https://www.geeksforgeeks.org/cpp/date-and-time-parsing-in-cpp/
|
||||||
|
static time_t parseDateTime(const char* datetimeString, const char* format)
|
||||||
|
{
|
||||||
|
struct tm tmStruct;
|
||||||
|
strptime(datetimeString, format, &tmStruct);
|
||||||
|
return mktime(&tmStruct);
|
||||||
|
}
|
||||||
|
|
||||||
DRMProcessor* DRMProcessor::createDRMProcessor(DRMProcessorClient* client, bool randomSerial, std::string dirName,
|
DRMProcessor* DRMProcessor::createDRMProcessor(DRMProcessorClient* client, bool randomSerial, std::string dirName,
|
||||||
const std::string& hobbes, const std::string& ACSServer)
|
const std::string& hobbes, const std::string& ACSServer)
|
||||||
{
|
{
|
||||||
|
|
@ -508,6 +518,16 @@ namespace gourou
|
||||||
|
|
||||||
GOUROU_LOG(INFO, "Fulfill " << ACSMFile);
|
GOUROU_LOG(INFO, "Fulfill " << ACSMFile);
|
||||||
|
|
||||||
|
std::string expiration = extractTextElem(rootNode, "expiration", false);
|
||||||
|
|
||||||
|
if (expiration != "")
|
||||||
|
{
|
||||||
|
time_t expirationTime = parseDateTime(expiration.c_str(), "%Y-%m-%dT%H:%M:%S");
|
||||||
|
|
||||||
|
if (time(NULL) > expirationTime)
|
||||||
|
GOUROU_LOG(WARN, "WARNING: ACSM file expired (" << expiration << "), It may not work.");
|
||||||
|
}
|
||||||
|
|
||||||
// Build req file
|
// Build req file
|
||||||
pugi::xml_document fulfillReq;
|
pugi::xml_document fulfillReq;
|
||||||
|
|
||||||
|
|
@ -859,6 +879,12 @@ namespace gourou
|
||||||
std::string DRMProcessor::getDefaultAdeptDir(void)
|
std::string DRMProcessor::getDefaultAdeptDir(void)
|
||||||
{
|
{
|
||||||
#ifndef DEFAULT_ADEPT_DIR
|
#ifndef DEFAULT_ADEPT_DIR
|
||||||
|
const char* home = getenv("HOME");
|
||||||
|
|
||||||
|
if (home)
|
||||||
|
return home + std::string("/.config/adept/");
|
||||||
|
else
|
||||||
|
{
|
||||||
const char* user = getenv("USER");
|
const char* user = getenv("USER");
|
||||||
|
|
||||||
if (user && user[0])
|
if (user && user[0])
|
||||||
|
|
@ -867,6 +893,7 @@ namespace gourou
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
return LOCAL_ADEPT_DIR;
|
return LOCAL_ADEPT_DIR;
|
||||||
|
}
|
||||||
#else
|
#else
|
||||||
return DEFAULT_ADEPT_DIR "/";
|
return DEFAULT_ADEPT_DIR "/";
|
||||||
#endif
|
#endif
|
||||||
|
|
@ -1315,8 +1342,9 @@ namespace gourou
|
||||||
|
|
||||||
uPDFParser::Integer* ebxVersion;
|
uPDFParser::Integer* ebxVersion;
|
||||||
std::vector<uPDFParser::Object*> objects = parser.objects();
|
std::vector<uPDFParser::Object*> objects = parser.objects();
|
||||||
std::vector<uPDFParser::Object*>::iterator it;
|
std::vector<uPDFParser::Object*>::iterator it, ebxIt;
|
||||||
std::vector<uPDFParser::Object*>::reverse_iterator rIt;
|
std::vector<uPDFParser::Object*>::reverse_iterator rIt;
|
||||||
|
std::vector<uPDFParser::Object*> ebxObjects;
|
||||||
unsigned char decryptedKey[16];
|
unsigned char decryptedKey[16];
|
||||||
int ebxId;
|
int ebxId;
|
||||||
|
|
||||||
|
|
@ -1375,7 +1403,7 @@ namespace gourou
|
||||||
|
|
||||||
if (object->objectId() == ebxId)
|
if (object->objectId() == ebxId)
|
||||||
{
|
{
|
||||||
// object->deleteKey("Filter");
|
ebxObjects.push_back(object);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1485,6 +1513,33 @@ namespace gourou
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Delete objects that reference EBX objects, except in trailer */
|
||||||
|
for(it = objects.begin(); it != objects.end(); it++)
|
||||||
|
{
|
||||||
|
uPDFParser::Object* object = *it;
|
||||||
|
|
||||||
|
if (object->hasKey("Encrypt") && (*object)["Encrypt"]->type() == uPDFParser::DataType::REFERENCE)
|
||||||
|
{
|
||||||
|
uPDFParser::Reference* encrypt = (uPDFParser::Reference*)(*object)["Encrypt"];
|
||||||
|
|
||||||
|
/* Delete EBX objects */
|
||||||
|
for(ebxIt = ebxObjects.begin(); ebxIt != ebxObjects.end(); ebxIt++)
|
||||||
|
{
|
||||||
|
if (encrypt->value() == (*ebxIt)->objectId())
|
||||||
|
{
|
||||||
|
GOUROU_LOG(ERROR, "Delete stream id " << object->objectId());
|
||||||
|
|
||||||
|
parser.removeObject(object);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Delete EBX objects */
|
||||||
|
for(it = ebxObjects.begin(); it != ebxObjects.end(); it++)
|
||||||
|
parser.removeObject(*it);
|
||||||
|
|
||||||
uPDFParser::Object& trailer = parser.getTrailer();
|
uPDFParser::Object& trailer = parser.getTrailer();
|
||||||
trailer.deleteKey("Encrypt");
|
trailer.deleteKey("Encrypt");
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -6,9 +6,10 @@ TARGETS=$(TARGET_BINARIES) launcher
|
||||||
|
|
||||||
MAN_PAGES=acsmdownloader adept_activate adept_remove adept_loan_mgt
|
MAN_PAGES=acsmdownloader adept_activate adept_remove adept_loan_mgt
|
||||||
|
|
||||||
CXXFLAGS=-Wall -fPIC -I$(ROOT)/include
|
CXXFLAGS=-Wall -fPIC -I$(ROOT)/include -fmacro-prefix-map=$(ROOT)/= -fdata-sections -ffunction-sections
|
||||||
|
|
||||||
STATIC_DEP=
|
STATIC_DEP=
|
||||||
|
# LDFLAGS += -Wl,--gc-sections
|
||||||
LDFLAGS += -L$(ROOT) -lcrypto -lzip -lz -lcurl -lpugixml
|
LDFLAGS += -L$(ROOT) -lcrypto -lzip -lz -lcurl -lpugixml
|
||||||
|
|
||||||
ifneq ($(STATIC_UTILS),)
|
ifneq ($(STATIC_UTILS),)
|
||||||
|
|
@ -31,7 +32,7 @@ COMMON_LIB = utils.a
|
||||||
all: $(TARGETS)
|
all: $(TARGETS)
|
||||||
|
|
||||||
${COMMON_LIB}: $(COMMON_DEPS)
|
${COMMON_LIB}: $(COMMON_DEPS)
|
||||||
$(CXX) $(CXXFLAGS) $(COMMON_DEPS) $(LDFLAGS) -c
|
$(CXX) $(CXXFLAGS) $(COMMON_DEPS) -c
|
||||||
$(AR) crs $@ $(COMMON_OBJECTS)
|
$(AR) crs $@ $(COMMON_OBJECTS)
|
||||||
|
|
||||||
%: %.cpp $(COMMON_LIB) $(STATIC_DEP)
|
%: %.cpp $(COMMON_LIB) $(STATIC_DEP)
|
||||||
|
|
|
||||||
|
|
@ -64,19 +64,18 @@ public:
|
||||||
if (exportPrivateKey)
|
if (exportPrivateKey)
|
||||||
{
|
{
|
||||||
std::string filename;
|
std::string filename;
|
||||||
if (!outputFile)
|
if (outputFile)
|
||||||
filename = std::string("Adobe_PrivateLicenseKey--") + user->getUsername() + ".der";
|
|
||||||
else
|
|
||||||
filename = outputFile;
|
filename = outputFile;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
filename = std::string("Adobe_PrivateLicenseKey--") + user->getUsername() + ".der";
|
||||||
|
|
||||||
if (outputDir)
|
if (outputDir)
|
||||||
{
|
|
||||||
if (!fileExists(outputDir))
|
|
||||||
mkpath(outputDir);
|
|
||||||
|
|
||||||
filename = std::string(outputDir) + "/" + filename;
|
filename = std::string(outputDir) + "/" + filename;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
createPath(filename.c_str());
|
||||||
|
|
||||||
processor.exportPrivateLicenseKey(filename);
|
processor.exportPrivateLicenseKey(filename);
|
||||||
|
|
||||||
std::cout << "Private license key exported to " << filename << std::endl;
|
std::cout << "Private license key exported to " << filename << std::endl;
|
||||||
|
|
@ -86,7 +85,9 @@ public:
|
||||||
gourou::FulfillmentItem* item = processor.fulfill(acsmFile, notify);
|
gourou::FulfillmentItem* item = processor.fulfill(acsmFile, notify);
|
||||||
|
|
||||||
std::string filename;
|
std::string filename;
|
||||||
if (!outputFile)
|
if (outputFile)
|
||||||
|
filename = outputFile;
|
||||||
|
else
|
||||||
{
|
{
|
||||||
filename = item->getMetadata("title");
|
filename = item->getMetadata("title");
|
||||||
if (filename == "")
|
if (filename == "")
|
||||||
|
|
@ -96,18 +97,13 @@ public:
|
||||||
// Remove invalid characters
|
// Remove invalid characters
|
||||||
std::replace(filename.begin(), filename.end(), '/', '_');
|
std::replace(filename.begin(), filename.end(), '/', '_');
|
||||||
}
|
}
|
||||||
}
|
|
||||||
else
|
|
||||||
filename = outputFile;
|
|
||||||
|
|
||||||
if (outputDir)
|
if (outputDir)
|
||||||
{
|
|
||||||
if (!fileExists(outputDir))
|
|
||||||
mkpath(outputDir);
|
|
||||||
|
|
||||||
filename = std::string(outputDir) + "/" + filename;
|
filename = std::string(outputDir) + "/" + filename;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
createPath(filename.c_str());
|
||||||
|
|
||||||
gourou::DRMProcessor::ITEM_TYPE type = processor.download(item, filename, resume);
|
gourou::DRMProcessor::ITEM_TYPE type = processor.download(item, filename, resume);
|
||||||
|
|
||||||
if (!outputFile)
|
if (!outputFile)
|
||||||
|
|
@ -186,8 +182,8 @@ static void usage(const char* cmd)
|
||||||
std::cout << basename((char*)cmd) << " download EPUB file from ACSM request file" << std::endl << std::endl;
|
std::cout << basename((char*)cmd) << " download EPUB file from ACSM request file" << std::endl << std::endl;
|
||||||
std::cout << "Usage: " << basename((char*)cmd) << " [OPTIONS] file.acsm" << std::endl << std::endl;
|
std::cout << "Usage: " << basename((char*)cmd) << " [OPTIONS] file.acsm" << std::endl << std::endl;
|
||||||
std::cout << "Global Options:" << std::endl;
|
std::cout << "Global Options:" << std::endl;
|
||||||
std::cout << " " << "-O|--output-dir" << "\t" << "Optional output directory were to put result (default ./)" << std::endl;
|
std::cout << " " << "-O|--output-dir" << "\t" << "Optional output directory were to put result (default ./) (not compatible with -o)" << std::endl;
|
||||||
std::cout << " " << "-o|--output-file" << "\t" << "Optional output filename (default <title.(epub|pdf|der)>)" << std::endl;
|
std::cout << " " << "-o|--output-file" << "\t" << "Optional output filename (default <title.(epub|pdf|der)>) (not compatible with -O)" << std::endl;
|
||||||
std::cout << " " << "-f|--acsm-file" << "\t" << "Backward compatibility: ACSM request file for epub download" << std::endl;
|
std::cout << " " << "-f|--acsm-file" << "\t" << "Backward compatibility: ACSM request file for epub download" << std::endl;
|
||||||
std::cout << " " << "-e|--export-private-key"<< "\t" << "Export private key in DER format" << std::endl;
|
std::cout << " " << "-e|--export-private-key"<< "\t" << "Export private key in DER format" << std::endl;
|
||||||
std::cout << " " << "-r|--resume" << "\t\t" << "Try to resume download (in case of previous failure)" << std::endl;
|
std::cout << " " << "-r|--resume" << "\t\t" << "Try to resume download (in case of previous failure)" << std::endl;
|
||||||
|
|
@ -309,6 +305,12 @@ int main(int argc, char** argv)
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (outputDir && outputFile)
|
||||||
|
{
|
||||||
|
std::cout << "Error : you cannot use both -o and -O" << std::endl;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
ACSMDownloader downloader;
|
ACSMDownloader downloader;
|
||||||
|
|
||||||
int i;
|
int i;
|
||||||
|
|
@ -339,7 +341,7 @@ int main(int argc, char** argv)
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (!fileExists(acsmFile))
|
if (!pathExists(acsmFile))
|
||||||
{
|
{
|
||||||
std::cout << "Error : " << acsmFile << " doesn't exists" << std::endl;
|
std::cout << "Error : " << acsmFile << " doesn't exists" << std::endl;
|
||||||
ret = -1;
|
ret = -1;
|
||||||
|
|
|
||||||
|
|
@ -240,7 +240,7 @@ int main(int argc, char** argv)
|
||||||
if (_outputDir[0] == '.' || _outputDir[0] != '/')
|
if (_outputDir[0] == '.' || _outputDir[0] != '/')
|
||||||
{
|
{
|
||||||
// realpath doesn't works if file/dir doesn't exists
|
// realpath doesn't works if file/dir doesn't exists
|
||||||
if (fileExists(_outputDir))
|
if (pathExists(_outputDir))
|
||||||
outputDir = strdup(realpath(_outputDir, 0));
|
outputDir = strdup(realpath(_outputDir, 0));
|
||||||
else
|
else
|
||||||
outputDir = strdup(abspath(_outputDir));
|
outputDir = strdup(abspath(_outputDir));
|
||||||
|
|
@ -250,7 +250,7 @@ int main(int argc, char** argv)
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string pass;
|
std::string pass;
|
||||||
if (fileExists(outputDir))
|
if (pathExists(outputDir))
|
||||||
{
|
{
|
||||||
int key;
|
int key;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -109,7 +109,7 @@ private:
|
||||||
|
|
||||||
std::string loanDir = std::string(adeptDir) + std::string("/") + LOANS_DIR;
|
std::string loanDir = std::string(adeptDir) + std::string("/") + LOANS_DIR;
|
||||||
|
|
||||||
if (!fileExists(loanDir.c_str()))
|
if (!pathExists(loanDir.c_str()))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
dp = opendir (loanDir.c_str());
|
dp = opendir (loanDir.c_str());
|
||||||
|
|
@ -229,7 +229,12 @@ private:
|
||||||
maxSizeBookName = loan->bookName.size();
|
maxSizeBookName = loan->bookName.size();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (maxSizeBookName > MAX_SIZE_BOOK_NAME)
|
/* Manage empty names */
|
||||||
|
if (maxSizeBookName == 0)
|
||||||
|
maxSizeBookName = sizeof("No name ")-1;
|
||||||
|
else if (maxSizeBookName < 4)
|
||||||
|
maxSizeBookName = 4;
|
||||||
|
else if (maxSizeBookName > MAX_SIZE_BOOK_NAME)
|
||||||
maxSizeBookName = MAX_SIZE_BOOK_NAME;
|
maxSizeBookName = MAX_SIZE_BOOK_NAME;
|
||||||
else if ((maxSizeBookName % 2))
|
else if ((maxSizeBookName % 2))
|
||||||
maxSizeBookName++;
|
maxSizeBookName++;
|
||||||
|
|
@ -276,7 +281,9 @@ private:
|
||||||
std::cout << kv.first;
|
std::cout << kv.first;
|
||||||
std::cout << " ";
|
std::cout << " ";
|
||||||
|
|
||||||
if (loan->bookName.size() > MAX_SIZE_BOOK_NAME)
|
if (loan->bookName.size() == 0)
|
||||||
|
bookName = std::string("No name ");
|
||||||
|
else if (loan->bookName.size() > MAX_SIZE_BOOK_NAME)
|
||||||
bookName = std::string(loan->bookName.c_str(), MAX_SIZE_BOOK_NAME);
|
bookName = std::string(loan->bookName.c_str(), MAX_SIZE_BOOK_NAME);
|
||||||
else
|
else
|
||||||
bookName = loan->bookName;
|
bookName = loan->bookName;
|
||||||
|
|
|
||||||
|
|
@ -81,16 +81,13 @@ public:
|
||||||
gourou::DRMProcessor processor(&client, deviceFile, activationFile, devicekeyFile);
|
gourou::DRMProcessor processor(&client, deviceFile, activationFile, devicekeyFile);
|
||||||
|
|
||||||
std::string filename;
|
std::string filename;
|
||||||
if (!outputFile)
|
if (outputFile)
|
||||||
filename = std::string(inputFile);
|
|
||||||
else
|
|
||||||
filename = outputFile;
|
filename = outputFile;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
filename = std::string(inputFile);
|
||||||
|
|
||||||
if (outputDir)
|
if (outputDir)
|
||||||
{
|
|
||||||
if (!fileExists(outputDir))
|
|
||||||
mkpath(outputDir);
|
|
||||||
|
|
||||||
filename = std::string(outputDir) + "/" + filename;
|
filename = std::string(outputDir) + "/" + filename;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -103,6 +100,8 @@ public:
|
||||||
EXCEPTION(gourou::DRM_FORMAT_NOT_SUPPORTED, "Unsupported file format of " << filename);
|
EXCEPTION(gourou::DRM_FORMAT_NOT_SUPPORTED, "Unsupported file format of " << filename);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
createPath(filename.c_str());
|
||||||
|
|
||||||
if (inputFile != filename)
|
if (inputFile != filename)
|
||||||
{
|
{
|
||||||
unlink(filename.c_str());
|
unlink(filename.c_str());
|
||||||
|
|
@ -147,8 +146,8 @@ static void usage(const char* cmd)
|
||||||
std::cout << "Usage: " << basename((char*)cmd) << " [OPTIONS] file(.epub|pdf)" << std::endl << std::endl;
|
std::cout << "Usage: " << basename((char*)cmd) << " [OPTIONS] file(.epub|pdf)" << std::endl << std::endl;
|
||||||
|
|
||||||
std::cout << "Global Options:" << std::endl;
|
std::cout << "Global Options:" << std::endl;
|
||||||
std::cout << " " << "-O|--output-dir" << "\t" << "Optional output directory were to put result (default ./)" << std::endl;
|
std::cout << " " << "-O|--output-dir" << "\t" << "Optional output directory were to put result (default ./) (not compatible with -o)" << std::endl;
|
||||||
std::cout << " " << "-o|--output-file" << "\t" << "Optional output filename (default inplace DRM removal>)" << std::endl;
|
std::cout << " " << "-o|--output-file" << "\t" << "Optional output filename (default inplace DRM removal>) (not compatible with -O)" << std::endl;
|
||||||
std::cout << " " << "-f|--input-file" << "\t" << "Backward compatibility: EPUB/PDF file to process" << std::endl;
|
std::cout << " " << "-f|--input-file" << "\t" << "Backward compatibility: EPUB/PDF file to process" << std::endl;
|
||||||
std::cout << " " << "-v|--verbose" << "\t\t" << "Increase verbosity, can be set multiple times" << std::endl;
|
std::cout << " " << "-v|--verbose" << "\t\t" << "Increase verbosity, can be set multiple times" << std::endl;
|
||||||
std::cout << " " << "-V|--version" << "\t\t" << "Display libgourou version" << std::endl;
|
std::cout << " " << "-V|--version" << "\t\t" << "Display libgourou version" << std::endl;
|
||||||
|
|
@ -259,6 +258,12 @@ int main(int argc, char** argv)
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (outputDir && outputFile)
|
||||||
|
{
|
||||||
|
std::cout << "Error : you cannot use both -o and -O" << std::endl;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
ADEPTRemove remover;
|
ADEPTRemove remover;
|
||||||
|
|
||||||
int i;
|
int i;
|
||||||
|
|
|
||||||
|
|
@ -49,17 +49,27 @@
|
||||||
#include <libgourou_common.h>
|
#include <libgourou_common.h>
|
||||||
#include "drmprocessorclientimpl.h"
|
#include "drmprocessorclientimpl.h"
|
||||||
|
|
||||||
|
static int error_cb(const char *str, size_t len, void *u)
|
||||||
|
{
|
||||||
|
std::cout << str << std::endl;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
DRMProcessorClientImpl::DRMProcessorClientImpl():
|
DRMProcessorClientImpl::DRMProcessorClientImpl():
|
||||||
legacy(0), deflt(0)
|
legacy(0), deflt(0)
|
||||||
{
|
{
|
||||||
#if OPENSSL_VERSION_MAJOR >= 3
|
#if OPENSSL_VERSION_MAJOR >= 3
|
||||||
legacy = OSSL_PROVIDER_load(NULL, "legacy");
|
legacy = OSSL_PROVIDER_load(NULL, "legacy");
|
||||||
if (!legacy)
|
if (!legacy)
|
||||||
|
{
|
||||||
|
ERR_print_errors_cb(error_cb, NULL);
|
||||||
EXCEPTION(gourou::CLIENT_OSSL_ERROR, "Error, OpenSSL legacy provider not available");
|
EXCEPTION(gourou::CLIENT_OSSL_ERROR, "Error, OpenSSL legacy provider not available");
|
||||||
|
}
|
||||||
|
|
||||||
deflt = OSSL_PROVIDER_load(NULL, "default");
|
deflt = OSSL_PROVIDER_load(NULL, "default");
|
||||||
if (!deflt)
|
if (!deflt)
|
||||||
EXCEPTION(gourou::CLIENT_OSSL_ERROR, "Error, OpenSSL default provider not available");
|
EXCEPTION(gourou::CLIENT_OSSL_ERROR, "Error, OpenSSL default provider not available");
|
||||||
|
OSSL_PROVIDER_load(NULL, "base");
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef WIN32
|
#ifdef WIN32
|
||||||
|
|
@ -68,7 +78,13 @@ DRMProcessorClientImpl::DRMProcessorClientImpl():
|
||||||
strcpy(cookiejar, "/tmp/libgourou_cookie_jar_XXXXXX");
|
strcpy(cookiejar, "/tmp/libgourou_cookie_jar_XXXXXX");
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
mkstemp(cookiejar);
|
int fd = mkstemp(cookiejar);
|
||||||
|
if (fd >= 0)
|
||||||
|
close(fd);
|
||||||
|
else
|
||||||
|
{
|
||||||
|
EXCEPTION(gourou::CLIENT_FILE_ERROR, "mkstemp error");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
DRMProcessorClientImpl::~DRMProcessorClientImpl()
|
DRMProcessorClientImpl::~DRMProcessorClientImpl()
|
||||||
|
|
@ -131,6 +147,7 @@ void DRMProcessorClientImpl::randBytes(unsigned char* bytesOut, unsigned int len
|
||||||
#define HTTP_REQ_MAX_RETRY 5
|
#define HTTP_REQ_MAX_RETRY 5
|
||||||
#define DISPLAY_THRESHOLD 10*1024 // Threshold to display download progression
|
#define DISPLAY_THRESHOLD 10*1024 // Threshold to display download progression
|
||||||
static unsigned downloadedBytes;
|
static unsigned downloadedBytes;
|
||||||
|
static int lastPercent = -1;
|
||||||
|
|
||||||
static int downloadProgress(void *clientp, curl_off_t dltotal, curl_off_t dlnow,
|
static int downloadProgress(void *clientp, curl_off_t dltotal, curl_off_t dlnow,
|
||||||
curl_off_t ultotal, curl_off_t ulnow)
|
curl_off_t ultotal, curl_off_t ulnow)
|
||||||
|
|
@ -142,7 +159,11 @@ static int downloadProgress(void *clientp, curl_off_t dltotal, curl_off_t dlnow,
|
||||||
if (dltotal)
|
if (dltotal)
|
||||||
percent = (dlnow * 100) / dltotal;
|
percent = (dlnow * 100) / dltotal;
|
||||||
|
|
||||||
|
if (lastPercent != percent)
|
||||||
|
{
|
||||||
std::cout << "\rDownload " << percent << "%" << std::flush;
|
std::cout << "\rDownload " << percent << "%" << std::flush;
|
||||||
|
lastPercent = percent;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
@ -263,6 +284,7 @@ std::string DRMProcessorClientImpl::sendHTTPRequest(const std::string& URL, cons
|
||||||
|
|
||||||
curl_easy_setopt(curl, CURLOPT_XFERINFOFUNCTION, downloadProgress);
|
curl_easy_setopt(curl, CURLOPT_XFERINFOFUNCTION, downloadProgress);
|
||||||
curl_easy_setopt(curl, CURLOPT_NOPROGRESS, 0);
|
curl_easy_setopt(curl, CURLOPT_NOPROGRESS, 0);
|
||||||
|
lastPercent = -1;
|
||||||
|
|
||||||
for (int i=0; i<HTTP_REQ_MAX_RETRY; i++)
|
for (int i=0; i<HTTP_REQ_MAX_RETRY; i++)
|
||||||
{
|
{
|
||||||
|
|
@ -298,14 +320,15 @@ std::string DRMProcessorClientImpl::sendHTTPRequest(const std::string& URL, cons
|
||||||
}
|
}
|
||||||
|
|
||||||
curl_slist_free_all(list);
|
curl_slist_free_all(list);
|
||||||
|
|
||||||
|
long http_code = 400;
|
||||||
|
curl_easy_getinfo (curl, CURLINFO_RESPONSE_CODE, &http_code);
|
||||||
|
|
||||||
curl_easy_cleanup(curl);
|
curl_easy_cleanup(curl);
|
||||||
|
|
||||||
if (res != CURLE_OK)
|
if (res != CURLE_OK)
|
||||||
EXCEPTION(gourou::CLIENT_NETWORK_ERROR, "Error " << curl_easy_strerror(res));
|
EXCEPTION(gourou::CLIENT_NETWORK_ERROR, "Error " << curl_easy_strerror(res));
|
||||||
|
|
||||||
long http_code = 400;
|
|
||||||
curl_easy_getinfo (curl, CURLINFO_RESPONSE_CODE, &http_code);
|
|
||||||
|
|
||||||
if (http_code >= 400)
|
if (http_code >= 400)
|
||||||
EXCEPTION(gourou::CLIENT_HTTP_ERROR, "HTTP Error code " << http_code);
|
EXCEPTION(gourou::CLIENT_HTTP_ERROR, "HTTP Error code " << http_code);
|
||||||
|
|
||||||
|
|
@ -332,11 +355,39 @@ void DRMProcessorClientImpl::padWithPKCS1(unsigned char* out, unsigned int outLe
|
||||||
0x00 0x01 0xff * n 0x00 dataIn
|
0x00 0x01 0xff * n 0x00 dataIn
|
||||||
*/
|
*/
|
||||||
|
|
||||||
memset(out, 0xFF, outLength);
|
memset(out, 0xFF, outLength - inLength - 1);
|
||||||
|
|
||||||
out[0] = 0x0;
|
out[0] = 0x0;
|
||||||
out[1] = 0x1;
|
out[1] = 0x1;
|
||||||
out[outLength - inLength - 1] = 0x00;
|
out[outLength - inLength - 1] = 0x00;
|
||||||
|
|
||||||
|
memcpy(&out[outLength - inLength], in, inLength);
|
||||||
|
}
|
||||||
|
|
||||||
|
void DRMProcessorClientImpl::padWithPKCS1Type2(unsigned char* out, unsigned int outLength,
|
||||||
|
const unsigned char* in, unsigned int inLength)
|
||||||
|
{
|
||||||
|
if (outLength < (inLength + 3))
|
||||||
|
EXCEPTION(gourou::CLIENT_RSA_ERROR, "Not enough space for PKCS1 padding");
|
||||||
|
|
||||||
|
/*
|
||||||
|
PKCS1v5 type 2 Padding is :
|
||||||
|
0x00 0x02 0xXX * n 0x00 dataIn
|
||||||
|
XX is random non zero data
|
||||||
|
*/
|
||||||
|
|
||||||
|
RAND_bytes(&out[2], outLength - inLength - 1);
|
||||||
|
|
||||||
|
for(unsigned int i=2; i<outLength - inLength - 1; i++)
|
||||||
|
{
|
||||||
|
while (out[i] == 0)
|
||||||
|
RAND_bytes(&out[i], 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
out[0] = 0x0;
|
||||||
|
out[1] = 0x2;
|
||||||
|
out[outLength - inLength - 1] = 0x00;
|
||||||
|
|
||||||
memcpy(&out[outLength - inLength], in, inLength);
|
memcpy(&out[outLength - inLength], in, inLength);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -428,33 +479,45 @@ void DRMProcessorClientImpl::RSAPublicEncrypt(const unsigned char* RSAKey, unsig
|
||||||
unsigned char* res)
|
unsigned char* res)
|
||||||
{
|
{
|
||||||
size_t outlen;
|
size_t outlen;
|
||||||
|
unsigned char* tmp;
|
||||||
|
|
||||||
X509 * x509 = d2i_X509(0, &RSAKey, RSAKeyLength);
|
X509 * x509 = d2i_X509(0, &RSAKey, RSAKeyLength);
|
||||||
if (!x509)
|
if (!x509)
|
||||||
EXCEPTION(gourou::CLIENT_INVALID_CERTIFICATE, "Invalid certificate");
|
EXCEPTION(gourou::CLIENT_INVALID_CERTIFICATE, "Invalid certificate");
|
||||||
|
|
||||||
EVP_PKEY_CTX *ctx;
|
EVP_PKEY_CTX *ctx;
|
||||||
EVP_PKEY * evpKey = X509_get_pubkey(x509);
|
EVP_PKEY * pkey = X509_get_pubkey(x509);
|
||||||
|
|
||||||
if (!evpKey)
|
if (!pkey)
|
||||||
EXCEPTION(gourou::CLIENT_NO_PUB_KEY, "No public key in certificate");
|
EXCEPTION(gourou::CLIENT_NO_PUB_KEY, "No public key in certificate");
|
||||||
|
|
||||||
ctx = EVP_PKEY_CTX_new(evpKey, NULL);
|
ctx = EVP_PKEY_CTX_new(pkey, NULL);
|
||||||
|
|
||||||
if (EVP_PKEY_encrypt_init(ctx) <= 0)
|
if (EVP_PKEY_encrypt_init(ctx) <= 0)
|
||||||
EXCEPTION(gourou::CLIENT_RSA_ERROR, ERR_error_string(ERR_get_error(), NULL));
|
EXCEPTION(gourou::CLIENT_RSA_ERROR, ERR_error_string(ERR_get_error(), NULL));
|
||||||
|
|
||||||
if (EVP_PKEY_CTX_set_rsa_padding(ctx, RSA_PKCS1_PADDING) <= 0)
|
if (EVP_PKEY_CTX_set_rsa_padding(ctx, RSA_NO_PADDING) <= 0)
|
||||||
EXCEPTION(gourou::CLIENT_RSA_ERROR, ERR_error_string(ERR_get_error(), NULL));
|
EXCEPTION(gourou::CLIENT_RSA_ERROR, ERR_error_string(ERR_get_error(), NULL));
|
||||||
|
|
||||||
int ret = EVP_PKEY_encrypt(ctx, res, &outlen, data, dataLength);
|
outlen = EVP_PKEY_get_size(pkey);
|
||||||
|
|
||||||
|
tmp = (unsigned char*)malloc(outlen);
|
||||||
|
|
||||||
|
/*
|
||||||
|
PKCS1 functions are no more exported.
|
||||||
|
Some OpenSSL libraries still use type 1
|
||||||
|
*/
|
||||||
|
padWithPKCS1Type2(tmp, outlen, data, dataLength);
|
||||||
|
|
||||||
|
int ret = EVP_PKEY_encrypt(ctx, res, &outlen, tmp, outlen);
|
||||||
|
|
||||||
EVP_PKEY_CTX_free(ctx);
|
EVP_PKEY_CTX_free(ctx);
|
||||||
|
free(tmp);
|
||||||
|
|
||||||
|
EVP_PKEY_free(pkey);
|
||||||
|
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
EXCEPTION(gourou::CLIENT_RSA_ERROR, ERR_error_string(ERR_get_error(), NULL));
|
EXCEPTION(gourou::CLIENT_RSA_ERROR, ERR_error_string(ERR_get_error(), NULL));
|
||||||
|
|
||||||
EVP_PKEY_free(evpKey);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void* DRMProcessorClientImpl::generateRSAKey(int keyLengthBits)
|
void* DRMProcessorClientImpl::generateRSAKey(int keyLengthBits)
|
||||||
|
|
@ -468,7 +531,6 @@ void* DRMProcessorClientImpl::generateRSAKey(int keyLengthBits)
|
||||||
EVP_PKEY_keygen_init(ctx);
|
EVP_PKEY_keygen_init(ctx);
|
||||||
|
|
||||||
EVP_PKEY_CTX_set_rsa_keygen_bits(ctx, keyLengthBits);
|
EVP_PKEY_CTX_set_rsa_keygen_bits(ctx, keyLengthBits);
|
||||||
EVP_PKEY_CTX_set_rsa_padding(ctx, RSA_PKCS1_PADDING);
|
|
||||||
EVP_PKEY_CTX_set1_rsa_keygen_pubexp(ctx, bn);
|
EVP_PKEY_CTX_set1_rsa_keygen_pubexp(ctx, bn);
|
||||||
EVP_PKEY_keygen(ctx, &key);
|
EVP_PKEY_keygen(ctx, &key);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -130,6 +130,8 @@ private:
|
||||||
|
|
||||||
void padWithPKCS1(unsigned char* out, unsigned int outLength,
|
void padWithPKCS1(unsigned char* out, unsigned int outLength,
|
||||||
const unsigned char* in, unsigned int inLength);
|
const unsigned char* in, unsigned int inLength);
|
||||||
|
void padWithPKCS1Type2(unsigned char* out, unsigned int outLength,
|
||||||
|
const unsigned char* in, unsigned int inLength);
|
||||||
|
|
||||||
#if OPENSSL_VERSION_MAJOR >= 3
|
#if OPENSSL_VERSION_MAJOR >= 3
|
||||||
OSSL_PROVIDER *legacy, *deflt;
|
OSSL_PROVIDER *legacy, *deflt;
|
||||||
|
|
|
||||||
|
|
@ -23,7 +23,7 @@ int main(int argc, char** argv)
|
||||||
|
|
||||||
fullPath = std::string(mountPoint) + util;
|
fullPath = std::string(mountPoint) + util;
|
||||||
|
|
||||||
if (std::string(util) == "launcher" || !fileExists(fullPath.c_str()))
|
if (std::string(util) == "launcher" || !pathExists(fullPath.c_str()))
|
||||||
fullPath = std::string(mountPoint) + DEFAULT_UTIL;
|
fullPath = std::string(mountPoint) + DEFAULT_UTIL;
|
||||||
|
|
||||||
free(argv0);
|
free(argv0);
|
||||||
|
|
|
||||||
|
|
@ -33,6 +33,7 @@
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
#include <limits.h>
|
#include <limits.h>
|
||||||
|
#include <libgen.h>
|
||||||
|
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
|
|
||||||
|
|
@ -51,10 +52,10 @@ void version(void)
|
||||||
std::cout << "Current libgourou version : " << gourou::DRMProcessor::VERSION << std::endl ;
|
std::cout << "Current libgourou version : " << gourou::DRMProcessor::VERSION << std::endl ;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool fileExists(const char* filename)
|
bool pathExists(const char* path)
|
||||||
{
|
{
|
||||||
struct stat _stat;
|
struct stat _stat;
|
||||||
int ret = stat(filename, &_stat);
|
int ret = stat(path, &_stat);
|
||||||
|
|
||||||
return (ret == 0);
|
return (ret == 0);
|
||||||
}
|
}
|
||||||
|
|
@ -67,15 +68,15 @@ const char* findFile(const char* filename, bool inDefaultDirs)
|
||||||
if (adeptDir && adeptDir[0])
|
if (adeptDir && adeptDir[0])
|
||||||
{
|
{
|
||||||
path = adeptDir + std::string("/") + filename;
|
path = adeptDir + std::string("/") + filename;
|
||||||
if (fileExists(path.c_str()))
|
if (pathExists(path.c_str()))
|
||||||
return strdup(path.c_str());
|
return strdup(path.c_str());
|
||||||
}
|
}
|
||||||
|
|
||||||
path = gourou::DRMProcessor::getDefaultAdeptDir() + filename;
|
path = gourou::DRMProcessor::getDefaultAdeptDir() + filename;
|
||||||
if (fileExists(path.c_str()))
|
if (pathExists(path.c_str()))
|
||||||
return strdup(path.c_str());
|
return strdup(path.c_str());
|
||||||
|
|
||||||
if (fileExists(filename))
|
if (pathExists(filename))
|
||||||
return strdup(filename);
|
return strdup(filename);
|
||||||
|
|
||||||
if (!inDefaultDirs) return 0;
|
if (!inDefaultDirs) return 0;
|
||||||
|
|
@ -83,7 +84,7 @@ const char* findFile(const char* filename, bool inDefaultDirs)
|
||||||
for (int i=0; i<(int)ARRAY_SIZE(defaultDirs); i++)
|
for (int i=0; i<(int)ARRAY_SIZE(defaultDirs); i++)
|
||||||
{
|
{
|
||||||
path = std::string(defaultDirs[i]) + filename;
|
path = std::string(defaultDirs[i]) + filename;
|
||||||
if (fileExists(path.c_str()))
|
if (pathExists(path.c_str()))
|
||||||
return strdup(path.c_str());
|
return strdup(path.c_str());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -152,3 +153,12 @@ void fileCopy(const char* in, const char* out)
|
||||||
close (fdIn);
|
close (fdIn);
|
||||||
close (fdOut);
|
close (fdOut);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void createPath(const char* filename)
|
||||||
|
{
|
||||||
|
char* basepath = strdup(filename);
|
||||||
|
char* outputDir = dirname(basepath);
|
||||||
|
if (outputDir && !pathExists(outputDir))
|
||||||
|
mkpath(outputDir);
|
||||||
|
free(basepath);
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -50,9 +50,9 @@ void version(void);
|
||||||
const char* findFile(const char* filename, bool inDefaultDirs=true);
|
const char* findFile(const char* filename, bool inDefaultDirs=true);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Does the file (or directory exists)
|
* @brief Does the file (or directory) exists
|
||||||
*/
|
*/
|
||||||
bool fileExists(const char* filename);
|
bool pathExists(const char* path);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Recursively created dir
|
* @brief Recursively created dir
|
||||||
|
|
@ -64,4 +64,9 @@ void mkpath(const char *dir);
|
||||||
*/
|
*/
|
||||||
void fileCopy(const char* in, const char* out);
|
void fileCopy(const char* in, const char* out);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Create intermediate directories if it does not exists
|
||||||
|
*/
|
||||||
|
void createPath(const char* filename);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue