#include <inttypes.h>
#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#include <unistd.h>
#include <openssl/sha.h>
#include <openssl/aes.h>

struct {
	unsigned char magic[ 4 ];
	unsigned char version[ 3 ];
	unsigned char encrypted;
	unsigned char unknow1[ 20 ];
	unsigned char key1[ 32 ];
	unsigned char unknow2[ 4 ];
	unsigned char key2[ 16 ];
	unsigned char unknow3[ 1968 ];
} header8900;

char inbuf[ 65536 ];
char outbuf[ 65536 ];

void print_hex( char* text, uint8_t* data, uint32_t len )
{
	uint32_t ctr;
	char* sep;
	if( len > 64 )
		len = 64;
	printf( "%s", text );
	for( ctr = 0; ctr < len; ctr++ )
	{
		printf( "%02x ", data[ ctr ] );
	}
	printf( "\n" );
}

int main( int argc, char** argv )
{
	FILE *infile, *outfile;
	int encrypted;
	off_t data_begin;
	AES_KEY ctx;

	unsigned char keybuf[ 16 ];
	unsigned char iv[ AES_BLOCK_SIZE ];
	
	if( argc != 3 )
	{
		fprintf( stderr, "Usage: %s infile outfile\n", argv[ 0 ] );
		return 1;
	}

	infile = fopen( argv[ 1 ], "r" );
	if( !infile )
	{
		perror( "infile fopen" );
		return 1;
	}

	outfile = fopen( argv[ 2 ], "w+" );
	if( !outfile )
	{
		perror( "outfile fopen" );
		return 1;
	}

	if( sizeof( header8900 ) != fread( &header8900, 1, sizeof( header8900 ), infile ) )
	{
		fprintf( stderr, "Can't read header\n" );
		return 1;
	}

	if( ( header8900.magic[ 0 ] != 0x38 ) && // 8
	    ( header8900.magic[ 1 ] != 0x39 ) && // 9
	    ( header8900.magic[ 2 ] != 0x30 ) && // 0
	    ( header8900.magic[ 3 ] != 0x30 ) )  // 0
	{
		fprintf( stderr, "Bad magic\n" );
		return 1;
	}

	if( header8900.encrypted == 0x03 )
		encrypted = 1;
	else if( header8900.encrypted = 0x04 )
		encrypted = 0;

	data_begin = sizeof( header8900 );

	printf( "iPhone 8900 decryptor by aljen\n" );
	printf( "[*] filename	: %s\n", argv[ 1 ] );
	printf( "[*] magic	: %s\n", header8900.magic );
	printf( "[*] version	: %s\n", header8900.version );
	printf( "[*] encrypted	: %d\n", encrypted );
	print_hex( "[*] key 1	: ", header8900.key1, sizeof( header8900.key1 ) );
	print_hex( "[*] key 2	: ", header8900.key2, sizeof( header8900.key2 ) );
	printf( "[*] data	: 0x%02x\n", data_begin );

	memset( keybuf, 0, 32 );
	memcpy( keybuf, header8900.key1, 32 );
	AES_set_decrypt_key( keybuf, 256, &ctx );
	memset( iv, 0, AES_BLOCK_SIZE );
	memcpy( iv, header8900.key2, 16 );
	
	fseek( infile, data_begin, SEEK_SET );

	while( fread( &inbuf, 1, AES_BLOCK_SIZE, infile ) > 0 )
	{
		AES_cbc_encrypt( inbuf, outbuf, AES_BLOCK_SIZE, &ctx, iv, AES_DECRYPT );
		fwrite( outbuf, 1, AES_BLOCK_SIZE, outfile );
	}

	if( infile )
		fclose( infile );
	if( outfile )
		fclose( outfile );
	return 0;
}