forked from soutade/libgourou
		
	Initial commit
This commit is contained in:
		
							
								
								
									
										26
									
								
								utils/LICENSE
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										26
									
								
								utils/LICENSE
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,26 @@ | ||||
| Copyright (c) 2021, Grégory Soutadé | ||||
|  | ||||
| All rights reserved. | ||||
| Redistribution and use in source and binary forms, with or without | ||||
| modification, are permitted provided that the following conditions are met: | ||||
|  | ||||
| * Redistributions of source code must retain the above copyright | ||||
|   notice, this list of conditions and the following disclaimer. | ||||
| * Redistributions in binary form must reproduce the above copyright | ||||
|   notice, this list of conditions and the following disclaimer in the | ||||
|   documentation and/or other materials provided with the distribution. | ||||
| * Neither the name of the copyright holder nor the | ||||
|   names of its contributors may be used to endorse or promote products | ||||
|   derived from this software without specific prior written permission. | ||||
|  | ||||
| THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY | ||||
| EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED | ||||
| WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | ||||
| DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS BE LIABLE FOR ANY | ||||
| DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES | ||||
| (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; | ||||
| LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND | ||||
| ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||||
| (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS | ||||
| SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||||
|  | ||||
							
								
								
									
										24
									
								
								utils/Makefile
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										24
									
								
								utils/Makefile
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,24 @@ | ||||
|  | ||||
| TARGETS=acsmdownloader activate | ||||
|  | ||||
| CXXFLAGS=-Wall `pkg-config --cflags Qt5Core Qt5Network` -fPIC -I$(ROOT)/include -I$(ROOT)/lib/pugixml/src/ | ||||
| LDFLAGS=`pkg-config --libs Qt5Core Qt5Network` -L$(ROOT) -lgourou -lcrypto -lzip | ||||
|  | ||||
| ifneq ($(DEBUG),) | ||||
| CXXFLAGS += -ggdb -O0 | ||||
| else | ||||
| CXXFLAGS += -O2 | ||||
| endif | ||||
|  | ||||
| all: $(TARGETS) | ||||
|  | ||||
| acsmdownloader: drmprocessorclientimpl.cpp acsmdownloader.cpp  | ||||
| 	$(CXX) $(CXXFLAGS) $^ $(LDFLAGS) -o $@ | ||||
|  | ||||
| activate: drmprocessorclientimpl.cpp activate.cpp  | ||||
| 	$(CXX) $(CXXFLAGS) $^ $(LDFLAGS) -o $@ | ||||
|  | ||||
| clean: | ||||
| 	rm -f $(TARGETS) | ||||
|  | ||||
| ultraclean: clean | ||||
							
								
								
									
										255
									
								
								utils/acsmdownloader.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										255
									
								
								utils/acsmdownloader.cpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,255 @@ | ||||
| /* | ||||
|   Copyright (c) 2021, Grégory Soutadé | ||||
|  | ||||
|   All rights reserved. | ||||
|   Redistribution and use in source and binary forms, with or without | ||||
|   modification, are permitted provided that the following conditions are met: | ||||
|    | ||||
|   * Redistributions of source code must retain the above copyright | ||||
|     notice, this list of conditions and the following disclaimer. | ||||
|   * Redistributions in binary form must reproduce the above copyright | ||||
|     notice, this list of conditions and the following disclaimer in the | ||||
|     documentation and/or other materials provided with the distribution. | ||||
|   * Neither the name of the copyright holder nor the | ||||
|     names of its contributors may be used to endorse or promote products | ||||
|     derived from this software without specific prior written permission. | ||||
|    | ||||
|   THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY | ||||
|   EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED | ||||
|   WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | ||||
|   DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS BE LIABLE FOR ANY | ||||
|   DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES | ||||
|   (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; | ||||
|   LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND | ||||
|   ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||||
|   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS | ||||
|   SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||||
| */ | ||||
|  | ||||
| #include <unistd.h> | ||||
| #include <getopt.h> | ||||
|  | ||||
| #include <iostream> | ||||
|  | ||||
| #include <QFile> | ||||
| #include <QDir> | ||||
| #include <QCoreApplication> | ||||
| #include <QRunnable> | ||||
| #include <QThreadPool> | ||||
|  | ||||
| #include <libgourou.h> | ||||
| #include "drmprocessorclientimpl.h" | ||||
|  | ||||
| #define ARRAY_SIZE(arr) (sizeof(arr)/sizeof(arr[0])) | ||||
|  | ||||
| static const char* deviceFile     = "device.xml"; | ||||
| static const char* activationFile = "activation.xml"; | ||||
| static const char* devicekeyFile  = "devicesalt"; | ||||
| static const char* acsmFile       = 0; | ||||
| static const char* outputFile     = 0; | ||||
| static const char* outputDir      = 0; | ||||
| static const char* defaultDirs[]  = { | ||||
|     ".adept/", | ||||
|     "./adobe-digital-editions/", | ||||
|     "./.adobe-digital-editions/" | ||||
| }; | ||||
|  | ||||
|  | ||||
| class ACSMDownloader: public QRunnable | ||||
| { | ||||
| public: | ||||
|     ACSMDownloader(QCoreApplication* app): | ||||
| 	app(app) | ||||
|     { | ||||
| 	setAutoDelete(false); | ||||
|     } | ||||
|     | ||||
|     void run() | ||||
|     { | ||||
| 	try | ||||
| 	{ | ||||
| 	    DRMProcessorClientImpl client; | ||||
| 	    gourou::DRMProcessor processor(&client, deviceFile, activationFile, devicekeyFile); | ||||
|  | ||||
| 	    gourou::FulfillmentItem* item = processor.fulfill(acsmFile); | ||||
|  | ||||
| 	    std::string filename; | ||||
| 	    if (!outputFile) | ||||
| 	    { | ||||
| 		filename = item->getMetadata("title"); | ||||
| 		if (filename == "") | ||||
| 		    filename = "output.epub"; | ||||
| 		else | ||||
| 		    filename += ".epub"; | ||||
| 	    } | ||||
|  | ||||
| 	    if (outputDir) | ||||
| 	    { | ||||
| 		QDir dir(outputDir); | ||||
| 		if (!dir.exists(outputDir)) | ||||
| 		    dir.mkpath(outputDir); | ||||
|  | ||||
| 		filename = std::string(outputDir) + "/" + filename; | ||||
| 	    } | ||||
| 	     | ||||
| 	    processor.download(item, filename); | ||||
| 	    std::cout << "Created " << filename << std::endl; | ||||
| 	} catch(std::exception& e) | ||||
| 	{ | ||||
| 	    std::cout << e.what() << std::endl; | ||||
| 	    this->app->exit(1); | ||||
| 	} | ||||
|  | ||||
| 	this->app->exit(0); | ||||
|     } | ||||
|  | ||||
| private: | ||||
|     QCoreApplication* app; | ||||
| };	       | ||||
|  | ||||
| static const char* findFile(const char* filename, bool inDefaultDirs=true) | ||||
| { | ||||
|     QFile file(filename); | ||||
|  | ||||
|     if (file.exists()) | ||||
| 	return strdup(filename); | ||||
|  | ||||
|     if (!inDefaultDirs) return 0; | ||||
|      | ||||
|     for (int i=0; i<(int)ARRAY_SIZE(defaultDirs); i++) | ||||
|     { | ||||
| 	QString path = QString(defaultDirs[i]) + QString(filename); | ||||
| 	file.setFileName(path); | ||||
| 	if (file.exists()) | ||||
| 	    return strdup(path.toStdString().c_str()); | ||||
|     } | ||||
|      | ||||
|     return 0; | ||||
| } | ||||
|  | ||||
| static void usage(const char* cmd) | ||||
| { | ||||
|     std::cout << "Download EPUB file from ACSM request file" << std::endl; | ||||
|      | ||||
|     std::cout << "Usage: " << cmd << " [(-d|--device-file) device.xml] [(-a|--activation-file) activation.xml] [(-s|--device-key-file) devicesalt] [(-O|--output-dir) dir] [(-o|--output-file) output.epub] [(-v|--verbose)] [(-h|--help)] (-f|--acsm-file) file.acsm" << std::endl << std::endl; | ||||
|      | ||||
|     std::cout << "  " << "-d|--device-file"     << "\t"   << "device.xml file from eReader" << std::endl; | ||||
|     std::cout << "  " << "-a|--activation-file" << "\t"   << "activation.xml file from eReader" << std::endl; | ||||
|     std::cout << "  " << "-k|--device-key-file" << "\t"   << "private device key file (eg devicesalt/devkey.bin) from eReader" << std::endl; | ||||
|     std::cout << "  " << "-O|--output-dir"      << "\t"   << "Optional output directory were to put result (default ./)" << std::endl; | ||||
|     std::cout << "  " << "-o|--output-file"     << "\t"   << "Optional output epub filename (default <title.epub>)" << std::endl; | ||||
|     std::cout << "  " << "-f|--acsm-file"       << "\t"   << "ACSM request file for epub download" << std::endl; | ||||
|     std::cout << "  " << "-v|--verbose"         << "\t\t" << "Increase verbosity, can be set multiple times" << std::endl; | ||||
|     std::cout << "  " << "-h|--help"            << "\t\t" << "This help" << std::endl; | ||||
|  | ||||
|     std::cout << std::endl; | ||||
|     std::cout << "Device file, activation file and device key file are optionals. If not set, they are looked into :" << std::endl; | ||||
|     std::cout << "  * Current directory" << std::endl; | ||||
|     std::cout << "  * .adept" << std::endl; | ||||
|     std::cout << "  * adobe-digital-editions directory" << std::endl; | ||||
|     std::cout << "  * .adobe-digital-editions directory" << std::endl; | ||||
| } | ||||
|  | ||||
| int main(int argc, char** argv) | ||||
| { | ||||
|     int c, ret = -1; | ||||
|  | ||||
|     const char** files[] = {&devicekeyFile, &deviceFile, &activationFile}; | ||||
|     int verbose = gourou::DRMProcessor::getLogLevel(); | ||||
|  | ||||
|     while (1) { | ||||
| 	int option_index = 0; | ||||
| 	static struct option long_options[] = { | ||||
| 	    {"device-file",      required_argument, 0,  'd' }, | ||||
| 	    {"activation-file",  required_argument, 0,  'a' }, | ||||
| 	    {"device-key-file",  required_argument, 0,  'k' }, | ||||
| 	    {"output-dir",       required_argument, 0,  'O' }, | ||||
| 	    {"output-file",      required_argument, 0,  'o' }, | ||||
| 	    {"acsm-file",        required_argument, 0,  'f' }, | ||||
| 	    {"verbose",          no_argument,       0,  'v' }, | ||||
| 	    {"help",             no_argument,       0,  'h' }, | ||||
| 	    {0,                  0,                 0,  0 } | ||||
| 	}; | ||||
|  | ||||
| 	c = getopt_long(argc, argv, "d:a:k:O:o:f:vh", | ||||
|                         long_options, &option_index); | ||||
| 	if (c == -1) | ||||
| 	    break; | ||||
|  | ||||
| 	switch (c) { | ||||
| 	case 'd': | ||||
| 	    deviceFile = optarg; | ||||
| 	    break; | ||||
| 	case 'a': | ||||
| 	    activationFile = optarg; | ||||
| 	    break; | ||||
| 	case 'k': | ||||
| 	    devicekeyFile = optarg; | ||||
| 	    break; | ||||
| 	case 'f': | ||||
| 	    acsmFile = optarg; | ||||
| 	    break; | ||||
| 	case 'O': | ||||
| 	    outputDir = optarg; | ||||
| 	    break; | ||||
| 	case 'o': | ||||
| 	    outputFile = optarg; | ||||
| 	    break; | ||||
| 	case 'v': | ||||
| 	    verbose++; | ||||
| 	    break; | ||||
| 	case 'h': | ||||
| 	    usage(argv[0]); | ||||
| 	    return 0; | ||||
| 	    break; | ||||
| 	default: | ||||
| 	    usage(argv[0]); | ||||
| 	    return -1; | ||||
| 	} | ||||
|     } | ||||
|     | ||||
|     gourou::DRMProcessor::setLogLevel(verbose); | ||||
|  | ||||
|     if (!acsmFile || (outputDir && !outputDir[0]) || | ||||
| 	(outputFile && !outputFile[0])) | ||||
|     { | ||||
| 	usage(argv[0]); | ||||
| 	return -1; | ||||
|     } | ||||
|  | ||||
|     QCoreApplication app(argc, argv); | ||||
|     ACSMDownloader downloader(&app); | ||||
|  | ||||
|     int i; | ||||
|     for (i=0; i<(int)ARRAY_SIZE(files); i++) | ||||
|     { | ||||
| 	*files[i] = findFile(*files[i]); | ||||
| 	if (!*files[i]) | ||||
| 	{ | ||||
| 	    std::cout << "Error : " << *files[i] << " doesn't exists" << std::endl; | ||||
| 	    ret = -1; | ||||
| 	    goto end; | ||||
| 	} | ||||
|     } | ||||
|      | ||||
|     QFile file(acsmFile); | ||||
|     if (!file.exists()) | ||||
|     { | ||||
| 	std::cout << "Error : " << acsmFile << " doesn't exists" << std::endl; | ||||
| 	ret = -1; | ||||
| 	goto end; | ||||
|     } | ||||
|      | ||||
|     QThreadPool::globalInstance()->start(&downloader); | ||||
|  | ||||
|     ret = app.exec(); | ||||
|  | ||||
| end: | ||||
|     for (i=0; i<(int)ARRAY_SIZE(files); i++) | ||||
|     { | ||||
| 	if (*files[i]) | ||||
| 	    free((void*)*files[i]); | ||||
|     } | ||||
|  | ||||
|     return ret; | ||||
| } | ||||
							
								
								
									
										263
									
								
								utils/activate.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										263
									
								
								utils/activate.cpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,263 @@ | ||||
| /* | ||||
|   Copyright (c) 2021, Grégory Soutadé | ||||
|  | ||||
|   All rights reserved. | ||||
|   Redistribution and use in source and binary forms, with or without | ||||
|   modification, are permitted provided that the following conditions are met: | ||||
|    | ||||
|   * Redistributions of source code must retain the above copyright | ||||
|     notice, this list of conditions and the following disclaimer. | ||||
|   * Redistributions in binary form must reproduce the above copyright | ||||
|     notice, this list of conditions and the following disclaimer in the | ||||
|     documentation and/or other materials provided with the distribution. | ||||
|   * Neither the name of the copyright holder nor the | ||||
|     names of its contributors may be used to endorse or promote products | ||||
|     derived from this software without specific prior written permission. | ||||
|    | ||||
|   THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY | ||||
|   EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED | ||||
|   WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | ||||
|   DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS BE LIABLE FOR ANY | ||||
|   DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES | ||||
|   (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; | ||||
|   LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND | ||||
|   ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||||
|   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS | ||||
|   SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||||
| */ | ||||
|  | ||||
| #include <unistd.h> | ||||
| #include <getopt.h> | ||||
| #include <stdlib.h> | ||||
| #include <termios.h> | ||||
|  | ||||
| #include <iostream> | ||||
| #include <ostream> | ||||
|  | ||||
| #include <QFile> | ||||
| #include <QDir> | ||||
| #include <QCoreApplication> | ||||
| #include <QRunnable> | ||||
| #include <QThreadPool> | ||||
|  | ||||
| #include <libgourou.h> | ||||
| #include "drmprocessorclientimpl.h" | ||||
|  | ||||
| #define ARRAY_SIZE(arr) (sizeof(arr)/sizeof(arr[0])) | ||||
|  | ||||
| static const char* username      = 0; | ||||
| static const char* password      = 0; | ||||
| static const char* outputDir     = 0; | ||||
| static const char* hobbesVersion = HOBBES_DEFAULT_VERSION; | ||||
| static bool        randomSerial  = false; | ||||
|  | ||||
| // From http://www.cplusplus.com/articles/E6vU7k9E/ | ||||
| static int getch() { | ||||
|     int ch; | ||||
|     struct termios t_old, t_new; | ||||
|  | ||||
|     tcgetattr(STDIN_FILENO, &t_old); | ||||
|     t_new = t_old; | ||||
|     t_new.c_lflag &= ~(ICANON | ECHO); | ||||
|     tcsetattr(STDIN_FILENO, TCSANOW, &t_new); | ||||
|  | ||||
|     ch = getchar(); | ||||
|  | ||||
|     tcsetattr(STDIN_FILENO, TCSANOW, &t_old); | ||||
|     return ch; | ||||
| } | ||||
|  | ||||
| static std::string getpass(const char *prompt, bool show_asterisk=false) | ||||
| { | ||||
|   const char BACKSPACE=127; | ||||
|   const char RETURN=10; | ||||
|  | ||||
|   std::string password; | ||||
|   unsigned char ch=0; | ||||
|  | ||||
|   std::cout <<prompt; | ||||
|  | ||||
|   while((ch=getch())!= RETURN) | ||||
|     { | ||||
| 	if(ch==BACKSPACE) | ||||
|          { | ||||
|             if(password.length()!=0) | ||||
|               { | ||||
|                  if(show_asterisk) | ||||
|                  std::cout <<"\b \b"; | ||||
|                  password.resize(password.length()-1); | ||||
|               } | ||||
|          } | ||||
|        else | ||||
|          { | ||||
|              password+=ch; | ||||
|              if(show_asterisk) | ||||
|                  std::cout <<'*'; | ||||
|          } | ||||
|     } | ||||
|   std::cout <<std::endl; | ||||
|   return password; | ||||
| } | ||||
|  | ||||
|  | ||||
| class Activate: public QRunnable | ||||
| { | ||||
| public: | ||||
|     Activate(QCoreApplication* app): | ||||
| 	app(app) | ||||
|     { | ||||
| 	setAutoDelete(false); | ||||
|     } | ||||
|     | ||||
|     void run() | ||||
|     { | ||||
| 	try | ||||
| 	{ | ||||
| 	    DRMProcessorClientImpl client; | ||||
| 	    gourou::DRMProcessor* processor = gourou::DRMProcessor::createDRMProcessor( | ||||
| 		&client, randomSerial, outputDir, hobbesVersion); | ||||
|  | ||||
| 	    processor->signIn(username, password); | ||||
| 	    processor->activateDevice(); | ||||
|  | ||||
| 	    std::cout << username << " fully signed and device activated in " << outputDir << std::endl; | ||||
| 	} catch(std::exception& e) | ||||
| 	{ | ||||
| 	    std::cout << e.what() << std::endl; | ||||
| 	    this->app->exit(1); | ||||
| 	} | ||||
|  | ||||
| 	this->app->exit(0); | ||||
|     } | ||||
|  | ||||
| private: | ||||
|     QCoreApplication* app; | ||||
| };	       | ||||
|  | ||||
| static void usage(const char* cmd) | ||||
| { | ||||
|     std::cout << "Create new device files used by ADEPT DRM" << std::endl; | ||||
|      | ||||
|     std::cout << "Usage: " << cmd << " (-u|--username) username [(-p|--password) password] [(-O|--output-dir) dir] [(-r|--random-serial)] [(-v|--verbose)] [(-h|--help)]" << std::endl << std::endl; | ||||
|      | ||||
|     std::cout << "  " << "-u|--username"   << "\t\t" << "AdobeID username (ie adobe.com email account)" << std::endl; | ||||
|     std::cout << "  " << "-p|--password"   << "\t\t" << "AdobeID password (asked if not set via command line) " << std::endl; | ||||
|     std::cout << "  " << "-O|--output-dir" << "\t"   << "Optional output directory were to put result (default ./.adept). This directory must not already exists" << std::endl; | ||||
|     std::cout << "  " << "-H|--hobbes-version" << "\t"<< "Force RMSDK version to a specific value (default: version of current librmsdk)" << std::endl; | ||||
|     std::cout << "  " << "-r|--random-serial" << "\t"<< "Generate a random device serial (if not set, it will be dependent of your current configuration)" << std::endl; | ||||
|     std::cout << "  " << "-v|--verbose"    << "\t\t" << "Increase verbosity, can be set multiple times" << std::endl; | ||||
|     std::cout << "  " << "-h|--help"       << "\t\t" << "This help" << std::endl; | ||||
|  | ||||
|     std::cout << std::endl; | ||||
| } | ||||
|  | ||||
| static const char* abspath(const char* filename) | ||||
| { | ||||
|     const char* root = getcwd(0, PATH_MAX); | ||||
|     QString fullPath = QString(root) + QString("/") + QString(filename); | ||||
|     const char* res = strdup(fullPath.toStdString().c_str()); | ||||
|  | ||||
|     free((void*)root); | ||||
|  | ||||
|     return res; | ||||
| } | ||||
|  | ||||
| int main(int argc, char** argv) | ||||
| { | ||||
|     int c, ret = -1; | ||||
|     const char* _outputDir = outputDir; | ||||
|     int verbose = gourou::DRMProcessor::getLogLevel(); | ||||
|      | ||||
|     while (1) { | ||||
| 	int option_index = 0; | ||||
| 	static struct option long_options[] = { | ||||
| 	    {"username",      required_argument, 0,  'u' }, | ||||
| 	    {"password",      required_argument, 0,  'p' }, | ||||
| 	    {"output-dir",    required_argument, 0,  'O' }, | ||||
| 	    {"hobbes-version",required_argument, 0,  'H' }, | ||||
| 	    {"random-serial", no_argument,       0,  'r' }, | ||||
| 	    {"verbose",       no_argument,       0,  'v' }, | ||||
| 	    {"help",          no_argument,       0,  'h' }, | ||||
| 	    {0,               0,                 0,  0 } | ||||
| 	}; | ||||
|  | ||||
| 	c = getopt_long(argc, argv, "u:p:O:H:rvh", | ||||
|                         long_options, &option_index); | ||||
| 	if (c == -1) | ||||
| 	    break; | ||||
|  | ||||
| 	switch (c) { | ||||
| 	case 'u': | ||||
| 	    username = optarg; | ||||
| 	    break; | ||||
| 	case 'p': | ||||
| 	    password = optarg; | ||||
| 	    break; | ||||
| 	case 'O': | ||||
| 	    _outputDir = optarg; | ||||
| 	    break; | ||||
| 	case 'H': | ||||
| 	    hobbesVersion = optarg; | ||||
| 	    break; | ||||
| 	case 'v': | ||||
| 	    verbose++; | ||||
| 	    break; | ||||
| 	case 'h': | ||||
| 	    usage(argv[0]); | ||||
| 	    return 0; | ||||
| 	    break; | ||||
| 	case 'r': | ||||
| 	    randomSerial = true; | ||||
| 	    break; | ||||
| 	default: | ||||
| 	    usage(argv[0]); | ||||
| 	    return -1; | ||||
| 	} | ||||
|     } | ||||
|     | ||||
|     gourou::DRMProcessor::setLogLevel(verbose); | ||||
|  | ||||
|     if (!username) | ||||
|     { | ||||
| 	usage(argv[0]); | ||||
| 	return -1; | ||||
|     } | ||||
|     | ||||
|     if (!_outputDir || _outputDir[0] == 0) | ||||
|     { | ||||
| 	outputDir = abspath(DEFAULT_ADEPT_DIR); | ||||
|     } | ||||
|     else | ||||
|     { | ||||
| 	// Relative path | ||||
| 	if (_outputDir[0] == '.' || _outputDir[0] != '/') | ||||
| 	{ | ||||
| 	    QFile file(_outputDir); | ||||
| 	    // realpath doesn't works if file/dir doesn't exists | ||||
| 	    if (file.exists()) | ||||
| 		outputDir = realpath(_outputDir, 0); | ||||
| 	    else | ||||
| 		outputDir = abspath(_outputDir); | ||||
| 	} | ||||
| 	else | ||||
| 	    outputDir = strdup(_outputDir); | ||||
|     } | ||||
|  | ||||
|     if (!password) | ||||
|     { | ||||
| 	char prompt[128]; | ||||
| 	std::snprintf(prompt, sizeof(prompt), "Enter password for <%s> : ", username); | ||||
| 	std::string pass = getpass((const char*)prompt, false); | ||||
| 	password = pass.c_str(); | ||||
|     } | ||||
|      | ||||
|     QCoreApplication app(argc, argv); | ||||
|      | ||||
|     Activate activate(&app); | ||||
|     QThreadPool::globalInstance()->start(&activate); | ||||
|  | ||||
|     ret = app.exec(); | ||||
|  | ||||
|     free((void*)outputDir); | ||||
|     return ret; | ||||
| } | ||||
							
								
								
									
										385
									
								
								utils/drmprocessorclientimpl.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										385
									
								
								utils/drmprocessorclientimpl.cpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,385 @@ | ||||
| /* | ||||
|   Copyright (c) 2021, Grégory Soutadé | ||||
|  | ||||
|   All rights reserved. | ||||
|   Redistribution and use in source and binary forms, with or without | ||||
|   modification, are permitted provided that the following conditions are met: | ||||
|    | ||||
|   * Redistributions of source code must retain the above copyright | ||||
|     notice, this list of conditions and the following disclaimer. | ||||
|   * Redistributions in binary form must reproduce the above copyright | ||||
|     notice, this list of conditions and the following disclaimer in the | ||||
|     documentation and/or other materials provided with the distribution. | ||||
|   * Neither the name of the copyright holder nor the | ||||
|     names of its contributors may be used to endorse or promote products | ||||
|     derived from this software without specific prior written permission. | ||||
|    | ||||
|   THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY | ||||
|   EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED | ||||
|   WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | ||||
|   DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS BE LIABLE FOR ANY | ||||
|   DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES | ||||
|   (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; | ||||
|   LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND | ||||
|   ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||||
|   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS | ||||
|   SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||||
| */ | ||||
|  | ||||
| #include <openssl/rand.h> | ||||
| #include <openssl/pkcs12.h> | ||||
| #include <openssl/evp.h> | ||||
| #include <openssl/err.h> | ||||
|  | ||||
| #include <QCoreApplication> | ||||
| #include <QNetworkReply> | ||||
| #include <QNetworkRequest> | ||||
| #include <QNetworkAccessManager> | ||||
| #include <QFile> | ||||
|  | ||||
| #include <zip.h> | ||||
|  | ||||
| #include <libgourou_common.h> | ||||
| #include <libgourou_log.h> | ||||
| #include "drmprocessorclientimpl.h" | ||||
|  | ||||
| /* Digest interface */ | ||||
| void* DRMProcessorClientImpl::createDigest(const std::string& digestName) | ||||
| { | ||||
|     EVP_MD_CTX *sha_ctx = EVP_MD_CTX_new(); | ||||
|     const EVP_MD* md = EVP_get_digestbyname(digestName.c_str()); | ||||
|     EVP_DigestInit(sha_ctx, md); | ||||
|  | ||||
|     return sha_ctx; | ||||
| } | ||||
|  | ||||
| int DRMProcessorClientImpl::digestUpdate(void* handler, unsigned char* data, unsigned int length) | ||||
| { | ||||
|     return EVP_DigestUpdate((EVP_MD_CTX *)handler, data, length); | ||||
| } | ||||
|  | ||||
| int DRMProcessorClientImpl::digestFinalize(void* handler, unsigned char* digestOut) | ||||
| { | ||||
|     int res = EVP_DigestFinal((EVP_MD_CTX *)handler, digestOut, NULL); | ||||
|     EVP_MD_CTX_free((EVP_MD_CTX *)handler); | ||||
|     return res; | ||||
| } | ||||
|  | ||||
| int DRMProcessorClientImpl::digest(const std::string& digestName, unsigned char* data, unsigned int length, unsigned char* digestOut) | ||||
| { | ||||
|     void* handler = createDigest(digestName); | ||||
|     if (!handler) | ||||
| 	return -1; | ||||
|     if (digestUpdate(handler, data, length)) | ||||
| 	return -1; | ||||
|     return digestFinalize(handler, digestOut); | ||||
| } | ||||
|  | ||||
| /* Random interface */ | ||||
| void DRMProcessorClientImpl::randBytes(unsigned char* bytesOut, unsigned int length) | ||||
| { | ||||
|     RAND_bytes(bytesOut, length); | ||||
| } | ||||
|  | ||||
| /* HTTP interface */ | ||||
| std::string DRMProcessorClientImpl::sendHTTPRequest(const std::string& URL, const std::string& POSTData, const std::string& contentType) | ||||
| { | ||||
|     QNetworkRequest request(QUrl(URL.c_str())); | ||||
|     QNetworkAccessManager networkManager; | ||||
|     QByteArray replyData; | ||||
|  | ||||
|     GOUROU_LOG(gourou::INFO, "Send request to " << URL); | ||||
|     if (POSTData.size()) | ||||
|     { | ||||
| 	GOUROU_LOG(gourou::DEBUG, "<<< " << std::endl << POSTData); | ||||
|     } | ||||
| 	 | ||||
|     request.setRawHeader("Accept", "*/*"); | ||||
|     request.setRawHeader("User-Agent", "book2png"); | ||||
|     if (contentType.size()) | ||||
| 	request.setRawHeader("Content-Type", contentType.c_str()); | ||||
|  | ||||
|     QNetworkReply* reply; | ||||
|  | ||||
|     if (POSTData.size()) | ||||
| 	reply = networkManager.post(request, POSTData.c_str()); | ||||
|     else | ||||
| 	reply = networkManager.get(request); | ||||
|  | ||||
|     QCoreApplication* app = QCoreApplication::instance(); | ||||
|     networkManager.moveToThread(app->thread()); | ||||
|     while (!reply->isFinished()) | ||||
| 	app->processEvents(); | ||||
|  | ||||
|     replyData = reply->readAll(); | ||||
|     if (reply->rawHeader("Content-Type") == "application/vnd.adobe.adept+xml") | ||||
|     { | ||||
| 	GOUROU_LOG(gourou::DEBUG, ">>> " << std::endl << replyData.data()); | ||||
|     } | ||||
| 	 | ||||
|     return std::string(replyData.data(), replyData.length()); | ||||
| } | ||||
|  | ||||
| void DRMProcessorClientImpl::RSAPrivateEncrypt(const unsigned char* RSAKey, unsigned int RSAKeyLength, | ||||
| 					       const RSA_KEY_TYPE keyType, const std::string& password, | ||||
| 					       const unsigned char* data, unsigned dataLength, | ||||
| 					       unsigned char* res) | ||||
| { | ||||
|     PKCS12 * pkcs12; | ||||
|     EVP_PKEY* pkey; | ||||
|     X509* cert; | ||||
|     STACK_OF(X509)* ca; | ||||
|     RSA * rsa; | ||||
|  | ||||
|     pkcs12 = d2i_PKCS12(NULL, &RSAKey, RSAKeyLength); | ||||
|     if (!pkcs12) | ||||
| 	EXCEPTION(gourou::CLIENT_INVALID_PKCS12, ERR_error_string(ERR_get_error(), NULL)); | ||||
|     PKCS12_parse(pkcs12, password.c_str(), &pkey, &cert, &ca); | ||||
|     rsa = EVP_PKEY_get1_RSA(pkey); | ||||
|  | ||||
|     int ret = RSA_private_encrypt(dataLength, data, res, rsa, RSA_PKCS1_PADDING); | ||||
|  | ||||
|     if (ret < 0) | ||||
| 	EXCEPTION(gourou::CLIENT_RSA_ERROR, ERR_error_string(ERR_get_error(), NULL)); | ||||
|  | ||||
|     if (gourou::logLevel >= gourou::DEBUG) | ||||
|     { | ||||
| 	printf("Sig : "); | ||||
| 	for(int i=0; i<(int)sizeof(res); i++) | ||||
| 	    printf("%02x ", res[i]); | ||||
| 	printf("\n"); | ||||
|     } | ||||
| } | ||||
| 			     | ||||
| void DRMProcessorClientImpl::RSAPublicEncrypt(const unsigned char* RSAKey, unsigned int RSAKeyLength, | ||||
| 					      const RSA_KEY_TYPE keyType, | ||||
| 					      const unsigned char* data, unsigned dataLength, | ||||
| 					      unsigned char* res) | ||||
| { | ||||
|     X509 * x509 = d2i_X509(0, &RSAKey, RSAKeyLength); | ||||
|     if (!x509) | ||||
| 	EXCEPTION(gourou::CLIENT_INVALID_CERTIFICATE, "Invalid certificate"); | ||||
| 	 | ||||
|     EVP_PKEY * evpKey = X509_get_pubkey(x509); | ||||
|     RSA* rsa = EVP_PKEY_get1_RSA(evpKey); | ||||
|     EVP_PKEY_free(evpKey); | ||||
|  | ||||
|     if (!rsa) | ||||
| 	EXCEPTION(gourou::CLIENT_NO_PRIV_KEY, "No private key in certificate"); | ||||
|  | ||||
|     int ret = RSA_public_encrypt(dataLength, data, res, rsa, RSA_PKCS1_PADDING); | ||||
|     if (ret < 0) | ||||
| 	EXCEPTION(gourou::CLIENT_RSA_ERROR, ERR_error_string(ERR_get_error(), NULL)); | ||||
| } | ||||
|  | ||||
| void* DRMProcessorClientImpl::generateRSAKey(int keyLengthBits) | ||||
| { | ||||
|     BIGNUM * bn = BN_new(); | ||||
|     RSA * rsa = RSA_new(); | ||||
|     BN_set_word(bn, 0x10001); | ||||
|     RSA_generate_key_ex(rsa, keyLengthBits, bn, 0); | ||||
|     BN_free(bn); | ||||
|  | ||||
|     return rsa; | ||||
| } | ||||
|  | ||||
| void DRMProcessorClientImpl::destroyRSAHandler(void* handler) | ||||
| { | ||||
|     RSA_free((RSA*)handler); | ||||
| } | ||||
|  | ||||
| void DRMProcessorClientImpl::extractRSAPublicKey(void* handler, unsigned char** keyOut, unsigned int* keyOutLength) | ||||
| { | ||||
|     EVP_PKEY * evpKey = EVP_PKEY_new(); | ||||
|     EVP_PKEY_set1_RSA(evpKey, (RSA*)handler); | ||||
|     X509_PUBKEY *x509_pubkey = 0; | ||||
|     X509_PUBKEY_set(&x509_pubkey, evpKey); | ||||
|  | ||||
|     *keyOutLength = i2d_X509_PUBKEY(x509_pubkey, keyOut); | ||||
|  | ||||
|     X509_PUBKEY_free(x509_pubkey); | ||||
|     EVP_PKEY_free(evpKey); | ||||
| } | ||||
|  | ||||
| void DRMProcessorClientImpl::extractRSAPrivateKey(void* handler, unsigned char** keyOut, unsigned int* keyOutLength) | ||||
| { | ||||
|     EVP_PKEY * evpKey = EVP_PKEY_new(); | ||||
|     EVP_PKEY_set1_RSA(evpKey, (RSA*)handler); | ||||
|     PKCS8_PRIV_KEY_INFO * privKey = EVP_PKEY2PKCS8(evpKey); | ||||
|  | ||||
|     *keyOutLength = i2d_PKCS8_PRIV_KEY_INFO(privKey, keyOut); | ||||
|  | ||||
|     PKCS8_PRIV_KEY_INFO_free(privKey); | ||||
|     EVP_PKEY_free(evpKey); | ||||
| } | ||||
| 				  | ||||
| /* Crypto interface */ | ||||
| void DRMProcessorClientImpl::AESEncrypt(CHAINING_MODE chaining, | ||||
| 					const unsigned char* key, unsigned int keyLength, | ||||
| 					const unsigned char* iv, unsigned int ivLength, | ||||
| 					const unsigned char* dataIn, unsigned int dataInLength, | ||||
| 					unsigned char* dataOut, unsigned int* dataOutLength) | ||||
| { | ||||
|     void* handler = AESEncryptInit(chaining, key, keyLength, iv, ivLength); | ||||
|     AESEncryptUpdate(handler, dataIn, dataInLength, dataOut, dataOutLength); | ||||
|     AESEncryptFinalize(handler, dataOut+*dataOutLength, dataOutLength); | ||||
| } | ||||
|  | ||||
| void* DRMProcessorClientImpl::AESEncryptInit(CHAINING_MODE chaining, | ||||
| 					     const unsigned char* key, unsigned int keyLength, | ||||
| 					     const unsigned char* iv, unsigned int ivLength) | ||||
| { | ||||
|     EVP_CIPHER_CTX *ctx = EVP_CIPHER_CTX_new(); | ||||
|  | ||||
|     switch(keyLength) | ||||
|     { | ||||
|     case 16: | ||||
| 	switch(chaining) | ||||
| 	{ | ||||
| 	case CHAIN_ECB: | ||||
| 	    EVP_EncryptInit_ex(ctx, EVP_aes_128_ecb(), NULL, key, iv); | ||||
| 	    break; | ||||
| 	case CHAIN_CBC: | ||||
| 	    EVP_EncryptInit_ex(ctx, EVP_aes_128_cbc(), NULL, key, iv); | ||||
| 	    break; | ||||
| 	default: | ||||
| 	    EXCEPTION(gourou::CLIENT_BAD_CHAINING, "Unknown chaining mode " << chaining); | ||||
| 	break; | ||||
| 	} | ||||
|     default: | ||||
| 	EVP_CIPHER_CTX_free(ctx); | ||||
| 	EXCEPTION(gourou::CLIENT_BAD_KEY_SIZE, "Invalid key size " << keyLength); | ||||
|     } | ||||
|  | ||||
|     return ctx; | ||||
| } | ||||
|  | ||||
| void* DRMProcessorClientImpl::AESDecryptInit(CHAINING_MODE chaining, | ||||
| 					     const unsigned char* key, unsigned int keyLength, | ||||
| 					     const unsigned char* iv, unsigned int ivLength) | ||||
| { | ||||
|     EVP_CIPHER_CTX *ctx = EVP_CIPHER_CTX_new(); | ||||
|  | ||||
|     switch(keyLength) | ||||
|     { | ||||
|     case 16: | ||||
| 	switch(chaining) | ||||
| 	{ | ||||
| 	case CHAIN_ECB: | ||||
| 	    EVP_DecryptInit_ex(ctx, EVP_aes_128_ecb(), NULL, key, iv); | ||||
| 	    break; | ||||
| 	case CHAIN_CBC: | ||||
| 	    EVP_DecryptInit_ex(ctx, EVP_aes_128_cbc(), NULL, key, iv); | ||||
| 	    break; | ||||
| 	default: | ||||
| 	    EXCEPTION(gourou::CLIENT_BAD_CHAINING, "Unknown chaining mode " << chaining); | ||||
| 	} | ||||
| 	break; | ||||
|     default: | ||||
| 	EVP_CIPHER_CTX_free(ctx); | ||||
| 	EXCEPTION(gourou::CLIENT_BAD_KEY_SIZE, "Invalid key size " << keyLength); | ||||
|     } | ||||
|  | ||||
|     return ctx; | ||||
| } | ||||
|  | ||||
| void DRMProcessorClientImpl::AESEncryptUpdate(void* handler, const unsigned char* dataIn, unsigned int dataInLength, | ||||
| 		 unsigned char* dataOut, unsigned int* dataOutLength) | ||||
| { | ||||
|     EVP_EncryptUpdate((EVP_CIPHER_CTX*)handler, dataOut, (int*)dataOutLength, dataIn, dataInLength); | ||||
| } | ||||
|  | ||||
| void DRMProcessorClientImpl::AESEncryptFinalize(void* handler, | ||||
| 						unsigned char* dataOut, unsigned int* dataOutLength) | ||||
| { | ||||
|     int len; | ||||
|     EVP_EncryptFinal_ex((EVP_CIPHER_CTX*)handler, dataOut, &len); | ||||
|     *dataOutLength += len; | ||||
|     EVP_CIPHER_CTX_free((EVP_CIPHER_CTX*)handler); | ||||
| } | ||||
|  | ||||
| void DRMProcessorClientImpl::AESDecrypt(CHAINING_MODE chaining, | ||||
| 					const unsigned char* key, unsigned int keyLength, | ||||
| 					const unsigned char* iv, unsigned int ivLength, | ||||
| 					const unsigned char* dataIn, unsigned int dataInLength, | ||||
| 					unsigned char* dataOut, unsigned int* dataOutLength) | ||||
| { | ||||
|     void* handler = AESDecryptInit(chaining, key, keyLength, iv, ivLength); | ||||
|     AESDecryptUpdate(handler, dataIn, dataInLength, dataOut, dataOutLength); | ||||
|     AESDecryptFinalize(handler, dataOut+*dataOutLength, dataOutLength); | ||||
| } | ||||
|  | ||||
| void DRMProcessorClientImpl::AESDecryptUpdate(void* handler, const unsigned char* dataIn, unsigned int dataInLength, | ||||
| 					       unsigned char* dataOut, unsigned int* dataOutLength) | ||||
| { | ||||
|     EVP_DecryptUpdate((EVP_CIPHER_CTX*)handler, dataOut, (int*)dataOutLength, dataIn, dataInLength); | ||||
| } | ||||
|  | ||||
| void DRMProcessorClientImpl::AESDecryptFinalize(void* handler, unsigned char* dataOut, unsigned int* dataOutLength) | ||||
| { | ||||
|     int len; | ||||
|     EVP_DecryptFinal_ex((EVP_CIPHER_CTX*)handler, dataOut, &len); | ||||
|     *dataOutLength += len; | ||||
|     EVP_CIPHER_CTX_free((EVP_CIPHER_CTX*)handler); | ||||
| } | ||||
|  | ||||
| void* DRMProcessorClientImpl::zipOpen(const std::string& path) | ||||
| { | ||||
|     zip_t* handler = zip_open(path.c_str(), 0, 0); | ||||
|  | ||||
|     if (!handler) | ||||
| 	EXCEPTION(gourou::CLIENT_BAD_ZIP_FILE, "Invalid zip file " << path); | ||||
|  | ||||
|     return handler; | ||||
| } | ||||
|  | ||||
| std::string DRMProcessorClientImpl::zipReadFile(void* handler, const std::string& path) | ||||
| { | ||||
|     std::string res; | ||||
|     unsigned char* buffer; | ||||
|     zip_stat_t sb; | ||||
|      | ||||
|     if (zip_stat((zip_t *)handler, path.c_str(), 0, &sb) < 0) | ||||
| 	EXCEPTION(gourou::CLIENT_ZIP_ERROR, "Zip error " << zip_strerror((zip_t *)handler)); | ||||
|  | ||||
|     if (!(sb.valid & (ZIP_STAT_INDEX|ZIP_STAT_SIZE))) | ||||
| 	EXCEPTION(gourou::CLIENT_ZIP_ERROR, "Required fields missing"); | ||||
|      | ||||
|     buffer = new unsigned char[sb.size]; | ||||
|      | ||||
|     zip_file_t *f = zip_fopen_index((zip_t *)handler, sb.index, ZIP_FL_COMPRESSED); | ||||
|  | ||||
|     zip_fread(f, buffer, sb.size); | ||||
|     zip_fclose(f); | ||||
|  | ||||
|     res = std::string((char*)buffer, sb.size); | ||||
|     delete[] buffer; | ||||
|      | ||||
|     return res; | ||||
| } | ||||
|  | ||||
| void DRMProcessorClientImpl::zipWriteFile(void* handler, const std::string& path, const std::string& content) | ||||
| { | ||||
|     zip_source_t* s = zip_source_buffer((zip_t*)handler, content.c_str(), content.length(), 0); | ||||
|     if (zip_file_add((zip_t*)handler, path.c_str(), s, ZIP_FL_OVERWRITE|ZIP_FL_ENC_UTF_8) < 0) | ||||
|     { | ||||
| 	zip_source_free(s); | ||||
| 	EXCEPTION(gourou::CLIENT_ZIP_ERROR, "Zip error " << zip_strerror((zip_t *)handler)); | ||||
|     } | ||||
| } | ||||
|  | ||||
| void DRMProcessorClientImpl::zipDeleteFile(void* handler, const std::string& path) | ||||
| { | ||||
|     zip_int64_t idx = zip_name_locate((zip_t*)handler, path.c_str(), 0); | ||||
|  | ||||
|     if (idx < 0) | ||||
| 	EXCEPTION(gourou::CLIENT_ZIP_ERROR, "No such file " << path.c_str()); | ||||
|      | ||||
|     if (zip_delete((zip_t*)handler, idx)) | ||||
| 	EXCEPTION(gourou::CLIENT_ZIP_ERROR, "Zip error " << zip_strerror((zip_t *)handler)); | ||||
| } | ||||
|  | ||||
| void DRMProcessorClientImpl::zipClose(void* handler) | ||||
| { | ||||
|     zip_close((zip_t*)handler); | ||||
| } | ||||
							
								
								
									
										110
									
								
								utils/drmprocessorclientimpl.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										110
									
								
								utils/drmprocessorclientimpl.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,110 @@ | ||||
| /* | ||||
|   Copyright (c) 2021, Grégory Soutadé | ||||
|  | ||||
|   All rights reserved. | ||||
|   Redistribution and use in source and binary forms, with or without | ||||
|   modification, are permitted provided that the following conditions are met: | ||||
|    | ||||
|   * Redistributions of source code must retain the above copyright | ||||
|     notice, this list of conditions and the following disclaimer. | ||||
|   * Redistributions in binary form must reproduce the above copyright | ||||
|     notice, this list of conditions and the following disclaimer in the | ||||
|     documentation and/or other materials provided with the distribution. | ||||
|   * Neither the name of the copyright holder nor the | ||||
|     names of its contributors may be used to endorse or promote products | ||||
|     derived from this software without specific prior written permission. | ||||
|    | ||||
|   THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY | ||||
|   EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED | ||||
|   WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | ||||
|   DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS BE LIABLE FOR ANY | ||||
|   DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES | ||||
|   (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; | ||||
|   LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND | ||||
|   ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||||
|   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS | ||||
|   SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||||
| */ | ||||
|  | ||||
| #ifndef _DRMPROCESSORCLIENTIMPL_H_ | ||||
| #define _DRMPROCESSORCLIENTIMPL_H_ | ||||
|  | ||||
| #include <string> | ||||
|  | ||||
| #include <drmprocessorclient.h> | ||||
|  | ||||
| class DRMProcessorClientImpl : public gourou::DRMProcessorClient | ||||
| { | ||||
|     public: | ||||
|     /* Digest interface */ | ||||
|     virtual void* createDigest(const std::string& digestName); | ||||
|     virtual int digestUpdate(void* handler, unsigned char* data, unsigned int length); | ||||
|     virtual int digestFinalize(void* handler,unsigned char* digestOut); | ||||
|     virtual int digest(const std::string& digestName, unsigned char* data, unsigned int length, unsigned char* digestOut); | ||||
|  | ||||
|     /* Random interface */ | ||||
|     virtual void randBytes(unsigned char* bytesOut, unsigned int length); | ||||
|  | ||||
|     /* HTTP interface */ | ||||
|     virtual std::string sendHTTPRequest(const std::string& URL, const std::string& POSTData=std::string(""), const std::string& contentType=std::string("")); | ||||
|  | ||||
|     virtual void RSAPrivateEncrypt(const unsigned char* RSAKey, unsigned int RSAKeyLength, | ||||
| 				   const RSA_KEY_TYPE keyType, const std::string& password, | ||||
| 				   const unsigned char* data, unsigned dataLength, | ||||
| 				   unsigned char* res); | ||||
| 			     | ||||
|     virtual void RSAPublicEncrypt(const unsigned char* RSAKey, unsigned int RSAKeyLength, | ||||
| 				  const RSA_KEY_TYPE keyType, | ||||
| 				  const unsigned char* data, unsigned dataLength, | ||||
| 				  unsigned char* res); | ||||
|  | ||||
|     virtual void* generateRSAKey(int keyLengthBits); | ||||
|     virtual void destroyRSAHandler(void* handler); | ||||
|      | ||||
|     virtual void extractRSAPublicKey(void* RSAKeyHandler, unsigned char** keyOut, unsigned int* keyOutLength); | ||||
|     virtual void extractRSAPrivateKey(void* RSAKeyHandler, unsigned char** keyOut, unsigned int* keyOutLength); | ||||
| 				  | ||||
|     /* Crypto interface */ | ||||
|     virtual void AESEncrypt(CHAINING_MODE chaining, | ||||
| 			    const unsigned char* key, unsigned int keyLength, | ||||
| 			    const unsigned char* iv, unsigned int ivLength, | ||||
| 			    const unsigned char* dataIn, unsigned int dataInLength, | ||||
| 			    unsigned char* dataOut, unsigned int* dataOutLength); | ||||
|  | ||||
|     virtual void* AESEncryptInit(CHAINING_MODE chaining, | ||||
| 				 const unsigned char* key, unsigned int keyLength, | ||||
| 				 const unsigned char* iv=0, unsigned int ivLength=0); | ||||
|  | ||||
|  | ||||
|     virtual void AESEncryptUpdate(void* handler, const unsigned char* dataIn, unsigned int dataInLength, | ||||
| 				   unsigned char* dataOut, unsigned int* dataOutLength); | ||||
|     virtual void AESEncryptFinalize(void* handler, unsigned char* dataOut, unsigned int* dataOutLength); | ||||
|  | ||||
|     virtual void AESDecrypt(CHAINING_MODE chaining, | ||||
| 			    const unsigned char* key, unsigned int keyLength, | ||||
| 			    const unsigned char* iv, unsigned int ivLength, | ||||
| 			    const unsigned char* dataIn, unsigned int dataInLength, | ||||
| 			    unsigned char* dataOut, unsigned int* dataOutLength); | ||||
|  | ||||
|     virtual void* AESDecryptInit(CHAINING_MODE chaining, | ||||
| 				 const unsigned char* key, unsigned int keyLength, | ||||
| 				 const unsigned char* iv=0, unsigned int ivLength=0); | ||||
|  | ||||
|     virtual void AESDecryptUpdate(void* handler, const unsigned char* dataIn, unsigned int dataInLength, | ||||
| 				   unsigned char* dataOut, unsigned int* dataOutLength); | ||||
|     virtual void AESDecryptFinalize(void* handler, unsigned char* dataOut, unsigned int* dataOutLength); | ||||
|  | ||||
|     /* ZIP Interface */ | ||||
|     virtual void* zipOpen(const std::string& path); | ||||
|      | ||||
|     virtual std::string zipReadFile(void* handler, const std::string& path); | ||||
|      | ||||
|     virtual void zipWriteFile(void* handler, const std::string& path, const std::string& content); | ||||
|      | ||||
|     virtual void zipDeleteFile(void* handler, const std::string& path); | ||||
|      | ||||
|     virtual void zipClose(void* handler); | ||||
|      | ||||
| }; | ||||
|  | ||||
| #endif | ||||
		Reference in New Issue
	
	Block a user