From 5fe3edb6d2896e9880031775162ded38c611330d Mon Sep 17 00:00:00 2001 From: Sven Weidauer Date: Mon, 9 Nov 2015 19:40:55 +0100 Subject: [PATCH 1/7] Split to multiple files and add Makefile. --- Buffer.c | 51 ++++++++++++++++++++++++++++++++++++ Buffer.h | 21 +++++++++++++++ Common.h | 26 +++++++++++++++++++ Decrypt.c | 77 +++---------------------------------------------------- Makefile | 11 ++++++++ README.md | 2 +- 6 files changed, 113 insertions(+), 75 deletions(-) create mode 100644 Buffer.c create mode 100644 Buffer.h create mode 100644 Common.h create mode 100644 Makefile diff --git a/Buffer.c b/Buffer.c new file mode 100644 index 0000000..769ac8a --- /dev/null +++ b/Buffer.c @@ -0,0 +1,51 @@ +#include "Buffer.h" + +#include +#include +#include +#include + +void Read( struct buffer *buf, size_t length, void *destination ) +{ + assert( buf->next + length < buf->start + buf->length ); + memcpy( destination, buf->next, length ); + buf->next += length; +} + +uint32_t Read32( struct buffer *buf ) +{ + uint32_t result; + Read( buf, sizeof result, &result ); + return CFSwapInt32BigToHost( result ); +} + +uint16_t Read16( struct buffer *buf ) +{ + uint16_t result; + Read( buf, sizeof result, &result ); + return CFSwapInt16BigToHost( result ); +} + +bool OpenFile( struct buffer *buf, const char *fn ) +{ + buf->fd = open( fn, O_RDONLY ); + if (buf->fd < 0) return false; + + struct stat stat; + if (fstat( buf->fd, &stat ) < 0) { + close( buf->fd ); + return false; + } + + buf->length = stat.st_size; + + buf->start = mmap( NULL, buf->length, PROT_READ, MAP_FILE | MAP_PRIVATE, buf->fd, 0 ); + if (!buf->start) { + close( buf->fd ); + return false; + } + + buf->next = buf->start; + + return true; +} \ No newline at end of file diff --git a/Buffer.h b/Buffer.h new file mode 100644 index 0000000..f79f522 --- /dev/null +++ b/Buffer.h @@ -0,0 +1,21 @@ +#ifndef _Buffer_h_included_ +#define _Buffer_h_included_ + +#include +#include +#include + +struct buffer { + uint8_t *start; + size_t length; + uint8_t *next; + int fd; +}; + +void Read( struct buffer *buf, size_t length, void *destination ); +uint32_t Read32( struct buffer *buf ); +uint16_t Read16( struct buffer *buf ); + +bool OpenFile( struct buffer *buf, const char *fn ); + +#endif diff --git a/Common.h b/Common.h new file mode 100644 index 0000000..dad80fd --- /dev/null +++ b/Common.h @@ -0,0 +1,26 @@ +#ifndef _Common_h_included_ +#define _Common_h_included_ + +#include + +struct header +{ + char magic[4]; // magic bytes \x43 \x46 \x47 \x31 (CFG1) + uint32_t payload_size; // length of ciphertext = length of padded plaintext (big endian) + char header_md5[8]; // first 8 bytes of MD5 computed over header (assuming the 8 bytes of "header_md5" are \x00) + char etl[7]; // blank electronic label (etl), always "000000" (null-terminated char array) + char unused1; // not used at the moment + uint16_t password_len; // length of the password used in AES encryption (big endian) + uint16_t padding_len; // number of padding bytes added to plaintext (big endian) + char unused2[4]; // not used at the moment + char plaintext_md5[16]; // MD5 hash of the plaintext +}; + +static const char aes_key[32] = { + 0x64, 0x75, 0x6d, 0x6d, 0x79, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 +}; + +#endif diff --git a/Decrypt.c b/Decrypt.c index 38578f1..1cba71d 100644 --- a/Decrypt.c +++ b/Decrypt.c @@ -2,59 +2,12 @@ * Code is under the MIT license, see the LICENSE file. */ +#include "Common.h" +#include "Buffer.h" + #include #include -#include -#include -struct header -{ - char magic[4]; // magic bytes \x43 \x46 \x47 \x31 (CFG1) - uint32_t payload_size; // length of ciphertext = length of padded plaintext (big endian) - char header_md5[8]; // first 8 bytes of MD5 computed over header (assuming the 8 bytes of "header_md5" are \x00) - char etl[7]; // blank electronic label (etl), always "000000" (null-terminated char array) - char unused1; // not used at the moment - uint16_t password_len; // length of the password used in AES encryption (big endian) - uint16_t padding_len; // number of padding bytes added to plaintext (big endian) - char unused2[4]; // not used at the moment - char plaintext_md5[16]; // MD5 hash of the plaintext -}; - -static const char aes_key[32] = { - 0x64, 0x75, 0x6d, 0x6d, 0x79, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 -}; - - -struct buffer { - uint8_t *start; - size_t length; - uint8_t *next; - int fd; -}; - -void Read( struct buffer *buf, size_t length, void *destination ) -{ - assert( buf->next + length < buf->start + buf->length ); - memcpy( destination, buf->next, length ); - buf->next += length; -} - -uint32_t Read32( struct buffer *buf ) -{ - uint32_t result; - Read( buf, sizeof result, &result ); - return CFSwapInt32BigToHost( result ); -} - -uint16_t Read16( struct buffer *buf ) -{ - uint16_t result; - Read( buf, sizeof result, &result ); - return CFSwapInt16BigToHost( result ); -} void ReadHeader( struct buffer *buf, struct header *header ) { @@ -69,30 +22,6 @@ void ReadHeader( struct buffer *buf, struct header *header ) Read( buf, 16, header->plaintext_md5 ); } -bool OpenFile( struct buffer *buf, const char *fn ) -{ - buf->fd = open( fn, O_RDONLY ); - if (buf->fd < 0) return false; - - struct stat stat; - if (fstat( buf->fd, &stat ) < 0) { - close( buf->fd ); - return false; - } - - buf->length = stat.st_size; - - buf->start = mmap( NULL, buf->length, PROT_READ, MAP_FILE | MAP_PRIVATE, buf->fd, 0 ); - if (!buf->start) { - close( buf->fd ); - return false; - } - - buf->next = buf->start; - - return true; -} - int main( int argc, const char *argv[] ) { if (argc != 3) { diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..57fa380 --- /dev/null +++ b/Makefile @@ -0,0 +1,11 @@ +all: Decrypt + +Decrypt: Decrypt.o Buffer.o + clang -o $@ Decrypt.o Buffer.o + +Decrypt.o: Decrypt.c Buffer.h Common.h +Buffer.o: Buffer.c Buffer.h + +.c.o: + clang -c -o $@ $< + diff --git a/README.md b/README.md index 762c852..c10ddd4 100644 --- a/README.md +++ b/README.md @@ -6,7 +6,7 @@ Thanks to [hph][1] for reverse engineering the details of that config format. ## Compile: - clang Decrypt.c -o Decrypt + make ## Run: From f53b189d6c2e86c4daf85a181819f5cc721be809 Mon Sep 17 00:00:00 2001 From: Sven Weidauer Date: Mon, 9 Nov 2015 19:49:35 +0100 Subject: [PATCH 2/7] Add skeleton for encrypt program. --- Encrypt.c | 14 ++++++++++++++ Makefile | 8 ++++++-- 2 files changed, 20 insertions(+), 2 deletions(-) create mode 100644 Encrypt.c diff --git a/Encrypt.c b/Encrypt.c new file mode 100644 index 0000000..5414cfa --- /dev/null +++ b/Encrypt.c @@ -0,0 +1,14 @@ +#include "Buffer.h" +#include "Common.h" + +#include + +int main( int argc, const char *argv[] ) +{ + if (argc != 3) { + fprintf( stderr, "Call %s \n", argv[0] ); + return 1; + } + + return 0; +} diff --git a/Makefile b/Makefile index 57fa380..738a411 100644 --- a/Makefile +++ b/Makefile @@ -1,10 +1,14 @@ -all: Decrypt +all: Decrypt Encrypt Decrypt: Decrypt.o Buffer.o - clang -o $@ Decrypt.o Buffer.o + clang -o $@ $^ + +Encrypt: Encrypt.o Buffer.o + clang -o $@ $^ Decrypt.o: Decrypt.c Buffer.h Common.h Buffer.o: Buffer.c Buffer.h +Encrypt.o: Encrypt.c Buffer.h Common.h .c.o: clang -c -o $@ $< From 5d0b4bd0e5d70566b244812cace1beede458b3be Mon Sep 17 00:00:00 2001 From: Sven Weidauer Date: Mon, 9 Nov 2015 22:43:58 +0100 Subject: [PATCH 3/7] Implement encrypting. --- Buffer.c | 27 +++++++++++++++++- Buffer.h | 6 ++++ Common.h | 12 +++++--- Encrypt.c | 84 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 124 insertions(+), 5 deletions(-) diff --git a/Buffer.c b/Buffer.c index 769ac8a..51e8dd9 100644 --- a/Buffer.c +++ b/Buffer.c @@ -48,4 +48,29 @@ bool OpenFile( struct buffer *buf, const char *fn ) buf->next = buf->start; return true; -} \ No newline at end of file +} + +void OpenBuffer( struct buffer *buf, void *data, size_t length ) +{ + buf->start = buf->next = data; + buf->length = length; + buf->fd = -1; +} + +void Write( struct buffer *buf, const void *data, size_t length ) +{ + memcpy(buf->next, data, length); + buf->next += length; +} + +void Write32( struct buffer *buf, uint32_t value ) +{ + uint32_t write = CFSwapInt32HostToBig(value); + Write(buf, &write, sizeof write); +} + +void Write16( struct buffer *buf, uint16_t value ) +{ + uint16_t write = CFSwapInt16HostToBig(value); + Write(buf, &write, sizeof write); +} diff --git a/Buffer.h b/Buffer.h index f79f522..84cde40 100644 --- a/Buffer.h +++ b/Buffer.h @@ -16,6 +16,12 @@ void Read( struct buffer *buf, size_t length, void *destination ); uint32_t Read32( struct buffer *buf ); uint16_t Read16( struct buffer *buf ); +void Write( struct buffer *buf, const void *data, size_t length ); +void Write32( struct buffer *buf, uint32_t value ); +void Write16( struct buffer *buf, uint16_t value ); + +void OpenBuffer( struct buffer *buf, void *data, size_t length ); + bool OpenFile( struct buffer *buf, const char *fn ); #endif diff --git a/Common.h b/Common.h index dad80fd..39156b1 100644 --- a/Common.h +++ b/Common.h @@ -7,13 +7,13 @@ struct header { char magic[4]; // magic bytes \x43 \x46 \x47 \x31 (CFG1) uint32_t payload_size; // length of ciphertext = length of padded plaintext (big endian) - char header_md5[8]; // first 8 bytes of MD5 computed over header (assuming the 8 bytes of "header_md5" are \x00) + uint8_t header_md5[8]; // first 8 bytes of MD5 computed over header (assuming the 8 bytes of "header_md5" are \x00) char etl[7]; // blank electronic label (etl), always "000000" (null-terminated char array) - char unused1; // not used at the moment + uint8_t unused1; // not used at the moment uint16_t password_len; // length of the password used in AES encryption (big endian) uint16_t padding_len; // number of padding bytes added to plaintext (big endian) - char unused2[4]; // not used at the moment - char plaintext_md5[16]; // MD5 hash of the plaintext + uint8_t unused2[4]; // not used at the moment + uint8_t plaintext_md5[16]; // MD5 hash of the plaintext }; static const char aes_key[32] = { @@ -23,4 +23,8 @@ static const char aes_key[32] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; +enum { + HeaderSize = 48 +}; + #endif diff --git a/Encrypt.c b/Encrypt.c index 5414cfa..2498346 100644 --- a/Encrypt.c +++ b/Encrypt.c @@ -2,6 +2,8 @@ #include "Common.h" #include +#include +#include int main( int argc, const char *argv[] ) { @@ -10,5 +12,87 @@ int main( int argc, const char *argv[] ) return 1; } + struct buffer inputFile = { 0 }; + if (!OpenFile(&inputFile, argv[1])) { + fprintf(stderr, "Cannot open input file %s\n", argv[1]); + return 1; + } + + struct header header = { 0 }; + + memcpy(header.magic, "CFG1", sizeof header.magic); + strcpy(header.etl, "000000"); + + CC_MD5_CTX context; + CC_MD5_Init(&context); + + // Hash input data. + CC_MD5_Update(&context,inputFile.start, inputFile.length); + + // Add PKCS7 padding data to hash. Decoder calculates hash over padded data. + uint8_t pad = kCCBlockSizeAES128 - (inputFile.length % kCCBlockSizeAES128); + for (uint8_t i = 0; i < pad; i++) { + CC_MD5_Update(&context,&pad, sizeof pad); + } + + // Finalize hash and store in header. + CC_MD5_Final(header.plaintext_md5, &context); + + size_t encryptedBufferSize = inputFile.length + kCCBlockSizeAES128; + void *encryptedBuffer = malloc(encryptedBufferSize); + if (!encryptedBuffer) { + fprintf(stderr, "Not enough memory to encrypt file\n"); + return 1; + } + size_t encryptedDataLength = 0; + + CCCryptorStatus status = CCCrypt(kCCEncrypt, kCCAlgorithmAES, kCCOptionPKCS7Padding|kCCOptionECBMode, + aes_key, sizeof aes_key, + NULL, + inputFile.start, inputFile.length, + encryptedBuffer, encryptedBufferSize, &encryptedDataLength); + + if (status != kCCSuccess) { + fprintf(stderr, "Error encrypting (%d)\n", status); + return 1; + } + + header.payload_size = encryptedDataLength; + header.padding_len = encryptedDataLength - inputFile.length; + + uint8_t headerData[HeaderSize] = {0}; + struct buffer headerBuf = {0}; + OpenBuffer(&headerBuf, headerData, sizeof headerData); + + Write(&headerBuf, header.magic, sizeof header.magic); + Write32(&headerBuf, header.payload_size); + headerBuf.next += sizeof header.header_md5; // Skip header_md5 + Write(&headerBuf, header.etl, sizeof header.etl); + Write(&headerBuf, &header.unused1, sizeof header.unused1); + Write16(&headerBuf, header.password_len); + Write16(&headerBuf, header.padding_len); + Write(&headerBuf, header.unused2, sizeof header.unused2); + Write(&headerBuf, header.plaintext_md5, sizeof header.plaintext_md5); + + uint8_t header_md5[CC_MD5_DIGEST_LENGTH]; + CC_MD5(headerData, sizeof headerData, header_md5); + memcpy(&headerData[8], header_md5, sizeof header.header_md5); + + int fdout = open( argv[2], O_WRONLY | O_CREAT | O_TRUNC, 0600 ); + if (fdout < 0) { + fprintf( stderr, "Error: cannot write output file\n" ); + return 1; + } + + bool written = write(fdout, headerData, sizeof headerData) == sizeof headerData; + written = written && write(fdout, encryptedBuffer, encryptedDataLength) == encryptedDataLength; + + if (!written) { + fprintf(stderr, "Cannot write output file\n"); + return 1; + } + + close(fdout); + return 0; } From 3f372fdcc3f25fd9d8f76b5855248f5cef20e271 Mon Sep 17 00:00:00 2001 From: Sven Weidauer Date: Mon, 9 Nov 2015 22:44:14 +0100 Subject: [PATCH 4/7] Use HeaderSize constant in Decrypt. --- Decrypt.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Decrypt.c b/Decrypt.c index 1cba71d..d88b3af 100644 --- a/Decrypt.c +++ b/Decrypt.c @@ -46,7 +46,7 @@ int main( int argc, const char *argv[] ) return 1; } - char header_data[48]; + char header_data[HeaderSize]; memcpy( header_data, buf.start, sizeof header_data ); memset( &header_data[8], 0, 8 ); @@ -61,7 +61,7 @@ int main( int argc, const char *argv[] ) printf( "Password len: %d\n", header.password_len ); printf( "ETL: %s\n", header.etl ); - if (buf.length - header.payload_size != 48) { + if (buf.length - header.payload_size != HeaderSize) { fprintf( stderr, "Error: Invalid file size\n" ); return 1; } From 9c55e9688ef66f853a588c1b84f60fe4b86a2fba Mon Sep 17 00:00:00 2001 From: Sven Weidauer Date: Mon, 9 Nov 2015 22:45:39 +0100 Subject: [PATCH 5/7] Update readme file for encryption. --- README.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index c10ddd4..dd4f864 100644 --- a/README.md +++ b/README.md @@ -6,10 +6,11 @@ Thanks to [hph][1] for reverse engineering the details of that config format. ## Compile: - make + make ## Run: - Decrypt path/to/config.bin path/to/output.tgz + Decrypt path/to/config.bin path/to/output.tgz + Encrypt path/to/output.tgz path/to/new/config.bin [1]: http://hph.name/207 From bd2acccfc20366ad1c0647c4fed7b6068d671aa5 Mon Sep 17 00:00:00 2001 From: Sven Weidauer Date: Mon, 9 Nov 2015 22:46:46 +0100 Subject: [PATCH 6/7] Ignore executables. --- .gitignore | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.gitignore b/.gitignore index 9fa3b1b..894211e 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,7 @@ +# Products +Encrypt +Decrypt + # Object files *.o *.ko From a15727ff975d46526ecb64a9ff0c32641413eb89 Mon Sep 17 00:00:00 2001 From: Sven Weidauer Date: Mon, 9 Nov 2015 22:47:50 +0100 Subject: [PATCH 7/7] Use tabs in readme file. --- README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index dd4f864..55036d5 100644 --- a/README.md +++ b/README.md @@ -6,11 +6,11 @@ Thanks to [hph][1] for reverse engineering the details of that config format. ## Compile: - make + make ## Run: - Decrypt path/to/config.bin path/to/output.tgz - Encrypt path/to/output.tgz path/to/new/config.bin + Decrypt path/to/config.bin path/to/output.tgz + Encrypt path/to/output.tgz path/to/new/config.bin [1]: http://hph.name/207