| /*************************************************************************** |
| * __________ __ ___. |
| * Open \______ \ ____ ____ | | _\_ |__ _______ ___ |
| * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / |
| * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < |
| * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ |
| * \/ \/ \/ \/ \/ |
| * $Id$ |
| * |
| * Copyright (C) 2008 by Maurus Cuelenaere |
| * |
| * All files in this archive are subject to the GNU General Public License. |
| * See the file COPYING in the source tree root for full license agreement. |
| * |
| * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY |
| * KIND, either express or implied. |
| * |
| ****************************************************************************/ |
| |
| #include <stdio.h> |
| #include <stdbool.h> |
| #include <stdlib.h> |
| #include <string.h> |
| |
| #include "creative.h" |
| #include "hmac-sha1.h" |
| |
| static const char null_key_v1[] = "CTL:N0MAD|PDE0.SIGN."; |
| static const char null_key_v2[] = "CTL:N0MAD|PDE0.DPMP."; |
| static const char null_key_v3[] = "CTL:Z3N07|PDE0.DPMP."; |
| static const char null_key_v4[] = "CTL:N0MAD|PDE0.DPFP."; |
| |
| static const struct device_info devices[] = |
| { |
| {"C\0r\0e\0a\0t\0i\0v\0e\0 \0Z\0e\0n\0 \0V\0i\0s\0i\0o\0n\0:\0M", |
| 42, null_key_v2}, |
| {"C\0r\0e\0a\0t\0i\0v\0e\0 \0Z\0e\0n\0 \0V\0i\0s\0i\0o\0n\0:\0M\0 \0G\0o\0!", |
| 50, null_key_v2}, |
| {"C\0r\0e\0a\0t\0i\0v\0e\0 \0Z\0e\0n\0 \0V\0i\0s\0i\0o\0n\0 \0©\0T\0L", |
| 48, null_key_v2}, |
| {"C\0r\0e\0a\0t\0i\0v\0e\0 \0Z\0E\0N\0 \0V", 42, null_key_v4} |
| }; |
| |
| |
| /* |
| Create a Zen Vision:M FRESCUE structure file |
| */ |
| extern void int2le(unsigned int val, unsigned char* addr); |
| extern unsigned int le2int(unsigned char* buf); |
| |
| |
| static int make_ciff_file(unsigned char *inbuf, int length, |
| unsigned char *outbuf, int device) |
| { |
| char key[20]; |
| memcpy(outbuf, "FFIC", 4); |
| int2le(length+90, &outbuf[4]); |
| memcpy(&outbuf[8], "FNIC", 4); |
| int2le(96, &outbuf[0xC]); |
| memcpy(&outbuf[0x10], devices[device].cinf, devices[device].cinf_size); |
| memset(&outbuf[0x10+devices[device].cinf_size], 0, |
| 96 - devices[device].cinf_size); |
| memcpy(&outbuf[0x70], "ATAD", 4); |
| int2le(length+32, &outbuf[0x74]); |
| memcpy(&outbuf[0x78], "H\0j\0u\0k\0e\0b\0o\0x\0\x32\0.\0j\0r\0m", |
| 32); /*Unicode encoded*/ |
| memcpy(&outbuf[0x98], inbuf, length); |
| memcpy(&outbuf[0x98+length], "LLUN", 4); |
| int2le(20, &outbuf[0x98+length+4]); |
| /* Do checksum */ |
| hmac_sha((char *)devices[device].null, strlen(devices[device].null), |
| (char *)outbuf, 0x98+length, key, 20); |
| memcpy(&outbuf[0x98+length+8], key, 20); |
| return length+0x90+0x1C+8; |
| } |
| |
| static int make_jrm_file(unsigned char *inbuf, int length, |
| unsigned char *outbuf) |
| { |
| int i; |
| unsigned int sum = 0; |
| /* Calculate checksum for later use in header */ |
| for(i=0; i<length; i+= 4) |
| sum += le2int(&inbuf[i]) + (le2int(&inbuf[i])>>16); |
| |
| /* Clear the header area to zero */ |
| memset(outbuf, 0, 0x18); |
| |
| /* Header (EDOC) */ |
| memcpy(outbuf, "EDOC", 4); |
| /* Total Size */ |
| int2le(length+0x20, &outbuf[0x4]); |
| /* 4 bytes of zero */ |
| |
| /* Address = 0x900000 */ |
| int2le(0x900000, &outbuf[0xC]); |
| /* Size */ |
| int2le(length, &outbuf[0x10]); |
| /* Checksum */ |
| int2le(sum, &outbuf[0x14]); |
| outbuf[0x16] = 0; |
| outbuf[0x17] = 0; |
| /* Data starts here... */ |
| memcpy(&outbuf[0x18], inbuf, length); |
| |
| /* Second block starts here ... */ |
| /* Address = 0x0 */ |
| /* Size */ |
| int2le(0x4, &outbuf[0x18+length+0x4]); |
| /* Checksum */ |
| outbuf[0x18+length+0x8] = 0xA9; |
| outbuf[0x18+length+0x9] = 0xD9; |
| /* Data: MOV PC, 0x900000 */ |
| outbuf[0x18+length+0xC] = 0x09; |
| outbuf[0x18+length+0xD] = 0xF6; |
| outbuf[0x18+length+0xE] = 0xA0; |
| outbuf[0x18+length+0xF] = 0xE3; |
| |
| return length+0x18+0x10; |
| } |
| |
| int zvm_encode(char *iname, char *oname, int device) |
| { |
| size_t len; |
| int length; |
| FILE *file; |
| unsigned char *outbuf; |
| unsigned char *buf; |
| |
| file = fopen(iname, "rb"); |
| if (!file) { |
| perror(iname); |
| return -1; |
| } |
| fseek(file, 0, SEEK_END); |
| length = ftell(file); |
| |
| fseek(file, 0, SEEK_SET); |
| |
| buf = (unsigned char*)malloc(length); |
| if ( !buf ) { |
| printf("out of memory!\n"); |
| return -1; |
| } |
| |
| len = fread(buf, 1, length, file); |
| if(len < (size_t)length) { |
| perror(iname); |
| return -2; |
| } |
| fclose(file); |
| |
| outbuf = (unsigned char*)malloc(length+0x300); |
| if ( !outbuf ) { |
| free(buf); |
| printf("out of memory!\n"); |
| return -1; |
| } |
| length = make_jrm_file(buf, len, outbuf); |
| free(buf); |
| buf = (unsigned char*)malloc(length+0x200); |
| memset(buf, 0, length+0x200); |
| length = make_ciff_file(outbuf, length, buf, device); |
| free(outbuf); |
| |
| file = fopen(oname, "wb"); |
| if (!file) { |
| free(buf); |
| perror(oname); |
| return -3; |
| } |
| |
| len = fwrite(buf, 1, length, file); |
| if(len < (size_t)length) { |
| free(buf); |
| perror(oname); |
| return -4; |
| } |
| |
| free(buf); |
| |
| fclose(file); |
| |
| return 0; |
| } |