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>
40 #define bug(...) do { fprintf(stderr,"ERROR: "__VA_ARGS__); exit(1); } while(0)
41 #define bugp(a) do { perror("ERROR: "a); exit(1); } while(0)
45 #define ROUND_UP(val, round) ((((val) + (round) - 1) / (round)) * (round))
51 void generate_random_data(void *buf
, size_t sz
)
53 static int rand_fd
= -1;
55 rand_fd
= open("/dev/urandom", O_RDONLY
);
57 bugp("failed to open /dev/urandom");
58 if(read(rand_fd
, buf
, sz
) != (ssize_t
)sz
)
59 bugp("failed to read /dev/urandom");
62 void *xmalloc(size_t s
) /* malloc helper, used in elf.c */
65 if(!r
) bugp("malloc");
69 static int convxdigit(char digit
, byte
*val
)
71 if(digit
>= '0' && digit
<= '9')
76 else if(digit
>= 'A' && digit
<= 'F')
78 *val
= digit
- 'A' + 10;
81 else if(digit
>= 'a' && digit
<= 'f')
83 *val
= digit
- 'a' + 10;
94 typedef byte (*key_array_t
)[16];
97 key_array_t g_key_array
;
99 static key_array_t
read_keys(const char *key_file
, int *num_keys
)
103 int fd
= open(key_file
,O_RDONLY
);
105 bugp("opening key file failed");
106 if(fstat(fd
,&st
) == -1)
107 bugp("key file stat() failed");
109 char *buf
= xmalloc(size
);
110 if(read(fd
, buf
, size
) != (ssize_t
)size
)
111 bugp("reading key file");
114 *num_keys
= size
? 1 : 0;
116 /* allow trailing newline at the end (but no space after it) */
117 while(ptr
!= buf
+ size
&& (ptr
+ 1) != buf
+ size
)
123 key_array_t keys
= xmalloc(sizeof(byte
[16]) * *num_keys
);
125 for(int i
= 0; i
< *num_keys
; i
++)
128 while(pos
< size
&& isspace(buf
[pos
]))
131 if((pos
+ 32) > size
)
132 bugp("invalid key file");
133 for(int j
= 0; j
< 16; j
++)
136 if(convxdigit(buf
[pos
+ 2 * j
], &a
) || convxdigit(buf
[pos
+ 2 * j
+ 1], &b
))
137 bugp(" invalid key, it should be a 128-bit key written in hexadecimal\n");
138 keys
[i
][j
] = (a
<< 4) | b
;
148 * Command file parsing
155 struct cmd_source_t
*next
;
158 struct elf_params_t elf
;
170 enum cmd_inst_type_t type
;
172 struct cmd_inst_t
*next
;
178 struct cmd_inst_t
*inst_list
;
179 struct cmd_section_t
*next
;
184 struct cmd_source_t
*source_list
;
185 struct cmd_section_t
*section_list
;
194 LEX_STRING
, /* double-quoted string */
204 enum lexem_type_t type
;
209 static void __parse_string(char **ptr
, char *end
, void *user
, void (*emit_fn
)(void *user
, char c
))
215 else if(**ptr
== '\\')
219 bug("Unfinished string");
220 if(**ptr
== '\\') emit_fn(user
, '\\');
221 else if(**ptr
== '\'') emit_fn(user
, '\'');
222 else if(**ptr
== '\"') emit_fn(user
, '\"');
223 else bug("Unknown escape sequence \\%c", **ptr
);
227 emit_fn(user
, *(*ptr
)++);
229 if(*ptr
== end
|| **ptr
!= '"')
230 bug("unfinished string");
234 static void __parse_string_emit(void *user
, char c
)
236 char **pstr
= (char **)user
;
240 static void __parse_string_count(void *user
, char c
)
246 static void parse_string(char **ptr
, char *end
, struct lexem_t
*lexem
)
253 __parse_string(&p
, end
, (void *)&length
, __parse_string_count
);
255 lexem
->type
= LEX_STRING
;
256 lexem
->str
= xmalloc(length
+ 1);
257 lexem
->str
[length
] = 0;
258 char *pstr
= lexem
->str
;
259 __parse_string(ptr
, end
, (void *)&pstr
, __parse_string_emit
);
262 static void parse_number(char **ptr
, char *end
, struct lexem_t
*lexem
)
265 if(**ptr
== '0' && (*ptr
) + 1 != end
&& (*ptr
)[1] == 'x')
271 lexem
->type
= LEX_NUMBER
;
273 while(*ptr
!= end
&& isxdigit(**ptr
))
275 if(base
== 10 && !isdigit(**ptr
))
278 if(convxdigit(**ptr
, &v
))
280 lexem
->num
= base
* lexem
->num
+ v
;
285 static void parse_identifier(char **ptr
, char *end
, struct lexem_t
*lexem
)
287 /* remember position */
289 while(*ptr
!= end
&& (isalnum(**ptr
) || **ptr
== '_'))
291 lexem
->type
= LEX_IDENTIFIER
;
292 int len
= *ptr
- old
;
293 lexem
->str
= xmalloc(len
+ 1);
295 memcpy(lexem
->str
, old
, len
);
298 static void next_lexem(char **ptr
, char *end
, struct lexem_t
*lexem
)
300 #define ret_simple(t, advance) ({(*ptr) += advance; lexem->type = t; return;})
303 /* skip whitespace */
304 if(**ptr
== ' ' || **ptr
== '\t' || **ptr
== '\n' || **ptr
== '\r')
310 if(**ptr
== '/' && (*ptr
) + 1 != end
&& (*ptr
)[1] == '/')
312 while(*ptr
!= end
&& **ptr
!= '\n')
318 if(*ptr
== end
) ret_simple(LEX_EOF
, 0);
319 if(**ptr
== '(') ret_simple(LEX_LPAREN
, 1);
320 if(**ptr
== ')') ret_simple(LEX_RPAREN
, 1);
321 if(**ptr
== '{') ret_simple(LEX_LBRACE
, 1);
322 if(**ptr
== '}') ret_simple(LEX_RBRACE
, 1);
323 if(**ptr
== '=') ret_simple(LEX_EQUAL
, 1);
324 if(**ptr
== ';') ret_simple(LEX_SEMICOLON
, 1);
325 if(**ptr
== '"') return parse_string(ptr
, end
, lexem
);
326 if(isdigit(**ptr
)) return parse_number(ptr
, end
, lexem
);
327 if(isalpha(**ptr
) || **ptr
== '_') return parse_identifier(ptr
, end
, lexem
);
328 bug("Unexpected character '%c' in command file\n", **ptr
);
333 static void log_lexem(struct lexem_t
*lexem
)
337 case LEX_EOF
: printf("<eof>"); break;
338 case LEX_EQUAL
: printf("="); break;
339 case LEX_IDENTIFIER
: printf("id(%s)", lexem
->str
); break;
340 case LEX_LPAREN
: printf("("); break;
341 case LEX_RPAREN
: printf(")"); break;
342 case LEX_LBRACE
: printf("{"); break;
343 case LEX_RBRACE
: printf("}"); break;
344 case LEX_SEMICOLON
: printf(";"); break;
345 case LEX_NUMBER
: printf("num(%d)", lexem
->num
); break;
346 case LEX_STRING
: printf("str(%s)", lexem
->str
); break;
347 default: printf("<unk>");
352 static struct cmd_source_t
*find_source_by_id(struct cmd_file_t
*cmd_file
, const char *id
)
354 struct cmd_source_t
*src
= cmd_file
->source_list
;
357 if(strcmp(src
->identifier
, id
) == 0)
364 static struct cmd_file_t
*read_command_file(const char *file
)
368 int fd
= open(file
,O_RDONLY
);
370 bugp("opening command file failed");
371 if(fstat(fd
,&st
) == -1)
372 bugp("command file stat() failed");
374 char *buf
= xmalloc(size
);
375 if(read(fd
, buf
, size
) != (ssize_t
)size
)
376 bugp("reading command file");
379 struct cmd_file_t
*cmd_file
= xmalloc(sizeof(struct cmd_file_t
));
380 memset(cmd_file
, 0, sizeof(struct cmd_file_t
));
382 struct lexem_t lexem
;
384 char *end
= buf
+ size
;
385 #define next() next_lexem(&p, end, &lexem)
388 if(lexem
.type
!= LEX_IDENTIFIER
|| strcmp(lexem
.str
, "sources") != 0)
389 bug("invalid command file: 'sources' expected");
391 if(lexem
.type
!= LEX_LBRACE
)
392 bug("invalid command file: '{' expected after 'sources'");
397 if(lexem
.type
== LEX_RBRACE
)
399 struct cmd_source_t
*src
= xmalloc(sizeof(struct cmd_source_t
));
400 src
->next
= cmd_file
->source_list
;
401 if(lexem
.type
!= LEX_IDENTIFIER
)
402 bug("invalid command file: identifier expected in sources");
403 src
->identifier
= lexem
.str
;
405 if(lexem
.type
!= LEX_EQUAL
)
406 bug("invalid command file: '=' expected after identifier");
408 if(lexem
.type
!= LEX_STRING
)
409 bug("invalid command file: string expected after '='");
410 src
->filename
= lexem
.str
;
412 if(lexem
.type
!= LEX_SEMICOLON
)
413 bug("invalid command file: ';' expected after string");
414 if(find_source_by_id(cmd_file
, src
->identifier
) != NULL
)
415 bug("invalid command file: duplicated source identifier");
416 cmd_file
->source_list
= src
;
420 struct cmd_section_t
*end_sec
= NULL
;
423 struct cmd_section_t
*sec
= xmalloc(sizeof(struct cmd_section_t
));
424 struct cmd_inst_t
*end_list
= NULL
;
425 memset(sec
, 0, sizeof(struct cmd_section_t
));
427 if(lexem
.type
== LEX_EOF
)
429 if(lexem
.type
!= LEX_IDENTIFIER
|| strcmp(lexem
.str
, "section") != 0)
430 bug("invalid command file: 'section' expected");
432 if(lexem
.type
!= LEX_LPAREN
)
433 bug("invalid command file: '(' expected after 'section'");
435 if(lexem
.type
!= LEX_NUMBER
)
436 bug("invalid command file: number expected as section identifier");
437 sec
->identifier
= lexem
.num
;
439 if(lexem
.type
!= LEX_RPAREN
)
440 bug("invalid command file: ')' expected after section identifier");
442 if(lexem
.type
!= LEX_LBRACE
)
443 bug("invalid command file: '{' expected after section directive");
447 struct cmd_inst_t
*inst
= xmalloc(sizeof(struct cmd_inst_t
));
448 memset(inst
, 0, sizeof(struct cmd_inst_t
));
450 if(lexem
.type
== LEX_RBRACE
)
452 if(lexem
.type
!= LEX_IDENTIFIER
)
453 bug("invalid command file: instruction expected in section");
454 if(strcmp(lexem
.str
, "load") == 0)
455 inst
->type
= CMD_LOAD
;
456 else if(strcmp(lexem
.str
, "call") == 0)
457 inst
->type
= CMD_CALL
;
458 else if(strcmp(lexem
.str
, "jump") == 0)
459 inst
->type
= CMD_JUMP
;
461 bug("invalid command file: instruction expected in section");
463 if(lexem
.type
!= LEX_IDENTIFIER
)
464 bug("invalid command file: identifier expected after instruction");
465 inst
->identifier
= lexem
.str
;
466 if(find_source_by_id(cmd_file
, inst
->identifier
) == NULL
)
467 bug("invalid command file: undefined reference to source '%s'", inst
->identifier
);
469 if(lexem
.type
!= LEX_SEMICOLON
)
470 bug("invalid command file: expected ';' after command");
474 sec
->inst_list
= inst
;
479 end_list
->next
= inst
;
486 cmd_file
->section_list
= sec
;
501 * command file to sb conversion
506 uint8_t inst
; /* SB_INST_* */
513 /* for production use */
514 uint32_t padding_size
;
522 struct sb_inst_t
*insts
;
523 /* for production use */
524 uint32_t file_offset
; /* in blocks */
525 uint32_t sec_size
; /* in blocks */
531 struct sb_section_t
*sections
;
532 /* for production use */
533 uint32_t image_size
; /* in blocks */
536 static bool elf_read(void *user
, uint32_t addr
, void *buf
, size_t count
)
538 if(lseek(*(int *)user
, addr
, SEEK_SET
) == (off_t
)-1)
540 return read(*(int *)user
, buf
, count
) == (ssize_t
)count
;
543 static void elf_printf(void *user
, bool error
, const char *fmt
, ...)
545 if(!g_debug
&& !error
)
554 static void load_elf_by_id(struct cmd_file_t
*cmd_file
, const char *id
)
556 struct cmd_source_t
*src
= find_source_by_id(cmd_file
, id
);
558 bug("undefined reference to source '%s'\n", id
);
559 /* avoid reloading */
562 int fd
= open(src
->filename
, O_RDONLY
);
564 bug("cannot open '%s' (id '%s')\n", src
->filename
, id
);
566 src
->elf_loaded
= elf_read_file(&src
->elf
, elf_read
, elf_printf
, &fd
);
569 bug("error loading elf file '%s' (id '%s')\n", src
->filename
, id
);
572 static struct sb_file_t
*apply_cmd_file(struct cmd_file_t
*cmd_file
)
574 struct sb_file_t
*sb
= xmalloc(sizeof(struct sb_file_t
));
575 memset(sb
, 0, sizeof(struct sb_file_t
));
577 struct cmd_section_t
*csec
= cmd_file
->section_list
;
584 sb
->sections
= xmalloc(sb
->nr_sections
* sizeof(struct sb_section_t
));
585 memset(sb
->sections
, 0, sb
->nr_sections
* sizeof(struct sb_section_t
));
586 /* flatten sections */
587 csec
= cmd_file
->section_list
;
588 for(int i
= 0; i
< sb
->nr_sections
; i
++, csec
= csec
->next
)
590 struct sb_section_t
*sec
= &sb
->sections
[i
];
591 sec
->identifier
= csec
->identifier
;
592 /* count instructions */
593 struct cmd_inst_t
*cinst
= csec
->inst_list
;
596 load_elf_by_id(cmd_file
, cinst
->identifier
);
597 struct elf_params_t
*elf
= &find_source_by_id(cmd_file
, cinst
->identifier
)->elf
;
599 if(cinst
->type
== CMD_LOAD
)
600 sec
->nr_insts
+= elf_get_nr_sections(elf
);
601 else if(cinst
->type
== CMD_JUMP
|| cinst
->type
== CMD_CALL
)
603 if(!elf_get_start_addr(elf
, NULL
))
604 bug("cannot jump/call '%s' because it has no starting point !\n", cinst
->identifier
);
611 sec
->insts
= xmalloc(sec
->nr_insts
* sizeof(struct sb_inst_t
));
612 memset(sec
->insts
, 0, sec
->nr_insts
* sizeof(struct sb_inst_t
));
615 cinst
= csec
->inst_list
;
618 struct elf_params_t
*elf
= &find_source_by_id(cmd_file
, cinst
->identifier
)->elf
;
620 if(cinst
->type
== CMD_LOAD
)
622 struct elf_section_t
*esec
= elf
->first_section
;
625 if(esec
->type
== EST_LOAD
)
627 sec
->insts
[idx
].inst
= SB_INST_LOAD
;
628 sec
->insts
[idx
].addr
= esec
->addr
;
629 sec
->insts
[idx
].size
= esec
->size
;
630 sec
->insts
[idx
++].data
= esec
->section
;
632 else if(esec
->type
== EST_FILL
)
634 sec
->insts
[idx
].inst
= SB_INST_FILL
;
635 sec
->insts
[idx
].addr
= esec
->addr
;
636 sec
->insts
[idx
].size
= esec
->size
;
637 sec
->insts
[idx
++].pattern
= esec
->pattern
;
642 else if(cinst
->type
== CMD_JUMP
|| cinst
->type
== CMD_CALL
)
644 sec
->insts
[idx
].inst
= (cinst
->type
== CMD_JUMP
) ? SB_INST_JUMP
: SB_INST_CALL
;
645 sec
->insts
[idx
++].addr
= elf
->start_addr
;
659 static void fill_gaps(struct sb_file_t
*sb
)
661 for(int i
= 0; i
< sb
->nr_sections
; i
++)
663 struct sb_section_t
*sec
= &sb
->sections
[i
];
664 for(int j
= 0; j
< sec
->nr_insts
; j
++)
666 struct sb_inst_t
*inst
= &sec
->insts
[j
];
667 if(inst
->inst
!= SB_INST_LOAD
)
669 inst
->padding_size
= ROUND_UP(inst
->size
, BLOCK_SIZE
) - inst
->size
;
670 /* emulate elftosb2 behaviour: generate 15 bytes (that's a safe maximum) */
671 inst
->padding
= xmalloc(15);
672 generate_random_data(inst
->padding
, 15);
677 static void compute_sb_offsets(struct sb_file_t
*sb
)
681 sb
->image_size
+= sizeof(struct sb_header_t
) / BLOCK_SIZE
;
682 /* sections headers */
683 sb
->image_size
+= sb
->nr_sections
* sizeof(struct sb_section_header_t
) / BLOCK_SIZE
;
685 sb
->image_size
+= g_nr_keys
* sizeof(struct sb_key_dictionary_entry_t
) / BLOCK_SIZE
;
687 for(int i
= 0; i
< sb
->nr_sections
; i
++)
689 /* each section has a preliminary TAG command */
690 sb
->image_size
+= sizeof(struct sb_instruction_tag_t
) / BLOCK_SIZE
;
692 struct sb_section_t
*sec
= &sb
->sections
[i
];
693 sec
->file_offset
= sb
->image_size
;
694 for(int j
= 0; j
< sec
->nr_insts
; j
++)
696 struct sb_inst_t
*inst
= &sec
->insts
[j
];
697 if(inst
->inst
== SB_INST_CALL
|| inst
->inst
== SB_INST_JUMP
)
700 printf("%s | addr=0x%08x | arg=0x%08x\n",
701 inst
->inst
== SB_INST_CALL
? "CALL" : "JUMP", inst
->addr
, 0);
702 sb
->image_size
+= sizeof(struct sb_instruction_call_t
) / BLOCK_SIZE
;
703 sec
->sec_size
+= sizeof(struct sb_instruction_call_t
) / BLOCK_SIZE
;
705 else if(inst
->inst
== SB_INST_FILL
)
708 printf("FILL | addr=0x%08x | len=0x%08x | pattern=0x%08x\n",
709 inst
->addr
, inst
->size
, inst
->pattern
);
710 sb
->image_size
+= sizeof(struct sb_instruction_fill_t
) / BLOCK_SIZE
;
711 sec
->sec_size
+= sizeof(struct sb_instruction_fill_t
) / BLOCK_SIZE
;
713 else if(inst
->inst
== SB_INST_LOAD
)
716 printf("LOAD | addr=0x%08x | len=0x%08x\n", inst
->addr
, inst
->size
);
718 sb
->image_size
+= sizeof(struct sb_instruction_load_t
) / BLOCK_SIZE
;
719 sec
->sec_size
+= sizeof(struct sb_instruction_load_t
) / BLOCK_SIZE
;
720 /* data + alignment */
721 sb
->image_size
+= (inst
->size
+ inst
->padding_size
) / BLOCK_SIZE
;
722 sec
->sec_size
+= (inst
->size
+ inst
->padding_size
) / BLOCK_SIZE
;
726 /* final signature */
730 static uint64_t generate_timestamp()
732 struct tm tm_base
= {0, 0, 0, 1, 0, 100, 0, 0, 1, 0, NULL
}; /* 2000/1/1 0:00:00 */
733 time_t t
= time(NULL
) - mktime(&tm_base
);
734 return (uint64_t)t
* 1000000L;
737 void generate_version(struct sb_version_t
*ver
)
743 ver
->revision
= 0x999;
747 static void produce_sb_header(struct sb_file_t
*sb
, struct sb_header_t
*sb_hdr
)
749 struct sha_1_params_t sha_1_params
;
751 sb_hdr
->signature
[0] = 'S';
752 sb_hdr
->signature
[1] = 'T';
753 sb_hdr
->signature
[2] = 'M';
754 sb_hdr
->signature
[3] = 'P';
755 sb_hdr
->major_ver
= IMAGE_MAJOR_VERSION
;
756 sb_hdr
->minor_ver
= IMAGE_MINOR_VERSION
;
758 sb_hdr
->image_size
= sb
->image_size
;
759 sb_hdr
->header_size
= sizeof(struct sb_header_t
) / BLOCK_SIZE
;
760 sb_hdr
->first_boot_sec_id
= sb
->sections
[0].identifier
;
761 sb_hdr
->nr_keys
= g_nr_keys
;
762 sb_hdr
->nr_sections
= sb
->nr_sections
;
763 sb_hdr
->sec_hdr_size
= sizeof(struct sb_section_header_t
) / BLOCK_SIZE
;
764 sb_hdr
->key_dict_off
= sb_hdr
->header_size
+
765 sb_hdr
->sec_hdr_size
* sb_hdr
->nr_sections
;
766 sb_hdr
->first_boot_tag_off
= sb_hdr
->key_dict_off
+
767 sizeof(struct sb_key_dictionary_entry_t
) * sb_hdr
->nr_keys
/ BLOCK_SIZE
;
768 generate_random_data(sb_hdr
->rand_pad0
, sizeof(sb_hdr
->rand_pad0
));
769 generate_random_data(sb_hdr
->rand_pad1
, sizeof(sb_hdr
->rand_pad1
));
770 sb_hdr
->timestamp
= generate_timestamp();
771 generate_version(&sb_hdr
->product_ver
);
772 generate_version(&sb_hdr
->component_ver
);
773 sb_hdr
->drive_tag
= 0;
775 sha_1_init(&sha_1_params
);
776 sha_1_update(&sha_1_params
, &sb_hdr
->signature
[0],
777 sizeof(struct sb_header_t
) - sizeof(sb_hdr
->sha1_header
));
778 sha_1_finish(&sha_1_params
);
779 sha_1_output(&sha_1_params
, sb_hdr
->sha1_header
);
782 static void produce_sb_section_header(struct sb_section_t
*sec
,
783 struct sb_section_header_t
*sec_hdr
)
785 sec_hdr
->identifier
= sec
->identifier
;
786 sec_hdr
->offset
= sec
->file_offset
;
787 sec_hdr
->size
= sec
->sec_size
;
788 sec_hdr
->flags
= SECTION_BOOTABLE
;
791 static uint8_t instruction_checksum(struct sb_instruction_header_t
*hdr
)
794 byte
*ptr
= (byte
*)hdr
;
795 for(int i
= 1; i
< 16; i
++)
800 static void produce_section_tag_cmd(struct sb_section_t
*sec
,
801 struct sb_instruction_tag_t
*tag
, bool is_last
)
803 tag
->hdr
.opcode
= SB_INST_TAG
;
804 tag
->hdr
.flags
= is_last
? SB_INST_LAST_TAG
: 0;
805 tag
->identifier
= sec
->identifier
;
806 tag
->len
= sec
->sec_size
;
807 tag
->flags
= SECTION_BOOTABLE
;
808 tag
->hdr
.checksum
= instruction_checksum(&tag
->hdr
);
811 void produce_sb_instruction(struct sb_inst_t
*inst
,
812 struct sb_instruction_common_t
*cmd
)
815 cmd
->hdr
.opcode
= inst
->inst
;
816 cmd
->addr
= inst
->addr
;
817 cmd
->len
= inst
->size
;
826 cmd
->data
= inst
->pattern
;
829 cmd
->data
= crc_continue(crc(inst
->data
, inst
->size
),
830 inst
->padding
, inst
->padding_size
);
835 cmd
->hdr
.checksum
= instruction_checksum(&cmd
->hdr
);
838 static void produce_sb_file(struct sb_file_t
*sb
, const char *filename
)
840 int fd
= open(filename
, O_WRONLY
| O_TRUNC
| O_CREAT
,
841 S_IRUSR
| S_IWUSR
| S_IRGRP
| S_IROTH
);
843 bugp("cannot open output file");
846 byte (*cbc_macs
)[16] = xmalloc(16 * g_nr_keys
);
848 for(int i
= 0; i
< g_nr_keys
; i
++)
849 memset(cbc_macs
[i
], 0, 16);
852 compute_sb_offsets(sb
);
854 generate_random_data(real_key
, sizeof(real_key
));
857 struct sha_1_params_t file_sha1
;
858 sha_1_init(&file_sha1
);
859 /* produce and write header */
860 struct sb_header_t sb_hdr
;
861 produce_sb_header(sb
, &sb_hdr
);
862 sha_1_update(&file_sha1
, (byte
*)&sb_hdr
, sizeof(sb_hdr
));
863 write(fd
, &sb_hdr
, sizeof(sb_hdr
));
864 /* update CBC-MACs */
865 for(int i
= 0; i
< g_nr_keys
; i
++)
866 cbc_mac((byte
*)&sb_hdr
, NULL
, sizeof(sb_hdr
) / BLOCK_SIZE
, g_key_array
[i
],
867 cbc_macs
[i
], &cbc_macs
[i
], 1);
869 /* produce and write section headers */
870 for(int i
= 0; i
< sb_hdr
.nr_sections
; i
++)
872 struct sb_section_header_t sb_sec_hdr
;
873 produce_sb_section_header(&sb
->sections
[i
], &sb_sec_hdr
);
874 sha_1_update(&file_sha1
, (byte
*)&sb_sec_hdr
, sizeof(sb_sec_hdr
));
875 write(fd
, &sb_sec_hdr
, sizeof(sb_sec_hdr
));
876 /* update CBC-MACs */
877 for(int j
= 0; j
< g_nr_keys
; j
++)
878 cbc_mac((byte
*)&sb_sec_hdr
, NULL
, sizeof(sb_sec_hdr
) / BLOCK_SIZE
,
879 g_key_array
[j
], cbc_macs
[j
], &cbc_macs
[j
], 1);
881 /* produce key dictionary */
882 for(int i
= 0; i
< g_nr_keys
; i
++)
884 struct sb_key_dictionary_entry_t entry
;
885 memcpy(entry
.hdr_cbc_mac
, cbc_macs
[i
], 16);
886 cbc_mac(real_key
, entry
.key
, sizeof(real_key
) / BLOCK_SIZE
, g_key_array
[i
],
887 (byte
*)&sb_hdr
, NULL
, 1);
889 write(fd
, &entry
, sizeof(entry
));
890 sha_1_update(&file_sha1
, (byte
*)&entry
, sizeof(entry
));
892 /* produce sections data */
893 for(int i
= 0; i
< sb_hdr
.nr_sections
; i
++)
895 /* produce tag command */
896 struct sb_instruction_tag_t tag_cmd
;
897 produce_section_tag_cmd(&sb
->sections
[i
], &tag_cmd
, (i
+ 1) == sb_hdr
.nr_sections
);
899 cbc_mac((byte
*)&tag_cmd
, (byte
*)&tag_cmd
, sizeof(tag_cmd
) / BLOCK_SIZE
,
900 real_key
, (byte
*)&sb_hdr
, NULL
, 1);
901 sha_1_update(&file_sha1
, (byte
*)&tag_cmd
, sizeof(tag_cmd
));
902 write(fd
, &tag_cmd
, sizeof(tag_cmd
));
903 /* produce other commands */
904 byte cur_cbc_mac
[16];
905 memcpy(cur_cbc_mac
, (byte
*)&sb_hdr
, 16);
906 for(int j
= 0; j
< sb
->sections
[i
].nr_insts
; j
++)
908 struct sb_inst_t
*inst
= &sb
->sections
[i
].insts
[j
];
910 struct sb_instruction_common_t cmd
;
911 produce_sb_instruction(inst
, &cmd
);
913 cbc_mac((byte
*)&cmd
, (byte
*)&cmd
, sizeof(cmd
) / BLOCK_SIZE
,
914 real_key
, cur_cbc_mac
, &cur_cbc_mac
, 1);
915 sha_1_update(&file_sha1
, (byte
*)&cmd
, sizeof(cmd
));
916 write(fd
, &cmd
, sizeof(cmd
));
918 if(inst
->inst
== SB_INST_LOAD
)
920 uint32_t sz
= inst
->size
+ inst
->padding_size
;
921 byte
*data
= xmalloc(sz
);
922 memcpy(data
, inst
->data
, inst
->size
);
923 memcpy(data
+ inst
->size
, inst
->padding
, inst
->padding_size
);
925 cbc_mac(data
, data
, sz
/ BLOCK_SIZE
,
926 real_key
, cur_cbc_mac
, &cur_cbc_mac
, 1);
927 sha_1_update(&file_sha1
, data
, sz
);
933 /* write file SHA-1 */
935 sha_1_finish(&file_sha1
);
936 sha_1_output(&file_sha1
, final_sig
);
937 generate_random_data(final_sig
+ 20, 12);
939 cbc_mac(final_sig
, final_sig
, 2, real_key
, (byte
*)&sb_hdr
, NULL
, 1);
940 write(fd
, final_sig
, 32);
945 int main(int argc
, const char **argv
)
949 printf("Usage: %s <cmd file> <key file> <out file>\n",*argv
);
950 printf("To enable debug mode, set environement variable SB_DEBUG to YES\n");
954 if(getenv("SB_DEBUG") != NULL
&& strcmp(getenv("SB_DEBUG"), "YES") == 0)
957 g_key_array
= read_keys(argv
[2], &g_nr_keys
);
958 struct cmd_file_t
*cmd_file
= read_command_file(argv
[1]);
959 struct sb_file_t
*sb_file
= apply_cmd_file(cmd_file
);
960 produce_sb_file(sb_file
, argv
[3]);