Skip to content
This repository has been archived by the owner on Aug 18, 2022. It is now read-only.

Commit

Permalink
Add support for large zips.
Browse files Browse the repository at this point in the history
  • Loading branch information
kmdm committed Dec 16, 2013
1 parent 9121f70 commit b967d41
Show file tree
Hide file tree
Showing 7 changed files with 150 additions and 45 deletions.
2 changes: 1 addition & 1 deletion Makefile.am
Original file line number Original file line Diff line number Diff line change
Expand Up @@ -2,6 +2,6 @@ ACLOCAL_AMFLAGS = -I m4
AM_CPPFLAGS = -D_FORTIFY_SOURCE=0 $(LIBMCRYPT_CFLAGS) AM_CPPFLAGS = -D_FORTIFY_SOURCE=0 $(LIBMCRYPT_CFLAGS)
AM_LDFLAGS = $(EXTRA_LDFLAGS) $(LIBMCRYPT_LDFLAGS) AM_LDFLAGS = $(EXTRA_LDFLAGS) $(LIBMCRYPT_LDFLAGS)
bin_PROGRAMS = ruuveal bin_PROGRAMS = ruuveal
ruuveal_SOURCES = main.c htcaes.c htckey.c htczip.c htc/devices.c ruuveal_SOURCES = main.c htcaes.c htckey.c htclargezip.c htczip.c htc/devices.c
ruuveal_LDADD = $(LIBMCRYPT_LIBS) ruuveal_LDADD = $(LIBMCRYPT_LIBS)
EXTRA_DIST = *.h htc/*.h htc/*.c EXTRA_DIST = *.h htc/*.h htc/*.c
33 changes: 21 additions & 12 deletions htcaes.c
Original file line number Original file line Diff line number Diff line change
Expand Up @@ -66,12 +66,13 @@ static int encrypt_chunk(MCRYPT td, char *buf, int size, char *key, char *iv)
memcpy(iv, &buf[size - HTC_AES_KEYSIZE], HTC_AES_KEYSIZE); memcpy(iv, &buf[size - HTC_AES_KEYSIZE], HTC_AES_KEYSIZE);
} }


static int htc_aes_crypt(FILE *in, FILE *out, char *key, char *iv, static int htc_aes_crypt(FILE *in, unsigned int maxlen,
unsigned char chunks_in, htc_aes_progress_t callback, FILE *out, char *key, char *iv,
htc_aes_crypt_t crypt_func) unsigned char chunks_in, htc_aes_progress_t callback,
htc_aes_crypt_t crypt_func)
{ {
char buf[HTC_AES_READBUF], orig_iv[HTC_AES_KEYSIZE]; char buf[HTC_AES_READBUF], orig_iv[HTC_AES_KEYSIZE];
unsigned int pos, size, chunks, bytes, chunksdone = 0; unsigned int pos, size, chunks, bytes, bytesdone = 0, chunksdone = 0;
unsigned int count = HTC_AES_READBUF_ROUNDS + 1; unsigned int count = HTC_AES_READBUF_ROUNDS + 1;
unsigned int chunk_size = (((int)chunks_in)<<HTC_AES_CHUNK_SIZE); unsigned int chunk_size = (((int)chunks_in)<<HTC_AES_CHUNK_SIZE);
MCRYPT td; MCRYPT td;
Expand All @@ -82,6 +83,10 @@ static int htc_aes_crypt(FILE *in, FILE *out, char *key, char *iv,
size = ftell(in) - pos; size = ftell(in) - pos;
fseek(in, pos, SEEK_SET); fseek(in, pos, SEEK_SET);


if(maxlen > 0 && maxlen < size) {
size = maxlen;
}

chunks = get_num_chunks(size, chunk_size); chunks = get_num_chunks(size, chunk_size);


td = mcrypt_module_open(MCRYPT_RIJNDAEL_128, NULL, MCRYPT_CBC, NULL); td = mcrypt_module_open(MCRYPT_RIJNDAEL_128, NULL, MCRYPT_CBC, NULL);
Expand All @@ -93,39 +98,43 @@ static int htc_aes_crypt(FILE *in, FILE *out, char *key, char *iv,


memcpy(orig_iv, iv, HTC_AES_KEYSIZE); memcpy(orig_iv, iv, HTC_AES_KEYSIZE);


while((bytes = fread(buf, sizeof(char), sizeof(buf), in)) > 0) { while(bytesdone < size &&
if(callback) callback(ftell(in), size); (bytes = fread(buf, sizeof(char), sizeof(buf), in)) > 0) {
bytesdone += bytes;
if(bytesdone > size) bytes -= (bytesdone - size);

if(callback) callback(bytesdone, size);
if(chunksdone < chunks) { if(chunksdone < chunks) {
if((ftell(in) - bytes - pos) % chunk_size == 0) { if((ftell(in) - bytes - pos) % chunk_size == 0) {
count = 0; count = 0;
memcpy(iv, orig_iv, HTC_AES_KEYSIZE); memcpy(iv, orig_iv, HTC_AES_KEYSIZE);
} }


if(count < HTC_AES_READBUF_ROUNDS) { if(count < HTC_AES_READBUF_ROUNDS) {
crypt_func(td, buf, sizeof(buf), key, iv); crypt_func(td, buf, bytes, key, iv);
count++; count++;
} else if(count == HTC_AES_READBUF_ROUNDS) { } else if(count == HTC_AES_READBUF_ROUNDS) {
chunksdone++; chunksdone++;
count++; count++;
} }
} }
fwrite(buf, sizeof(char), sizeof(buf), out); fwrite(buf, sizeof(char), bytes, out);
} }


mcrypt_module_close(td); mcrypt_module_close(td);
return 1; return 1;
} }


int htc_aes_decrypt(FILE *in, FILE *out, char *key, char *iv, int htc_aes_decrypt(FILE *in, unsigned int maxlen, FILE *out, char *key,
unsigned char chunks, htc_aes_progress_t callback) char *iv, unsigned char chunks, htc_aes_progress_t callback)
{ {
return htc_aes_crypt(in, out, key, iv, chunks, callback, decrypt_chunk); return htc_aes_crypt(in,maxlen,out,key,iv,chunks,callback,decrypt_chunk);
} }


int htc_aes_encrypt(FILE *in, FILE *out, char *key, char *iv, int htc_aes_encrypt(FILE *in, FILE *out, char *key, char *iv,
unsigned char chunks, htc_aes_progress_t callback) unsigned char chunks, htc_aes_progress_t callback)
{ {
return htc_aes_crypt(in, out, key, iv, chunks, callback, encrypt_chunk); return htc_aes_crypt(in, -1, out, key, iv, chunks, callback, encrypt_chunk);
} }




2 changes: 1 addition & 1 deletion htcaes.h
Original file line number Original file line Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
#include <mcrypt.h> #include <mcrypt.h>
typedef void (*htc_aes_progress_t) (unsigned int, unsigned int); typedef void (*htc_aes_progress_t) (unsigned int, unsigned int);
typedef int (*htc_aes_crypt_t) (MCRYPT, char *, int, char *, char *); typedef int (*htc_aes_crypt_t) (MCRYPT, char *, int, char *, char *);
int htc_aes_decrypt(FILE *, FILE *, char *, char *, unsigned char, int htc_aes_decrypt(FILE *, unsigned int, FILE *, char *, char *, unsigned char,
htc_aes_progress_t); htc_aes_progress_t);
int htc_aes_encrypt(FILE *, FILE *, char *, char *, unsigned char, int htc_aes_encrypt(FILE *, FILE *, char *, char *, unsigned char,
htc_aes_progress_t); htc_aes_progress_t);
Expand Down
45 changes: 45 additions & 0 deletions htclargezip.c
Original file line number Original file line Diff line number Diff line change
@@ -0,0 +1,45 @@
/* ruuveal - Decrypt HTC encrypted RUUs (rom.zip files).
*
* Copyright (C) 2013 Kenny Millington
*
* This file is part of ruuveal.
*
* ruuveal is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* ruuveal is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with ruuveal. If not, see <http://www.gnu.org/licenses/>.
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include "htclargezip.h"

int htc_largezip_read_header(FILE *in, htc_largezip_header_t *header)
{
int pos = ftell(in);

if(fread(header, 1, sizeof(*header), in) != sizeof(*header)) {
printf("%d\n", sizeof(*header));
perror("failed to read htc largezip header");
fseek(in, pos, SEEK_SET);
return 0;
}

if(strncmp(header->magic, HTC_LARGEZIP_HEADER_MAGIC,
strlen(HTC_LARGEZIP_HEADER_MAGIC))) {
fseek(in, pos, SEEK_SET);
fprintf(stderr, "not a largezip - header mismatch!\n");
return 0;
}

return 1;
}
13 changes: 13 additions & 0 deletions htclargezip.h
Original file line number Original file line Diff line number Diff line change
@@ -0,0 +1,13 @@
#ifndef HTC_LARGEZIP_H
#define HTC_LARGEZIP_HEADER_MAGIC "LaR@eZip"
typedef struct {
char magic[8];
unsigned int starts[8];
unsigned int lengths[8];
unsigned int count;
unsigned int unknown;
char padding[0x100 - (8 + ((8 + 8 + 1 + 1)*4))];
} htc_largezip_header_t;

int htc_largezip_read_header(FILE *, htc_largezip_header_t *);
#endif
6 changes: 5 additions & 1 deletion htczip.c
Original file line number Original file line Diff line number Diff line change
Expand Up @@ -55,13 +55,17 @@ int htc_zip_init_header(htc_zip_header_t *header)


int htc_zip_read_header(FILE *in, htc_zip_header_t *header) int htc_zip_read_header(FILE *in, htc_zip_header_t *header)
{ {
int pos = ftell(in);

if(fread(header, 1, sizeof(*header), in) != sizeof(*header)) { if(fread(header, 1, sizeof(*header), in) != sizeof(*header)) {
perror("failed to read htc zip header"); perror("failed to read htc zip header");
fseek(in, pos, SEEK_SET);
return 0; return 0;
} }

if(strncmp(header->magic, HTC_ZIP_HEADER_MAGIC, if(strncmp(header->magic, HTC_ZIP_HEADER_MAGIC,
strlen(HTC_ZIP_HEADER_MAGIC))) { strlen(HTC_ZIP_HEADER_MAGIC))) {
fseek(in, pos, SEEK_SET);
return 0; return 0;
} }


Expand Down
94 changes: 64 additions & 30 deletions main.c
Original file line number Original file line Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@


#include "htcaes.h" #include "htcaes.h"
#include "htckey.h" #include "htckey.h"
#include "htclargezip.h"
#include "htczip.h" #include "htczip.h"


#include "htc/devices.h" #include "htc/devices.h"
Expand Down Expand Up @@ -180,42 +181,21 @@ static int parse_opts(int argc, char * const *argv)
return 1; return 1;
} }


int main(int argc, char * const *argv) static int process_zip(FILE *in, int length, const char *filename)
{ {
int rc = 0;
char key[HTC_AES_KEYSIZE] = {0}; char key[HTC_AES_KEYSIZE] = {0};
char iv[HTC_AES_KEYSIZE] = {0}; char iv[HTC_AES_KEYSIZE] = {0};
char *keydata = NULL; char *keydata = NULL;
int rc = 0; int rc = 0;


FILE *fh; FILE *out;

htc_zip_header_t header; htc_zip_header_t header;


// FIXME: Better way to set these defaults.
opts.keymap_index = HTC_ZIP_HEADER_DEFAULT_KEYMAP;
opts.chunks = HTC_ZIP_HEADER_DEFAULT_CHUNKS;
strncpy(opts.mainver, HTC_ZIP_HEADER_DEFAULT_MAINVER, sizeof(opts.mainver));

FILE *in = NULL, *out = NULL;

printf("ruuveal\n");
printf("-------\n\n");

if(!parse_opts(argc, argv)) {
usage(argv);
FAIL(-1);
}

/* Open the source file. */
if((in = fopen(opts.source, "rb")) == NULL) {
perror("failed to open source zip");
FAIL(-2)
}

