diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..fbc60ad --- /dev/null +++ b/.gitignore @@ -0,0 +1,8 @@ + +*.xcuserstate + +*.xcbkptlist + +*.xcscheme + +*.plist diff --git a/DRMDecrypt.sln b/DRMDecrypt.sln new file mode 100755 index 0000000..d02f2ca --- /dev/null +++ b/DRMDecrypt.sln @@ -0,0 +1,26 @@ + +Microsoft Visual Studio Solution File, Format Version 10.00 +# Visual Studio 2008 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "DRMDecrypt", "DRMDecrypt\DRMDecrypt.vcproj", "{57AF2F79-3983-4087-9048-95920EEAE818}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Win32 = Debug|Win32 + Debug|x64 = Debug|x64 + Release|Win32 = Release|Win32 + Release|x64 = Release|x64 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {57AF2F79-3983-4087-9048-95920EEAE818}.Debug|Win32.ActiveCfg = Debug|Win32 + {57AF2F79-3983-4087-9048-95920EEAE818}.Debug|Win32.Build.0 = Debug|Win32 + {57AF2F79-3983-4087-9048-95920EEAE818}.Debug|x64.ActiveCfg = Debug|x64 + {57AF2F79-3983-4087-9048-95920EEAE818}.Debug|x64.Build.0 = Debug|x64 + {57AF2F79-3983-4087-9048-95920EEAE818}.Release|Win32.ActiveCfg = Release|Win32 + {57AF2F79-3983-4087-9048-95920EEAE818}.Release|Win32.Build.0 = Release|Win32 + {57AF2F79-3983-4087-9048-95920EEAE818}.Release|x64.ActiveCfg = Release|x64 + {57AF2F79-3983-4087-9048-95920EEAE818}.Release|x64.Build.0 = Release|x64 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/DRMDecrypt.xcodeproj/project.pbxproj b/DRMDecrypt.xcodeproj/project.pbxproj new file mode 100644 index 0000000..0f828bc --- /dev/null +++ b/DRMDecrypt.xcodeproj/project.pbxproj @@ -0,0 +1,241 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 46; + objects = { + +/* Begin PBXBuildFile section */ + 4C612133185E371E007B307A /* DRMDecrypt.1 in CopyFiles */ = {isa = PBXBuildFile; fileRef = 4C612132185E371E007B307A /* DRMDecrypt.1 */; }; + 4C61213A185E37A3007B307A /* aes.c in Sources */ = {isa = PBXBuildFile; fileRef = 4C612139185E37A3007B307A /* aes.c */; }; + 4C6E3A7A18612A64001C4C78 /* DRMDecrypt.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4C6E3A7918612A64001C4C78 /* DRMDecrypt.cpp */; }; +/* End PBXBuildFile section */ + +/* Begin PBXCopyFilesBuildPhase section */ + 4C61212B185E371E007B307A /* CopyFiles */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 2147483647; + dstPath = /opt/local/share/man/man1; + dstSubfolderSpec = 0; + files = ( + 4C612133185E371E007B307A /* DRMDecrypt.1 in CopyFiles */, + ); + runOnlyForDeploymentPostprocessing = 1; + }; +/* End PBXCopyFilesBuildPhase section */ + +/* Begin PBXFileReference section */ + 4C61212D185E371E007B307A /* DRMDecrypt */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = DRMDecrypt; sourceTree = BUILT_PRODUCTS_DIR; }; + 4C612132185E371E007B307A /* DRMDecrypt.1 */ = {isa = PBXFileReference; lastKnownFileType = text.man; path = DRMDecrypt.1; sourceTree = ""; }; + 4C612139185E37A3007B307A /* aes.c */ = {isa = PBXFileReference; explicitFileType = sourcecode.cpp.objcpp; fileEncoding = 4; path = aes.c; sourceTree = ""; }; + 4C6E3A7918612A64001C4C78 /* DRMDecrypt.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = DRMDecrypt.cpp; sourceTree = ""; }; + 4CDB748618621DCC00F805F8 /* README.md */ = {isa = PBXFileReference; lastKnownFileType = text; path = README.md; sourceTree = ""; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + 4C61212A185E371E007B307A /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + 4C612124185E371E007B307A = { + isa = PBXGroup; + children = ( + 4CDB748618621DCC00F805F8 /* README.md */, + 4C61212F185E371E007B307A /* DRMDecrypt */, + 4C61212E185E371E007B307A /* Products */, + ); + sourceTree = ""; + }; + 4C61212E185E371E007B307A /* Products */ = { + isa = PBXGroup; + children = ( + 4C61212D185E371E007B307A /* DRMDecrypt */, + ); + name = Products; + sourceTree = ""; + }; + 4C61212F185E371E007B307A /* DRMDecrypt */ = { + isa = PBXGroup; + children = ( + 4C612139185E37A3007B307A /* aes.c */, + 4C6E3A7918612A64001C4C78 /* DRMDecrypt.cpp */, + 4C612132185E371E007B307A /* DRMDecrypt.1 */, + ); + path = DRMDecrypt; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + 4C61212C185E371E007B307A /* DRMDecrypt */ = { + isa = PBXNativeTarget; + buildConfigurationList = 4C612136185E371E007B307A /* Build configuration list for PBXNativeTarget "DRMDecrypt" */; + buildPhases = ( + 4C612129185E371E007B307A /* Sources */, + 4C61212A185E371E007B307A /* Frameworks */, + 4C61212B185E371E007B307A /* CopyFiles */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = DRMDecrypt; + productName = DRMDecrypt; + productReference = 4C61212D185E371E007B307A /* DRMDecrypt */; + productType = "com.apple.product-type.tool"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + 4C612125185E371E007B307A /* Project object */ = { + isa = PBXProject; + attributes = { + LastUpgradeCheck = 0500; + ORGANIZATIONNAME = mcbSolutions; + }; + buildConfigurationList = 4C612128185E371E007B307A /* Build configuration list for PBXProject "DRMDecrypt" */; + compatibilityVersion = "Xcode 3.2"; + developmentRegion = English; + hasScannedForEncodings = 0; + knownRegions = ( + en, + ); + mainGroup = 4C612124185E371E007B307A; + productRefGroup = 4C61212E185E371E007B307A /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + 4C61212C185E371E007B307A /* DRMDecrypt */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXSourcesBuildPhase section */ + 4C612129185E371E007B307A /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 4C61213A185E37A3007B307A /* aes.c in Sources */, + 4C6E3A7A18612A64001C4C78 /* DRMDecrypt.cpp in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin XCBuildConfiguration section */ + 4C612134185E371E007B307A /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + COPY_PHASE_STRIP = NO; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_DYNAMIC_NO_PIC = NO; + GCC_ENABLE_OBJC_EXCEPTIONS = YES; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG=1", + "$(inherited)", + ); + GCC_SYMBOLS_PRIVATE_EXTERN = NO; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + MACOSX_DEPLOYMENT_TARGET = 10.9; + ONLY_ACTIVE_ARCH = YES; + SDKROOT = macosx; + }; + name = Debug; + }; + 4C612135185E371E007B307A /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + COPY_PHASE_STRIP = YES; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + ENABLE_NS_ASSERTIONS = NO; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_ENABLE_OBJC_EXCEPTIONS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + MACOSX_DEPLOYMENT_TARGET = 10.9; + SDKROOT = macosx; + }; + name = Release; + }; + 4C612137185E371E007B307A /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + INSTALL_PATH = /opt/local/bin/; + PRODUCT_NAME = "$(TARGET_NAME)"; + }; + name = Debug; + }; + 4C612138185E371E007B307A /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + INSTALL_PATH = /opt/local/bin/; + PRODUCT_NAME = "$(TARGET_NAME)"; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 4C612128185E371E007B307A /* Build configuration list for PBXProject "DRMDecrypt" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 4C612134185E371E007B307A /* Debug */, + 4C612135185E371E007B307A /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 4C612136185E371E007B307A /* Build configuration list for PBXNativeTarget "DRMDecrypt" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 4C612137185E371E007B307A /* Debug */, + 4C612138185E371E007B307A /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = 4C612125185E371E007B307A /* Project object */; +} diff --git a/DRMDecrypt.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/DRMDecrypt.xcodeproj/project.xcworkspace/contents.xcworkspacedata new file mode 100644 index 0000000..e9f8ae7 --- /dev/null +++ b/DRMDecrypt.xcodeproj/project.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,7 @@ + + + + + diff --git a/DRMDecrypt.xcodeproj/project.xcworkspace/xcshareddata/DRMDecrypt.xccheckout b/DRMDecrypt.xcodeproj/project.xcworkspace/xcshareddata/DRMDecrypt.xccheckout new file mode 100644 index 0000000..c7989bb --- /dev/null +++ b/DRMDecrypt.xcodeproj/project.xcworkspace/xcshareddata/DRMDecrypt.xccheckout @@ -0,0 +1,51 @@ + + + + + IDESourceControlProjectFavoriteDictionaryKey + + IDESourceControlProjectIdentifier + ACC9EBC8-A86B-486A-9FAA-155E3A9EA288 + IDESourceControlProjectName + DRMDecrypt + IDESourceControlProjectOriginsDictionary + + E483CBBF-1BD3-47B7-BD28-0895B198B847 + https://github.com/marvin0815/drmdecrypt.git + + IDESourceControlProjectPath + DRMDecrypt.xcodeproj/project.xcworkspace + IDESourceControlProjectRelativeInstallPathDictionary + + 058AF5A6-E2DB-4CA0-8A86-33A453641C04 + ../../../DRMDecrypt + E483CBBF-1BD3-47B7-BD28-0895B198B847 + ../.. + + IDESourceControlProjectURL + https://github.com/marvin0815/drmdecrypt.git + IDESourceControlProjectVersion + 110 + IDESourceControlProjectWCCIdentifier + E483CBBF-1BD3-47B7-BD28-0895B198B847 + IDESourceControlProjectWCConfigurations + + + IDESourceControlRepositoryExtensionIdentifierKey + public.vcs.git + IDESourceControlWCCIdentifierKey + E483CBBF-1BD3-47B7-BD28-0895B198B847 + IDESourceControlWCCName + drmdecrypt + + + IDESourceControlRepositoryExtensionIdentifierKey + public.vcs.git + IDESourceControlWCCIdentifierKey + 058AF5A6-E2DB-4CA0-8A86-33A453641C04 + IDESourceControlWCCName + DRMDecrypt + + + + diff --git a/DRMDecrypt/DRMDecrypt.1 b/DRMDecrypt/DRMDecrypt.1 new file mode 100755 index 0000000..471c82e --- /dev/null +++ b/DRMDecrypt/DRMDecrypt.1 @@ -0,0 +1,79 @@ +.\"Modified from man(1) of FreeBSD, the NetBSD mdoc.template, and mdoc.samples. +.\"See Also: +.\"man mdoc.samples for a complete listing of options +.\"man mdoc for the short list of editing options +.\"/usr/share/misc/mdoc.template +.Dd 15.12.13 \" DATE +.Dt DRMDecrypt 1 \" Program name and manual section number +.Os Darwin +.Sh NAME \" Section Header - required - don't modify +.Nm DRMDecrypt, +.\" The following lines are read in generating the apropos(man -k) database. Use only key +.\" words here as the database is built based on the words here and in the .ND line. +.Nm Other_name_for_same_program(), +.Nm Yet another name for the same program. +.\" Use .Nm macro to designate other names for the documented program. +.Nd This line parsed for whatis database. +.Sh SYNOPSIS \" Section Header - required - don't modify +.Nm +.Op Fl abcd \" [-abcd] +.Op Fl a Ar path \" [-a path] +.Op Ar file \" [file] +.Op Ar \" [file ...] +.Ar arg0 \" Underlined argument - use .Ar anywhere to underline +arg2 ... \" Arguments +.Sh DESCRIPTION \" Section Header - required - don't modify +Use the .Nm macro to refer to your program throughout the man page like such: +.Nm +Underlining is accomplished with the .Ar macro like this: +.Ar underlined text . +.Pp \" Inserts a space +A list of items with descriptions: +.Bl -tag -width -indent \" Begins a tagged list +.It item a \" Each item preceded by .It macro +Description of item a +.It item b +Description of item b +.El \" Ends the list +.Pp +A list of flags and their descriptions: +.Bl -tag -width -indent \" Differs from above in tag removed +.It Fl a \"-a flag as a list item +Description of -a flag +.It Fl b +Description of -b flag +.El \" Ends the list +.Pp +.\" .Sh ENVIRONMENT \" May not be needed +.\" .Bl -tag -width "ENV_VAR_1" -indent \" ENV_VAR_1 is width of the string ENV_VAR_1 +.\" .It Ev ENV_VAR_1 +.\" Description of ENV_VAR_1 +.\" .It Ev ENV_VAR_2 +.\" Description of ENV_VAR_2 +.\" .El +.Sh FILES \" File used or created by the topic of the man page +.Bl -tag -width "/Users/joeuser/Library/really_long_file_name" -compact +.It Pa /usr/share/file_name +FILE_1 description +.It Pa /Users/joeuser/Library/really_long_file_name +FILE_2 description +.El \" Ends the list +.\" .Sh DIAGNOSTICS \" May not be needed +.\" .Bl -diag +.\" .It Diagnostic Tag +.\" Diagnostic informtion here. +.\" .It Diagnostic Tag +.\" Diagnostic informtion here. +.\" .El +.Sh SEE ALSO +.\" List links in ascending order by section, alphabetically within a section. +.\" Please do not reference files that do not exist without filing a bug report +.Xr a 1 , +.Xr b 1 , +.Xr c 1 , +.Xr a 2 , +.Xr b 2 , +.Xr a 3 , +.Xr b 3 +.\" .Sh BUGS \" Document known, unremedied bugs +.\" .Sh HISTORY \" Document history if command behaves in a unique manner \ No newline at end of file diff --git a/DRMDecrypt.c b/DRMDecrypt/DRMDecrypt.c similarity index 100% rename from DRMDecrypt.c rename to DRMDecrypt/DRMDecrypt.c diff --git a/DRMDecrypt/DRMDecrypt.cpp b/DRMDecrypt/DRMDecrypt.cpp new file mode 100755 index 0000000..54f926e --- /dev/null +++ b/DRMDecrypt/DRMDecrypt.cpp @@ -0,0 +1,353 @@ +#if defined(_WIN32) || defined(_WIN64) + #define _CRT_SECURE_NO_WARNINGS + #include +#else + #include +#endif +#include +#include +#include + +using namespace std; + +// defines +#define PROGRESS_WIDTH 60.0f +#define PACKET_SIZE 188 +#define BLOCK_SIZE 3948 // the HDD ist best working with 4096 bytes, but we need + // multiples of 188 (PACKET_SIZE) + +#if defined(_WIN32) || defined(_WIN64) + #define DIR_SEP ((char)'\\') +#else + #define DIR_SEP char('/') +#endif + +#if __APPLE__ + typedef uint64_t off64_t; +#else + //http://lists.mplayerhq.hu/pipermail/mplayer-dev-eng/2007-January/048904.html + #define fseeko _fseeki64 + #define ftello _ftelli64 + + typedef unsigned __int64 off64_t; +#endif + +// Prototypes +inline unsigned char process_section (unsigned char *data); +int rijndaelKeySetupDec(unsigned int rk[], const unsigned char cipherKey[], int keyBits); +void rijndaelDecrypt(const unsigned int rk[], int Nr, const unsigned char ct[16], unsigned char pt[16]); +void printUsage(); +string createFilenameFromInformation(string filename, string path); + +// Globals +unsigned char drm_key[0x10]; +static unsigned int rk[44]; + +/// Entrypoint +/// +/// @return 0 ... success +/// 1 ... Invalid intput filename +/// 2 ... Cannot open intput file +/// 3 ... Cannot open mdb +/// 4 ... Cannot open key +/// 5 ... Cannot open output +/// 6 ... Invalid options +int main( int argc, char *argv[] ) +{ + FILE *inputfp,*outputfp, *keyfp; + + unsigned char buf[BLOCK_SIZE]; + + string outfile, filename; +// cout << setfill('=') << setw(80) << '=' << endl; + cout << "Samsung TV PVR Recording DRM Decrypt (x64)" << endl << endl; + + switch (argc) { + case 3: + outfile = createFilenameFromInformation(argv[1], argv[2]); + + case 2: + + if(argc == 2) + outfile = createFilenameFromInformation(argv[1], ""); + + filename = argv[1]; + if(filename.length() < 3) + { + printUsage(); + return 1; + } + + if((inputfp = fopen(argv[1], "rb")) == NULL){ + cout << "Cannot open intput file: '" << argv[1] << "'" << endl; + return 2; + } + + filename.replace(filename.end()-3, filename.end(), "mdb"); + keyfp = fopen(filename.c_str(), "rb"); + if(keyfp) { // try .mdb + + fseek(keyfp, 8, SEEK_SET); + if(keyfp) { + fread(&buf, sizeof(unsigned char), 0x10, keyfp); + + for (int j = 0; j < 0x10; j++) + drm_key[(j&0xc)+(3-(j&3))] = buf[j]; // reorder the bytes + + fclose(keyfp); + } else { + cout << "Cannot open mdb file: '" << filename << "'" << endl; + return 3; + } + } else { // try .key + + filename.replace(filename.end()-3, filename.end(), "key"); + keyfp = fopen(filename.c_str(), "rb"); + if(keyfp){ + fread(drm_key, sizeof(unsigned char), 0x10, keyfp); + fclose(keyfp); + } else { + cout << "Cannot open key file: '" << filename << "'" << endl; + return 4; + } + } + + outputfp = fopen(outfile.c_str(), "wb"); + if(!outputfp){ + cout << "Cannot open output file for writing: '" << outfile << "'" << endl; + return 5; + } + break; + + default: + printUsage(); + return 6; + } + + fseeko(inputfp,0,2); + off64_t filesize = ftello (inputfp); + rewind(inputfp); + +// cout << setfill('=') << setw(80) << '=' << endl << endl; + cout << outfile << endl << endl; + cout << setfill(' ') << setw(13) << filesize << " bytes to decrypt (" << filesize/1024/1024 << " MB)"<< endl; + + fread(buf, sizeof(unsigned char), BLOCK_SIZE, inputfp); + int sync_found=0; + for(int i=0; i<(BLOCK_SIZE - PACKET_SIZE); ++i){ + if (buf[i] == 0x47){ + sync_found = 1; + fseeko(inputfp,i,SEEK_SET); + cout << "sync found at " << i << endl; + break; + } + } + if (sync_found) { + + float percent = 0.0; + bool sync_lost = false; + clock_t start = clock(); + + rijndaelKeySetupDec(rk, drm_key, 128); + + for(off64_t i = 0, j = 0; i < filesize; i += BLOCK_SIZE, ++j) { + + fread(buf, sizeof(unsigned char), BLOCK_SIZE, inputfp); + + for (int n = 0; n < BLOCK_SIZE; n += PACKET_SIZE) { + + if (buf[n] != 0x47) { + + if(!sync_lost) + { + cout << "\r[" << setw(0) << "lost sync at " << i ; + sync_lost = true; + } + continue; + + } else { + + if(sync_lost) { + cout << setw(0) << endl << "found sync at " << i << endl; + sync_lost = false; + } + + process_section (buf+n); + } + } + + if(!(j%500)) // update the progress bar every 500 times + { + percent = (PROGRESS_WIDTH/filesize)*i; + cout << "\r[" << setfill('=') << setw(int(percent+0.5f)) << "" + << setfill(' ') << setw(PROGRESS_WIDTH+2-int(percent+0.5f)) << "] " + << setprecision(3) << (100.0f/filesize)*i << " % " + << setw(3) << setfill(' ') << ""; + } + + fwrite(buf,sizeof(unsigned char),BLOCK_SIZE, outputfp); + } + cout << endl << "duration: " << double(clock() - start)/CLOCKS_PER_SEC << " Sec." << endl; + } + + fclose(inputfp); + fclose(outputfp); + + return 1; +} + +/// http://en.wikipedia.org/wiki/Mpeg_transport_stream#Packet +/// +/// Name Bits Values +/// +/// sync byte 8 0x47 +/// +/// Transport Error Indicator (TEI) 1 Set by demodulator if can't correct errors in the +/// stream, to tell the demultiplexer that the packet +/// has an uncorrectable error [11] +/// +/// Payload Unit Start Indicator 1 1 means start of PES data or PSI otherwise zero only. +/// +/// Transport Priority 1 1 means higher priority than other packets with the +/// same PID. +/// +/// PID 13 Packet ID +/// +/// Scrambling control 2 '00' = Not scrambled. The following per DVB spec:[12] +/// '01' = Reserved for future use, +/// '10' = Scrambled with even key, +/// '11' = Scrambled with odd key +/// +/// Adaptation field 1 1 means adaptation field exist +/// +/// Contains payload 1 1 means payload exist +/// +/// Continuity counter 4 Incremented only when a payload is present (i.e., +/// adaptation field exist is 01 or 11)[13] +/// +/// @note The total number of bits above is 32 and is called the transport stream 4-byte prefix +/// or Transport Stream Header. +inline unsigned char process_section (unsigned char *data) { + + // 0-3 ... Transport Stream Header + if(!(data[3] & 0xC0)) // unencrypted + return 0; + + int offset = 4; + + if(data[3] & 0x20) + offset += (data[4] + 1); // skip adaption field + + data[3] &= 0x3f; // remove scrambling bits + + int rounds = (PACKET_SIZE - offset) / 0x10; + + // AES CBC + for (int i = 0; i < rounds; ++i) + rijndaelDecrypt(rk, 10, data + offset + i * 0x10, data + offset + i * 0x10); + + return 1; +} + +/// https://code.google.com/p/samy-pvr-manager/wiki/InfFileStructure +/// +/// RAWTITLE 0x0100 - 0x0200 +/// RECTIME 0x0304 - 0x0308 +/// RECTITLE 0x0318 - 0x0418 +string createFilenameFromInformation(string filename, string path) +{ + if (!path.length()) { + size_t pos = filename.rfind(DIR_SEP)+1; + path = string(filename.begin(), filename.begin() + pos); + } else if(*(path.end()-1) != DIR_SEP) { + path += DIR_SEP; + } + + filename.replace(filename.end()-3, filename.end(), "inf"); + + FILE *fp = NULL; + + fp = fopen(filename.c_str(), "rb"); + if(!fp) { + cout << "Cannot open '" << filename << "' file" << endl; + filename.replace(filename.end()-4, filename.end(), ".ts"); + return filename; + } + + unsigned char buf[0x0418]; + //fseeko(keyfp,0x100,SEEK_SET); + fread(buf, sizeof(unsigned char), 0x0418, fp); + fclose(fp); + + stringstream recordtitle; + recordtitle << path; + + // try to read the raw title + for (int n=0x0100; n<0x0200; ++n) { + switch (buf[n]) { + case 0: + case ':': + case DIR_SEP: continue; + default : recordtitle << buf[n]; break; + } + } + + if(!recordtitle.str().length()) { + // read the record title + for (int n=0x318; n<0x418; ++n) { + switch (buf[n]) { + case 0: + case ':': + case DIR_SEP: continue; + default : recordtitle << buf[n]; break; + } + } + } + + if(!recordtitle.str().length()) { + + size_t pos = filename.rfind(DIR_SEP)+1; + filename = filename.substr(pos); + filename.replace(filename.end()-4, filename.end(), ""); + recordtitle << filename; + } + + // get the record time + char recordtime [80]; memset(recordtime, 0, 80); + time_t t = (buf[0x0307] << 24) + (buf[0x0306] << 16) + (buf[0x0305] << 8) + buf[0x0304]; + strftime (recordtime, 80, " %Y-%m-%d %H-%M", localtime (&t)); + + // check existing filename; append number if neccessary + filename = recordtitle.str() + recordtime + ".ts"; + if((fp = fopen(filename.c_str(), "rb")) != NULL) { + fclose(fp); + int n = 1; + stringstream num; + num << '_' << setfill('0') << setw(4) << n; + filename = recordtitle.str() + recordtime + num.str() + ".ts"; + + while ((fp = fopen(filename.c_str(), "rb")) != NULL) { + fclose(fp); + + num.str(string()); + num << '_' << setfill('0') << setw(4) << ++n; + filename = recordtitle.str() + recordtime + num.str() + ".ts"; + + if(n>1000) + { + cout << "Did not find a valid Filename after " << n-1 << " tries" << endl; + return ""; + } + } + } + + return filename; +} + + +void printUsage() +{ + cout << "usage: DRMDecrypt full_path_to_srf_file [output_path]" << endl << endl; + cout << "The mdb file must also be present in the" << endl; + cout << "current working directory" << endl << endl; +} \ No newline at end of file diff --git a/DRMDecrypt/DRMDecrypt.vcproj b/DRMDecrypt/DRMDecrypt.vcproj new file mode 100755 index 0000000..f30b024 --- /dev/null +++ b/DRMDecrypt/DRMDecrypt.vcproj @@ -0,0 +1,379 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/aes.c b/DRMDecrypt/aes.c old mode 100644 new mode 100755 similarity index 97% rename from aes.c rename to DRMDecrypt/aes.c index 3ec4937..50cd152 --- a/aes.c +++ b/DRMDecrypt/aes.c @@ -1,7 +1,4 @@ - - -#include -#include +#include /** * rijndael-alg-fst.h * diff --git a/DRMDecrypt/targetver.h b/DRMDecrypt/targetver.h new file mode 100755 index 0000000..a38195a --- /dev/null +++ b/DRMDecrypt/targetver.h @@ -0,0 +1,13 @@ +#pragma once + +// The following macros define the minimum required platform. The minimum required platform +// is the earliest version of Windows, Internet Explorer etc. that has the necessary features to run +// your application. The macros work by enabling all features available on platform versions up to and +// including the version specified. + +// Modify the following defines if you have to target a platform prior to the ones specified below. +// Refer to MSDN for the latest info on corresponding values for different platforms. +#ifndef _WIN32_WINNT // Specifies that the minimum required platform is Windows Vista. +#define _WIN32_WINNT 0x0600 // Change this to the appropriate value to target other versions of Windows. +#endif + diff --git a/README.md b/README.md old mode 100644 new mode 100755 index 78f3ca5..0912218 --- a/README.md +++ b/README.md @@ -1,18 +1,30 @@ -# drmdecrypt +# DRMDecrypt + ## Synopsis -This is a UNIX(c) Port of the DRMdecrypt i found somewhere on the net. It is capable of extracting the encryption key from the .mdb file and decrypts the .srf to a standard transport stream format. -Working but slooooowwww. +This is a UNIX(c) / Windows / OS X Port of the DRMdecrypt i found somewhere on the net. It is capable of extracting the encryption key from the .mdb file and decrypts the .srf to a standard transport stream format. + +## Platforms ++ [X] OS X Mavericks (10.9) ++ [X] Windows 7 x64 + +## TV ++ [x] Samsung PS50C7700 ## Building -There is no Makefile at the moment. You will need a C-Compiler +There is no Makefile at the moment. You will need a C++-Compiler. Apple Xcode project and MS Visual Studio solution are included. -* gcc -D_FILE_OFFSET_BITS=64 -D_LARGEFILE_SOURCE -D_LARGEFILE64_SOURCE -c aes.c -o aes.o -* gcc -D_FILE_OFFSET_BITS=64 -D_LARGEFILE_SOURCE -D_LARGEFILE64_SOURCE -c DRMDecrypt.c -o DRMDecrypt.o -* gcc -o drmdecrypt aes.o DRMDecrypt.o ++ `g++ -D_FILE_OFFSET_BITS=64 -D_LARGEFILE_SOURCE -D_LARGEFILE64_SOURCE -c aes.c -o aes.o` ++ `g++ -D_FILE_OFFSET_BITS=64 -D_LARGEFILE_SOURCE -D_LARGEFILE64_SOURCE -c DRMDecrypt.cpp -o DRMDecrypt.o` ++ `g++ -o drmdecrypt aes.o DRMDecrypt.o -lstdc++` ## ToDo -* Fancy output (progressbar, etc.) -* Speedup of decryption (ASM, CPU assisted) +* [x] Fancy output (progressbar, etc.) +* [x] Speedup of decryption (ASM, CPU assisted) +* [x] Read the recorded filename / timestamp from the .inf file +* [x] Change to C++ +* [x] Create Visual Studio Solution and test it +* [x] Create Xcode project and test it +* [ ] QT GUI