1 /***************************************************************************
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
10 * Copyright (C) 2011 Amaury Pouly
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation; either version 2
15 * of the License, or (at your option) any later version.
17 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
18 * KIND, either express or implied.
20 ****************************************************************************/
22 #define _ISOC99_SOURCE
24 #include <sys/types.h>
41 #define bug(...) do { fprintf(stderr,"ERROR: "__VA_ARGS__); exit(1); } while(0)
42 #define bugp(a) do { perror("ERROR: "a); exit(1); } while(0)
46 #define ROUND_UP(val, round) ((((val) + (round) - 1) / (round)) * (round))
52 char *s_getenv(const char *name
)
54 char *s
= getenv(name
);
58 void generate_random_data(void *buf
, size_t sz
)
60 static int rand_fd
= -1;
62 rand_fd
= open("/dev/urandom", O_RDONLY
);
64 bugp("failed to open /dev/urandom");
65 if(read(rand_fd
, buf
, sz
) != (ssize_t
)sz
)
66 bugp("failed to read /dev/urandom");
69 void *xmalloc(size_t s
) /* malloc helper, used in elf.c */
72 if(!r
) bugp("malloc");
76 static int convxdigit(char digit
, byte
*val
)
78 if(digit
>= '0' && digit
<= '9')
83 else if(digit
>= 'A' && digit
<= 'F')
85 *val
= digit
- 'A' + 10;
88 else if(digit
>= 'a' && digit
<= 'f')
90 *val
= digit
- 'a' + 10;
101 typedef byte (*key_array_t
)[16];
104 key_array_t g_key_array
;
106 static key_array_t
read_keys(const char *key_file
, int *num_keys
)
110 int fd
= open(key_file
,O_RDONLY
);
112 bugp("opening key file failed");
113 if(fstat(fd
,&st
) == -1)
114 bugp("key file stat() failed");
116 char *buf
= xmalloc(size
);
117 if(read(fd
, buf
, size
) != (ssize_t
)size
)
118 bugp("reading key file");
122 printf("Parsing key file '%s'...\n", key_file
);
123 *num_keys
= size
? 1 : 0;
125 /* allow trailing newline at the end (but no space after it) */
126 while(ptr
!= buf
+ size
&& (ptr
+ 1) != buf
+ size
)
132 key_array_t keys
= xmalloc(sizeof(byte
[16]) * *num_keys
);
134 for(int i
= 0; i
< *num_keys
; i
++)
137 while(pos
< size
&& isspace(buf
[pos
]))
140 if((pos
+ 32) > size
)
141 bugp("invalid key file");
142 for(int j
= 0; j
< 16; j
++)
145 if(convxdigit(buf
[pos
+ 2 * j
], &a
) || convxdigit(buf
[pos
+ 2 * j
+ 1], &b
))
146 bugp(" invalid key, it should be a 128-bit key written in hexadecimal\n");
147 keys
[i
][j
] = (a
<< 4) | b
;
152 for(int j
= 0; j
< 16; j
++)
153 printf("%02x", keys
[i
][j
]);
164 * Command file parsing
171 struct cmd_source_t
*next
;
174 struct elf_params_t elf
;
186 enum cmd_inst_type_t type
;
188 struct cmd_inst_t
*next
;
194 struct cmd_inst_t
*inst_list
;
195 struct cmd_section_t
*next
;
200 struct cmd_source_t
*source_list
;
201 struct cmd_section_t
*section_list
;
210 LEX_STRING
, /* double-quoted string */
220 enum lexem_type_t type
;
225 static void __parse_string(char **ptr
, char *end
, void *user
, void (*emit_fn
)(void *user
, char c
))
231 else if(**ptr
== '\\')
235 bug("Unfinished string");
236 if(**ptr
== '\\') emit_fn(user
, '\\');
237 else if(**ptr
== '\'') emit_fn(user
, '\'');
238 else if(**ptr
== '\"') emit_fn(user
, '\"');
239 else bug("Unknown escape sequence \\%c", **ptr
);
243 emit_fn(user
, *(*ptr
)++);
245 if(*ptr
== end
|| **ptr
!= '"')
246 bug("unfinished string");
250 static void __parse_string_emit(void *user
, char c
)
252 char **pstr
= (char **)user
;
256 static void __parse_string_count(void *user
, char c
)
262 static void parse_string(char **ptr
, char *end
, struct lexem_t
*lexem
)
269 __parse_string(&p
, end
, (void *)&length
, __parse_string_count
);
271 lexem
->type
= LEX_STRING
;
272 lexem
->str
= xmalloc(length
+ 1);
273 lexem
->str
[length
] = 0;
274 char *pstr
= lexem
->str
;
275 __parse_string(ptr
, end
, (void *)&pstr
, __parse_string_emit
);
278 static void parse_number(char **ptr
, char *end
, struct lexem_t
*lexem
)
281 if(**ptr
== '0' && (*ptr
) + 1 != end
&& (*ptr
)[1] == 'x')
287 lexem
->type
= LEX_NUMBER
;
289 while(*ptr
!= end
&& isxdigit(**ptr
))
291 if(base
== 10 && !isdigit(**ptr
))
294 if(convxdigit(**ptr
, &v
))
296 lexem
->num
= base
* lexem
->num
+ v
;
301 static void parse_identifier(char **ptr
, char *end
, struct lexem_t
*lexem
)
303 /* remember position */
305 while(*ptr
!= end
&& (isalnum(**ptr
) || **ptr
== '_'))
307 lexem
->type
= LEX_IDENTIFIER
;
308 int len
= *ptr
- old
;
309 lexem
->str
= xmalloc(len
+ 1);
311 memcpy(lexem
->str
, old
, len
);
314 static void next_lexem(char **ptr
, char *end
, struct lexem_t
*lexem
)
316 #define ret_simple(t, advance) ({(*ptr) += advance; lexem->type = t; return;})
319 /* skip whitespace */
320 if(**ptr
== ' ' || **ptr
== '\t' || **ptr
== '\n' || **ptr
== '\r')
326 if(**ptr
== '/' && (*ptr
) + 1 != end
&& (*ptr
)[1] == '/')
328 while(*ptr
!= end
&& **ptr
!= '\n')
334 if(*ptr
== end
) ret_simple(LEX_EOF
, 0);
335 if(**ptr
== '(') ret_simple(LEX_LPAREN
, 1);
336 if(**ptr
== ')') ret_simple(LEX_RPAREN
, 1);
337 if(**ptr
== '{') ret_simple(LEX_LBRACE
, 1);
338 if(**ptr
== '}') ret_simple(LEX_RBRACE
, 1);
339 if(**ptr
== '=') ret_simple(LEX_EQUAL
, 1);
340 if(**ptr
== ';') ret_simple(LEX_SEMICOLON
, 1);
341 if(**ptr
== '"') return parse_string(ptr
, end
, lexem
);
342 if(isdigit(**ptr
)) return parse_number(ptr
, end
, lexem
);
343 if(isalpha(**ptr
) || **ptr
== '_') return parse_identifier(ptr
, end
, lexem
);
344 bug("Unexpected character '%c' in command file\n", **ptr
);
349 static void log_lexem(struct lexem_t
*lexem
)
353 case LEX_EOF
: printf("<eof>"); break;
354 case LEX_EQUAL
: printf("="); break;
355 case LEX_IDENTIFIER
: printf("id(%s)", lexem
->str
); break;
356 case LEX_LPAREN
: printf("("); break;
357 case LEX_RPAREN
: printf(")"); break;
358 case LEX_LBRACE
: printf("{"); break;
359 case LEX_RBRACE
: printf("}"); break;
360 case LEX_SEMICOLON
: printf(";"); break;
361 case LEX_NUMBER
: printf("num(%d)", lexem
->num
); break;
362 case LEX_STRING
: printf("str(%s)", lexem
->str
); break;
363 default: printf("<unk>");
368 static struct cmd_source_t
*find_source_by_id(struct cmd_file_t
*cmd_file
, const char *id
)
370 struct cmd_source_t
*src
= cmd_file
->source_list
;
373 if(strcmp(src
->identifier
, id
) == 0)
380 static struct cmd_file_t
*read_command_file(const char *file
)
384 int fd
= open(file
,O_RDONLY
);
386 bugp("opening command file failed");
387 if(fstat(fd
,&st
) == -1)
388 bugp("command file stat() failed");
390 char *buf
= xmalloc(size
);
391 if(read(fd
, buf
, size
) != (ssize_t
)size
)
392 bugp("reading command file");
396 printf("Parsing command file '%s'...\n", file
);
397 struct cmd_file_t
*cmd_file
= xmalloc(sizeof(struct cmd_file_t
));
398 memset(cmd_file
, 0, sizeof(struct cmd_file_t
));
400 struct lexem_t lexem
;
402 char *end
= buf
+ size
;
403 #define next() next_lexem(&p, end, &lexem)
406 if(lexem
.type
!= LEX_IDENTIFIER
|| strcmp(lexem
.str
, "sources") != 0)
407 bug("invalid command file: 'sources' expected");
409 if(lexem
.type
!= LEX_LBRACE
)
410 bug("invalid command file: '{' expected after 'sources'");
415 if(lexem
.type
== LEX_RBRACE
)
417 struct cmd_source_t
*src
= xmalloc(sizeof(struct cmd_source_t
));
418 memset(src
, 0, sizeof(struct cmd_source_t
));
419 src
->next
= cmd_file
->source_list
;
420 if(lexem
.type
!= LEX_IDENTIFIER
)
421 bug("invalid command file: identifier expected in sources");
422 src
->identifier
= lexem
.str
;
424 if(lexem
.type
!= LEX_EQUAL
)
425 bug("invalid command file: '=' expected after identifier");
427 if(lexem
.type
!= LEX_STRING
)
428 bug("invalid command file: string expected after '='");
429 src
->filename
= lexem
.str
;
431 if(lexem
.type
!= LEX_SEMICOLON
)
432 bug("invalid command file: ';' expected after string");
433 if(find_source_by_id(cmd_file
, src
->identifier
) != NULL
)
434 bug("invalid command file: duplicated source identifier");
435 cmd_file
->source_list
= src
;
439 struct cmd_section_t
*end_sec
= NULL
;
442 struct cmd_section_t
*sec
= xmalloc(sizeof(struct cmd_section_t
));
443 struct cmd_inst_t
*end_list
= NULL
;
444 memset(sec
, 0, sizeof(struct cmd_section_t
));
446 if(lexem
.type
== LEX_EOF
)
448 if(lexem
.type
!= LEX_IDENTIFIER
|| strcmp(lexem
.str
, "section") != 0)
449 bug("invalid command file: 'section' expected");
451 if(lexem
.type
!= LEX_LPAREN
)
452 bug("invalid command file: '(' expected after 'section'");
454 if(lexem
.type
!= LEX_NUMBER
)
455 bug("invalid command file: number expected as section identifier");
456 sec
->identifier
= lexem
.num
;
458 if(lexem
.type
!= LEX_RPAREN
)
459 bug("invalid command file: ')' expected after section identifier");
461 if(lexem
.type
!= LEX_LBRACE
)
462 bug("invalid command file: '{' expected after section directive");
466 struct cmd_inst_t
*inst
= xmalloc(sizeof(struct cmd_inst_t
));
467 memset(inst
, 0, sizeof(struct cmd_inst_t
));
469 if(lexem
.type
== LEX_RBRACE
)
471 if(lexem
.type
!= LEX_IDENTIFIER
)
472 bug("invalid command file: instruction expected in section");
473 if(strcmp(lexem
.str
, "load") == 0)
474 inst
->type
= CMD_LOAD
;
475 else if(strcmp(lexem
.str
, "call") == 0)
476 inst
->type
= CMD_CALL
;
477 else if(strcmp(lexem
.str
, "jump") == 0)
478 inst
->type
= CMD_JUMP
;
480 bug("invalid command file: instruction expected in section");
482 if(lexem
.type
!= LEX_IDENTIFIER
)
483 bug("invalid command file: identifier expected after instruction");
484 inst
->identifier
= lexem
.str
;
485 if(find_source_by_id(cmd_file
, inst
->identifier
) == NULL
)
486 bug("invalid command file: undefined reference to source '%s'", inst
->identifier
);
488 if(lexem
.type
!= LEX_SEMICOLON
)
489 bug("invalid command file: expected ';' after command");
493 sec
->inst_list
= inst
;
498 end_list
->next
= inst
;
505 cmd_file
->section_list
= sec
;
520 * command file to sb conversion
525 uint8_t inst
; /* SB_INST_* */
532 /* for production use */
533 uint32_t padding_size
;
541 struct sb_inst_t
*insts
;
542 /* for production use */
543 uint32_t file_offset
; /* in blocks */
544 uint32_t sec_size
; /* in blocks */
550 struct sb_section_t
*sections
;
551 /* for production use */
552 uint32_t image_size
; /* in blocks */
555 static bool elf_read(void *user
, uint32_t addr
, void *buf
, size_t count
)
557 if(lseek(*(int *)user
, addr
, SEEK_SET
) == (off_t
)-1)
559 return read(*(int *)user
, buf
, count
) == (ssize_t
)count
;
562 static void elf_printf(void *user
, bool error
, const char *fmt
, ...)
564 if(!g_debug
&& !error
)
573 static void load_elf_by_id(struct cmd_file_t
*cmd_file
, const char *id
)
575 struct cmd_source_t
*src
= find_source_by_id(cmd_file
, id
);
577 bug("undefined reference to source '%s'\n", id
);
578 /* avoid reloading */
581 int fd
= open(src
->filename
, O_RDONLY
);
583 bug("cannot open '%s' (id '%s')\n", src
->filename
, id
);
585 printf("Loading ELF file '%s'...\n", src
->filename
);
587 src
->elf_loaded
= elf_read_file(&src
->elf
, elf_read
, elf_printf
, &fd
);
590 bug("error loading elf file '%s' (id '%s')\n", src
->filename
, id
);
593 static struct sb_file_t
*apply_cmd_file(struct cmd_file_t
*cmd_file
)
595 struct sb_file_t
*sb
= xmalloc(sizeof(struct sb_file_t
));
596 memset(sb
, 0, sizeof(struct sb_file_t
));
599 printf("Applying command file...\n");
601 struct cmd_section_t
*csec
= cmd_file
->section_list
;
608 sb
->sections
= xmalloc(sb
->nr_sections
* sizeof(struct sb_section_t
));
609 memset(sb
->sections
, 0, sb
->nr_sections
* sizeof(struct sb_section_t
));
610 /* flatten sections */
611 csec
= cmd_file
->section_list
;
612 for(int i
= 0; i
< sb
->nr_sections
; i
++, csec
= csec
->next
)
614 struct sb_section_t
*sec
= &sb
->sections
[i
];
615 sec
->identifier
= csec
->identifier
;
616 /* count instructions */
617 struct cmd_inst_t
*cinst
= csec
->inst_list
;
620 load_elf_by_id(cmd_file
, cinst
->identifier
);
621 struct elf_params_t
*elf
= &find_source_by_id(cmd_file
, cinst
->identifier
)->elf
;
623 if(cinst
->type
== CMD_LOAD
)
624 sec
->nr_insts
+= elf_get_nr_sections(elf
);
625 else if(cinst
->type
== CMD_JUMP
|| cinst
->type
== CMD_CALL
)
627 if(!elf_get_start_addr(elf
, NULL
))
628 bug("cannot jump/call '%s' because it has no starting point !\n", cinst
->identifier
);
635 sec
->insts
= xmalloc(sec
->nr_insts
* sizeof(struct sb_inst_t
));
636 memset(sec
->insts
, 0, sec
->nr_insts
* sizeof(struct sb_inst_t
));
639 cinst
= csec
->inst_list
;
642 struct elf_params_t
*elf
= &find_source_by_id(cmd_file
, cinst
->identifier
)->elf
;
644 if(cinst
->type
== CMD_LOAD
)
646 struct elf_section_t
*esec
= elf
->first_section
;
649 if(esec
->type
== EST_LOAD
)
651 sec
->insts
[idx
].inst
= SB_INST_LOAD
;
652 sec
->insts
[idx
].addr
= esec
->addr
;
653 sec
->insts
[idx
].size
= esec
->size
;
654 sec
->insts
[idx
++].data
= esec
->section
;
656 else if(esec
->type
== EST_FILL
)
658 sec
->insts
[idx
].inst
= SB_INST_FILL
;
659 sec
->insts
[idx
].addr
= esec
->addr
;
660 sec
->insts
[idx
].size
= esec
->size
;
661 sec
->insts
[idx
++].pattern
= esec
->pattern
;
666 else if(cinst
->type
== CMD_JUMP
|| cinst
->type
== CMD_CALL
)
668 sec
->insts
[idx
].inst
= (cinst
->type
== CMD_JUMP
) ? SB_INST_JUMP
: SB_INST_CALL
;
669 sec
->insts
[idx
++].addr
= elf
->start_addr
;
683 static void fill_gaps(struct sb_file_t
*sb
)
685 for(int i
= 0; i
< sb
->nr_sections
; i
++)
687 struct sb_section_t
*sec
= &sb
->sections
[i
];
688 for(int j
= 0; j
< sec
->nr_insts
; j
++)
690 struct sb_inst_t
*inst
= &sec
->insts
[j
];
691 if(inst
->inst
!= SB_INST_LOAD
)
693 inst
->padding_size
= ROUND_UP(inst
->size
, BLOCK_SIZE
) - inst
->size
;
694 /* emulate elftosb2 behaviour: generate 15 bytes (that's a safe maximum) */
695 inst
->padding
= xmalloc(15);
696 generate_random_data(inst
->padding
, 15);
701 static void compute_sb_offsets(struct sb_file_t
*sb
)
705 sb
->image_size
+= sizeof(struct sb_header_t
) / BLOCK_SIZE
;
706 /* sections headers */
707 sb
->image_size
+= sb
->nr_sections
* sizeof(struct sb_section_header_t
) / BLOCK_SIZE
;
709 sb
->image_size
+= g_nr_keys
* sizeof(struct sb_key_dictionary_entry_t
) / BLOCK_SIZE
;
711 for(int i
= 0; i
< sb
->nr_sections
; i
++)
713 /* each section has a preliminary TAG command */
714 sb
->image_size
+= sizeof(struct sb_instruction_tag_t
) / BLOCK_SIZE
;
716 struct sb_section_t
*sec
= &sb
->sections
[i
];
717 sec
->file_offset
= sb
->image_size
;
718 for(int j
= 0; j
< sec
->nr_insts
; j
++)
720 struct sb_inst_t
*inst
= &sec
->insts
[j
];
721 if(inst
->inst
== SB_INST_CALL
|| inst
->inst
== SB_INST_JUMP
)
724 printf("%s | addr=0x%08x | arg=0x%08x\n",
725 inst
->inst
== SB_INST_CALL
? "CALL" : "JUMP", inst
->addr
, 0);
726 sb
->image_size
+= sizeof(struct sb_instruction_call_t
) / BLOCK_SIZE
;
727 sec
->sec_size
+= sizeof(struct sb_instruction_call_t
) / BLOCK_SIZE
;
729 else if(inst
->inst
== SB_INST_FILL
)
732 printf("FILL | addr=0x%08x | len=0x%08x | pattern=0x%08x\n",
733 inst
->addr
, inst
->size
, inst
->pattern
);
734 sb
->image_size
+= sizeof(struct sb_instruction_fill_t
) / BLOCK_SIZE
;
735 sec
->sec_size
+= sizeof(struct sb_instruction_fill_t
) / BLOCK_SIZE
;
737 else if(inst
->inst
== SB_INST_LOAD
)
740 printf("LOAD | addr=0x%08x | len=0x%08x\n", inst
->addr
, inst
->size
);
742 sb
->image_size
+= sizeof(struct sb_instruction_load_t
) / BLOCK_SIZE
;
743 sec
->sec_size
+= sizeof(struct sb_instruction_load_t
) / BLOCK_SIZE
;
744 /* data + alignment */
745 sb
->image_size
+= (inst
->size
+ inst
->padding_size
) / BLOCK_SIZE
;
746 sec
->sec_size
+= (inst
->size
+ inst
->padding_size
) / BLOCK_SIZE
;
750 /* final signature */
754 static uint64_t generate_timestamp()
756 struct tm tm_base
= {0, 0, 0, 1, 0, 100, 0, 0, 1, 0, NULL
}; /* 2000/1/1 0:00:00 */
757 time_t t
= time(NULL
) - mktime(&tm_base
);
758 return (uint64_t)t
* 1000000L;
761 void generate_version(struct sb_version_t
*ver
)
767 ver
->revision
= 0x999;
771 static void produce_sb_header(struct sb_file_t
*sb
, struct sb_header_t
*sb_hdr
)
773 struct sha_1_params_t sha_1_params
;
775 sb_hdr
->signature
[0] = 'S';
776 sb_hdr
->signature
[1] = 'T';
777 sb_hdr
->signature
[2] = 'M';
778 sb_hdr
->signature
[3] = 'P';
779 sb_hdr
->major_ver
= IMAGE_MAJOR_VERSION
;
780 sb_hdr
->minor_ver
= IMAGE_MINOR_VERSION
;
782 sb_hdr
->image_size
= sb
->image_size
;
783 sb_hdr
->header_size
= sizeof(struct sb_header_t
) / BLOCK_SIZE
;
784 sb_hdr
->first_boot_sec_id
= sb
->sections
[0].identifier
;
785 sb_hdr
->nr_keys
= g_nr_keys
;
786 sb_hdr
->nr_sections
= sb
->nr_sections
;
787 sb_hdr
->sec_hdr_size
= sizeof(struct sb_section_header_t
) / BLOCK_SIZE
;
788 sb_hdr
->key_dict_off
= sb_hdr
->header_size
+
789 sb_hdr
->sec_hdr_size
* sb_hdr
->nr_sections
;
790 sb_hdr
->first_boot_tag_off
= sb_hdr
->key_dict_off
+
791 sizeof(struct sb_key_dictionary_entry_t
) * sb_hdr
->nr_keys
/ BLOCK_SIZE
;
792 generate_random_data(sb_hdr
->rand_pad0
, sizeof(sb_hdr
->rand_pad0
));
793 generate_random_data(sb_hdr
->rand_pad1
, sizeof(sb_hdr
->rand_pad1
));
794 sb_hdr
->timestamp
= generate_timestamp();
795 generate_version(&sb_hdr
->product_ver
);
796 generate_version(&sb_hdr
->component_ver
);
797 sb_hdr
->drive_tag
= 0;
799 sha_1_init(&sha_1_params
);
800 sha_1_update(&sha_1_params
, &sb_hdr
->signature
[0],
801 sizeof(struct sb_header_t
) - sizeof(sb_hdr
->sha1_header
));
802 sha_1_finish(&sha_1_params
);
803 sha_1_output(&sha_1_params
, sb_hdr
->sha1_header
);
806 static void produce_sb_section_header(struct sb_section_t
*sec
,
807 struct sb_section_header_t
*sec_hdr
)
809 sec_hdr
->identifier
= sec
->identifier
;
810 sec_hdr
->offset
= sec
->file_offset
;
811 sec_hdr
->size
= sec
->sec_size
;
812 sec_hdr
->flags
= SECTION_BOOTABLE
;
815 static uint8_t instruction_checksum(struct sb_instruction_header_t
*hdr
)
818 byte
*ptr
= (byte
*)hdr
;
819 for(int i
= 1; i
< 16; i
++)
824 static void produce_section_tag_cmd(struct sb_section_t
*sec
,
825 struct sb_instruction_tag_t
*tag
, bool is_last
)
827 tag
->hdr
.opcode
= SB_INST_TAG
;
828 tag
->hdr
.flags
= is_last
? SB_INST_LAST_TAG
: 0;
829 tag
->identifier
= sec
->identifier
;
830 tag
->len
= sec
->sec_size
;
831 tag
->flags
= SECTION_BOOTABLE
;
832 tag
->hdr
.checksum
= instruction_checksum(&tag
->hdr
);
835 void produce_sb_instruction(struct sb_inst_t
*inst
,
836 struct sb_instruction_common_t
*cmd
)
839 cmd
->hdr
.opcode
= inst
->inst
;
840 cmd
->addr
= inst
->addr
;
841 cmd
->len
= inst
->size
;
850 cmd
->data
= inst
->pattern
;
853 cmd
->data
= crc_continue(crc(inst
->data
, inst
->size
),
854 inst
->padding
, inst
->padding_size
);
859 cmd
->hdr
.checksum
= instruction_checksum(&cmd
->hdr
);
862 static void produce_sb_file(struct sb_file_t
*sb
, const char *filename
)
864 int fd
= open(filename
, O_WRONLY
| O_TRUNC
| O_CREAT
,
865 S_IRUSR
| S_IWUSR
| S_IRGRP
| S_IROTH
);
867 bugp("cannot open output file");
870 byte (*cbc_macs
)[16] = xmalloc(16 * g_nr_keys
);
872 for(int i
= 0; i
< g_nr_keys
; i
++)
873 memset(cbc_macs
[i
], 0, 16);
876 compute_sb_offsets(sb
);
878 generate_random_data(real_key
, sizeof(real_key
));
881 struct sha_1_params_t file_sha1
;
882 sha_1_init(&file_sha1
);
883 /* produce and write header */
884 struct sb_header_t sb_hdr
;
885 produce_sb_header(sb
, &sb_hdr
);
886 sha_1_update(&file_sha1
, (byte
*)&sb_hdr
, sizeof(sb_hdr
));
887 write(fd
, &sb_hdr
, sizeof(sb_hdr
));
888 /* update CBC-MACs */
889 for(int i
= 0; i
< g_nr_keys
; i
++)
890 cbc_mac((byte
*)&sb_hdr
, NULL
, sizeof(sb_hdr
) / BLOCK_SIZE
, g_key_array
[i
],
891 cbc_macs
[i
], &cbc_macs
[i
], 1);
893 /* produce and write section headers */
894 for(int i
= 0; i
< sb_hdr
.nr_sections
; i
++)
896 struct sb_section_header_t sb_sec_hdr
;
897 produce_sb_section_header(&sb
->sections
[i
], &sb_sec_hdr
);
898 sha_1_update(&file_sha1
, (byte
*)&sb_sec_hdr
, sizeof(sb_sec_hdr
));
899 write(fd
, &sb_sec_hdr
, sizeof(sb_sec_hdr
));
900 /* update CBC-MACs */
901 for(int j
= 0; j
< g_nr_keys
; j
++)
902 cbc_mac((byte
*)&sb_sec_hdr
, NULL
, sizeof(sb_sec_hdr
) / BLOCK_SIZE
,
903 g_key_array
[j
], cbc_macs
[j
], &cbc_macs
[j
], 1);
905 /* produce key dictionary */
906 for(int i
= 0; i
< g_nr_keys
; i
++)
908 struct sb_key_dictionary_entry_t entry
;
909 memcpy(entry
.hdr_cbc_mac
, cbc_macs
[i
], 16);
910 cbc_mac(real_key
, entry
.key
, sizeof(real_key
) / BLOCK_SIZE
, g_key_array
[i
],
911 (byte
*)&sb_hdr
, NULL
, 1);
913 write(fd
, &entry
, sizeof(entry
));
914 sha_1_update(&file_sha1
, (byte
*)&entry
, sizeof(entry
));
916 /* produce sections data */
917 for(int i
= 0; i
< sb_hdr
.nr_sections
; i
++)
919 /* produce tag command */
920 struct sb_instruction_tag_t tag_cmd
;
921 produce_section_tag_cmd(&sb
->sections
[i
], &tag_cmd
, (i
+ 1) == sb_hdr
.nr_sections
);
923 cbc_mac((byte
*)&tag_cmd
, (byte
*)&tag_cmd
, sizeof(tag_cmd
) / BLOCK_SIZE
,
924 real_key
, (byte
*)&sb_hdr
, NULL
, 1);
925 sha_1_update(&file_sha1
, (byte
*)&tag_cmd
, sizeof(tag_cmd
));
926 write(fd
, &tag_cmd
, sizeof(tag_cmd
));
927 /* produce other commands */
928 byte cur_cbc_mac
[16];
929 memcpy(cur_cbc_mac
, (byte
*)&sb_hdr
, 16);
930 for(int j
= 0; j
< sb
->sections
[i
].nr_insts
; j
++)
932 struct sb_inst_t
*inst
= &sb
->sections
[i
].insts
[j
];
934 struct sb_instruction_common_t cmd
;
935 produce_sb_instruction(inst
, &cmd
);
937 cbc_mac((byte
*)&cmd
, (byte
*)&cmd
, sizeof(cmd
) / BLOCK_SIZE
,
938 real_key
, cur_cbc_mac
, &cur_cbc_mac
, 1);
939 sha_1_update(&file_sha1
, (byte
*)&cmd
, sizeof(cmd
));
940 write(fd
, &cmd
, sizeof(cmd
));
942 if(inst
->inst
== SB_INST_LOAD
)
944 uint32_t sz
= inst
->size
+ inst
->padding_size
;
945 byte
*data
= xmalloc(sz
);
946 memcpy(data
, inst
->data
, inst
->size
);
947 memcpy(data
+ inst
->size
, inst
->padding
, inst
->padding_size
);
949 cbc_mac(data
, data
, sz
/ BLOCK_SIZE
,
950 real_key
, cur_cbc_mac
, &cur_cbc_mac
, 1);
951 sha_1_update(&file_sha1
, data
, sz
);
957 /* write file SHA-1 */
959 sha_1_finish(&file_sha1
);
960 sha_1_output(&file_sha1
, final_sig
);
961 generate_random_data(final_sig
+ 20, 12);
963 cbc_mac(final_sig
, final_sig
, 2, real_key
, (byte
*)&sb_hdr
, NULL
, 1);
964 write(fd
, final_sig
, 32);
969 int main(int argc
, const char **argv
)
973 printf("Usage: %s <cmd file> <key file> <out file>\n",*argv
);
974 printf("To enable debug mode, set environement variable SB_DEBUG to YES\n");
978 if(strcasecmp(s_getenv("SB_DEBUG"), "YES") == 0)
981 g_key_array
= read_keys(argv
[2], &g_nr_keys
);
982 struct cmd_file_t
*cmd_file
= read_command_file(argv
[1]);
983 struct sb_file_t
*sb_file
= apply_cmd_file(cmd_file
);
984 produce_sb_file(sb_file
, argv
[3]);