/* Read the header. */ /* Read the header. */
if(!opts.encrypt) { if(!opts.encrypt) {
if(!htc_zip_read_header(in, &header)) { if(!htc_zip_read_header(in, &header)) {
fseek(in, 0x100, SEEK_SET); fseek(in, 0x100, SEEK_CUR);
if(!htc_zip_read_header(in, &header)) { if(!htc_zip_read_header(in, &header)) {
fprintf(stderr, "invalid htc aes encrypted zip file!\n"); fprintf(stderr, "invalid htc aes encrypted zip file!\n");
FAIL(-4); FAIL(-4);
Expand Down Expand Up @@ -273,7 +253,7 @@ int main(int argc, char * const *argv)
DEBUG(dump("iv", iv, sizeof(iv));) DEBUG(dump("iv", iv, sizeof(iv));)


/* Open the output file. */ /* Open the output file. */
if((out = fopen(opts.dest, "wb")) == NULL) { if((out = fopen(filename, "wb")) == NULL) {
perror("failed to open output zip destination"); perror("failed to open output zip destination");
FAIL(-6) FAIL(-6)
} }
Expand All @@ -286,19 +266,73 @@ int main(int argc, char * const *argv)
FAIL(-7) FAIL(-7)
} }


printf("Encrypted RUU (zip) written to: %s\n", opts.dest); printf("Encrypted RUU (zip) written to: %s\n", filename);
} else { } else {
if(!htc_aes_decrypt(in, out, key, iv, header.chunks, progress_update)) { if(!htc_aes_decrypt(in, length, out, key, iv, header.chunks,
progress_update)) {
fprintf(stderr, "failed to decrypt zip file!\n"); fprintf(stderr, "failed to decrypt zip file!\n");
FAIL(-7) FAIL(-7)
} }


printf("Decrypted RUU (zip) written to: %s\n", opts.dest); printf("Decrypted RUU (zip) written to: %s\n", filename);
} }





end: end:
if(in) fclose(in);
if(out) fclose(out); if(out) fclose(out);
return rc; return rc;
} }

int main(int argc, char * const *argv)
{
int i, rc = 0;
char *name = 0;
htc_largezip_header_t hdr;

// FIXME: Better way to set these defaults.
opts.keymap_index = HTC_ZIP_HEADER_DEFAULT_KEYMAP;
opts.chunks = HTC_ZIP_HEADER_DEFAULT_CHUNKS;
strncpy(opts.mainver, HTC_ZIP_HEADER_DEFAULT_MAINVER, sizeof(opts.mainver));

FILE *in = NULL;

printf("ruuveal\n");
printf("-------\n\n");

if(!parse_opts(argc, argv)) {
usage(argv);
FAIL(-1);
}

/* Open the source file. */
if((in = fopen(opts.source, "rb")) == NULL) {
perror("failed to open source zip");
FAIL(-2)
}

/* Check for a "Large Zip" */
if(!opts.encrypt && htc_largezip_read_header(in, &hdr)) {
printf("Large zip format detected containing %d zipfile(s)\n",
hdr.count);

if((name = calloc(strlen(opts.dest) + 3, sizeof(char))) == NULL) {
FAIL(-8)
};

for(i=0; i<hdr.count;i++) {
sprintf(name, "%02d_", i + 1);
strcat(name, opts.dest);
fseek(in, sizeof(hdr) + hdr.starts[i], SEEK_SET);
rc = process_zip(in, hdr.lengths[i], name);
if(rc != 0) goto end;
}
} else {
rc = process_zip(in, -1, opts.dest);
}

end:
if(in) fclose(in);
if(name) free(name);
return rc;
}

0 comments on commit b967d41

Please sign in to comment.