check in rabbitsign/tilem
This commit is contained in:
parent
f10dd4afce
commit
850b4987cc
2
.gitignore
vendored
2
.gitignore
vendored
|
|
@ -6,3 +6,5 @@ main.8xk
|
|||
main.bin
|
||||
|
||||
ti83pv116.sav
|
||||
|
||||
tool/rabbitsign
|
||||
|
|
|
|||
24
Makefile
24
Makefile
|
|
@ -1,15 +1,19 @@
|
|||
|
||||
CC=sdcc
|
||||
CFLAGS=-Ilib83 -c -mz80 --std-sdcc2x --no-std-crt0 --reserve-regs-iy --opt-code-size
|
||||
SDCC=sdcc
|
||||
SDCCFLAGS=-Ilib83 -c -mz80 --std-sdcc2x --no-std-crt0 --reserve-regs-iy --opt-code-size
|
||||
|
||||
OBJS=_crt0.rel clrscr.rel putchar.rel puts.rel exit.rel gotoxy.rel __assert_fail.rel \
|
||||
getchar.rel put_int.rel ctype.rel memcpy.rel memset.rel memmove.rel memcmp.rel \
|
||||
strcpy.rel strlen.rel strncpy.rel \
|
||||
main.rel
|
||||
|
||||
.PHONY: all clean try
|
||||
.PHONY: all clean try init
|
||||
all: main.8xk
|
||||
|
||||
init:
|
||||
@echo "Compiling rabbitsign..."
|
||||
@$(CC) tool/rabbitsign-src/*.c -o tool/rabbitsign -O2 -g -w -DPROTOTYPES
|
||||
|
||||
clean:
|
||||
@rm -f obj/* main.ihx main.bin main.8xk
|
||||
|
||||
|
|
@ -17,16 +21,16 @@ try: main.8xk
|
|||
@tilem2 --rom=ti83pv116.bin
|
||||
|
||||
%.rel: lib83/%.c
|
||||
@echo "(lib) CC $<"
|
||||
@$(CC) $(CFLAGS) $< -o obj/$@
|
||||
@echo "(lib) SDCC $<"
|
||||
@$(SDCC) $(SDCCFLAGS) $< -o obj/$@
|
||||
|
||||
%.rel: %.c
|
||||
@echo "CC $<"
|
||||
@$(CC) $(CFLAGS) $< -o obj/$@
|
||||
@echo "SDCC $<"
|
||||
@$(SDCC) $(SDCCFLAGS) $< -o obj/$@
|
||||
|
||||
obj/main.ihx: $(OBJS)
|
||||
@echo "LD $@"
|
||||
@cd obj && $(CC) -mz80 --no-std-crt0 --code-loc 0x4000 --code-size 0x4000 --xram-loc 0x9D95 --xram-size 0x6060 $^ -o ../$@ && cd ..
|
||||
@echo "SDCCLD $@"
|
||||
@cd obj && $(SDCC) -mz80 --no-std-crt0 --code-loc 0x4000 --code-size 0x4000 --xram-loc 0x9D95 --xram-size 0x6060 $^ -o ../$@ && cd ..
|
||||
|
||||
main.bin: obj/main.ihx
|
||||
@echo "IHX->BIN $@"
|
||||
|
|
@ -35,5 +39,5 @@ main.bin: obj/main.ihx
|
|||
|
||||
main.8xk: main.bin
|
||||
@echo "SIGN $@"
|
||||
@rabbitsign -P -p -t 8xk -g $<
|
||||
@tool/rabbitsign -P -p -t 8xk -g $<
|
||||
|
||||
|
|
|
|||
22
README.md
22
README.md
|
|
@ -4,11 +4,25 @@ A C programming SDK for the TI-83 calculator. Includes pre-configured build syst
|
|||
|
||||
## Requirements
|
||||
|
||||
- SDCC
|
||||
- GNU Make
|
||||
- TilEm
|
||||
- RabbitSign
|
||||
- A GNU/Linux system.
|
||||
|
||||
## Status
|
||||
|
||||
WIP.
|
||||
|
||||
## Usage
|
||||
|
||||
Initialise the build environment:
|
||||
|
||||
```bash
|
||||
git clone https://git.palaiologos.rocks/Palaiologos/ti83-sdk
|
||||
cd ti83-sdk
|
||||
make init
|
||||
make
|
||||
```
|
||||
|
||||
Run the pre-supplied program:
|
||||
|
||||
```bash
|
||||
make try
|
||||
```
|
||||
|
|
|
|||
445
tool/rabbitsign-src/app8x.c
Normal file
445
tool/rabbitsign-src/app8x.c
Normal file
|
|
@ -0,0 +1,445 @@
|
|||
/*
|
||||
* RabbitSign - Tools for signing TI graphing calculator software
|
||||
* Copyright (C) 2009 Benjamin Moody
|
||||
*
|
||||
* This program 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.
|
||||
*
|
||||
* This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
# include <config.h>
|
||||
#endif
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#include "rabbitsign.h"
|
||||
#include "internal.h"
|
||||
#include "md5.h"
|
||||
|
||||
/*
|
||||
* Check/fix Flash app header and data.
|
||||
*
|
||||
* This function checks various parts of the application header which,
|
||||
* if incorrect, are known to cause applications to be rejected by the
|
||||
* calculator. Depending on the flags, this function will also fix
|
||||
* incorrect header fields.
|
||||
*
|
||||
* Note that this function can also add padding to the end of the app.
|
||||
* The entire signature must be stored on one page, so if there is not
|
||||
* enough room on the final page of the app, an extra page needs to be
|
||||
* added to hold the signature.
|
||||
*
|
||||
* In addition, some versions of the boot code have a bug which
|
||||
* results in incorrect MD5 hashes for applications that are 55 bytes
|
||||
* long mod 64; this function will add an extra padding byte to avoid
|
||||
* that case.
|
||||
*/
|
||||
int rs_repair_ti8x_app(RSProgram* app, /* app to repair */
|
||||
unsigned int flags) /* flags */
|
||||
{
|
||||
unsigned long length, hdrstart, hdrsize, fieldstart, fieldsize, i;
|
||||
unsigned char* hdr;
|
||||
unsigned char dummy = 0;
|
||||
int e, pagecount, addedpage = 0;
|
||||
|
||||
/* Various parts of the OS, as well as other software on the
|
||||
calculator and PC, expect that every application begins with the
|
||||
bytes 80 0F -- a "long" field. Some things may work for apps
|
||||
with an 80 0E (or even 80 0D) field, but not everything. Please
|
||||
stick with 80 0F. */
|
||||
|
||||
if (app->length < 6
|
||||
|| app->data[0] != 0x80
|
||||
|| app->data[1] != 0x0f) {
|
||||
rs_error(NULL, app, "no app header found");
|
||||
return RS_ERR_MISSING_HEADER;
|
||||
}
|
||||
|
||||
/* Determine application length */
|
||||
|
||||
length = app->length;
|
||||
rs_get_field_size(app->data, &hdrstart, &hdrsize);
|
||||
|
||||
/* If requested, remove the old signature (truncate the application
|
||||
to its stated length.) */
|
||||
|
||||
if (flags & RS_REMOVE_OLD_SIGNATURE) {
|
||||
if (length < hdrstart + hdrsize) {
|
||||
rs_warning(NULL, app, "provided app data too short");
|
||||
}
|
||||
else {
|
||||
if (length > hdrstart + hdrsize + 96)
|
||||
rs_warning(NULL, app, "re-signing discards %lu bytes",
|
||||
length - hdrstart - hdrsize);
|
||||
length = hdrstart + hdrsize;
|
||||
}
|
||||
}
|
||||
else if (hdrsize && hdrstart + hdrsize != length) {
|
||||
rs_warning(NULL, app, "application length incorrect");
|
||||
rs_warning(NULL, app, "(perhaps you meant to use -r?)");
|
||||
}
|
||||
|
||||
/* If necessary, add an extra page to ensure that the signature
|
||||
doesn't span a page boundary. */
|
||||
|
||||
if (((length + 69 + 0x3fff) >> 14) != ((length + 0x3fff) >> 14)) {
|
||||
if (flags & (RS_ZEALOUSLY_PAD_APP | RS_IGNORE_ALL_WARNINGS)) {
|
||||
rs_warning(NULL, app, "adding an extra page to hold app signature");
|
||||
length = ((length + 0x4000) & ~0x3fff) + 1;
|
||||
addedpage = 1;
|
||||
}
|
||||
else {
|
||||
rs_error(NULL, app, "application ends too close to a page boundary");
|
||||
return RS_ERR_FINAL_PAGE_TOO_LONG;
|
||||
}
|
||||
}
|
||||
|
||||
if ((e = rs_program_set_length(app, length)))
|
||||
return e;
|
||||
|
||||
/* If the length is 55 mod 64, add an extra byte. (Note that, with
|
||||
512-bit keys, this can never cause a page overflow.) We use zero
|
||||
for the padding value, rather than FF, so that our output matches
|
||||
that of other tools. */
|
||||
|
||||
if ((length % 64) == 55) {
|
||||
length++;
|
||||
rs_message(2, NULL, app, "adding an extra byte due to boot code bugs");
|
||||
if ((e = rs_program_append_data(app, &dummy, 1)))
|
||||
return e;
|
||||
}
|
||||
|
||||
/* Set app size header to the correct value */
|
||||
|
||||
hdrsize = length - hdrstart;
|
||||
if (rs_set_field_size(app->data, hdrsize)) {
|
||||
if (flags & RS_IGNORE_ALL_WARNINGS)
|
||||
rs_warning(NULL, app, "application length header too small");
|
||||
else {
|
||||
rs_error(NULL, app, "application length header too small");
|
||||
return RS_ERR_FIELD_TOO_SMALL;
|
||||
}
|
||||
}
|
||||
|
||||
/* Check/fix page count. This field is required to be present and
|
||||
contain the correct number of pages. It must be one byte long
|
||||
(some parts of the OS don't even check the length and assume it
|
||||
is one byte long.) */
|
||||
|
||||
hdr = app->data + hdrstart;
|
||||
if (hdrsize > 128)
|
||||
hdrsize = 128;
|
||||
|
||||
if (rs_find_app_field(0x8080, hdr, hdrsize,
|
||||
NULL, &fieldstart, &fieldsize)) {
|
||||
if (flags & RS_IGNORE_ALL_WARNINGS)
|
||||
rs_warning(NULL, app, "application has no page count field");
|
||||
else {
|
||||
rs_error(NULL, app, "application has no page count field");
|
||||
return RS_ERR_MISSING_PAGE_COUNT;
|
||||
}
|
||||
}
|
||||
else if (fieldsize != 1) {
|
||||
if (flags & RS_IGNORE_ALL_WARNINGS)
|
||||
rs_warning(NULL, app, "application has an invalid page count field");
|
||||
else {
|
||||
rs_error(NULL, app, "application has an invalid page count field");
|
||||
return RS_ERR_INCORRECT_PAGE_COUNT;
|
||||
}
|
||||
}
|
||||
else {
|
||||
pagecount = ((length + 0x3fff) >> 14);
|
||||
|
||||
if (flags & RS_FIX_PAGE_COUNT) {
|
||||
hdr[fieldstart] = pagecount;
|
||||
}
|
||||
else if (addedpage && hdr[fieldstart] == pagecount - 1) {
|
||||
hdr[fieldstart] = pagecount;
|
||||
}
|
||||
else if (hdr[fieldstart] != pagecount) {
|
||||
if (flags & RS_IGNORE_ALL_WARNINGS) {
|
||||
rs_warning(NULL, app,
|
||||
"application has an incorrect page count (actual: %lu)",
|
||||
((length + 0x3fff) >> 14));
|
||||
hdr[fieldstart] = pagecount;
|
||||
}
|
||||
else {
|
||||
rs_error(NULL, app,
|
||||
"application has an incorrect page count (actual: %lu)",
|
||||
((length + 0x3fff) >> 14));
|
||||
return RS_ERR_INCORRECT_PAGE_COUNT;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Check for key ID. This field is required to be present; it
|
||||
determines which public key is used for validation. (The
|
||||
contents of this field are usually thought of as a big-endian
|
||||
integer, but to be more precise, they're really treated as a
|
||||
binary string.) */
|
||||
|
||||
if (rs_find_app_field(0x8010, hdr, hdrsize, NULL, NULL, NULL)) {
|
||||
if (flags & RS_IGNORE_ALL_WARNINGS)
|
||||
rs_warning(NULL, app, "application has no key ID");
|
||||
else {
|
||||
rs_error(NULL, app, "application has no key ID");
|
||||
return RS_ERR_MISSING_KEY_ID;
|
||||
}
|
||||
}
|
||||
|
||||
/* Check for date stamp. This seems to be required -- the OS will
|
||||
use it to update its last-known date stamp if necessary -- and
|
||||
should consist of an 032x field containing an 090x field,
|
||||
followed by an 020x field containing the date stamp signature.
|
||||
(The contents of the latter only matter if the date stamp is
|
||||
"new.") */
|
||||
|
||||
if (rs_find_app_field(0x0320, hdr, hdrsize,
|
||||
NULL, &fieldstart, &fieldsize)) {
|
||||
if (flags & RS_IGNORE_ALL_WARNINGS)
|
||||
rs_warning(NULL, app, "application has no date stamp");
|
||||
else {
|
||||
rs_error(NULL, app, "application has no date stamp");
|
||||
return RS_ERR_MISSING_DATE_STAMP;
|
||||
}
|
||||
}
|
||||
else if (rs_find_app_field(0x0900, hdr + fieldstart, fieldsize,
|
||||
NULL, NULL, NULL)) {
|
||||
if (flags & RS_IGNORE_ALL_WARNINGS)
|
||||
rs_warning(NULL, app, "application has no date stamp");
|
||||
else {
|
||||
rs_error(NULL, app, "application has no date stamp");
|
||||
return RS_ERR_MISSING_DATE_STAMP;
|
||||
}
|
||||
}
|
||||
else if (hdr[fieldstart + fieldsize] != 0x02
|
||||
|| (hdr[fieldstart + fieldsize + 1] & 0xf0) != 0) {
|
||||
if (flags & RS_IGNORE_ALL_WARNINGS)
|
||||
rs_warning(NULL, app, "application has no date stamp signature");
|
||||
else {
|
||||
rs_error(NULL, app, "application has no date stamp signature");
|
||||
return RS_ERR_MISSING_DATE_STAMP;
|
||||
}
|
||||
}
|
||||
|
||||
/* Check for program image field. This field indicates the end of
|
||||
the header and the start of application code. Note, however,
|
||||
that the OS handles this field in an exceedingly broken way. To
|
||||
be safe, this must always be the last field of the header, and
|
||||
should always be written as 80 7F followed by four length bytes.
|
||||
The length bytes may be anything you like -- they're ignored. */
|
||||
|
||||
if (rs_find_app_field(0x8070, hdr, hdrsize,
|
||||
NULL, NULL, NULL)) {
|
||||
if (flags & RS_IGNORE_ALL_WARNINGS)
|
||||
rs_warning(NULL, app, "application has no program image field");
|
||||
else {
|
||||
rs_error(NULL, app, "application has no program image field");
|
||||
return RS_ERR_MISSING_PROGRAM_IMAGE;
|
||||
}
|
||||
}
|
||||
|
||||
/* Check for invalid pages (those beginning with FF.) An OS bug
|
||||
means that such pages will end up being erased completely if
|
||||
defragmenting requires the application to be moved in Flash. */
|
||||
|
||||
e = RS_SUCCESS;
|
||||
|
||||
for (i = 0; i < app->length; i += 0x4000) {
|
||||
if (app->data[i] == 0xff) {
|
||||
if (flags & RS_IGNORE_ALL_WARNINGS)
|
||||
rs_warning(NULL, app, "page %ld begins with FFh", (i >> 14));
|
||||
else {
|
||||
rs_error(NULL, app, "page %ld begins with FFh", (i >> 14));
|
||||
e = RS_ERR_INVALID_PROGRAM_DATA;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return e;
|
||||
}
|
||||
|
||||
/*
|
||||
* Compute signature for a Flash app.
|
||||
*
|
||||
* The app header should be checked and/or repaired by
|
||||
* rs_repair_ti8x_app() prior to calling this function.
|
||||
*
|
||||
* There are four equally valid Rabin signatures for any application;
|
||||
* rootnum determines which of the four should be used.
|
||||
*/
|
||||
int rs_sign_ti8x_app(RSProgram* app, /* app to sign */
|
||||
RSKey* key, /* signing key */
|
||||
int rootnum) /* signature number */
|
||||
{
|
||||
md5_uint32 hash[4];
|
||||
mpz_t hashv, sigv;
|
||||
int f;
|
||||
unsigned int lastpagelength;
|
||||
unsigned char sigdata[512];
|
||||
size_t siglength;
|
||||
int e;
|
||||
|
||||
/* Check if app length is risky */
|
||||
|
||||
if ((app->length % 64) == 55) {
|
||||
rs_warning(NULL, app, "application has length 55 mod 64");
|
||||
rs_warning(NULL, app, "(this will fail to validate on TI-83+ BE)");
|
||||
}
|
||||
|
||||
/* Compute signature */
|
||||
|
||||
md5_buffer((char*) app->data, app->length, hash);
|
||||
|
||||
mpz_init(hashv);
|
||||
mpz_init(sigv);
|
||||
|
||||
mpz_import(hashv, 16, -1, 1, 0, 0, hash);
|
||||
rs_message(2, NULL, app, "hash = %ZX", hashv);
|
||||
|
||||
if ((e = rs_sign_rabin(sigv, &f, hashv, rootnum, key))) {
|
||||
mpz_clear(hashv);
|
||||
mpz_clear(sigv);
|
||||
return e;
|
||||
}
|
||||
|
||||
rs_message(2, NULL, app, "sig = %ZX", sigv);
|
||||
rs_message(2, NULL, app, "f = %d", f);
|
||||
|
||||
/* Write the square root value as an 022D field... */
|
||||
|
||||
sigdata[0] = 0x02;
|
||||
sigdata[1] = 0x2d;
|
||||
mpz_export(sigdata + 3, &siglength, -1, 1, 0, 0, sigv);
|
||||
sigdata[2] = siglength & 0xff;
|
||||
siglength += 3;
|
||||
|
||||
mpz_clear(hashv);
|
||||
mpz_clear(sigv);
|
||||
|
||||
/* ...and append the f value as a big integer */
|
||||
|
||||
if (f == 0) {
|
||||
sigdata[siglength++] = 0;
|
||||
}
|
||||
else {
|
||||
sigdata[siglength++] = 1;
|
||||
sigdata[siglength++] = f;
|
||||
}
|
||||
|
||||
/* Add padding, but not too much (it seems to make some link
|
||||
programs happier) */
|
||||
|
||||
lastpagelength = app->length & 0x3fff;
|
||||
|
||||
while (siglength < 96 && (lastpagelength + siglength) < 0x3fff)
|
||||
sigdata[siglength++] = 0xff;
|
||||
|
||||
return rs_program_append_data(app, sigdata, siglength);
|
||||
}
|
||||
|
||||
/*
|
||||
* Validate a Flash app signature.
|
||||
*/
|
||||
int rs_validate_ti8x_app(const RSProgram* app, /* app to validate */
|
||||
const RSKey* key) /* signing key */
|
||||
{
|
||||
unsigned long length, hdrstart, hdrsize, fieldstart, fieldsize, i;
|
||||
const unsigned char *hdr, *sig;
|
||||
md5_uint32 hash[4];
|
||||
mpz_t hashv, sigv;
|
||||
int f, e, e2 = RS_SUCCESS;
|
||||
|
||||
if (app->length < 6) {
|
||||
rs_error(NULL, app, "no app header found");
|
||||
return RS_ERR_MISSING_HEADER;
|
||||
}
|
||||
|
||||
rs_get_field_size(app->data, &hdrstart, &hdrsize);
|
||||
length = hdrstart + hdrsize;
|
||||
hdr = app->data + hdrstart;
|
||||
if (hdrsize > 128)
|
||||
hdrsize = 128;
|
||||
|
||||
if (((length + 0x3fff) >> 14) != ((app->length + 0x3fff) >> 14)
|
||||
|| length + 4 > app->length || length + 96 < app->length) {
|
||||
rs_error(NULL, app, "incorrect application length");
|
||||
return RS_ERR_INCORRECT_PROGRAM_SIZE;
|
||||
}
|
||||
|
||||
if (rs_find_app_field(0x8070, hdr, hdrsize,
|
||||
NULL, NULL, NULL)) {
|
||||
rs_warning(NULL, app, "application has no program image field");
|
||||
e2 = RS_ERR_MISSING_PROGRAM_IMAGE;
|
||||
}
|
||||
|
||||
if (rs_find_app_field(0x8080, hdr, hdrsize,
|
||||
NULL, &fieldstart, &fieldsize)) {
|
||||
rs_warning(NULL, app, "application has no no page count field");
|
||||
e2 = RS_ERR_MISSING_PAGE_COUNT;
|
||||
}
|
||||
else if (fieldsize != 1) {
|
||||
rs_warning(NULL, app, "application has an invalid page count field");
|
||||
e2 = RS_ERR_INCORRECT_PAGE_COUNT;
|
||||
}
|
||||
else if (hdr[fieldstart] != ((length + 0x3fff) >> 14)) {
|
||||
rs_warning(NULL, app, "application has an incorrect page count field");
|
||||
e2 = RS_ERR_INCORRECT_PAGE_COUNT;
|
||||
}
|
||||
|
||||
if ((length % 64) == 55) {
|
||||
rs_warning(NULL, app, "application has length 55 mod 64");
|
||||
rs_warning(NULL, app, "(this will fail to validate on TI-83+ BE)");
|
||||
e2 = RS_ERR_INVALID_PROGRAM_SIZE;
|
||||
}
|
||||
|
||||
for (i = 0; i < app->length; i += 0x4000) {
|
||||
if (app->data[i] == 0xff) {
|
||||
rs_warning(NULL, app, "page %ld begins with FFh", (i >> 14));
|
||||
e2 = RS_ERR_INVALID_PROGRAM_DATA;
|
||||
}
|
||||
}
|
||||
|
||||
md5_buffer((char*) app->data, length, &hash);
|
||||
|
||||
sig = app->data + length;
|
||||
if (sig[0] != 0x02 || sig[1] != 0x2d) {
|
||||
rs_error(NULL, app, "application does not have a Rabin signature");
|
||||
return RS_ERR_MISSING_RABIN_SIGNATURE;
|
||||
}
|
||||
rs_get_field_size(sig, &fieldstart, &fieldsize);
|
||||
|
||||
mpz_init(sigv);
|
||||
mpz_init(hashv);
|
||||
|
||||
mpz_import(hashv, 16, -1, 1, 0, 0, hash);
|
||||
rs_message(2, NULL, app, "hash = %ZX", hashv);
|
||||
|
||||
mpz_import(sigv, fieldsize, -1, 1, 0, 0, sig + fieldstart);
|
||||
rs_message(2, NULL, app, "sig = %ZX", sigv);
|
||||
|
||||
if (sig[fieldstart + fieldsize] == 0)
|
||||
f = 0;
|
||||
else
|
||||
f = sig[fieldstart + fieldsize + 1];
|
||||
rs_message(2, NULL, app, "f = %d", f);
|
||||
|
||||
e = rs_validate_rabin(sigv, f, hashv, key);
|
||||
if (e == RS_SIGNATURE_INCORRECT)
|
||||
rs_message(0, NULL, app, "application signature incorrect");
|
||||
|
||||
mpz_clear(sigv);
|
||||
mpz_clear(hashv);
|
||||
return (e ? e : e2);
|
||||
}
|
||||
|
||||
297
tool/rabbitsign-src/app9x.c
Normal file
297
tool/rabbitsign-src/app9x.c
Normal file
|
|
@ -0,0 +1,297 @@
|
|||
/*
|
||||
* RabbitSign - Tools for signing TI graphing calculator software
|
||||
* Copyright (C) 2009 Benjamin Moody
|
||||
*
|
||||
* This program 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.
|
||||
*
|
||||
* This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
# include <config.h>
|
||||
#endif
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#include "rabbitsign.h"
|
||||
#include "internal.h"
|
||||
#include "md5.h"
|
||||
|
||||
/*
|
||||
* Check/fix app/OS header and data.
|
||||
*
|
||||
* (This is something of a work in progress; a lot more
|
||||
* experimentation would be useful to determine what exactly is
|
||||
* required of app and OS headers on the 68k calculators.)
|
||||
*/
|
||||
static int repair_app(RSProgram* app, /* app to repair */
|
||||
unsigned int flags, /* flags */
|
||||
unsigned int type) /* field type */
|
||||
{
|
||||
unsigned long length, hdrstart, hdrsize, fieldhead,
|
||||
fieldstart, fieldsize;
|
||||
unsigned char *hdr;
|
||||
int e;
|
||||
|
||||
if (app->length < 6
|
||||
|| app->data[0] != type
|
||||
|| (app->data[1] & 0xf0) != 0) {
|
||||
rs_error(NULL, app, "no app header found");
|
||||
return RS_ERR_MISSING_HEADER;
|
||||
}
|
||||
|
||||
/* Determine application length */
|
||||
|
||||
length = app->length;
|
||||
rs_get_field_size(app->data, &hdrstart, &hdrsize);
|
||||
|
||||
/* If requested, remove the old signature (truncate the application
|
||||
to its stated length.) */
|
||||
|
||||
if (flags & RS_REMOVE_OLD_SIGNATURE) {
|
||||
if (length < hdrstart + hdrsize) {
|
||||
rs_warning(NULL, app, "provided app data too short");
|
||||
}
|
||||
else {
|
||||
if (length > hdrstart + hdrsize + 67)
|
||||
rs_warning(NULL, app, "re-signing discards %lu bytes",
|
||||
length - hdrstart - hdrsize);
|
||||
length = hdrstart + hdrsize;
|
||||
}
|
||||
}
|
||||
else if (hdrsize && hdrstart + hdrsize != length) {
|
||||
rs_warning(NULL, app, "application length incorrect");
|
||||
rs_warning(NULL, app, "(perhaps you meant to use -r?)");
|
||||
}
|
||||
|
||||
if ((e = rs_program_set_length(app, length)))
|
||||
return e;
|
||||
|
||||
/* Set app size header to the correct value */
|
||||
|
||||
hdrsize = length - hdrstart;
|
||||
if (rs_set_field_size(app->data, hdrsize)) {
|
||||
if (flags & RS_IGNORE_ALL_WARNINGS)
|
||||
rs_warning(NULL, app, "cannot set application length");
|
||||
else {
|
||||
rs_error(NULL, app, "cannot set application length");
|
||||
return RS_ERR_FIELD_TOO_SMALL;
|
||||
}
|
||||
}
|
||||
|
||||
/* Check for key ID */
|
||||
|
||||
hdr = app->data + hdrstart;
|
||||
if (hdrsize > 128)
|
||||
hdrsize = 128;
|
||||
|
||||
if (rs_find_app_field((type << 8) | 0x10, hdr, hdrsize,
|
||||
NULL, NULL, NULL)) {
|
||||
if (flags & RS_IGNORE_ALL_WARNINGS)
|
||||
rs_warning(NULL, app, "application has no key ID");
|
||||
else {
|
||||
rs_error(NULL, app, "application has no key ID");
|
||||
return RS_ERR_MISSING_KEY_ID;
|
||||
}
|
||||
}
|
||||
|
||||
/* Check for date stamp (note: I haven't actually tested whether
|
||||
this is required, but it always seems to be present in both 68k
|
||||
apps and OSes, and it is required for TI-83+ apps) */
|
||||
|
||||
if (rs_find_app_field(0x0320, hdr, hdrsize,
|
||||
NULL, &fieldstart, &fieldsize)) {
|
||||
if (flags & RS_IGNORE_ALL_WARNINGS)
|
||||
rs_warning(NULL, app, "application has no date stamp");
|
||||
else {
|
||||
rs_error(NULL, app, "application has no date stamp");
|
||||
return RS_ERR_MISSING_DATE_STAMP;
|
||||
}
|
||||
}
|
||||
else if (rs_find_app_field(0x0900, hdr + fieldstart, fieldsize,
|
||||
NULL, NULL, NULL)) {
|
||||
if (flags & RS_IGNORE_ALL_WARNINGS)
|
||||
rs_warning(NULL, app, "application has no date stamp");
|
||||
else {
|
||||
rs_error(NULL, app, "application has no date stamp");
|
||||
return RS_ERR_MISSING_DATE_STAMP;
|
||||
}
|
||||
}
|
||||
else if (hdr[fieldstart + fieldsize] != 0x02
|
||||
|| (hdr[fieldstart + fieldsize + 1] & 0xf0) != 0) {
|
||||
if (flags & RS_IGNORE_ALL_WARNINGS)
|
||||
rs_warning(NULL, app, "application has no date stamp signature");
|
||||
else {
|
||||
rs_error(NULL, app, "application has no date stamp signature");
|
||||
return RS_ERR_MISSING_DATE_STAMP;
|
||||
}
|
||||
}
|
||||
|
||||
/* Check for program image field and fix length */
|
||||
|
||||
if (rs_find_app_field((type << 8) | 0x70, hdr, hdrsize,
|
||||
&fieldhead, &fieldstart, &fieldsize)) {
|
||||
if (flags & RS_IGNORE_ALL_WARNINGS)
|
||||
rs_warning(NULL, app, "application has no program image field");
|
||||
else {
|
||||
rs_error(NULL, app, "application has no program image field");
|
||||
return RS_ERR_MISSING_PROGRAM_IMAGE;
|
||||
}
|
||||
}
|
||||
else {
|
||||
if ((fieldstart + hdrstart) % 2) {
|
||||
/* The OS appears to align apps so the start of the app header
|
||||
is at an even address; if the application code itself is at
|
||||
an odd address, bad stuff will happen. */
|
||||
if (flags & RS_IGNORE_ALL_WARNINGS)
|
||||
rs_warning(NULL, app, "application header is not a multiple of 2 bytes");
|
||||
else {
|
||||
rs_error(NULL, app, "application header is not a multiple of 2 bytes");
|
||||
return RS_ERR_MISALIGNED_PROGRAM_IMAGE;
|
||||
}
|
||||
}
|
||||
|
||||
if (fieldsize && fieldstart + fieldsize != length - hdrstart)
|
||||
rs_warning(NULL, app, "program image length incorrect");
|
||||
|
||||
if (rs_set_field_size(hdr + fieldhead, length - hdrstart - fieldstart)) {
|
||||
rs_error(NULL, app, "cannot set program image length");
|
||||
return RS_ERR_FIELD_TOO_SMALL;
|
||||
}
|
||||
}
|
||||
|
||||
return RS_SUCCESS;
|
||||
}
|
||||
|
||||
/*
|
||||
* Check/fix Flash app header and data.
|
||||
*/
|
||||
int rs_repair_ti9x_app(RSProgram* app, /* app to repair */
|
||||
unsigned int flags) /* flags */
|
||||
{
|
||||
return repair_app(app, flags, 0x81);
|
||||
}
|
||||
|
||||
/*
|
||||
* Check/fix OS header and data.
|
||||
*/
|
||||
int rs_repair_ti9x_os(RSProgram* app, /* app to repair */
|
||||
unsigned int flags) /* flags */
|
||||
{
|
||||
return repair_app(app, flags, 0x80);
|
||||
}
|
||||
|
||||
/*
|
||||
* Compute signature for a 68k app/OS.
|
||||
*
|
||||
* The app header should be checked and/or repaired by
|
||||
* rs_repair_ti9x_app() prior to calling this function.
|
||||
*/
|
||||
int rs_sign_ti9x_app(RSProgram* app, /* app to sign */
|
||||
RSKey* key) /* signing key */
|
||||
{
|
||||
md5_uint32 hash[4];
|
||||
mpz_t hashv, sigv;
|
||||
unsigned char sigdata[512];
|
||||
size_t siglength;
|
||||
int e;
|
||||
|
||||
md5_buffer((char*) app->data, app->length, &hash);
|
||||
|
||||
mpz_init(hashv);
|
||||
mpz_init(sigv);
|
||||
|
||||
mpz_import(hashv, 16, -1, 1, 0, 0, hash);
|
||||
rs_message(2, NULL, app, "hash = %ZX", hashv);
|
||||
|
||||
if ((e = rs_sign_rsa(sigv, hashv, key))) {
|
||||
mpz_clear(hashv);
|
||||
mpz_clear(sigv);
|
||||
return e;
|
||||
}
|
||||
|
||||
rs_message(2, NULL, app, "sig = %ZX", sigv);
|
||||
|
||||
sigdata[0] = 0x02;
|
||||
sigdata[1] = 0x0d;
|
||||
mpz_export(sigdata + 3, &siglength, -1, 1, 0, 0, sigv);
|
||||
sigdata[2] = siglength & 0xff;
|
||||
siglength += 3;
|
||||
|
||||
return rs_program_append_data(app, sigdata, siglength);
|
||||
}
|
||||
|
||||
/*
|
||||
* Validate app/OS signature.
|
||||
*/
|
||||
int rs_validate_ti9x_app(const RSProgram* app, /* app to validate */
|
||||
const RSKey* key) /* signing key */
|
||||
{
|
||||
unsigned long length, hdrstart, hdrsize, fieldstart, fieldsize;
|
||||
const unsigned char *hdr, *sig;
|
||||
md5_uint32 hash[4];
|
||||
mpz_t hashv, sigv;
|
||||
int e, e2 = RS_SUCCESS;
|
||||
|
||||
if (app->length < 6) {
|
||||
rs_error(NULL, app, "no app header found");
|
||||
return RS_ERR_MISSING_HEADER;
|
||||
}
|
||||
|
||||
rs_get_field_size(app->data, &hdrstart, &hdrsize);
|
||||
length = hdrstart + hdrsize;
|
||||
hdr = app->data + hdrstart;
|
||||
if (hdrsize > 128)
|
||||
hdrsize = 128;
|
||||
|
||||
if (length + 4 > app->length || length + 67 < app->length) {
|
||||
rs_error(NULL, app, "incorrect application length");
|
||||
return RS_ERR_INCORRECT_PROGRAM_SIZE;
|
||||
}
|
||||
|
||||
if (rs_find_app_field((app->data[0] << 8) | 0x70, hdr, hdrsize,
|
||||
NULL, &fieldstart, &fieldsize)) {
|
||||
rs_warning(NULL, app, "application has no program image field");
|
||||
e2 = RS_ERR_MISSING_PROGRAM_IMAGE;
|
||||
}
|
||||
else if ((fieldstart + hdrstart) % 2) {
|
||||
rs_warning(NULL, app, "application header is not a multiple of 2 bytes");
|
||||
e2 = RS_ERR_MISALIGNED_PROGRAM_IMAGE;
|
||||
}
|
||||
|
||||
md5_buffer((char*) app->data, length, &hash);
|
||||
|
||||
sig = app->data + length;
|
||||
if (sig[0] != 0x02 || (sig[1] & 0xf0) != 0x00) {
|
||||
rs_error(NULL, app, "application does not have an RSA signature");
|
||||
return RS_ERR_MISSING_RSA_SIGNATURE;
|
||||
}
|
||||
rs_get_field_size(sig, &fieldstart, &fieldsize);
|
||||
|
||||
mpz_init(sigv);
|
||||
mpz_init(hashv);
|
||||
|
||||
mpz_import(hashv, 16, -1, 1, 0, 0, hash);
|
||||
rs_message(2, NULL, app, "hash = %ZX", hashv);
|
||||
|
||||
mpz_import(sigv, fieldsize, -1, 1, 0, 0, sig + fieldstart);
|
||||
rs_message(2, NULL, app, "sig = %ZX", sigv);
|
||||
|
||||
e = rs_validate_rsa(sigv, hashv, key);
|
||||
if (e == RS_SIGNATURE_INCORRECT)
|
||||
rs_message(0, NULL, app, "application signature incorrect");
|
||||
|
||||
mpz_clear(sigv);
|
||||
mpz_clear(hashv);
|
||||
return (e ? e : e2);
|
||||
}
|
||||
|
||||
85
tool/rabbitsign-src/apps.c
Normal file
85
tool/rabbitsign-src/apps.c
Normal file
|
|
@ -0,0 +1,85 @@
|
|||
/*
|
||||
* RabbitSign - Tools for signing TI graphing calculator software
|
||||
* Copyright (C) 2009 Benjamin Moody
|
||||
*
|
||||
* This program 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.
|
||||
*
|
||||
* This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
# include <config.h>
|
||||
#endif
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#include "rabbitsign.h"
|
||||
#include "internal.h"
|
||||
|
||||
/*
|
||||
* Check/fix program header and data.
|
||||
*/
|
||||
int rs_repair_program(RSProgram* prgm, /* app to repair */
|
||||
unsigned int flags) /* flags */
|
||||
{
|
||||
if (rs_calc_is_ti8x(prgm->calctype)) {
|
||||
if (prgm->datatype == RS_DATA_OS)
|
||||
return rs_repair_ti8x_os(prgm, flags);
|
||||
else if (prgm->datatype == RS_DATA_APP)
|
||||
return rs_repair_ti8x_app(prgm, flags);
|
||||
}
|
||||
|
||||
if (rs_calc_is_ti9x(prgm->calctype)) {
|
||||
if (prgm->datatype == RS_DATA_OS)
|
||||
return rs_repair_ti9x_os(prgm, flags);
|
||||
else if (prgm->datatype == RS_DATA_APP)
|
||||
return rs_repair_ti9x_app(prgm, flags);
|
||||
}
|
||||
|
||||
rs_error(NULL, prgm, "calc/data type (%X/%X) unrecognized",
|
||||
prgm->calctype, prgm->datatype);
|
||||
return RS_ERR_UNKNOWN_PROGRAM_TYPE;
|
||||
}
|
||||
|
||||
/*
|
||||
* Add a signature to the program.
|
||||
*/
|
||||
int rs_sign_program(RSProgram* prgm, /* app to sign */
|
||||
RSKey* key, /* signing key */
|
||||
int rootnum) /* signature number */
|
||||
{
|
||||
if (rs_calc_is_ti8x(prgm->calctype)) {
|
||||
if (prgm->datatype == RS_DATA_OS)
|
||||
return rs_sign_ti8x_os(prgm, key);
|
||||
else if (prgm->datatype == RS_DATA_APP)
|
||||
return rs_sign_ti8x_app(prgm, key, rootnum);
|
||||
}
|
||||
|
||||
return rs_sign_ti9x_app(prgm, key);
|
||||
}
|
||||
|
||||
/*
|
||||
* Validate program signature.
|
||||
*/
|
||||
int rs_validate_program(const RSProgram* prgm, /* app to validate */
|
||||
const RSKey* key) /* signing key */
|
||||
{
|
||||
if (rs_calc_is_ti8x(prgm->calctype)) {
|
||||
if (prgm->datatype == RS_DATA_OS)
|
||||
return rs_validate_ti8x_os(prgm, key);
|
||||
else if (prgm->datatype == RS_DATA_APP)
|
||||
return rs_validate_ti8x_app(prgm, key);
|
||||
}
|
||||
|
||||
return rs_validate_ti9x_app(prgm, key);
|
||||
}
|
||||
|
||||
241
tool/rabbitsign-src/autokey.c
Normal file
241
tool/rabbitsign-src/autokey.c
Normal file
|
|
@ -0,0 +1,241 @@
|
|||
/*
|
||||
* RabbitSign - Tools for signing TI graphing calculator software
|
||||
* Copyright (C) 2009 Benjamin Moody
|
||||
*
|
||||
* This program 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.
|
||||
*
|
||||
* This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
# include <config.h>
|
||||
#endif
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#ifdef HAVE_STDLIB_H
|
||||
# include <stdlib.h>
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_STRING_H
|
||||
# include <string.h>
|
||||
#else
|
||||
# ifdef HAVE_STRINGS_H
|
||||
# include <strings.h>
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#include "rabbitsign.h"
|
||||
#include "internal.h"
|
||||
#include "autokeys.h"
|
||||
|
||||
/*
|
||||
* Get key ID for the given program.
|
||||
*/
|
||||
unsigned long rs_program_get_key_id(const RSProgram* prgm)
|
||||
{
|
||||
const unsigned char* hdr;
|
||||
unsigned long hdrstart, hdrsize;
|
||||
|
||||
if (prgm->header_length > 0) {
|
||||
hdr = prgm->header;
|
||||
hdrsize = prgm->header_length;
|
||||
}
|
||||
else if (prgm->length > 0) {
|
||||
hdr = prgm->data;
|
||||
hdrsize = prgm->length;
|
||||
if (hdrsize > 128)
|
||||
hdrsize = 128;
|
||||
}
|
||||
else
|
||||
return 0;
|
||||
|
||||
rs_get_field_size(hdr, &hdrstart, NULL);
|
||||
hdrsize -= hdrstart;
|
||||
|
||||
if (hdr[0] == 0x81)
|
||||
return rs_get_numeric_field(0x8110, hdr + hdrstart, hdrsize);
|
||||
else
|
||||
return rs_get_numeric_field(0x8010, hdr + hdrstart, hdrsize);
|
||||
}
|
||||
|
||||
/*
|
||||
* Try to load key from a file.
|
||||
*/
|
||||
static int try_key_file(RSKey* key, /* key structure to store result */
|
||||
const char* a, /* first path element */
|
||||
const char* b, /* second path element */
|
||||
const char* c) /* third path element */
|
||||
{
|
||||
char* s;
|
||||
FILE* f;
|
||||
int e;
|
||||
|
||||
s = rs_malloc(strlen(a) + strlen(b) + strlen(c) + 1);
|
||||
if (!s)
|
||||
return RS_ERR_OUT_OF_MEMORY;
|
||||
strcpy(s, a);
|
||||
strcat(s, b);
|
||||
strcat(s, c);
|
||||
|
||||
f = fopen(s, "rt");
|
||||
if (!f) {
|
||||
rs_free(s);
|
||||
return RS_ERR_KEY_NOT_FOUND;
|
||||
}
|
||||
|
||||
if ((e = rs_read_key_file(key, f, s, 1))) {
|
||||
fclose(f);
|
||||
rs_free(s);
|
||||
return e;
|
||||
}
|
||||
|
||||
fclose(f);
|
||||
rs_free(s);
|
||||
return RS_SUCCESS;
|
||||
}
|
||||
|
||||
/*
|
||||
* Try to locate a given key file.
|
||||
*/
|
||||
static int find_key_file(RSKey* key, /* key structure to
|
||||
store result */
|
||||
const char* filename) /* file name to search
|
||||
for */
|
||||
{
|
||||
const char* p;
|
||||
int e;
|
||||
|
||||
e = try_key_file(key, "", "", filename);
|
||||
if (e != RS_ERR_KEY_NOT_FOUND)
|
||||
return e;
|
||||
|
||||
if ((p = getenv("RABBITSIGN_KEY_DIR"))) {
|
||||
#if defined(__MSDOS__) || defined(__WIN32__)
|
||||
e = try_key_file(key, p, "\\", filename);
|
||||
#else
|
||||
e = try_key_file(key, p, "/", filename);
|
||||
#endif
|
||||
if (e != RS_ERR_KEY_NOT_FOUND)
|
||||
return e;
|
||||
}
|
||||
|
||||
#if defined(__MSDOS__) || defined(__WIN32__)
|
||||
if ((p = getenv("TI83PLUSDIR"))) {
|
||||
e = try_key_file(key, p, "\\Utils\\", filename);
|
||||
if (e != RS_ERR_KEY_NOT_FOUND)
|
||||
return e;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef SHARE_DIR
|
||||
e = try_key_file(key, SHARE_DIR, "", filename);
|
||||
if (e != RS_ERR_KEY_NOT_FOUND)
|
||||
return e;
|
||||
#endif
|
||||
|
||||
return RS_ERR_KEY_NOT_FOUND;
|
||||
}
|
||||
|
||||
/*
|
||||
* Find key file for the given ID.
|
||||
*/
|
||||
int rs_key_find_for_id(RSKey* key, /* key structure to store
|
||||
result */
|
||||
unsigned long keyid, /* key ID to search for */
|
||||
int publiconly) /* 1 = search for public
|
||||
key only */
|
||||
{
|
||||
static const char* fmts[] = { "%02lx.%s", "%02lX.%s",
|
||||
"%04lx.%s", "%04lX.%s", NULL };
|
||||
char buf[16];
|
||||
int i, e;
|
||||
|
||||
mpz_set_ui(key->p, 0);
|
||||
mpz_set_ui(key->q, 0);
|
||||
mpz_set_ui(key->qinv, 0);
|
||||
mpz_set_ui(key->d, 0);
|
||||
|
||||
if (keyid > 0xFF)
|
||||
sprintf(buf, "%04lX", keyid);
|
||||
else
|
||||
sprintf(buf, "%02lX", keyid);
|
||||
|
||||
for (i = 0; known_priv_keys[i].n; i++) {
|
||||
if (keyid == known_priv_keys[i].id) {
|
||||
if ((e = rs_parse_key_value(key->n, known_priv_keys[i].n)))
|
||||
return e;
|
||||
|
||||
if (known_priv_keys[i].p
|
||||
&& (e = rs_parse_key_value(key->p, known_priv_keys[i].p)))
|
||||
return e;
|
||||
if (known_priv_keys[i].q
|
||||
&& (e = rs_parse_key_value(key->q, known_priv_keys[i].q)))
|
||||
return e;
|
||||
if (known_priv_keys[i].d
|
||||
&& (e = rs_parse_key_value(key->d, known_priv_keys[i].d)))
|
||||
return e;
|
||||
|
||||
rs_message(2, key, NULL, "Loaded builtin private key %s:", buf);
|
||||
rs_message(2, key, NULL, " n = %ZX", key->n);
|
||||
if (mpz_sgn(key->p))
|
||||
rs_message(2, key, NULL, " p = %ZX", key->p);
|
||||
if (mpz_sgn(key->q))
|
||||
rs_message(2, key, NULL, " q = %ZX", key->q);
|
||||
if (mpz_sgn(key->d))
|
||||
rs_message(2, key, NULL, " d = %ZX", key->d);
|
||||
|
||||
key->id = keyid;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (publiconly) {
|
||||
for (i = 0; known_pub_keys[i].n; i++) {
|
||||
if (keyid == known_pub_keys[i].id) {
|
||||
if ((e = rs_parse_key_value(key->n, known_pub_keys[i].n)))
|
||||
return e;
|
||||
|
||||
rs_message(2, key, NULL, "Loaded builtin public key %s:", buf);
|
||||
rs_message(2, key, NULL, " n = %ZX", key->n);
|
||||
|
||||
key->id = keyid;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (i = 0; fmts[i]; i++) {
|
||||
sprintf(buf, fmts[i], keyid, "key");
|
||||
e = find_key_file(key, buf);
|
||||
if (e != RS_ERR_KEY_NOT_FOUND) {
|
||||
if (e == 0 && !key->id)
|
||||
key->id = keyid;
|
||||
return e;
|
||||
}
|
||||
}
|
||||
|
||||
if (publiconly) {
|
||||
for (i = 0; fmts[i]; i++) {
|
||||
sprintf(buf, fmts[i], keyid, "pub");
|
||||
e = find_key_file(key, buf);
|
||||
if (e != RS_ERR_KEY_NOT_FOUND) {
|
||||
if (e == 0 && !key->id)
|
||||
key->id = keyid;
|
||||
return e;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
rs_error(NULL, NULL, "cannot find key file %s", buf);
|
||||
return RS_ERR_KEY_NOT_FOUND;
|
||||
}
|
||||
47
tool/rabbitsign-src/autokeys.h
Normal file
47
tool/rabbitsign-src/autokeys.h
Normal file
|
|
@ -0,0 +1,47 @@
|
|||
/*
|
||||
* RabbitSign - Tools for signing TI graphing calculator software
|
||||
* Copyright (C) 2009 Benjamin Moody
|
||||
*
|
||||
* This program 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.
|
||||
*
|
||||
* This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
struct pubkeyinfo {
|
||||
unsigned long id;
|
||||
const char* n;
|
||||
} known_pub_keys[] =
|
||||
{{ 0x0101, "406104CDFAD955D41F1ECCB9B622007FE8BC75E8B28DA178334755FEF27C564D47B04FD82498C163B762991C68CF64E29236BC41A4C1BCB9793B6EE965407C74BC" },
|
||||
{ 0x0102, "4085F11FF810591B84875FDE4C92A5961CDD233A9B7ED76E8CFF65128C71420FCCC80E375DC8D2A8551AE2BEB9FD41654CE7B0A95E32BE9997750407904560BEFC" },
|
||||
{ 0x0103, "40ED0236FD3D8B0CBA88C1CECFA549F8A838CDBAC487F9253F6C67F20C9627984FEA0D0A0BA035424C7B9F5E702286CEDCC66D2DA93320F7071BF2C93C59DE6B91" },
|
||||
{ 0x010A, "4005D1EB8485AA14C983FFA04031B27C89950C3D7F4181FE603A353F48DE0933DFE1173BDD2E14FEB7325BAA35A12F21804DCFD30E56119C1305D348A77BCF448F" },
|
||||
{ 0x01, "40F78D55E9A40A92D11D5C1446BFCEA74C8368BE1A81B6BA1596970E6D5932D933B86FF3CEA6B381CE65F5E383BDB02C82F33B8190375D0B40DEF2F1FE3CCA49AD" },
|
||||
{ 0x02, "4081396D55C0989BC949FA30821FFE61C9441EDC3827D0E89EEE16DDEF697634B8E10B8B7F42FE7CC1A7478606D6D09F6FE96365E71E3D2AAA7C8D91068F1DFAF3" },
|
||||
{ 0x03, "40E7C21F66BD1116F2F4F691121F3330060E24C8C7A1858D49636E24E80015F3AA25C2F6033AB39067D453945ABD8A5F4CFAFADABAF8BA2BFB88895A04B5D47689" },
|
||||
{ 0x04, "408FE528B340EB1C88B505B2354BAADF47F3616D92CB532E7E5A2A0DFF1C4E4283CEEA2B2F7AD5F28B7E4BE4F3F4C99CABA0D98A8E5F2BE15E2AAC7CED0940EF82" },
|
||||
{ 0x08, "40110510EE17B0A300E2BB27441F266843EDB541BAC1077AC203CF18ABB7800F8F0E259495F80D863C49C4EE7E9FB1FE03488A140C7CD5A54CE148C8CE22B00783" },
|
||||
{ 0x0A, "40B11C71D4EA2C13C9AB2E501C6085FEC87FF3B88BFD783EAC43351E1B10F65AD31C79C1268F75051DC8FC008EBF593AE5912E8B653975C13127E2B60A0BEF5FEF" },
|
||||
{ 0, 0 }};
|
||||
|
||||
struct privkeyinfo {
|
||||
unsigned long id;
|
||||
const char* n;
|
||||
const char* p;
|
||||
const char* q;
|
||||
const char* d;
|
||||
} known_priv_keys[] =
|
||||
{{ 0x0104, "40AD2431DA2297E4175EAC61A3154FA3D847115794DD330AB7FF36BA59FEDA195FEA7C16743BD7BCED8A0DA885E5E5C34D5BF20D0AB3EF9181ED39BA2C4D898E87",
|
||||
"205B2E54E9B5C1FE26CE93261478D3873F3FC41BFFF1F5F934D7A5793A43C1C21C", "2197F7707B94079B73858720BF6D4909AB3BEDA1BA9B93112B041340A16ED597B604", 0 },
|
||||
{ 0x05, "406BABF27E9BF1826FD46CBF934E3360EF1F1D3D09D6C74E9DF78049D01A42F584BD383A10E64330C2EE6F1B1C5162789E91E94677900F85D98E7D99F49B30A2BF",
|
||||
/* "20F59BA0274F1CA6231A882B053AAD9A2B80EBE9D2B6E9FD1CDCFCE1AD9D9414D3", "20DFED657A28DE2BFF75DE4F1AEBB7555859779DA38A671B7C76F81B50F02A6AE8", */
|
||||
0, 0, "40E131D6636091E0F0EB3F6444FA2DABB7744FD4DDCF54018AD906C38A0789180D05C7A9275A9149819B05F279F357CEF3A0C53855AF90992572E0F09E3DC2B970" },
|
||||
{ 0, 0, 0, 0, 0 }};
|
||||
112
tool/rabbitsign-src/cmdline.c
Normal file
112
tool/rabbitsign-src/cmdline.c
Normal file
|
|
@ -0,0 +1,112 @@
|
|||
/*
|
||||
* RabbitSign - Tools for signing TI graphing calculator software
|
||||
* Copyright (C) 2009 Benjamin Moody
|
||||
*
|
||||
* This program 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.
|
||||
*
|
||||
* This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
# include <config.h>
|
||||
#endif
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#ifdef HAVE_STRING_H
|
||||
# include <string.h>
|
||||
#else
|
||||
# ifdef HAVE_STRINGS_H
|
||||
# include <strings.h>
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#include "rabbitsign.h"
|
||||
#include "internal.h"
|
||||
|
||||
#if !defined(strchr) && !defined(HAVE_STRCHR) && defined(HAVE_INDEX)
|
||||
# define strchr index
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Parse and return next command line option.
|
||||
*/
|
||||
int rs_parse_cmdline(int argc, char** argv, const char* optstring,
|
||||
int* i, int* j, const char** arg)
|
||||
{
|
||||
char c;
|
||||
char* p;
|
||||
|
||||
if (*i >= argc)
|
||||
return RS_CMDLINE_FINISHED;
|
||||
|
||||
if (argv[*i][0] != '-' || argv[*i][1] == 0) {
|
||||
*arg = argv[*i];
|
||||
(*i)++;
|
||||
*j = 1;
|
||||
return RS_CMDLINE_FILENAME;
|
||||
}
|
||||
|
||||
if (argv[*i][1] == '-') {
|
||||
if (!strcasecmp(argv[*i], "--help")) {
|
||||
(*i)++;
|
||||
*j = 1;
|
||||
return RS_CMDLINE_HELP;
|
||||
}
|
||||
else if (!strcasecmp(argv[*i], "--version")) {
|
||||
(*i)++;
|
||||
*j = 1;
|
||||
return RS_CMDLINE_VERSION;
|
||||
}
|
||||
else {
|
||||
rs_error(NULL, NULL, "unrecognized option %s (try --help)", argv[*i]);
|
||||
return RS_CMDLINE_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
c = argv[*i][*j];
|
||||
|
||||
if (c == ':' || !(p = strchr(optstring, c))) {
|
||||
rs_error(NULL, NULL, "unrecognized option -%c (try --help)", c);
|
||||
return RS_CMDLINE_ERROR;
|
||||
}
|
||||
|
||||
if (p[1] == ':') {
|
||||
if (argv[*i][*j + 1]) {
|
||||
*arg = &argv[*i][*j + 1];
|
||||
(*i)++;
|
||||
*j = 1;
|
||||
return c;
|
||||
}
|
||||
else {
|
||||
(*i) += 2;
|
||||
*j = 1;
|
||||
if (*i > argc) {
|
||||
rs_error(NULL, NULL, "-%c: requires an argument", c);
|
||||
return RS_CMDLINE_ERROR;
|
||||
}
|
||||
*arg = argv[*i - 1];
|
||||
return c;
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (argv[*i][*j + 1]) {
|
||||
(*j)++;
|
||||
}
|
||||
else {
|
||||
(*i)++;
|
||||
*j = 1;
|
||||
}
|
||||
*arg = NULL;
|
||||
return c;
|
||||
}
|
||||
}
|
||||
131
tool/rabbitsign-src/error.c
Normal file
131
tool/rabbitsign-src/error.c
Normal file
|
|
@ -0,0 +1,131 @@
|
|||
/*
|
||||
* RabbitSign - Tools for signing TI graphing calculator software
|
||||
* Copyright (C) 2009 Benjamin Moody
|
||||
*
|
||||
* This program 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.
|
||||
*
|
||||
* This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
# include <config.h>
|
||||
#endif
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdarg.h>
|
||||
|
||||
#ifdef HAVE_STRING_H
|
||||
# include <string.h>
|
||||
#else
|
||||
# ifdef HAVE_STRINGS_H
|
||||
# include <strings.h>
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#include "rabbitsign.h"
|
||||
#include "internal.h"
|
||||
|
||||
static const char* progname;
|
||||
static int verbose;
|
||||
static RSMessageFunc errorfunc, messagefunc;
|
||||
static void *errorfuncdata, *messagefuncdata;
|
||||
|
||||
void rs_set_progname(s)
|
||||
const char* s;
|
||||
{
|
||||
progname = s;
|
||||
}
|
||||
|
||||
void rs_set_verbose(v)
|
||||
int v;
|
||||
{
|
||||
verbose = v;
|
||||
}
|
||||
|
||||
void rs_set_error_func(RSMessageFunc func, void* data)
|
||||
{
|
||||
errorfunc = func;
|
||||
errorfuncdata = data;
|
||||
}
|
||||
|
||||
void rs_set_message_func(RSMessageFunc func, void* data)
|
||||
{
|
||||
messagefunc = func;
|
||||
messagefuncdata = data;
|
||||
}
|
||||
|
||||
static void print_message(const RSKey* key, const RSProgram* prgm,
|
||||
const char* msg)
|
||||
{
|
||||
if (prgm && prgm->filename)
|
||||
fprintf(stderr, "%s: ", prgm->filename);
|
||||
else if (key && key->filename)
|
||||
fprintf(stderr, "%s: ", key->filename);
|
||||
else if (progname)
|
||||
fprintf(stderr, "%s: ", progname);
|
||||
fputs(msg, stderr);
|
||||
fputc('\n', stderr);
|
||||
}
|
||||
|
||||
/* Display a critical error */
|
||||
void rs_error(const RSKey* key, const RSProgram* prgm, const char* fmt, ...)
|
||||
{
|
||||
char msg[512];
|
||||
va_list ap;
|
||||
|
||||
va_start(ap, fmt);
|
||||
strcpy(msg, "error: ");
|
||||
rs_vsnprintf(msg + 7, sizeof(msg) - 7, fmt, ap);
|
||||
va_end(ap);
|
||||
|
||||
if (errorfunc)
|
||||
(*errorfunc)(key, prgm, msg, errorfuncdata);
|
||||
else
|
||||
print_message(key, prgm, msg);
|
||||
}
|
||||
|
||||
/* Display a warning message */
|
||||
void rs_warning(const RSKey* key, const RSProgram* prgm, const char* fmt, ...)
|
||||
{
|
||||
char msg[512];
|
||||
va_list ap;
|
||||
|
||||
va_start(ap, fmt);
|
||||
strcpy(msg, "warning: ");
|
||||
rs_vsnprintf(msg + 9, sizeof(msg) - 9, fmt, ap);
|
||||
va_end(ap);
|
||||
|
||||
if (errorfunc)
|
||||
(*errorfunc)(key, prgm, msg, errorfuncdata);
|
||||
else
|
||||
print_message(key, prgm, msg);
|
||||
}
|
||||
|
||||
/* Display an informative message */
|
||||
void rs_message(int level, const RSKey* key, const RSProgram* prgm,
|
||||
const char* fmt, ...)
|
||||
{
|
||||
char msg[512];
|
||||
va_list ap;
|
||||
|
||||
if (level > verbose)
|
||||
return;
|
||||
|
||||
va_start(ap, fmt);
|
||||
rs_vsnprintf(msg, sizeof(msg), fmt, ap);
|
||||
va_end(ap);
|
||||
|
||||
if (messagefunc)
|
||||
(*messagefunc)(key, prgm, msg, messagefuncdata);
|
||||
else
|
||||
print_message(key, prgm, msg);
|
||||
}
|
||||
118
tool/rabbitsign-src/graphlink.c
Normal file
118
tool/rabbitsign-src/graphlink.c
Normal file
|
|
@ -0,0 +1,118 @@
|
|||
/*
|
||||
* RabbitSign - Tools for signing TI graphing calculator software
|
||||
* Copyright (C) 2009 Benjamin Moody
|
||||
*
|
||||
* This program 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.
|
||||
*
|
||||
* This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
# include <config.h>
|
||||
#endif
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#ifdef HAVE_STRING_H
|
||||
# include <string.h>
|
||||
#else
|
||||
# ifdef HAVE_STRINGS_H
|
||||
# include <strings.h>
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#ifdef TIME_WITH_SYS_TIME
|
||||
# include <sys/time.h>
|
||||
# include <time.h>
|
||||
#else
|
||||
# ifdef TM_IN_SYS_TIME
|
||||
# include <sys/time.h>
|
||||
# else
|
||||
# include <time.h>
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#include "rabbitsign.h"
|
||||
#include "internal.h"
|
||||
|
||||
#define BCD(x) ((x) + 6 * ((x)/10))
|
||||
|
||||
/*
|
||||
* Write a TIFL header to a file.
|
||||
*/
|
||||
int rs_write_tifl_header(FILE* outfile, /* file to write to */
|
||||
int is_hex, /* is file in hex format? */
|
||||
int major, /* major version # */
|
||||
int minor, /* minor version # */
|
||||
int month, /* current month */
|
||||
int day, /* current day */
|
||||
int year, /* current year */
|
||||
const char* name, /* name of program */
|
||||
int calctype, /* calculator type */
|
||||
int datatype, /* data type */
|
||||
unsigned long filesize) /* size of data */
|
||||
{
|
||||
unsigned char buf[78];
|
||||
time_t t;
|
||||
struct tm* tm;
|
||||
|
||||
memset(buf, 0, 78);
|
||||
|
||||
strcpy((char*) buf, "**TIFL**");
|
||||
|
||||
buf[8] = major;
|
||||
buf[9] = minor;
|
||||
|
||||
if (is_hex) {
|
||||
buf[10] = 0x01;
|
||||
buf[11] = 0x88;
|
||||
}
|
||||
else {
|
||||
buf[10] = 0;
|
||||
buf[11] = 0;
|
||||
}
|
||||
|
||||
if (!month && !day && !year) {
|
||||
time(&t);
|
||||
tm = localtime(&t);
|
||||
month = tm->tm_mon + 1;
|
||||
day = tm->tm_mday;
|
||||
year = tm->tm_year + 1900;
|
||||
}
|
||||
|
||||
buf[12] = BCD(month);
|
||||
buf[13] = BCD(day);
|
||||
buf[14] = BCD(year / 100);
|
||||
buf[15] = BCD(year % 100);
|
||||
|
||||
buf[16] = strlen(name);
|
||||
if (buf[16] > 8)
|
||||
buf[16] = 8;
|
||||
|
||||
strncpy((char*) buf + 17, name, 8);
|
||||
|
||||
buf[48] = calctype;
|
||||
buf[49] = datatype;
|
||||
|
||||
buf[74] = filesize & 0xff;
|
||||
buf[75] = (filesize >> 8) & 0xff;
|
||||
buf[76] = (filesize >> 16) & 0xff;
|
||||
buf[77] = (filesize >> 24) & 0xff;
|
||||
|
||||
if (fwrite(buf, 1, 78, outfile) != 78) {
|
||||
rs_error(NULL, NULL, "file I/O error");
|
||||
return RS_ERR_FILE_IO;
|
||||
}
|
||||
|
||||
return RS_SUCCESS;
|
||||
}
|
||||
|
||||
169
tool/rabbitsign-src/header.c
Normal file
169
tool/rabbitsign-src/header.c
Normal file
|
|
@ -0,0 +1,169 @@
|
|||
/*
|
||||
* RabbitSign - Tools for signing TI graphing calculator software
|
||||
* Copyright (C) 2009 Benjamin Moody
|
||||
*
|
||||
* This program 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.
|
||||
*
|
||||
* This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
# include <config.h>
|
||||
#endif
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#include "rabbitsign.h"
|
||||
#include "internal.h"
|
||||
|
||||
/*
|
||||
* Get length of a header field.
|
||||
*/
|
||||
void rs_get_field_size (const unsigned char* data, /* Data */
|
||||
unsigned long* fieldstart, /* Offset to start
|
||||
of field
|
||||
contents */
|
||||
unsigned long* fieldsize) /* Length of field
|
||||
contents */
|
||||
{
|
||||
switch (data[1] & 0x0f) {
|
||||
case 0x0D:
|
||||
if (fieldstart) *fieldstart = 3;
|
||||
if (fieldsize) *fieldsize = data[2];
|
||||
break;
|
||||
|
||||
case 0x0E:
|
||||
if (fieldstart) *fieldstart = 4;
|
||||
if (fieldsize) *fieldsize = ((data[2] << 8) | data[3]);
|
||||
break;
|
||||
|
||||
case 0x0F:
|
||||
if (fieldstart) *fieldstart = 6;
|
||||
if (fieldsize) {
|
||||
*fieldsize = (((unsigned long) data[2] << 24)
|
||||
| ((unsigned long) data[3] << 16)
|
||||
| ((unsigned long) data[4] << 8)
|
||||
| (unsigned long) data[5]);
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
if (fieldstart) *fieldstart = 2;
|
||||
if (fieldsize) *fieldsize = (data[1] & 0x0f);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* Set length of a header field. */
|
||||
int rs_set_field_size (unsigned char* data,
|
||||
unsigned long fieldsize)
|
||||
{
|
||||
switch (data[1] & 0x0f) {
|
||||
case 0x0D:
|
||||
if (fieldsize > 0xff)
|
||||
return -1;
|
||||
data[2] = fieldsize;
|
||||
return 0;
|
||||
|
||||
case 0x0E:
|
||||
if (fieldsize > 0xfffful)
|
||||
return -1;
|
||||
data[2] = (fieldsize >> 8) & 0xff;
|
||||
data[3] = fieldsize & 0xff;
|
||||
return 0;
|
||||
|
||||
case 0x0F:
|
||||
if (fieldsize > 0xfffffffful)
|
||||
return -1;
|
||||
data[2] = (fieldsize >> 24) & 0xff;
|
||||
data[3] = (fieldsize >> 16) & 0xff;
|
||||
data[4] = (fieldsize >> 8) & 0xff;
|
||||
data[5] = fieldsize & 0xff;
|
||||
return 0;
|
||||
|
||||
default:
|
||||
if (fieldsize > 0x0C)
|
||||
return -1;
|
||||
data[1] = (data[1] & 0xf0) | fieldsize;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Find a given header field in the data.
|
||||
*/
|
||||
int rs_find_app_field(unsigned int type, /* Type of field to
|
||||
search for (e.g.,
|
||||
0x8040 to search
|
||||
for the name) */
|
||||
const unsigned char* data, /* Data to search */
|
||||
unsigned long length, /* Maximum length of
|
||||
data to search */
|
||||
unsigned long* fieldhead, /* Offset to field
|
||||
type bytes, if
|
||||
found */
|
||||
unsigned long* fieldstart, /* Offset to start of
|
||||
field contents, if
|
||||
found */
|
||||
unsigned long* fieldsize) /* Length of field
|
||||
contents, if
|
||||
found */
|
||||
{
|
||||
unsigned char b1, b2;
|
||||
unsigned long pos = 0;
|
||||
unsigned long fstart, fsize;
|
||||
|
||||
b1 = ((type >> 8) & 0xff);
|
||||
b2 = (type & 0xf0);
|
||||
|
||||
while (pos < length) {
|
||||
if (data[pos] == b1 && (data[pos + 1] & 0xf0) == b2) {
|
||||
rs_get_field_size(data + pos, &fstart, fieldsize);
|
||||
if (fieldhead) *fieldhead = pos;
|
||||
if (fieldstart) *fieldstart = pos + fstart;
|
||||
return 0;
|
||||
}
|
||||
|
||||
rs_get_field_size(data + pos, &fstart, &fsize);
|
||||
pos += fstart + fsize;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Get value of a numeric header field.
|
||||
*
|
||||
* Return 0 if field is not found, or if its contents are longer than
|
||||
* 4 bytes.
|
||||
*/
|
||||
unsigned long rs_get_numeric_field (unsigned int type,
|
||||
const unsigned char* data,
|
||||
unsigned long length)
|
||||
{
|
||||
unsigned long fstart, fsize, value;
|
||||
|
||||
if (rs_find_app_field(type, data, length, NULL, &fstart, &fsize))
|
||||
return 0;
|
||||
|
||||
if (fsize > 4)
|
||||
return 0;
|
||||
|
||||
value = 0;
|
||||
while (fsize > 0) {
|
||||
value <<= 8;
|
||||
value |= data[fstart];
|
||||
fstart++;
|
||||
fsize--;
|
||||
}
|
||||
return value;
|
||||
}
|
||||
520
tool/rabbitsign-src/input.c
Normal file
520
tool/rabbitsign-src/input.c
Normal file
|
|
@ -0,0 +1,520 @@
|
|||
/*
|
||||
* RabbitSign - Tools for signing TI graphing calculator software
|
||||
* Copyright (C) 2009 Benjamin Moody
|
||||
*
|
||||
* This program 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.
|
||||
*
|
||||
* This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
# include <config.h>
|
||||
#endif
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#ifdef HAVE_STRING_H
|
||||
# include <string.h>
|
||||
#else
|
||||
# ifdef HAVE_STRINGS_H
|
||||
# include <strings.h>
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#include "rabbitsign.h"
|
||||
#include "internal.h"
|
||||
|
||||
/*
|
||||
* Determine the type of an unknown program, if possible.
|
||||
*/
|
||||
static void guess_type(RSProgram* prgm, int is_hex)
|
||||
{
|
||||
const unsigned char* hdr;
|
||||
unsigned long hdrstart, hdrsize, keyid, fieldstart, fieldsize;
|
||||
|
||||
/* Z80 OSes have a detached program header */
|
||||
|
||||
if (prgm->header_length > 2 && prgm->header[0] == 0x80) {
|
||||
rs_get_field_size(prgm->header, &hdrstart, NULL);
|
||||
hdr = prgm->header + hdrstart;
|
||||
hdrsize = prgm->header_length - hdrstart;
|
||||
keyid = rs_get_numeric_field(0x8010, hdr, hdrsize);
|
||||
|
||||
prgm->datatype = RS_DATA_OS;
|
||||
|
||||
if ((keyid & 0xff) == 0x02) {
|
||||
prgm->calctype = RS_CALC_TI73;
|
||||
}
|
||||
else {
|
||||
prgm->calctype = RS_CALC_TI83P;
|
||||
}
|
||||
}
|
||||
else if (prgm->length > 2) {
|
||||
rs_get_field_size(prgm->data, &hdrstart, NULL);
|
||||
hdr = prgm->data + hdrstart;
|
||||
hdrsize = prgm->length - hdrstart;
|
||||
if (hdrsize > 128)
|
||||
hdrsize = 128;
|
||||
|
||||
/* Z80 apps and 68k OSes have field type 0x8000 */
|
||||
|
||||
if (prgm->data[0] == 0x80 && (prgm->data[1] & 0xf0) == 0x00) {
|
||||
keyid = rs_get_numeric_field(0x8010, hdr, hdrsize);
|
||||
|
||||
switch (keyid & 0xff) {
|
||||
case 0x02:
|
||||
prgm->calctype = RS_CALC_TI73;
|
||||
prgm->datatype = RS_DATA_APP;
|
||||
break;
|
||||
|
||||
case 0x04:
|
||||
case 0x0A:
|
||||
prgm->calctype = RS_CALC_TI83P;
|
||||
prgm->datatype = RS_DATA_APP;
|
||||
break;
|
||||
|
||||
case 0x03:
|
||||
case 0x09:
|
||||
prgm->calctype = RS_CALC_TI89;
|
||||
prgm->datatype = RS_DATA_OS;
|
||||
break;
|
||||
|
||||
case 0x01:
|
||||
case 0x08:
|
||||
prgm->calctype = RS_CALC_TI92P;
|
||||
prgm->datatype = RS_DATA_OS;
|
||||
break;
|
||||
|
||||
default:
|
||||
if (is_hex) {
|
||||
prgm->calctype = RS_CALC_TI83P;
|
||||
prgm->datatype = RS_DATA_APP;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* 68k apps have field type 0x8100 */
|
||||
|
||||
else if (prgm->data[0] == 0x81 && (prgm->data[1] & 0xf0) == 0x00) {
|
||||
keyid = rs_get_numeric_field(0x8110, hdr, hdrsize);
|
||||
prgm->datatype = RS_DATA_APP;
|
||||
|
||||
switch (keyid & 0xff) {
|
||||
case 0x03:
|
||||
case 0x09:
|
||||
prgm->calctype = RS_CALC_TI89;
|
||||
break;
|
||||
|
||||
case 0x01:
|
||||
case 0x08:
|
||||
prgm->calctype = RS_CALC_TI92P;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* Certificates have field type 0x0300 */
|
||||
|
||||
else if (prgm->data[0] == 0x03 && (prgm->data[1] & 0xf0) == 0x00) {
|
||||
prgm->datatype = RS_DATA_CERT;
|
||||
|
||||
if (!rs_find_app_field(0x0400, hdr, hdrsize,
|
||||
NULL, &fieldstart, &fieldsize)
|
||||
&& fieldsize >= 1) {
|
||||
switch (hdr[fieldstart]) {
|
||||
case 0x02:
|
||||
prgm->calctype = RS_CALC_TI73;
|
||||
break;
|
||||
|
||||
case 0x04:
|
||||
case 0x0A:
|
||||
prgm->calctype = RS_CALC_TI83P;
|
||||
break;
|
||||
|
||||
case 0x03:
|
||||
case 0x09:
|
||||
prgm->calctype = RS_CALC_TI89;
|
||||
break;
|
||||
|
||||
case 0x01:
|
||||
case 0x08:
|
||||
prgm->calctype = RS_CALC_TI92P;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Read the contents of a binary file into an RSProgram.
|
||||
*/
|
||||
static int read_file_binary(RSProgram* prgm,
|
||||
FILE* f,
|
||||
unsigned long filesize)
|
||||
{
|
||||
unsigned char buf[1024];
|
||||
size_t count;
|
||||
|
||||
if (filesize) {
|
||||
while (filesize > 0) {
|
||||
if (filesize > 1024)
|
||||
count = fread(buf, 1, 1024, f);
|
||||
else
|
||||
count = fread(buf, 1, filesize, f);
|
||||
|
||||
if (count > 0)
|
||||
rs_program_append_data(prgm, buf, count);
|
||||
else
|
||||
break;
|
||||
|
||||
filesize -= count;
|
||||
}
|
||||
}
|
||||
else {
|
||||
do {
|
||||
count = fread(buf, 1, 1024, f);
|
||||
if (count > 0) {
|
||||
rs_program_append_data(prgm, buf, count);
|
||||
}
|
||||
} while (count > 0);
|
||||
}
|
||||
|
||||
if (!prgm->calctype || !prgm->datatype)
|
||||
guess_type(prgm, 0);
|
||||
return RS_SUCCESS;
|
||||
}
|
||||
|
||||
/*
|
||||
* Find a given page in the list of page numbers (or add it to the
|
||||
* end.)
|
||||
*/
|
||||
static int getpageidx(RSProgram* prgm, /* program */
|
||||
unsigned int pagenum) /* page number */
|
||||
{
|
||||
int i;
|
||||
unsigned int* array;
|
||||
|
||||
for (i = 0; i < prgm->npagenums; i++)
|
||||
if (prgm->pagenums[i] == pagenum)
|
||||
return i;
|
||||
|
||||
if (!(array = rs_realloc(prgm->pagenums, (i + 1) * sizeof(unsigned int))))
|
||||
return 0;
|
||||
prgm->pagenums = array;
|
||||
prgm->npagenums = i + 1;
|
||||
prgm->pagenums[i] = pagenum;
|
||||
return i;
|
||||
}
|
||||
|
||||
/*
|
||||
* Read an Intel/TI hex file into an RSProgram.
|
||||
*
|
||||
* Note that the first ':' is assumed to have been read already.
|
||||
*/
|
||||
static int read_file_hex(RSProgram* prgm,
|
||||
FILE* f,
|
||||
unsigned int flags)
|
||||
{
|
||||
int c;
|
||||
unsigned int nbytes, addr, rectype, sum, i, b, value;
|
||||
unsigned int pagenum = 0, pageidx = 0, lastaddr = 0;
|
||||
unsigned long offset;
|
||||
unsigned char data[256];
|
||||
unsigned char* sigp;
|
||||
int nparts = 0;
|
||||
int possibly_os_header = 1;
|
||||
|
||||
rs_free(prgm->pagenums);
|
||||
if (!(prgm->pagenums = rs_malloc(sizeof(unsigned int))))
|
||||
return RS_ERR_OUT_OF_MEMORY;
|
||||
prgm->pagenums[0] = 0;
|
||||
prgm->npagenums = 1;
|
||||
|
||||
while (!feof(f) && !ferror(f)) {
|
||||
if (3 > fscanf(f, "%2X%4X%2X", &nbytes, &addr, &rectype)) {
|
||||
rs_error(NULL, prgm, "invalid hex data (following %X:%X)",
|
||||
pagenum, lastaddr);
|
||||
return RS_ERR_HEX_SYNTAX;
|
||||
}
|
||||
|
||||
/* Read data bytes */
|
||||
|
||||
sum = nbytes + addr + (addr >> 8) + rectype;
|
||||
value = 0;
|
||||
for (i = 0; i < nbytes; i++) {
|
||||
if (1 > fscanf(f, "%2X", &b)) {
|
||||
rs_error(NULL, prgm, "invalid hex data (at %X:%X)",
|
||||
pagenum, addr);
|
||||
return RS_ERR_HEX_SYNTAX;
|
||||
}
|
||||
data[i] = b;
|
||||
sum += b;
|
||||
value = (value << 8) + b;
|
||||
}
|
||||
|
||||
/* Read checksum */
|
||||
|
||||
c = fgetc(f);
|
||||
if (c == 'X') {
|
||||
c = fgetc(f);
|
||||
if (c != 'X') {
|
||||
rs_error(NULL, prgm, "invalid hex data (at %X:%X)",
|
||||
pagenum, addr);
|
||||
return RS_ERR_HEX_SYNTAX;
|
||||
}
|
||||
}
|
||||
else {
|
||||
ungetc(c, f);
|
||||
if (1 > fscanf(f, "%2X", &b)) {
|
||||
rs_error(NULL, prgm, "invalid hex data (at %X:%X)",
|
||||
pagenum, addr);
|
||||
return RS_ERR_HEX_SYNTAX;
|
||||
}
|
||||
sum += b;
|
||||
if (sum & 0xff)
|
||||
rs_warning(NULL, prgm, "incorrect checksum (at %X:%X)",
|
||||
pagenum, addr);
|
||||
}
|
||||
|
||||
if (rectype == 0 && nbytes > 0) {
|
||||
/* Record type 0: program data */
|
||||
|
||||
if (addr & 0xff00)
|
||||
possibly_os_header = 0;
|
||||
|
||||
addr &= 0x3fff;
|
||||
|
||||
/* if program does not start at addr 0000 (or 4000), assume
|
||||
unsorted */
|
||||
if (addr && prgm->length == 0)
|
||||
flags &= ~RS_INPUT_SORTED;
|
||||
|
||||
if ((flags & RS_INPUT_SORTED) && !addr && lastaddr) {
|
||||
/* automatically switch to next page */
|
||||
pagenum++;
|
||||
pageidx = getpageidx(prgm, pagenum);
|
||||
if (!pageidx)
|
||||
return RS_ERR_OUT_OF_MEMORY;
|
||||
}
|
||||
else if (addr < lastaddr)
|
||||
flags &= ~RS_INPUT_SORTED;
|
||||
|
||||
if (nparts == 2 && prgm->header_length) {
|
||||
/* Reading an OS signature */
|
||||
if (addr + nbytes > prgm->signature_length) {
|
||||
if (!(sigp = rs_realloc(prgm->signature, addr + nbytes)))
|
||||
return RS_ERR_OUT_OF_MEMORY;
|
||||
|
||||
prgm->signature = sigp;
|
||||
if (addr > prgm->signature_length) {
|
||||
memset(prgm->signature + prgm->signature_length, 0xff,
|
||||
addr - prgm->signature_length);
|
||||
}
|
||||
prgm->signature_length = addr + nbytes;
|
||||
}
|
||||
memcpy(prgm->signature + addr, data, nbytes);
|
||||
}
|
||||
else {
|
||||
/* Reading normal program data */
|
||||
offset = ((unsigned long) pageidx << 14) | addr;
|
||||
if (offset + nbytes <= prgm->length) {
|
||||
memcpy(prgm->data + offset, data, nbytes);
|
||||
}
|
||||
else {
|
||||
rs_program_set_length(prgm, offset);
|
||||
rs_program_append_data(prgm, data, nbytes);
|
||||
}
|
||||
}
|
||||
|
||||
lastaddr = addr;
|
||||
}
|
||||
else if (rectype == 1) {
|
||||
/* Record type 1: "end of file" */
|
||||
nparts++;
|
||||
if (nparts == 3 && prgm->header_length)
|
||||
break;
|
||||
}
|
||||
else if (rectype == 2 || rectype == 4) {
|
||||
/* Record type 2 or 4: extended address */
|
||||
possibly_os_header = 0;
|
||||
flags &= ~RS_INPUT_SORTED;
|
||||
if (nparts < 2) {
|
||||
pagenum = value;
|
||||
pageidx = getpageidx(prgm, pagenum);
|
||||
if (pagenum && !pageidx)
|
||||
return RS_ERR_OUT_OF_MEMORY;
|
||||
}
|
||||
}
|
||||
|
||||
do {
|
||||
c = fgetc(f);
|
||||
} while (c == '\n' || c == '\r' || c == ' ');
|
||||
|
||||
if (c == EOF)
|
||||
break;
|
||||
else if (c != ':') {
|
||||
if (rectype == 1)
|
||||
break;
|
||||
else {
|
||||
rs_error(NULL, prgm, "invalid hex data (following %X:%X)",
|
||||
pagenum, lastaddr);
|
||||
return RS_ERR_HEX_SYNTAX;
|
||||
}
|
||||
}
|
||||
|
||||
if (rectype == 1 && nparts == 1 && prgm->length > 0
|
||||
&& possibly_os_header) {
|
||||
/* Just finished reading OS header */
|
||||
flags &= ~RS_INPUT_SORTED;
|
||||
pagenum = pageidx = 0;
|
||||
|
||||
rs_free(prgm->header);
|
||||
if (!(prgm->header = rs_malloc(prgm->length)))
|
||||
return RS_ERR_OUT_OF_MEMORY;
|
||||
|
||||
memcpy(prgm->header, prgm->data, prgm->length);
|
||||
prgm->header_length = prgm->length;
|
||||
prgm->length = 0;
|
||||
possibly_os_header = 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (!prgm->calctype || !prgm->datatype)
|
||||
guess_type(prgm, 1);
|
||||
return RS_SUCCESS;
|
||||
}
|
||||
|
||||
/*
|
||||
* Check if calc/data type matches expected type (or any recognized
|
||||
* type, if none was specified.)
|
||||
*/
|
||||
static int check_tifl_type(int calctype,
|
||||
int datatype,
|
||||
int calctype_expected,
|
||||
int datatype_expected)
|
||||
{
|
||||
if (calctype_expected) {
|
||||
if (calctype_expected != calctype)
|
||||
return 0;
|
||||
}
|
||||
else {
|
||||
if (calctype != RS_CALC_TI73 && calctype != RS_CALC_TI83P
|
||||
&& calctype != RS_CALC_TI89 && calctype != RS_CALC_TI92P)
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (datatype_expected) {
|
||||
if (datatype_expected != datatype)
|
||||
return 0;
|
||||
}
|
||||
else {
|
||||
if (datatype != RS_DATA_APP && datatype != RS_DATA_OS)
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Read program contents from a file.
|
||||
*
|
||||
* Various file formats are supported:
|
||||
*
|
||||
* - Raw binary (must begin with the value 0x80 or 0x81)
|
||||
* - Plain Intel/TI hex
|
||||
* - Binary TIFL (89k, 89u, ...)
|
||||
* - Hex TIFL (8xk, 8xu, ...)
|
||||
*
|
||||
* Note: on platforms where it matters, all input files must be opened
|
||||
* in "binary" mode.
|
||||
*/
|
||||
int rs_read_program_file(RSProgram* prgm, /* program */
|
||||
FILE* f, /* file */
|
||||
const char* fname, /* file name */
|
||||
unsigned int flags) /* option flags */
|
||||
{
|
||||
int c;
|
||||
unsigned char tiflbuf[78];
|
||||
unsigned long tiflsize, i;
|
||||
int e;
|
||||
|
||||
rs_program_set_length(prgm, 0);
|
||||
prgm->header_length = 0;
|
||||
prgm->signature_length = 0;
|
||||
prgm->npagenums = 0;
|
||||
|
||||
rs_free(prgm->filename);
|
||||
prgm->filename = rs_strdup(fname);
|
||||
if (fname && !prgm->filename)
|
||||
return RS_ERR_OUT_OF_MEMORY;
|
||||
|
||||
if (flags & RS_INPUT_BINARY)
|
||||
return read_file_binary(prgm, f, 0);
|
||||
|
||||
c = fgetc(f);
|
||||
if (c == 0x80 || c == 0x81) {
|
||||
tiflbuf[0] = c;
|
||||
if ((e = rs_program_append_data(prgm, tiflbuf, 1)))
|
||||
return e;
|
||||
return read_file_binary(prgm, f, 0);
|
||||
}
|
||||
|
||||
while (!feof(f) && !ferror(f)) {
|
||||
if (c == ':') {
|
||||
return read_file_hex(prgm, f, flags);
|
||||
}
|
||||
else if (c == '*') {
|
||||
if (fread(tiflbuf, 1, 78, f) < 78
|
||||
|| strncmp((char*) tiflbuf, "*TIFL**", 7)) {
|
||||
rs_error(NULL, prgm, "unknown input file format");
|
||||
return RS_ERR_UNKNOWN_FILE_FORMAT;
|
||||
}
|
||||
|
||||
tiflsize = ((unsigned long) tiflbuf[73]
|
||||
| ((unsigned long) tiflbuf[74] << 8)
|
||||
| ((unsigned long) tiflbuf[75] << 16)
|
||||
| ((unsigned long) tiflbuf[76] << 24));
|
||||
|
||||
if (check_tifl_type(tiflbuf[47], tiflbuf[48],
|
||||
prgm->calctype, prgm->datatype)) {
|
||||
prgm->calctype = tiflbuf[47];
|
||||
prgm->datatype = tiflbuf[48];
|
||||
|
||||
if (tiflbuf[77] == ':')
|
||||
return read_file_hex(prgm, f, 0);
|
||||
else {
|
||||
if ((e = rs_program_append_data(prgm, tiflbuf + 77, 1)))
|
||||
return e;
|
||||
return read_file_binary(prgm, f, tiflsize ? tiflsize - 1 : 0);
|
||||
}
|
||||
}
|
||||
else {
|
||||
/* extra data (license, certificate, etc.) -- ignore */
|
||||
if (fseek(f, tiflsize - 1, SEEK_CUR)) {
|
||||
for (i = 0; i < tiflsize - 1; i++) {
|
||||
if (fgetc(f) == EOF) {
|
||||
rs_error(NULL, prgm, "unexpected EOF");
|
||||
return RS_ERR_UNKNOWN_FILE_FORMAT;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
c = fgetc(f);
|
||||
}
|
||||
|
||||
rs_error(NULL, prgm, "unknown input file format");
|
||||
return RS_ERR_UNKNOWN_FILE_FORMAT;
|
||||
}
|
||||
|
||||
111
tool/rabbitsign-src/internal.h
Normal file
111
tool/rabbitsign-src/internal.h
Normal file
|
|
@ -0,0 +1,111 @@
|
|||
/*
|
||||
* RabbitSign - Tools for signing TI graphing calculator software
|
||||
* Copyright (C) 2009 Benjamin Moody
|
||||
*
|
||||
* This program 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.
|
||||
*
|
||||
* This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef __RABBITSIGN_INTERNAL_H__
|
||||
#define __RABBITSIGN_INTERNAL_H__
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**** Memory management (mem.c) ****/
|
||||
|
||||
#define rs_malloc(nnn) rs_realloc(0, (nnn))
|
||||
#define rs_free(ppp) rs_realloc((ppp), 0)
|
||||
void* rs_realloc (void* ptr, unsigned long count) RS_ATTR_MALLOC;
|
||||
char* rs_strdup (const char* str) RS_ATTR_MALLOC;
|
||||
|
||||
|
||||
/**** Rabin signature functions (rabin.c) ****/
|
||||
|
||||
/* Compute a Rabin signature and the useful value of f. */
|
||||
RSStatus rs_sign_rabin (mpz_t res, int* f, const mpz_t hash,
|
||||
int rootnum, RSKey* key);
|
||||
|
||||
/* Check that the given Rabin signature is valid. */
|
||||
RSStatus rs_validate_rabin (const mpz_t sig, int f, const mpz_t hash,
|
||||
const RSKey* key);
|
||||
|
||||
|
||||
/**** RSA signature functions (rsa.c) ****/
|
||||
|
||||
/* Compute an RSA signature. */
|
||||
RSStatus rs_sign_rsa (mpz_t res, const mpz_t hash, RSKey* key);
|
||||
|
||||
/* Check that the given RSA signature is valid. */
|
||||
RSStatus rs_validate_rsa (const mpz_t sig, const mpz_t hash,
|
||||
const RSKey* key);
|
||||
|
||||
|
||||
/**** TIFL file output (graphlink.c) ****/
|
||||
|
||||
/* Write TIFL header to a file. */
|
||||
RSStatus rs_write_tifl_header (FILE* f, int is_hex, int major, int minor,
|
||||
int month, int day, int year,
|
||||
const char* name, int calctype, int datatype,
|
||||
unsigned long filesize);
|
||||
|
||||
|
||||
/**** Type <-> string conversions (typestr.c) ****/
|
||||
|
||||
/* Get default file suffix for a given calc/data type. */
|
||||
const char* rs_type_to_suffix (RSCalcType calctype, RSDataType datatype,
|
||||
int hexonly);
|
||||
|
||||
/* Get implied calc/data type for a given file suffix. */
|
||||
int rs_suffix_to_type (const char* suff, RSCalcType* calctype,
|
||||
RSDataType* datatype);
|
||||
|
||||
/* Get a human-readable description of a calculator type. */
|
||||
const char* rs_calc_type_to_string (RSCalcType calctype);
|
||||
|
||||
/* Get a human-readable description of a data type. */
|
||||
const char* rs_data_type_to_string (RSDataType datatype);
|
||||
|
||||
|
||||
/**** Command line option parsing (cmdline.c) ****/
|
||||
|
||||
#define RS_CMDLINE_FINISHED 0
|
||||
#define RS_CMDLINE_FILENAME '#'
|
||||
#define RS_CMDLINE_HELP '!'
|
||||
#define RS_CMDLINE_VERSION '@'
|
||||
#define RS_CMDLINE_ERROR '?'
|
||||
|
||||
int rs_parse_cmdline(int argc, char** argv, const char* optstring,
|
||||
int* i, int* j, const char** arg);
|
||||
|
||||
|
||||
/**** Error/message logging (error.c) ****/
|
||||
|
||||
/* Display an error message */
|
||||
void rs_error (const RSKey* key, const RSProgram* prgm,
|
||||
const char* fmt, ...) RS_ATTR_PRINTF(3,4);
|
||||
|
||||
/* Display a warning message */
|
||||
void rs_warning (const RSKey* key, const RSProgram* prgm,
|
||||
const char* fmt, ...) RS_ATTR_PRINTF(3,4);
|
||||
|
||||
/* Display an informational message */
|
||||
void rs_message (int level, const RSKey* key, const RSProgram* prgm,
|
||||
const char* fmt, ...) /*RS_ATTR_PRINTF(4,5)*/;
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* __RABBITSIGN_INTERNAL_H__ */
|
||||
234
tool/rabbitsign-src/keys.c
Normal file
234
tool/rabbitsign-src/keys.c
Normal file
|
|
@ -0,0 +1,234 @@
|
|||
/*
|
||||
* RabbitSign - Tools for signing TI graphing calculator software
|
||||
* Copyright (C) 2009 Benjamin Moody
|
||||
*
|
||||
* This program 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.
|
||||
*
|
||||
* This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
# include <config.h>
|
||||
#endif
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#ifdef HAVE_STRING_H
|
||||
# include <string.h>
|
||||
#else
|
||||
# ifdef HAVE_STRINGS_H
|
||||
# include <strings.h>
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#include "rabbitsign.h"
|
||||
#include "internal.h"
|
||||
|
||||
/*
|
||||
* Create a new key.
|
||||
*/
|
||||
RSKey* rs_key_new()
|
||||
{
|
||||
RSKey* key = rs_malloc(sizeof(RSKey));
|
||||
|
||||
if (!key)
|
||||
return NULL;
|
||||
|
||||
key->filename = NULL;
|
||||
key->id = 0;
|
||||
mpz_init(key->n);
|
||||
mpz_init(key->p);
|
||||
mpz_init(key->q);
|
||||
mpz_init(key->qinv);
|
||||
mpz_init(key->d);
|
||||
|
||||
return key;
|
||||
}
|
||||
|
||||
/*
|
||||
* Free a key.
|
||||
*/
|
||||
void rs_key_free(RSKey* key)
|
||||
{
|
||||
if (!key)
|
||||
return;
|
||||
|
||||
rs_free(key->filename);
|
||||
mpz_clear(key->n);
|
||||
mpz_clear(key->p);
|
||||
mpz_clear(key->q);
|
||||
mpz_clear(key->qinv);
|
||||
mpz_clear(key->d);
|
||||
rs_free(key);
|
||||
}
|
||||
|
||||
/*
|
||||
* Parse a number written in TI's hexadecimal key format.
|
||||
*/
|
||||
static int parse_value(mpz_t dest, /* mpz to store result */
|
||||
const char* str) /* string to parse */
|
||||
{
|
||||
unsigned int count, b, i;
|
||||
int n;
|
||||
unsigned char buf[256];
|
||||
|
||||
if (1 > sscanf(str, "%2X%n", &count, &n) || n != 2
|
||||
|| (count * 2 + 2) > strlen(str))
|
||||
return 1;
|
||||
|
||||
for (i = 0; i < count; i++) {
|
||||
if (1 > sscanf(str + 2 + 2 * i, "%2X%n", &b, &n) || n != 2)
|
||||
return 1;
|
||||
buf[i] = b;
|
||||
}
|
||||
|
||||
mpz_import(dest, i, -1, 1, 0, 0, buf);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Read key from a file.
|
||||
*
|
||||
* Two formats of key file are supported:
|
||||
*
|
||||
* "Rabin" style (the type used by the TI-83 Plus SDK) consists of
|
||||
* three lines: the public key (n) followed by its two factors (p and
|
||||
* q.)
|
||||
*
|
||||
* "RSA" style (the type used by the TI-89/92 Plus SDK) also consists
|
||||
* of three lines: the key ID, the public key (n), and the signing
|
||||
* exponent (d).
|
||||
*
|
||||
* In either case, if we are only interested in validating signatures,
|
||||
* the private key may be omitted.
|
||||
*
|
||||
* Note that "Rabin" style key files can be used to generate RSA
|
||||
* signatures, but not vice versa.
|
||||
*/
|
||||
int rs_read_key_file(RSKey* key, /* key structure */
|
||||
FILE* f, /* file to read */
|
||||
const char* fname, /* file name */
|
||||
int verify) /* 1 = check key validity */
|
||||
{
|
||||
char buf[1024];
|
||||
mpz_t tmp;
|
||||
|
||||
rs_free(key->filename);
|
||||
key->filename = rs_strdup(fname);
|
||||
if (fname && !key->filename)
|
||||
return RS_ERR_OUT_OF_MEMORY;
|
||||
|
||||
if (!fgets(buf, sizeof(buf), f)) {
|
||||
rs_error(key, NULL, "invalid key file syntax");
|
||||
return RS_ERR_KEY_SYNTAX;
|
||||
}
|
||||
|
||||
if (strlen(buf) < 11) {
|
||||
if (1 > sscanf(buf, "%lX", &key->id)) {
|
||||
rs_error(key, NULL, "invalid key file syntax");
|
||||
return RS_ERR_KEY_SYNTAX;
|
||||
}
|
||||
|
||||
if (!fgets(buf, sizeof(buf), f)
|
||||
|| parse_value(key->n, buf)) {
|
||||
rs_error(key, NULL, "invalid key file syntax");
|
||||
return RS_ERR_KEY_SYNTAX;
|
||||
}
|
||||
|
||||
if (!fgets(buf, sizeof(buf), f)
|
||||
|| parse_value(key->d, buf))
|
||||
mpz_set_ui(key->d, 0);
|
||||
else if (verify) {
|
||||
/* We can't truly verify the key without factoring n (which is
|
||||
possible, given d, but would take a bit of work.) Instead,
|
||||
test the key by performing a single RSA encryption and
|
||||
decryption. */
|
||||
mpz_init(tmp);
|
||||
mpz_set_ui(tmp, 17);
|
||||
mpz_powm(tmp, tmp, tmp, key->n);
|
||||
mpz_powm(tmp, tmp, key->d, key->n);
|
||||
if (mpz_cmp_ui(tmp, 17)) {
|
||||
mpz_clear(tmp);
|
||||
rs_error(key, NULL, "private key incorrect (de != 1 mod phi(n))");
|
||||
return RS_ERR_INVALID_KEY;
|
||||
}
|
||||
mpz_clear(tmp);
|
||||
}
|
||||
|
||||
mpz_set_ui(key->p, 0);
|
||||
mpz_set_ui(key->q, 0);
|
||||
mpz_set_ui(key->qinv, 0);
|
||||
}
|
||||
else {
|
||||
if (parse_value(key->n, buf)) {
|
||||
rs_error(key, NULL, "invalid key file");
|
||||
return RS_ERR_KEY_SYNTAX;
|
||||
}
|
||||
|
||||
if (!fgets(buf, sizeof(buf), f)
|
||||
|| parse_value(key->p, buf)
|
||||
|| !fgets(buf, sizeof(buf), f)
|
||||
|| parse_value(key->q, buf)) {
|
||||
mpz_set_ui(key->p, 0);
|
||||
mpz_set_ui(key->q, 0);
|
||||
}
|
||||
else if (verify) {
|
||||
/* Verify that p * q = n (of course, that doesn't guarantee that
|
||||
these are the only factors of n.) */
|
||||
mpz_init(tmp);
|
||||
mpz_mul(tmp, key->p, key->q);
|
||||
if (mpz_cmp(tmp, key->n)) {
|
||||
mpz_clear(tmp);
|
||||
rs_error(key, NULL, "private key incorrect (pq != n)");
|
||||
return RS_ERR_INVALID_KEY;
|
||||
}
|
||||
mpz_clear(tmp);
|
||||
}
|
||||
|
||||
mpz_set_ui(key->qinv, 0);
|
||||
mpz_set_ui(key->d, 0);
|
||||
key->id = 0;
|
||||
}
|
||||
|
||||
if (mpz_sgn(key->p) && mpz_sgn(key->q)) {
|
||||
rs_message(2, key, NULL, "Loaded Rabin/RSA private key:");
|
||||
rs_message(2, key, NULL, " n = %ZX", key->n);
|
||||
rs_message(2, key, NULL, " p = %ZX", key->p);
|
||||
rs_message(2, key, NULL, " q = %ZX", key->q);
|
||||
}
|
||||
else if (mpz_sgn(key->d)) {
|
||||
rs_message(2, key, NULL, "Loaded RSA private key:");
|
||||
rs_message(2, key, NULL, " n = %ZX", key->n);
|
||||
rs_message(2, key, NULL, " d = %ZX", key->d);
|
||||
}
|
||||
else {
|
||||
rs_message(2, key, NULL, "Loaded public key:");
|
||||
rs_message(2, key, NULL, " n = %ZX", key->n);
|
||||
}
|
||||
|
||||
return RS_SUCCESS;
|
||||
}
|
||||
|
||||
/*
|
||||
* Parse a number written in TI's hexadecimal key format.
|
||||
*/
|
||||
int rs_parse_key_value(mpz_t dest, /* mpz to store result */
|
||||
const char* str) /* string to parse */
|
||||
{
|
||||
if (parse_value(dest, str)) {
|
||||
rs_error(NULL, NULL, "invalid key value syntax");
|
||||
return RS_ERR_KEY_SYNTAX;
|
||||
}
|
||||
else {
|
||||
return RS_SUCCESS;
|
||||
}
|
||||
}
|
||||
419
tool/rabbitsign-src/md5.c
Normal file
419
tool/rabbitsign-src/md5.c
Normal file
|
|
@ -0,0 +1,419 @@
|
|||
/* md5.c - Functions to compute MD5 message digest of files or memory blocks
|
||||
according to the definition of MD5 in RFC 1321 from April 1992.
|
||||
Copyright (C) 1995, 1996 Free Software Foundation, Inc.
|
||||
NOTE: The canonical source of this file is maintained with the GNU C
|
||||
Library. Bugs can be reported to bug-glibc@prep.ai.mit.edu.
|
||||
|
||||
This program 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 2, or (at your option) any
|
||||
later version.
|
||||
|
||||
This program 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 this program; if not, write to the Free Software Foundation,
|
||||
Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
|
||||
|
||||
/* Written by Ulrich Drepper <drepper@gnu.ai.mit.edu>, 1995. */
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
# include <config.h>
|
||||
#endif
|
||||
|
||||
#include <sys/types.h>
|
||||
|
||||
#if STDC_HEADERS || defined _LIBC
|
||||
# include <stdlib.h>
|
||||
# include <string.h>
|
||||
#else
|
||||
# ifndef HAVE_MEMCPY
|
||||
# define memcpy(d, s, n) bcopy ((s), (d), (n))
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#include "md5.h"
|
||||
|
||||
#ifdef _LIBC
|
||||
# include <endian.h>
|
||||
# if __BYTE_ORDER == __BIG_ENDIAN
|
||||
# define WORDS_BIGENDIAN 1
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#ifdef WORDS_BIGENDIAN
|
||||
# define SWAP(n) \
|
||||
(((n) << 24) | (((n) & 0xff00) << 8) | (((n) >> 8) & 0xff00) | ((n) >> 24))
|
||||
#else
|
||||
# define SWAP(n) (n)
|
||||
#endif
|
||||
|
||||
|
||||
/* This array contains the bytes used to pad the buffer to the next
|
||||
64-byte boundary. (RFC 1321, 3.1: Step 1) */
|
||||
static const unsigned char fillbuf[64] = { 0x80, 0 /* , 0, 0, ... */ };
|
||||
|
||||
|
||||
/* Initialize structure containing state of computation.
|
||||
(RFC 1321, 3.3: Step 3) */
|
||||
void
|
||||
md5_init_ctx (ctx)
|
||||
struct md5_ctx *ctx;
|
||||
{
|
||||
ctx->A = 0x67452301;
|
||||
ctx->B = 0xefcdab89;
|
||||
ctx->C = 0x98badcfe;
|
||||
ctx->D = 0x10325476;
|
||||
|
||||
ctx->total[0] = ctx->total[1] = 0;
|
||||
ctx->buflen = 0;
|
||||
}
|
||||
|
||||
/* Put result from CTX in first 16 bytes following RESBUF. The result
|
||||
must be in little endian byte order.
|
||||
|
||||
IMPORTANT: On some systems it is required that RESBUF is correctly
|
||||
aligned for a 32 bits value. */
|
||||
void *
|
||||
md5_read_ctx (ctx, resbuf)
|
||||
const struct md5_ctx *ctx;
|
||||
void *resbuf;
|
||||
{
|
||||
((md5_uint32 *) resbuf)[0] = SWAP (ctx->A);
|
||||
((md5_uint32 *) resbuf)[1] = SWAP (ctx->B);
|
||||
((md5_uint32 *) resbuf)[2] = SWAP (ctx->C);
|
||||
((md5_uint32 *) resbuf)[3] = SWAP (ctx->D);
|
||||
|
||||
return resbuf;
|
||||
}
|
||||
|
||||
/* Process the remaining bytes in the internal buffer and the usual
|
||||
prolog according to the standard and write the result to RESBUF.
|
||||
|
||||
IMPORTANT: On some systems it is required that RESBUF is correctly
|
||||
aligned for a 32 bits value. */
|
||||
void *
|
||||
md5_finish_ctx (ctx, resbuf)
|
||||
struct md5_ctx *ctx;
|
||||
void *resbuf;
|
||||
{
|
||||
/* Take yet unprocessed bytes into account. */
|
||||
md5_uint32 bytes = ctx->buflen;
|
||||
size_t pad;
|
||||
|
||||
/* Now count remaining bytes. */
|
||||
ctx->total[0] += bytes;
|
||||
if (ctx->total[0] < bytes)
|
||||
++ctx->total[1];
|
||||
|
||||
pad = bytes >= 56 ? 64 + 56 - bytes : 56 - bytes;
|
||||
memcpy (&ctx->buffer[bytes], fillbuf, pad);
|
||||
|
||||
/* Put the 64-bit file length in *bits* at the end of the buffer. */
|
||||
*(md5_uint32 *) &ctx->buffer[bytes + pad] = SWAP (ctx->total[0] << 3);
|
||||
*(md5_uint32 *) &ctx->buffer[bytes + pad + 4] = SWAP ((ctx->total[1] << 3) |
|
||||
(ctx->total[0] >> 29));
|
||||
|
||||
/* Process last bytes. */
|
||||
md5_process_block (ctx->buffer, bytes + pad + 8, ctx);
|
||||
|
||||
return md5_read_ctx (ctx, resbuf);
|
||||
}
|
||||
|
||||
/* Compute MD5 message digest for bytes read from STREAM. The
|
||||
resulting message digest number will be written into the 16 bytes
|
||||
beginning at RESBLOCK. */
|
||||
int
|
||||
md5_stream (stream, resblock)
|
||||
FILE *stream;
|
||||
void *resblock;
|
||||
{
|
||||
/* Important: BLOCKSIZE must be a multiple of 64. */
|
||||
#define BLOCKSIZE 4096
|
||||
struct md5_ctx ctx;
|
||||
char buffer[BLOCKSIZE + 72];
|
||||
size_t sum;
|
||||
|
||||
/* Initialize the computation context. */
|
||||
md5_init_ctx (&ctx);
|
||||
|
||||
/* Iterate over full file contents. */
|
||||
while (1)
|
||||
{
|
||||
/* We read the file in blocks of BLOCKSIZE bytes. One call of the
|
||||
computation function processes the whole buffer so that with the
|
||||
next round of the loop another block can be read. */
|
||||
size_t n;
|
||||
sum = 0;
|
||||
|
||||
/* Read block. Take care for partial reads. */
|
||||
do
|
||||
{
|
||||
n = fread (buffer + sum, 1, BLOCKSIZE - sum, stream);
|
||||
|
||||
sum += n;
|
||||
}
|
||||
while (sum < BLOCKSIZE && n != 0);
|
||||
if (n == 0 && ferror (stream))
|
||||
return 1;
|
||||
|
||||
/* If end of file is reached, end the loop. */
|
||||
if (n == 0)
|
||||
break;
|
||||
|
||||
/* Process buffer with BLOCKSIZE bytes. Note that
|
||||
BLOCKSIZE % 64 == 0
|
||||
*/
|
||||
md5_process_block (buffer, BLOCKSIZE, &ctx);
|
||||
}
|
||||
|
||||
/* Add the last bytes if necessary. */
|
||||
if (sum > 0)
|
||||
md5_process_bytes (buffer, sum, &ctx);
|
||||
|
||||
/* Construct result in desired memory. */
|
||||
md5_finish_ctx (&ctx, resblock);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Compute MD5 message digest for LEN bytes beginning at BUFFER. The
|
||||
result is always in little endian byte order, so that a byte-wise
|
||||
output yields to the wanted ASCII representation of the message
|
||||
digest. */
|
||||
void *
|
||||
md5_buffer (buffer, len, resblock)
|
||||
const char *buffer;
|
||||
size_t len;
|
||||
void *resblock;
|
||||
{
|
||||
struct md5_ctx ctx;
|
||||
|
||||
/* Initialize the computation context. */
|
||||
md5_init_ctx (&ctx);
|
||||
|
||||
/* Process whole buffer but last len % 64 bytes. */
|
||||
md5_process_bytes (buffer, len, &ctx);
|
||||
|
||||
/* Put result in desired memory area. */
|
||||
return md5_finish_ctx (&ctx, resblock);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
md5_process_bytes (buffer, len, ctx)
|
||||
const void *buffer;
|
||||
size_t len;
|
||||
struct md5_ctx *ctx;
|
||||
{
|
||||
/* When we already have some bits in our internal buffer concatenate
|
||||
both inputs first. */
|
||||
if (ctx->buflen != 0)
|
||||
{
|
||||
size_t left_over = ctx->buflen;
|
||||
size_t add = 128 - left_over > len ? len : 128 - left_over;
|
||||
|
||||
memcpy (&ctx->buffer[left_over], buffer, add);
|
||||
ctx->buflen += add;
|
||||
|
||||
if (left_over + add > 64)
|
||||
{
|
||||
md5_process_block (ctx->buffer, (left_over + add) & ~63, ctx);
|
||||
/* The regions in the following copy operation cannot overlap. */
|
||||
memcpy (ctx->buffer, &ctx->buffer[(left_over + add) & ~63],
|
||||
(left_over + add) & 63);
|
||||
ctx->buflen = (left_over + add) & 63;
|
||||
}
|
||||
|
||||
buffer = (const char *) buffer + add;
|
||||
len -= add;
|
||||
}
|
||||
|
||||
/* Process available complete blocks. */
|
||||
if (len > 64)
|
||||
{
|
||||
md5_process_block (buffer, len & ~63, ctx);
|
||||
buffer = (const char *) buffer + (len & ~63);
|
||||
len &= 63;
|
||||
}
|
||||
|
||||
/* Move remaining bytes in internal buffer. */
|
||||
if (len > 0)
|
||||
{
|
||||
memcpy (ctx->buffer, buffer, len);
|
||||
ctx->buflen = len;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* These are the four functions used in the four steps of the MD5 algorithm
|
||||
and defined in the RFC 1321. The first function is a little bit optimized
|
||||
(as found in Colin Plumbs public domain implementation). */
|
||||
/* #define FF(b, c, d) ((b & c) | (~b & d)) */
|
||||
#define FF(b, c, d) (d ^ (b & (c ^ d)))
|
||||
#define FG(b, c, d) FF (d, b, c)
|
||||
#define FH(b, c, d) (b ^ c ^ d)
|
||||
#define FI(b, c, d) (c ^ (b | ~d))
|
||||
|
||||
/* Process LEN bytes of BUFFER, accumulating context into CTX.
|
||||
It is assumed that LEN % 64 == 0. */
|
||||
|
||||
void
|
||||
md5_process_block (buffer, len, ctx)
|
||||
const void *buffer;
|
||||
size_t len;
|
||||
struct md5_ctx *ctx;
|
||||
{
|
||||
md5_uint32 correct_words[16];
|
||||
const md5_uint32 *words = buffer;
|
||||
size_t nwords = len / sizeof (md5_uint32);
|
||||
const md5_uint32 *endp = words + nwords;
|
||||
md5_uint32 A = ctx->A;
|
||||
md5_uint32 B = ctx->B;
|
||||
md5_uint32 C = ctx->C;
|
||||
md5_uint32 D = ctx->D;
|
||||
|
||||
/* First increment the byte count. RFC 1321 specifies the possible
|
||||
length of the file up to 2^64 bits. Here we only compute the
|
||||
number of bytes. Do a double word increment. */
|
||||
ctx->total[0] += len;
|
||||
if (ctx->total[0] < len)
|
||||
++ctx->total[1];
|
||||
|
||||
/* Process all bytes in the buffer with 64 bytes in each round of
|
||||
the loop. */
|
||||
while (words < endp)
|
||||
{
|
||||
md5_uint32 *cwp = correct_words;
|
||||
md5_uint32 A_save = A;
|
||||
md5_uint32 B_save = B;
|
||||
md5_uint32 C_save = C;
|
||||
md5_uint32 D_save = D;
|
||||
|
||||
/* First round: using the given function, the context and a constant
|
||||
the next context is computed. Because the algorithms processing
|
||||
unit is a 32-bit word and it is determined to work on words in
|
||||
little endian byte order we perhaps have to change the byte order
|
||||
before the computation. To reduce the work for the next steps
|
||||
we store the swapped words in the array CORRECT_WORDS. */
|
||||
|
||||
#define OP(a, b, c, d, s, T) \
|
||||
do \
|
||||
{ \
|
||||
a += FF (b, c, d) + (*cwp++ = SWAP (*words)) + T; \
|
||||
++words; \
|
||||
CYCLIC (a, s); \
|
||||
a += b; \
|
||||
} \
|
||||
while (0)
|
||||
|
||||
/* It is unfortunate that C does not provide an operator for
|
||||
cyclic rotation. Hope the C compiler is smart enough. */
|
||||
#define CYCLIC(w, s) (w = (w << s) | (w >> (32 - s)))
|
||||
|
||||
/* Before we start, one word to the strange constants.
|
||||
They are defined in RFC 1321 as
|
||||
|
||||
T[i] = (int) (4294967296.0 * fabs (sin (i))), i=1..64
|
||||
*/
|
||||
|
||||
/* Round 1. */
|
||||
OP (A, B, C, D, 7, 0xd76aa478);
|
||||
OP (D, A, B, C, 12, 0xe8c7b756);
|
||||
OP (C, D, A, B, 17, 0x242070db);
|
||||
OP (B, C, D, A, 22, 0xc1bdceee);
|
||||
OP (A, B, C, D, 7, 0xf57c0faf);
|
||||
OP (D, A, B, C, 12, 0x4787c62a);
|
||||
OP (C, D, A, B, 17, 0xa8304613);
|
||||
OP (B, C, D, A, 22, 0xfd469501);
|
||||
OP (A, B, C, D, 7, 0x698098d8);
|
||||
OP (D, A, B, C, 12, 0x8b44f7af);
|
||||
OP (C, D, A, B, 17, 0xffff5bb1);
|
||||
OP (B, C, D, A, 22, 0x895cd7be);
|
||||
OP (A, B, C, D, 7, 0x6b901122);
|
||||
OP (D, A, B, C, 12, 0xfd987193);
|
||||
OP (C, D, A, B, 17, 0xa679438e);
|
||||
OP (B, C, D, A, 22, 0x49b40821);
|
||||
|
||||
/* For the second to fourth round we have the possibly swapped words
|
||||
in CORRECT_WORDS. Redefine the macro to take an additional first
|
||||
argument specifying the function to use. */
|
||||
#undef OP
|
||||
#define OP(f, a, b, c, d, k, s, T) \
|
||||
do \
|
||||
{ \
|
||||
a += f (b, c, d) + correct_words[k] + T; \
|
||||
CYCLIC (a, s); \
|
||||
a += b; \
|
||||
} \
|
||||
while (0)
|
||||
|
||||
/* Round 2. */
|
||||
OP (FG, A, B, C, D, 1, 5, 0xf61e2562);
|
||||
OP (FG, D, A, B, C, 6, 9, 0xc040b340);
|
||||
OP (FG, C, D, A, B, 11, 14, 0x265e5a51);
|
||||
OP (FG, B, C, D, A, 0, 20, 0xe9b6c7aa);
|
||||
OP (FG, A, B, C, D, 5, 5, 0xd62f105d);
|
||||
OP (FG, D, A, B, C, 10, 9, 0x02441453);
|
||||
OP (FG, C, D, A, B, 15, 14, 0xd8a1e681);
|
||||
OP (FG, B, C, D, A, 4, 20, 0xe7d3fbc8);
|
||||
OP (FG, A, B, C, D, 9, 5, 0x21e1cde6);
|
||||
OP (FG, D, A, B, C, 14, 9, 0xc33707d6);
|
||||
OP (FG, C, D, A, B, 3, 14, 0xf4d50d87);
|
||||
OP (FG, B, C, D, A, 8, 20, 0x455a14ed);
|
||||
OP (FG, A, B, C, D, 13, 5, 0xa9e3e905);
|
||||
OP (FG, D, A, B, C, 2, 9, 0xfcefa3f8);
|
||||
OP (FG, C, D, A, B, 7, 14, 0x676f02d9);
|
||||
OP (FG, B, C, D, A, 12, 20, 0x8d2a4c8a);
|
||||
|
||||
/* Round 3. */
|
||||
OP (FH, A, B, C, D, 5, 4, 0xfffa3942);
|
||||
OP (FH, D, A, B, C, 8, 11, 0x8771f681);
|
||||
OP (FH, C, D, A, B, 11, 16, 0x6d9d6122);
|
||||
OP (FH, B, C, D, A, 14, 23, 0xfde5380c);
|
||||
OP (FH, A, B, C, D, 1, 4, 0xa4beea44);
|
||||
OP (FH, D, A, B, C, 4, 11, 0x4bdecfa9);
|
||||
OP (FH, C, D, A, B, 7, 16, 0xf6bb4b60);
|
||||
OP (FH, B, C, D, A, 10, 23, 0xbebfbc70);
|
||||
OP (FH, A, B, C, D, 13, 4, 0x289b7ec6);
|
||||
OP (FH, D, A, B, C, 0, 11, 0xeaa127fa);
|
||||
OP (FH, C, D, A, B, 3, 16, 0xd4ef3085);
|
||||
OP (FH, B, C, D, A, 6, 23, 0x04881d05);
|
||||
OP (FH, A, B, C, D, 9, 4, 0xd9d4d039);
|
||||
OP (FH, D, A, B, C, 12, 11, 0xe6db99e5);
|
||||
OP (FH, C, D, A, B, 15, 16, 0x1fa27cf8);
|
||||
OP (FH, B, C, D, A, 2, 23, 0xc4ac5665);
|
||||
|
||||
/* Round 4. */
|
||||
OP (FI, A, B, C, D, 0, 6, 0xf4292244);
|
||||
OP (FI, D, A, B, C, 7, 10, 0x432aff97);
|
||||
OP (FI, C, D, A, B, 14, 15, 0xab9423a7);
|
||||
OP (FI, B, C, D, A, 5, 21, 0xfc93a039);
|
||||
OP (FI, A, B, C, D, 12, 6, 0x655b59c3);
|
||||
OP (FI, D, A, B, C, 3, 10, 0x8f0ccc92);
|
||||
OP (FI, C, D, A, B, 10, 15, 0xffeff47d);
|
||||
OP (FI, B, C, D, A, 1, 21, 0x85845dd1);
|
||||
OP (FI, A, B, C, D, 8, 6, 0x6fa87e4f);
|
||||
OP (FI, D, A, B, C, 15, 10, 0xfe2ce6e0);
|
||||
OP (FI, C, D, A, B, 6, 15, 0xa3014314);
|
||||
OP (FI, B, C, D, A, 13, 21, 0x4e0811a1);
|
||||
OP (FI, A, B, C, D, 4, 6, 0xf7537e82);
|
||||
OP (FI, D, A, B, C, 11, 10, 0xbd3af235);
|
||||
OP (FI, C, D, A, B, 2, 15, 0x2ad7d2bb);
|
||||
OP (FI, B, C, D, A, 9, 21, 0xeb86d391);
|
||||
|
||||
/* Add the starting values of the context. */
|
||||
A += A_save;
|
||||
B += B_save;
|
||||
C += C_save;
|
||||
D += D_save;
|
||||
}
|
||||
|
||||
/* Put checksum in context given as argument. */
|
||||
ctx->A = A;
|
||||
ctx->B = B;
|
||||
ctx->C = C;
|
||||
ctx->D = D;
|
||||
}
|
||||
146
tool/rabbitsign-src/md5.h
Normal file
146
tool/rabbitsign-src/md5.h
Normal file
|
|
@ -0,0 +1,146 @@
|
|||
/* md5.h - Declaration of functions and data types used for MD5 sum
|
||||
computing library functions.
|
||||
Copyright (C) 1995, 1996 Free Software Foundation, Inc.
|
||||
NOTE: The canonical source of this file is maintained with the GNU C
|
||||
Library. Bugs can be reported to bug-glibc@prep.ai.mit.edu.
|
||||
|
||||
This program 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 2, or (at your option) any
|
||||
later version.
|
||||
|
||||
This program 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 this program; if not, write to the Free Software Foundation,
|
||||
Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
|
||||
|
||||
#ifndef _MD5_H
|
||||
#define _MD5_H 1
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#if defined HAVE_LIMITS_H || _LIBC
|
||||
# include <limits.h>
|
||||
#endif
|
||||
|
||||
/* The following contortions are an attempt to use the C preprocessor
|
||||
to determine an unsigned integral type that is 32 bits wide. An
|
||||
alternative approach is to use autoconf's AC_CHECK_SIZEOF macro, but
|
||||
doing that would require that the configure script compile and *run*
|
||||
the resulting executable. Locally running cross-compiled executables
|
||||
is usually not possible. */
|
||||
|
||||
#ifdef _LIBC
|
||||
# include <sys/types.h>
|
||||
typedef u_int32_t md5_uint32;
|
||||
#else
|
||||
# if defined __STDC__ && __STDC__
|
||||
# define UINT_MAX_32_BITS 4294967295U
|
||||
# else
|
||||
# define UINT_MAX_32_BITS 0xFFFFFFFF
|
||||
# endif
|
||||
|
||||
/* If UINT_MAX isn't defined, assume it's a 32-bit type.
|
||||
This should be valid for all systems GNU cares about because
|
||||
that doesn't include 16-bit systems, and only modern systems
|
||||
(that certainly have <limits.h>) have 64+-bit integral types. */
|
||||
|
||||
# ifndef UINT_MAX
|
||||
# define UINT_MAX UINT_MAX_32_BITS
|
||||
# endif
|
||||
|
||||
# if UINT_MAX == UINT_MAX_32_BITS
|
||||
typedef unsigned int md5_uint32;
|
||||
# else
|
||||
# if USHRT_MAX == UINT_MAX_32_BITS
|
||||
typedef unsigned short md5_uint32;
|
||||
# else
|
||||
# if ULONG_MAX == UINT_MAX_32_BITS
|
||||
typedef unsigned long md5_uint32;
|
||||
# else
|
||||
/* The following line is intended to evoke an error.
|
||||
Using #error is not portable enough. */
|
||||
"Cannot determine unsigned 32-bit data type."
|
||||
# endif
|
||||
# endif
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#undef __P
|
||||
#if defined (__STDC__) && __STDC__
|
||||
#define __P(x) x
|
||||
#else
|
||||
#define __P(x) ()
|
||||
#endif
|
||||
|
||||
/* Structure to save state of computation between the single steps. */
|
||||
struct md5_ctx
|
||||
{
|
||||
md5_uint32 A;
|
||||
md5_uint32 B;
|
||||
md5_uint32 C;
|
||||
md5_uint32 D;
|
||||
|
||||
md5_uint32 total[2];
|
||||
md5_uint32 buflen;
|
||||
char buffer[128];
|
||||
};
|
||||
|
||||
/*
|
||||
* The following three functions are build up the low level used in
|
||||
* the functions `md5_stream' and `md5_buffer'.
|
||||
*/
|
||||
|
||||
/* Initialize structure containing state of computation.
|
||||
(RFC 1321, 3.3: Step 3) */
|
||||
extern void md5_init_ctx __P ((struct md5_ctx *ctx));
|
||||
|
||||
/* Starting with the result of former calls of this function (or the
|
||||
initialization function update the context for the next LEN bytes
|
||||
starting at BUFFER.
|
||||
It is necessary that LEN is a multiple of 64!!! */
|
||||
extern void md5_process_block __P ((const void *buffer, size_t len,
|
||||
struct md5_ctx *ctx));
|
||||
|
||||
/* Starting with the result of former calls of this function (or the
|
||||
initialization function update the context for the next LEN bytes
|
||||
starting at BUFFER.
|
||||
It is NOT required that LEN is a multiple of 64. */
|
||||
extern void md5_process_bytes __P ((const void *buffer, size_t len,
|
||||
struct md5_ctx *ctx));
|
||||
|
||||
/* Process the remaining bytes in the buffer and put result from CTX
|
||||
in first 16 bytes following RESBUF. The result is always in little
|
||||
endian byte order, so that a byte-wise output yields to the wanted
|
||||
ASCII representation of the message digest.
|
||||
|
||||
IMPORTANT: On some systems it is required that RESBUF is correctly
|
||||
aligned for a 32 bits value. */
|
||||
extern void *md5_finish_ctx __P ((struct md5_ctx *ctx, void *resbuf));
|
||||
|
||||
|
||||
/* Put result from CTX in first 16 bytes following RESBUF. The result is
|
||||
always in little endian byte order, so that a byte-wise output yields
|
||||
to the wanted ASCII representation of the message digest.
|
||||
|
||||
IMPORTANT: On some systems it is required that RESBUF is correctly
|
||||
aligned for a 32 bits value. */
|
||||
extern void *md5_read_ctx __P ((const struct md5_ctx *ctx, void *resbuf));
|
||||
|
||||
|
||||
/* Compute MD5 message digest for bytes read from STREAM. The
|
||||
resulting message digest number will be written into the 16 bytes
|
||||
beginning at RESBLOCK. */
|
||||
extern int md5_stream __P ((FILE *stream, void *resblock));
|
||||
|
||||
/* Compute MD5 message digest for LEN bytes beginning at BUFFER. The
|
||||
result is always in little endian byte order, so that a byte-wise
|
||||
output yields to the wanted ASCII representation of the message
|
||||
digest. */
|
||||
extern void *md5_buffer __P ((const char *buffer, size_t len, void *resblock));
|
||||
|
||||
#endif
|
||||
73
tool/rabbitsign-src/mem.c
Normal file
73
tool/rabbitsign-src/mem.c
Normal file
|
|
@ -0,0 +1,73 @@
|
|||
/*
|
||||
* RabbitSign - Tools for signing TI graphing calculator software
|
||||
* Copyright (C) 2009 Benjamin Moody
|
||||
*
|
||||
* This program 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.
|
||||
*
|
||||
* This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
# include <config.h>
|
||||
#endif
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#ifdef HAVE_STDLIB_H
|
||||
# include <stdlib.h>
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_STRING_H
|
||||
# include <string.h>
|
||||
#else
|
||||
# ifdef HAVE_STRINGS_H
|
||||
# include <strings.h>
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#include "rabbitsign.h"
|
||||
#include "internal.h"
|
||||
|
||||
void* rs_realloc(void* ptr, unsigned long count)
|
||||
{
|
||||
void* p;
|
||||
|
||||
if (!count) {
|
||||
if (ptr) {
|
||||
free(ptr);
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (ptr)
|
||||
p = realloc(ptr, count);
|
||||
else
|
||||
p = malloc(count);
|
||||
if (!p)
|
||||
rs_error(NULL, NULL, "out of memory (need %lu bytes)", count);
|
||||
return p;
|
||||
}
|
||||
|
||||
char* rs_strdup(const char* str)
|
||||
{
|
||||
int n;
|
||||
char* p;
|
||||
|
||||
if (!str)
|
||||
return NULL;
|
||||
|
||||
n = strlen(str);
|
||||
p = rs_malloc(n + 1);
|
||||
if (p)
|
||||
memcpy(p, str, n + 1);
|
||||
return p;
|
||||
}
|
||||
1026
tool/rabbitsign-src/mpz.c
Normal file
1026
tool/rabbitsign-src/mpz.c
Normal file
File diff suppressed because it is too large
Load Diff
123
tool/rabbitsign-src/mpz.h
Normal file
123
tool/rabbitsign-src/mpz.h
Normal file
|
|
@ -0,0 +1,123 @@
|
|||
/*
|
||||
* RabbitSign - Tools for signing TI graphing calculator software
|
||||
* Copyright (C) 2009 Benjamin Moody
|
||||
*
|
||||
* This program 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.
|
||||
*
|
||||
* This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef __RABBITSIGN_MPZ_H__
|
||||
#define __RABBITSIGN_MPZ_H__
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#if (SIZEOF_INT != 0) && (SIZEOF_LONG >= 2 * SIZEOF_INT)
|
||||
typedef unsigned int limb_t;
|
||||
typedef unsigned long double_limb_t;
|
||||
typedef signed long signed_double_limb_t;
|
||||
#else
|
||||
# if (SIZEOF_SHORT != 0) && (SIZEOF_INT >= 2 * SIZEOF_SHORT)
|
||||
typedef unsigned short limb_t;
|
||||
typedef unsigned int double_limb_t;
|
||||
typedef signed int signed_double_limb_t;
|
||||
# else
|
||||
typedef unsigned short limb_t;
|
||||
typedef unsigned long double_limb_t;
|
||||
typedef signed long signed_double_limb_t;
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#define LIMB_BITS (sizeof(limb_t)*8)
|
||||
#define LIMB_BYTES (sizeof(limb_t))
|
||||
#define LIMB_MASK ((((double_limb_t) 1) << LIMB_BITS) - 1)
|
||||
|
||||
struct _mpz {
|
||||
size_t size;
|
||||
size_t size_alloc;
|
||||
limb_t* m;
|
||||
int sign;
|
||||
};
|
||||
|
||||
typedef struct _mpz mpz_t[1];
|
||||
|
||||
#undef __P
|
||||
#ifdef PROTOTYPES
|
||||
# define __P(x) x
|
||||
#else
|
||||
# define __P(x) ()
|
||||
#endif
|
||||
|
||||
void mpz_init __P((mpz_t x));
|
||||
void mpz_clear __P((mpz_t x));
|
||||
|
||||
/* Set */
|
||||
void mpz_set __P((mpz_t dest, const mpz_t src));
|
||||
void mpz_set_ui __P((mpz_t dest, unsigned int a));
|
||||
unsigned int mpz_get_ui __P((const mpz_t a));
|
||||
|
||||
/* Import/export: assume order=-1, size=1, endian=0, nails=0 */
|
||||
void mpz_import __P((mpz_t dest, size_t count, int order, int size,
|
||||
int endian, size_t nails, const void* op));
|
||||
void mpz_export __P((void* dest, size_t* count, int order, int size,
|
||||
int endian, size_t nails, const mpz_t op));
|
||||
|
||||
/* Check sign */
|
||||
int mpz_sgn __P((const mpz_t a));
|
||||
|
||||
/* Compare */
|
||||
int mpz_cmp __P((const mpz_t a, const mpz_t b));
|
||||
int mpz_cmp_ui __P((const mpz_t a, unsigned int b));
|
||||
|
||||
/* Add */
|
||||
void mpz_add __P((mpz_t dest, const mpz_t a, const mpz_t b));
|
||||
void mpz_add_ui __P((mpz_t dest, const mpz_t a, unsigned int b));
|
||||
|
||||
/* Subtract */
|
||||
void mpz_sub __P((mpz_t dest, const mpz_t a, const mpz_t b));
|
||||
void mpz_sub_ui __P((mpz_t dest, const mpz_t a, unsigned int b));
|
||||
|
||||
/* Multiply */
|
||||
void mpz_mul __P((mpz_t dest, const mpz_t a, const mpz_t b));
|
||||
void mpz_mul_ui __P((mpz_t dest, const mpz_t a, unsigned int b));
|
||||
|
||||
/* Divide: requires b <= LIMB_BITS */
|
||||
void mpz_fdiv_q_2exp __P((mpz_t dest, const mpz_t a, unsigned int b));
|
||||
|
||||
/* Modulus */
|
||||
void mpz_mod __P((mpz_t dest, const mpz_t a, const mpz_t mod));
|
||||
|
||||
/* Modular exponent */
|
||||
void mpz_powm __P((mpz_t dest, const mpz_t base, const mpz_t exp,
|
||||
const mpz_t mod));
|
||||
|
||||
/* Legendre symbol */
|
||||
int mpz_legendre __P((const mpz_t a, const mpz_t p));
|
||||
|
||||
/* Extended GCD */
|
||||
void mpz_gcdext __P((mpz_t g, mpz_t ai, mpz_t bi,
|
||||
const mpz_t a, const mpz_t b));
|
||||
|
||||
/* Output */
|
||||
int rs_snprintf __P((char* buf, size_t size, const char* fmt, ...));
|
||||
|
||||
#ifdef va_start
|
||||
int rs_vsnprintf __P((char* buf, size_t size, const char* fmt, va_list ap));
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
298
tool/rabbitsign-src/os8x.c
Normal file
298
tool/rabbitsign-src/os8x.c
Normal file
|
|
@ -0,0 +1,298 @@
|
|||
/*
|
||||
* RabbitSign - Tools for signing TI graphing calculator software
|
||||
* Copyright (C) 2009 Benjamin Moody
|
||||
*
|
||||
* This program 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.
|
||||
*
|
||||
* This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
# include <config.h>
|
||||
#endif
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#ifdef HAVE_STRING_H
|
||||
# include <string.h>
|
||||
#else
|
||||
# ifdef HAVE_STRINGS_H
|
||||
# include <strings.h>
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#include "rabbitsign.h"
|
||||
#include "internal.h"
|
||||
#include "md5.h"
|
||||
|
||||
/*
|
||||
* Check/fix OS header fields and data.
|
||||
*
|
||||
* The OS header is much simpler than an application header, and its
|
||||
* correctness is not as crucial to validation. The most important
|
||||
* parts of the OS header are the key ID and (for newer calculators)
|
||||
* the hardware compatibility level. There is no date stamp required.
|
||||
* The page count is not required, and if present, is used only to
|
||||
* display the transfer percentage (when using the 84+ boot code.)
|
||||
*
|
||||
* TI only sets the OS and program image size fields in their TI-73 OS
|
||||
* headers. (Bizarrely, they are set in the true OS header, but not
|
||||
* in the fake OS header that is transferred to page 1A. Furthermore,
|
||||
* the OS size field is incorrect.) In any case, these fields appear
|
||||
* to be ignored by all versions of the boot code.
|
||||
*/
|
||||
int rs_repair_ti8x_os(RSProgram* os, /* OS */
|
||||
unsigned int flags) /* flags */
|
||||
{
|
||||
unsigned long hdrstart, hdrsize, fieldhead, fieldstart,
|
||||
fieldsize, ossize;
|
||||
unsigned char* hdr;
|
||||
int i;
|
||||
|
||||
/* Pad the OS to a multiple of 16384. (While strictly speaking we
|
||||
could get away with only padding each page to a multiple of 256,
|
||||
such "partial OSes" are not supported by most linking
|
||||
software.) */
|
||||
|
||||
rs_program_set_length(os, ((os->length + 0x3fff) & ~0x3fff));
|
||||
|
||||
/* If no OS header was provided in the input, try to get a header
|
||||
from page 1A instead */
|
||||
|
||||
if (os->header_length < 6
|
||||
|| os->header[0] != 0x80
|
||||
|| os->header[1] != 0x0f) {
|
||||
for (i = 0; i < os->npagenums; i++) {
|
||||
if (os->pagenums[i] == 0x1a) {
|
||||
rs_free(os->header);
|
||||
if (!(os->header = rs_malloc(256)))
|
||||
return RS_ERR_OUT_OF_MEMORY;
|
||||
memcpy(os->header, os->data + ((unsigned long) i << 14), 256);
|
||||
os->header_length = 256;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Clear old header/signature (not done on the TI-73 because
|
||||
official TI-73 OSes contain a fake header; I don't recommend
|
||||
doing this for third-party OSes) */
|
||||
|
||||
if (os->calctype != RS_CALC_TI73)
|
||||
for (i = 0; i < os->npagenums; i++)
|
||||
if (os->pagenums[i] == 0x1a)
|
||||
memset(os->data + ((unsigned long) i << 14), 0xff, 512);
|
||||
|
||||
/* Fix header size. OS headers must always begin with an 800x field
|
||||
and end with an 807x field (TI always uses 800F and 807F, as for
|
||||
apps; I'm not sure whether it's required.) */
|
||||
|
||||
if (os->header_length < 6
|
||||
|| os->header[0] != 0x80
|
||||
|| (os->header[1] & 0xf0) != 0) {
|
||||
rs_error(NULL, os, "no OS header found");
|
||||
return RS_ERR_MISSING_HEADER;
|
||||
}
|
||||
|
||||
rs_get_field_size(os->header, &hdrstart, NULL);
|
||||
hdr = os->header + hdrstart;
|
||||
hdrsize = os->header_length - hdrstart;
|
||||
|
||||
if (rs_find_app_field(0x8070, hdr, hdrsize,
|
||||
&fieldhead, &fieldstart, &fieldsize)) {
|
||||
rs_error(NULL, os, "OS header has no program image field");
|
||||
return RS_ERR_MISSING_PROGRAM_IMAGE;
|
||||
}
|
||||
|
||||
hdrsize = fieldstart;
|
||||
os->header_length = hdrstart + hdrsize;
|
||||
|
||||
if ((os->header_length % 64) == 55) {
|
||||
if (flags & RS_IGNORE_ALL_WARNINGS) {
|
||||
rs_warning(NULL, os, "OS header has length 55 mod 64");
|
||||
rs_warning(NULL, os, "(this will fail to validate on TI-83+ BE)");
|
||||
}
|
||||
else {
|
||||
rs_error(NULL, os, "OS header has length 55 mod 64");
|
||||
rs_error(NULL, os, "(this will fail to validate on TI-83+ BE)");
|
||||
return RS_ERR_INVALID_PROGRAM_SIZE;
|
||||
}
|
||||
}
|
||||
|
||||
/* Fix OS / OS image sizes if requested */
|
||||
|
||||
if (flags & RS_FIX_OS_SIZE) {
|
||||
ossize = os->length + hdrsize;
|
||||
if (rs_set_field_size(os->header, ossize)) {
|
||||
rs_error(NULL, os, "cannot set OS length");
|
||||
return RS_ERR_FIELD_TOO_SMALL;
|
||||
}
|
||||
|
||||
if (rs_set_field_size(hdr + fieldhead, os->length)) {
|
||||
rs_error(NULL, os, "cannot set OS image length");
|
||||
return RS_ERR_FIELD_TOO_SMALL;
|
||||
}
|
||||
}
|
||||
|
||||
/* Check for key ID */
|
||||
|
||||
if (rs_find_app_field(0x8010, hdr, hdrsize, NULL, NULL, NULL)) {
|
||||
if (flags & RS_IGNORE_ALL_WARNINGS)
|
||||
rs_warning(NULL, os, "OS header has no key ID field");
|
||||
else {
|
||||
rs_error(NULL, os, "OS header has no key ID field");
|
||||
return RS_ERR_MISSING_KEY_ID;
|
||||
}
|
||||
}
|
||||
|
||||
/* Check/fix page count */
|
||||
|
||||
if (rs_find_app_field(0x8080, hdr, hdrsize,
|
||||
NULL, &fieldstart, &fieldsize)) {
|
||||
if (os->length != 14 * 0x4000L) {
|
||||
rs_warning(NULL, os, "OS header has no page count field");
|
||||
}
|
||||
}
|
||||
else if (fieldsize != 1) {
|
||||
rs_warning(NULL, os, "OS header has an invalid page count field");
|
||||
}
|
||||
else if (flags & RS_FIX_PAGE_COUNT) {
|
||||
hdr[fieldstart] = os->length >> 14;
|
||||
}
|
||||
else if (hdr[fieldstart] != (os->length >> 14)) {
|
||||
rs_warning(NULL, os, "OS header has an incorrect page count field");
|
||||
}
|
||||
|
||||
/* Check and reset validation flag bytes */
|
||||
|
||||
if (os->data[0x56] != 0xff && os->data[0x56] != 0x5a) {
|
||||
if (flags & RS_IGNORE_ALL_WARNINGS)
|
||||
rs_warning(NULL, os, "OS has invalid data at 0056h");
|
||||
else {
|
||||
rs_error(NULL, os, "OS has invalid data at 0056h");
|
||||
return RS_ERR_INVALID_PROGRAM_DATA;
|
||||
}
|
||||
}
|
||||
|
||||
if (os->data[0x56] == 0x5a)
|
||||
os->data[0x56] = 0xff;
|
||||
|
||||
if (os->data[0x57] != 0xff && os->data[0x57] != 0xa5) {
|
||||
if (flags & RS_IGNORE_ALL_WARNINGS)
|
||||
rs_warning(NULL, os, "OS has invalid data at 0057h");
|
||||
else {
|
||||
rs_error(NULL, os, "OS has invalid data at 0057h");
|
||||
return RS_ERR_INVALID_PROGRAM_DATA;
|
||||
}
|
||||
}
|
||||
|
||||
if (os->data[0x57] == 0xff)
|
||||
os->data[0x57] = 0xa5;
|
||||
|
||||
return RS_SUCCESS;
|
||||
}
|
||||
|
||||
/*
|
||||
* Compute signature for an OS.
|
||||
*/
|
||||
int rs_sign_ti8x_os(RSProgram* os, /* OS */
|
||||
RSKey* key) /* signing key */
|
||||
{
|
||||
struct md5_ctx ctx;
|
||||
md5_uint32 hash[4];
|
||||
mpz_t hashv, sigv;
|
||||
unsigned char sigdata[512];
|
||||
size_t siglength;
|
||||
int e;
|
||||
|
||||
md5_init_ctx(&ctx);
|
||||
md5_process_bytes(os->header, os->header_length, &ctx);
|
||||
md5_process_bytes(os->data, os->length, &ctx);
|
||||
md5_finish_ctx(&ctx, hash);
|
||||
|
||||
mpz_init(hashv);
|
||||
mpz_init(sigv);
|
||||
|
||||
mpz_import(hashv, 16, -1, 1, 0, 0, hash);
|
||||
rs_message(2, NULL, os, "hash = %ZX", hashv);
|
||||
|
||||
if ((e = rs_sign_rsa(sigv, hashv, key))) {
|
||||
mpz_clear(hashv);
|
||||
mpz_clear(sigv);
|
||||
return e;
|
||||
}
|
||||
|
||||
rs_message(2, NULL, os, "sig = %ZX", sigv);
|
||||
|
||||
sigdata[0] = 0x02;
|
||||
sigdata[1] = 0x0d;
|
||||
mpz_export(sigdata + 3, &siglength, -1, 1, 0, 0, sigv);
|
||||
sigdata[2] = siglength & 0xff;
|
||||
siglength += 3;
|
||||
|
||||
while (siglength < 96)
|
||||
sigdata[siglength++] = 0xff;
|
||||
|
||||
rs_free(os->signature);
|
||||
if (!(os->signature = rs_malloc(siglength)))
|
||||
return RS_ERR_OUT_OF_MEMORY;
|
||||
|
||||
memcpy(os->signature, sigdata, siglength);
|
||||
os->signature_length = siglength;
|
||||
return RS_SUCCESS;
|
||||
}
|
||||
|
||||
/*
|
||||
* Validate OS signature.
|
||||
*/
|
||||
int rs_validate_ti8x_os(const RSProgram* os,
|
||||
const RSKey* key)
|
||||
{
|
||||
unsigned long fieldstart, fieldsize;
|
||||
struct md5_ctx ctx;
|
||||
md5_uint32 hash[4];
|
||||
mpz_t hashv, sigv;
|
||||
int e;
|
||||
|
||||
if (os->signature_length < 3) {
|
||||
rs_error(NULL, os, "OS does not have a signature");
|
||||
return RS_ERR_MISSING_RSA_SIGNATURE;
|
||||
}
|
||||
|
||||
if (os->signature[0] != 0x02 || (os->signature[1] & 0xf0) != 0x00) {
|
||||
rs_error(NULL, os, "OS does not have an RSA signature");
|
||||
return RS_ERR_MISSING_RSA_SIGNATURE;
|
||||
}
|
||||
rs_get_field_size(os->signature, &fieldstart, &fieldsize);
|
||||
|
||||
md5_init_ctx(&ctx);
|
||||
md5_process_bytes(os->header, os->header_length, &ctx);
|
||||
md5_process_bytes(os->data, os->length, &ctx);
|
||||
md5_finish_ctx(&ctx, hash);
|
||||
|
||||
mpz_init(hashv);
|
||||
mpz_init(sigv);
|
||||
|
||||
mpz_import(hashv, 16, -1, 1, 0, 0, hash);
|
||||
rs_message(2, NULL, os, "hash = %ZX", hashv);
|
||||
|
||||
mpz_import(sigv, fieldsize, -1, 1, 0, 0, os->signature + fieldstart);
|
||||
rs_message(2, NULL, os, "sig = %ZX", sigv);
|
||||
|
||||
e = rs_validate_rsa(sigv, hashv, key);
|
||||
if (e == RS_SIGNATURE_INCORRECT)
|
||||
rs_message(0, NULL, os, "OS signature incorrect");
|
||||
|
||||
mpz_clear(hashv);
|
||||
mpz_clear(sigv);
|
||||
return e;
|
||||
}
|
||||
39
tool/rabbitsign-src/output.c
Normal file
39
tool/rabbitsign-src/output.c
Normal file
|
|
@ -0,0 +1,39 @@
|
|||
/*
|
||||
* RabbitSign - Tools for signing TI graphing calculator software
|
||||
* Copyright (C) 2009 Benjamin Moody
|
||||
*
|
||||
* This program 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.
|
||||
*
|
||||
* This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
# include <config.h>
|
||||
#endif
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#include "rabbitsign.h"
|
||||
|
||||
/*
|
||||
* Write program contents to a file.
|
||||
*/
|
||||
int rs_write_program_file(const RSProgram* prgm, FILE* f,
|
||||
int month, int day, int year,
|
||||
unsigned int flags)
|
||||
{
|
||||
if (rs_calc_is_ti8x(prgm->calctype)
|
||||
&& (prgm->datatype == RS_DATA_OS || prgm->datatype == RS_DATA_APP))
|
||||
return rs_write_ti8x_file(prgm, f, month, day, year, flags);
|
||||
else
|
||||
return rs_write_ti9x_file(prgm, f, month, day, year, flags);
|
||||
}
|
||||
248
tool/rabbitsign-src/output8x.c
Normal file
248
tool/rabbitsign-src/output8x.c
Normal file
|
|
@ -0,0 +1,248 @@
|
|||
/*
|
||||
* RabbitSign - Tools for signing TI graphing calculator software
|
||||
* Copyright (C) 2009 Benjamin Moody
|
||||
*
|
||||
* This program 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.
|
||||
*
|
||||
* This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
# include <config.h>
|
||||
#endif
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#ifdef HAVE_STRING_H
|
||||
# include <string.h>
|
||||
#else
|
||||
# ifdef HAVE_STRINGS_H
|
||||
# include <strings.h>
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#include "rabbitsign.h"
|
||||
#include "internal.h"
|
||||
|
||||
/*
|
||||
* Write a single record to an Intel hex file.
|
||||
*/
|
||||
static int write_hex_record(FILE* outfile, /* output file */
|
||||
unsigned int nbytes, /* number of bytes */
|
||||
unsigned int addr, /* address */
|
||||
unsigned int type, /* record type */
|
||||
unsigned char* data, /* data */
|
||||
unsigned int flags, /* flags */
|
||||
int final)
|
||||
{
|
||||
char buf[256];
|
||||
unsigned int i;
|
||||
unsigned int sum;
|
||||
|
||||
sum = nbytes + addr + (addr >> 8) + type;
|
||||
sprintf(buf, ":%02X%04X%02X", nbytes, addr, type);
|
||||
|
||||
for (i = 0; i < nbytes; i++) {
|
||||
sprintf(buf + 9 + 2 * i, "%02X", data[i]);
|
||||
sum += data[i];
|
||||
}
|
||||
|
||||
sum = ((-sum) & 0xff);
|
||||
|
||||
sprintf(buf + 9 + 2 * i, "%02X", sum);
|
||||
|
||||
if (!final) {
|
||||
if (flags & RS_OUTPUT_APPSIGN)
|
||||
strcpy(buf + 11 + 2 * i, "\n");
|
||||
else
|
||||
strcpy(buf + 11 + 2 * i, "\r\n");
|
||||
}
|
||||
|
||||
if (fputs(buf, outfile) == EOF) {
|
||||
rs_error(NULL, NULL, "file I/O error");
|
||||
return RS_ERR_FILE_IO;
|
||||
}
|
||||
|
||||
return RS_SUCCESS;
|
||||
}
|
||||
|
||||
/*
|
||||
* Write a chunk of data to an Intel hex file.
|
||||
*/
|
||||
static int write_hex_data(FILE* outfile, /* output file */
|
||||
unsigned long length, /* number of bytes */
|
||||
unsigned long addr, /* starting address */
|
||||
unsigned char* data, /* data */
|
||||
unsigned int flags)
|
||||
{
|
||||
unsigned int count;
|
||||
int e;
|
||||
|
||||
while (length > 0) {
|
||||
if (length < 0x20)
|
||||
count = length;
|
||||
else
|
||||
count = 0x20;
|
||||
|
||||
if ((e = write_hex_record(outfile, count, addr, 0, data, flags, 0)))
|
||||
return e;
|
||||
|
||||
length -= count;
|
||||
addr += count;
|
||||
data += count;
|
||||
}
|
||||
|
||||
return RS_SUCCESS;
|
||||
}
|
||||
|
||||
/*
|
||||
* Write program to a .73k/.73u/.8xk/.8xu or .app file.
|
||||
*
|
||||
* If month = day = year = 0, use the current time.
|
||||
*
|
||||
* Note: on platforms where it matters, all output files must be
|
||||
* opened in "binary" mode.
|
||||
*/
|
||||
int rs_write_ti8x_file(const RSProgram* prgm, /* program */
|
||||
FILE* outfile, /* output file */
|
||||
int month, /* timestamp month */
|
||||
int day, /* timestamp day */
|
||||
int year, /* timestamp year*/
|
||||
unsigned int flags) /* flags */
|
||||
{
|
||||
const unsigned char *hdr;
|
||||
unsigned long hdrstart, hdrsize, fieldstart, fieldsize;
|
||||
int major, minor, i;
|
||||
unsigned long npages, nrecords, hexsize;
|
||||
char name[9];
|
||||
unsigned int pagenum, addr;
|
||||
unsigned long count;
|
||||
unsigned char pnbuf[2];
|
||||
int e;
|
||||
|
||||
if (!(flags & RS_OUTPUT_HEX_ONLY)) {
|
||||
if (prgm->header_length) {
|
||||
hdr = prgm->header;
|
||||
hdrsize = prgm->header_length;
|
||||
}
|
||||
else {
|
||||
hdr = prgm->data;
|
||||
hdrsize = prgm->length;
|
||||
}
|
||||
|
||||
if (hdrsize >= 6) {
|
||||
rs_get_field_size(hdr, &hdrstart, NULL);
|
||||
hdr += hdrstart;
|
||||
hdrsize -= hdrstart;
|
||||
if (hdrsize > 128)
|
||||
hdrsize = 128;
|
||||
|
||||
major = rs_get_numeric_field(0x8020, hdr, hdrsize);
|
||||
minor = rs_get_numeric_field(0x8030, hdr, hdrsize);
|
||||
|
||||
if (prgm->datatype == RS_DATA_OS) {
|
||||
if (prgm->calctype == RS_CALC_TI73)
|
||||
strcpy(name, "BASECODE");
|
||||
else
|
||||
strcpy(name, "basecode");
|
||||
}
|
||||
else if (!rs_find_app_field(0x8040, hdr, hdrsize,
|
||||
NULL, &fieldstart, &fieldsize)) {
|
||||
if (fieldsize > 8)
|
||||
fieldsize = 8;
|
||||
strncpy(name, (char*) hdr + fieldstart, fieldsize);
|
||||
name[fieldsize] = 0;
|
||||
}
|
||||
else {
|
||||
name[0] = 0;
|
||||
}
|
||||
}
|
||||
else {
|
||||
major = minor = 0;
|
||||
name[0] = 0;
|
||||
}
|
||||
|
||||
npages = ((prgm->length + 0x3fff) >> 14);
|
||||
nrecords = 1 + npages + ((prgm->length + 0x1f) >> 5);
|
||||
|
||||
if (prgm->header_length)
|
||||
nrecords += 1 + ((prgm->header_length + 0x1f) >> 5);
|
||||
if (prgm->signature_length)
|
||||
nrecords += 1 + ((prgm->signature_length + 0x1f) >> 5);
|
||||
|
||||
if (flags & RS_OUTPUT_APPSIGN) {
|
||||
hexsize = (npages * 4
|
||||
+ prgm->length * 2
|
||||
+ prgm->header_length * 2
|
||||
+ prgm->signature_length * 2
|
||||
+ nrecords * 12 - 1);
|
||||
}
|
||||
else {
|
||||
hexsize = (npages * 4
|
||||
+ prgm->length * 2
|
||||
+ prgm->header_length * 2
|
||||
+ prgm->signature_length * 2
|
||||
+ nrecords * 13 - 2);
|
||||
}
|
||||
|
||||
if ((e = rs_write_tifl_header(outfile, 1, major, minor,
|
||||
month, day, year, name,
|
||||
prgm->calctype, prgm->datatype,
|
||||
hexsize)))
|
||||
return e;
|
||||
}
|
||||
|
||||
if (prgm->header_length) {
|
||||
if ((e = write_hex_data(outfile, prgm->header_length, 0,
|
||||
prgm->header, flags)))
|
||||
return e;
|
||||
if ((e = write_hex_record(outfile, 0, 0, 1, NULL, flags, 0)))
|
||||
return e;
|
||||
}
|
||||
|
||||
for (i = 0; ((unsigned long) i << 14) < prgm->length; i++) {
|
||||
if (i < prgm->npagenums)
|
||||
pagenum = prgm->pagenums[i];
|
||||
else
|
||||
pagenum = i;
|
||||
|
||||
if (pagenum == 0 && prgm->header_length)
|
||||
addr = 0;
|
||||
else
|
||||
addr = 0x4000;
|
||||
|
||||
pnbuf[0] = (pagenum >> 8) & 0xff;
|
||||
pnbuf[1] = pagenum & 0xff;
|
||||
|
||||
if ((e = write_hex_record(outfile, 2, 0, 2, pnbuf, flags, 0)))
|
||||
return e;
|
||||
|
||||
count = prgm->length - i * 0x4000;
|
||||
if (count > 0x4000)
|
||||
count = 0x4000;
|
||||
|
||||
if ((e = write_hex_data(outfile, count, addr,
|
||||
prgm->data + i * 0x4000, flags)))
|
||||
return e;
|
||||
}
|
||||
|
||||
if (prgm->signature_length) {
|
||||
if ((e = write_hex_record(outfile, 0, 0, 1, NULL, flags, 0)))
|
||||
return e;
|
||||
if ((e = write_hex_data(outfile, prgm->signature_length, 0,
|
||||
prgm->signature, flags)))
|
||||
return e;
|
||||
}
|
||||
|
||||
return write_hex_record(outfile, 0, 0, 1, NULL, flags, 1);
|
||||
}
|
||||
|
||||
96
tool/rabbitsign-src/output9x.c
Normal file
96
tool/rabbitsign-src/output9x.c
Normal file
|
|
@ -0,0 +1,96 @@
|
|||
/*
|
||||
* RabbitSign - Tools for signing TI graphing calculator software
|
||||
* Copyright (C) 2009 Benjamin Moody
|
||||
*
|
||||
* This program 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.
|
||||
*
|
||||
* This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
# include <config.h>
|
||||
#endif
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#ifdef HAVE_STRING_H
|
||||
# include <string.h>
|
||||
#else
|
||||
# ifdef HAVE_STRINGS_H
|
||||
# include <strings.h>
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#include "rabbitsign.h"
|
||||
#include "internal.h"
|
||||
|
||||
/*
|
||||
* Write program to a .89k/.89u/.9xk/.9xu file.
|
||||
*
|
||||
* If month = day = year = 0, use the current time.
|
||||
*
|
||||
* Note: on platforms where it matters, all output files must be
|
||||
* opened in "binary" mode.
|
||||
*/
|
||||
int rs_write_ti9x_file(const RSProgram* prgm, /* program */
|
||||
FILE* outfile, /* output file */
|
||||
int month, /* timestamp month */
|
||||
int day, /* timestamp day */
|
||||
int year, /* timestamp year*/
|
||||
unsigned int flags RS_ATTR_UNUSED)
|
||||
{
|
||||
const unsigned char *hdr;
|
||||
unsigned long hdrstart, hdrsize, fieldstart, fieldsize;
|
||||
char name[9];
|
||||
int e;
|
||||
|
||||
if (prgm->length >= 6) {
|
||||
rs_get_field_size(prgm->data, &hdrstart, &hdrsize);
|
||||
hdr = prgm->data + hdrstart;
|
||||
if (hdrsize > 128)
|
||||
hdrsize = 128;
|
||||
|
||||
if (prgm->datatype == RS_DATA_OS) {
|
||||
strcpy(name, "basecode");
|
||||
}
|
||||
else if (!rs_find_app_field(0x8140, hdr, hdrsize,
|
||||
NULL, &fieldstart, &fieldsize)) {
|
||||
if (fieldsize > 8)
|
||||
fieldsize = 8;
|
||||
strncpy(name, (char*) hdr + fieldstart, fieldsize);
|
||||
name[fieldsize] = 0;
|
||||
}
|
||||
else {
|
||||
name[0] = 0;
|
||||
}
|
||||
}
|
||||
else {
|
||||
name[0] = 0;
|
||||
}
|
||||
|
||||
/* Note: the "version" header fields used in TI's 68k apps and
|
||||
OSes seem to have no relation to the actual version numbers. */
|
||||
|
||||
if ((e = rs_write_tifl_header(outfile, 0, 0, 0,
|
||||
month, day, year, name,
|
||||
prgm->calctype, prgm->datatype,
|
||||
prgm->length)))
|
||||
return e;
|
||||
|
||||
if (fwrite(prgm->data, 1, prgm->length, outfile) != prgm->length) {
|
||||
rs_error(NULL, NULL, "file I/O error");
|
||||
return RS_ERR_FILE_IO;
|
||||
}
|
||||
|
||||
return RS_SUCCESS;
|
||||
}
|
||||
|
||||
187
tool/rabbitsign-src/program.c
Normal file
187
tool/rabbitsign-src/program.c
Normal file
|
|
@ -0,0 +1,187 @@
|
|||
/*
|
||||
* RabbitSign - Tools for signing TI graphing calculator software
|
||||
* Copyright (C) 2009 Benjamin Moody
|
||||
*
|
||||
* This program 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.
|
||||
*
|
||||
* This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
# include <config.h>
|
||||
#endif
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#ifdef HAVE_STRING_H
|
||||
# include <string.h>
|
||||
#else
|
||||
# ifdef HAVE_STRINGS_H
|
||||
# include <strings.h>
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#include "rabbitsign.h"
|
||||
#include "internal.h"
|
||||
|
||||
/*
|
||||
* Create a new program.
|
||||
*/
|
||||
RSProgram* rs_program_new()
|
||||
{
|
||||
RSProgram* prgm = rs_malloc(sizeof(RSProgram));
|
||||
|
||||
if (!prgm)
|
||||
return NULL;
|
||||
|
||||
prgm->filename = NULL;
|
||||
prgm->calctype = 0;
|
||||
prgm->datatype = 0;
|
||||
prgm->data = NULL;
|
||||
prgm->length = 0;
|
||||
prgm->length_a = 0;
|
||||
prgm->header = NULL;
|
||||
prgm->header_length = 0;
|
||||
prgm->signature = NULL;
|
||||
prgm->signature_length = 0;
|
||||
prgm->pagenums = NULL;
|
||||
prgm->npagenums = 0;
|
||||
|
||||
return prgm;
|
||||
}
|
||||
|
||||
/*
|
||||
* Create a new program by wrapping an existing data buffer.
|
||||
*
|
||||
* If buffer_size is zero, data will be copied from the source buffer
|
||||
* into the new program.
|
||||
*
|
||||
* If buffer_size is nonzero, then the source buffer must have been
|
||||
* allocated using malloc(); buffer_size is the total amount of memory
|
||||
* allocated. The data will not be copied, and the new program object
|
||||
* assumes ownership of the buffer.
|
||||
*/
|
||||
RSProgram* rs_program_new_with_data(RSCalcType ctype, /* calc type */
|
||||
RSDataType dtype, /* data type */
|
||||
void* data, /* source buffer */
|
||||
unsigned long length, /* length of data */
|
||||
unsigned long buffer_size) /* amount of
|
||||
memory
|
||||
allocated */
|
||||
{
|
||||
RSProgram* prgm = rs_program_new();
|
||||
|
||||
if (!prgm)
|
||||
return NULL;
|
||||
|
||||
prgm->calctype = ctype;
|
||||
prgm->datatype = dtype;
|
||||
|
||||
if (data) {
|
||||
if (buffer_size) {
|
||||
prgm->data = data;
|
||||
prgm->length = length;
|
||||
prgm->length_a = buffer_size;
|
||||
}
|
||||
else {
|
||||
if (rs_program_append_data(prgm, data, length)) {
|
||||
rs_program_free(prgm);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return prgm;
|
||||
}
|
||||
|
||||
/*
|
||||
* Free program data.
|
||||
*/
|
||||
void rs_program_free(RSProgram* prgm)
|
||||
{
|
||||
if (!prgm)
|
||||
return;
|
||||
|
||||
rs_free(prgm->filename);
|
||||
rs_free(prgm->data);
|
||||
rs_free(prgm->header);
|
||||
rs_free(prgm->signature);
|
||||
rs_free(prgm->pagenums);
|
||||
rs_free(prgm);
|
||||
}
|
||||
|
||||
/*
|
||||
* Truncate or extend program.
|
||||
*
|
||||
* If length is less than the program's current length, the program is
|
||||
* truncated. If length is greater than the current size of the
|
||||
* program, additional space is added. The extra space is padded with
|
||||
* 0xFF, with the exception of bytes that fall at the start of a page.
|
||||
*/
|
||||
int rs_program_set_length(RSProgram* prgm, /* program */
|
||||
unsigned long length) /* new length of program */
|
||||
{
|
||||
unsigned long length_a, i;
|
||||
unsigned char* dptr;
|
||||
|
||||
if (length <= prgm->length) {
|
||||
prgm->length = length;
|
||||
return RS_SUCCESS;
|
||||
}
|
||||
else {
|
||||
if (length > prgm->length_a) {
|
||||
length_a = length + 16384;
|
||||
|
||||
dptr = rs_realloc(prgm->data, length_a);
|
||||
if (!dptr)
|
||||
return RS_ERR_OUT_OF_MEMORY;
|
||||
prgm->data = dptr;
|
||||
prgm->length_a = length_a;
|
||||
}
|
||||
|
||||
memset(prgm->data + prgm->length, 0xff, length - prgm->length);
|
||||
|
||||
for (i = ((prgm->length + 0x3fff) & ~0x3fff);
|
||||
i < length;
|
||||
i += 0x4000)
|
||||
prgm->data[i] = 0x42;
|
||||
|
||||
prgm->length = length;
|
||||
return RS_SUCCESS;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Add data to the end of the program.
|
||||
*/
|
||||
int rs_program_append_data(RSProgram* prgm, /* program */
|
||||
const unsigned char* data, /* data */
|
||||
unsigned long length) /* size of data */
|
||||
{
|
||||
unsigned long nlength, length_a;
|
||||
unsigned char* dptr;
|
||||
|
||||
nlength = prgm->length + length;
|
||||
if (nlength > prgm->length_a) {
|
||||
length_a = nlength + 16384;
|
||||
|
||||
dptr = rs_realloc(prgm->data, length_a);
|
||||
if (!dptr)
|
||||
return RS_ERR_OUT_OF_MEMORY;
|
||||
prgm->data = dptr;
|
||||
prgm->length_a = length_a;
|
||||
}
|
||||
|
||||
memcpy(prgm->data + prgm->length, data, length);
|
||||
prgm->length = nlength;
|
||||
return RS_SUCCESS;
|
||||
}
|
||||
463
tool/rabbitsign-src/rabbitsign.c
Normal file
463
tool/rabbitsign-src/rabbitsign.c
Normal file
|
|
@ -0,0 +1,463 @@
|
|||
/*
|
||||
* RabbitSign - Tools for signing TI graphing calculator software
|
||||
* Copyright (C) 2009 Benjamin Moody
|
||||
*
|
||||
* This program 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.
|
||||
*
|
||||
* This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
# include <config.h>
|
||||
#endif
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#ifdef HAVE_STDLIB_H
|
||||
# include <stdlib.h>
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_STRING_H
|
||||
# include <string.h>
|
||||
#else
|
||||
# ifdef HAVE_STRINGS_H
|
||||
# include <strings.h>
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#include "rabbitsign.h"
|
||||
#include "internal.h"
|
||||
|
||||
#if !defined(strcasecmp) && !defined(HAVE_STRCASECMP)
|
||||
# ifdef HAVE_STRICMP
|
||||
# define strcasecmp stricmp
|
||||
# else
|
||||
# define strcasecmp strcmp
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#if !defined(strrchr) && !defined(HAVE_STRRCHR) && defined(HAVE_RINDEX)
|
||||
# define strrchr rindex
|
||||
#endif
|
||||
|
||||
static const char* getbasename(const char* f)
|
||||
{
|
||||
const char *p;
|
||||
|
||||
if ((p = strrchr(f, '/')))
|
||||
f = p + 1;
|
||||
|
||||
#if defined(__MSDOS__) || defined(__WIN32__)
|
||||
if ((p = strrchr(f, '\\')))
|
||||
f = p + 1;
|
||||
#endif
|
||||
|
||||
return f;
|
||||
}
|
||||
|
||||
static const char* usage[]={
|
||||
"Usage: %s [options] app-file ...\n",
|
||||
"Where options may include:\n",
|
||||
" -a: appsign compatibility mode (Unix-style output)\n",
|
||||
" -b: read raw binary data (default: auto-detect)\n",
|
||||
" -c: check existing app signatures rather than signing\n",
|
||||
" -f: force signing despite errors\n",
|
||||
" -g: write app in GraphLink (XXk) format\n",
|
||||
" -k KEYFILE: use specified key file\n",
|
||||
" -K NUM: use specified key ID (hexadecimal)\n",
|
||||
" -n: do not alter the app header\n",
|
||||
" -o OUTFILE: write to specified output file (default is <name>.app\n",
|
||||
" or <name>.8xk)\n",
|
||||
" -p: fix the pages field if found\n",
|
||||
" -P: add an extra page if necessary\n",
|
||||
" -q: suppress warning messages\n",
|
||||
" -r: re-sign a previously signed app (i.e. strip off all\n",
|
||||
" data beyond that indicated by the size header)\n",
|
||||
" -R R: specify the root to use (0, 1, 2, or 3) (default is 0)\n",
|
||||
" -t TYPE: specify program type (e.g. 8xk, 73u)\n",
|
||||
" -u: assume plain hex input is unsorted (default is sorted)\n",
|
||||
" -v: be verbose (-vv for even more verbosity)\n",
|
||||
" --help: describe options\n",
|
||||
" --version: print version info\n",
|
||||
NULL};
|
||||
|
||||
int main(int argc, char** argv)
|
||||
{
|
||||
unsigned int flags = (RS_INPUT_SORTED | RS_OUTPUT_HEX_ONLY);
|
||||
|
||||
int rootnum = 0; /* which of the four valid signatures
|
||||
to generate
|
||||
|
||||
0 = standard (r,s)
|
||||
1 = (-r,s)
|
||||
2 = (r,-s)
|
||||
3 = (-r,-s) */
|
||||
|
||||
int rawmode = 0; /* 0 = fix app headers
|
||||
1 = sign "raw" data */
|
||||
|
||||
int valmode = 0; /* 0 = sign apps
|
||||
1 = validate apps */
|
||||
|
||||
const char* infilename; /* file name for input */
|
||||
|
||||
const char* outfilename = NULL; /* file name for output */
|
||||
|
||||
const char* keyfilename = NULL; /* file name for key */
|
||||
|
||||
int verbose = 0; /* -1 = quiet (errors only)
|
||||
0 = default (warnings + errors)
|
||||
1 = verbose (print file names / status)
|
||||
2 = very verbose (details of computation) */
|
||||
|
||||
static const char optstring[] = "abcfgk:K:no:pPqrR:t:uv";
|
||||
const char *progname;
|
||||
int i, j, c, e;
|
||||
const char* arg;
|
||||
char *tempname;
|
||||
|
||||
FILE* infile;
|
||||
FILE* outfile;
|
||||
RSKey* key;
|
||||
RSProgram* prgm;
|
||||
unsigned long keyid = 0, appkeyid;
|
||||
RSCalcType ctype = RS_CALC_UNKNOWN;
|
||||
RSDataType dtype = RS_DATA_UNKNOWN;
|
||||
|
||||
char *ptr;
|
||||
const char *ext;
|
||||
int invalidapps = 0;
|
||||
|
||||
progname = getbasename(argv[0]);
|
||||
rs_set_progname(progname);
|
||||
|
||||
if (argc == 1) {
|
||||
fprintf(stderr, usage[0], progname);
|
||||
for (i = 1; usage[i]; i++)
|
||||
fputs(usage[i], stderr);
|
||||
return 5;
|
||||
}
|
||||
|
||||
i = j = 1;
|
||||
while ((c = rs_parse_cmdline(argc, argv, optstring, &i, &j, &arg))) {
|
||||
switch (c) {
|
||||
case RS_CMDLINE_HELP:
|
||||
printf(usage[0], progname);
|
||||
for (i = 1; usage[i]; i++)
|
||||
fputs(usage[i], stdout);
|
||||
return 0;
|
||||
|
||||
case RS_CMDLINE_VERSION:
|
||||
printf("rabbitsign\n");
|
||||
fputs("Copyright (C) 2009 Benjamin Moody\n", stdout);
|
||||
fputs("This program is free software. ", stdout);
|
||||
fputs("There is NO WARRANTY of any kind.\n", stdout);
|
||||
return 0;
|
||||
|
||||
case 'o':
|
||||
outfilename = arg;
|
||||
break;
|
||||
|
||||
case 'k':
|
||||
keyfilename = arg;
|
||||
break;
|
||||
|
||||
case 'K':
|
||||
if (!sscanf(arg, "%lx", &keyid)) {
|
||||
fprintf(stderr, "%s: -K: invalid argument %s\n", progname, arg);
|
||||
return 5;
|
||||
}
|
||||
break;
|
||||
|
||||
case 'b':
|
||||
flags |= RS_INPUT_BINARY;
|
||||
break;
|
||||
|
||||
case 'u':
|
||||
flags &= ~RS_INPUT_SORTED;
|
||||
break;
|
||||
|
||||
case 'f':
|
||||
flags |= RS_IGNORE_ALL_WARNINGS;
|
||||
break;
|
||||
|
||||
case 'g':
|
||||
flags &= ~RS_OUTPUT_HEX_ONLY;
|
||||
break;
|
||||
|
||||
case 'a':
|
||||
flags |= RS_OUTPUT_APPSIGN;
|
||||
break;
|
||||
|
||||
case 'R':
|
||||
if (!sscanf(arg, "%d", &rootnum)) {
|
||||
fprintf(stderr, "%s: -R: invalid argument %s\n", progname, arg);
|
||||
return 5;
|
||||
}
|
||||
break;
|
||||
|
||||
case 't':
|
||||
if (rs_suffix_to_type(arg, &ctype, &dtype)) {
|
||||
fprintf(stderr, "%s: unrecognized file type %s\n", progname, arg);
|
||||
return 5;
|
||||
}
|
||||
break;
|
||||
|
||||
case 'n':
|
||||
rawmode = 1;
|
||||
break;
|
||||
|
||||
case 'r':
|
||||
flags |= RS_REMOVE_OLD_SIGNATURE;
|
||||
break;
|
||||
|
||||
case 'P':
|
||||
flags |= RS_ZEALOUSLY_PAD_APP;
|
||||
break;
|
||||
|
||||
case 'p':
|
||||
flags |= RS_FIX_PAGE_COUNT;
|
||||
break;
|
||||
|
||||
case 'c':
|
||||
valmode = 1;
|
||||
break;
|
||||
|
||||
case 'v':
|
||||
verbose++;
|
||||
break;
|
||||
|
||||
case 'q':
|
||||
verbose--;
|
||||
break;
|
||||
|
||||
case RS_CMDLINE_FILENAME:
|
||||
break;
|
||||
|
||||
case RS_CMDLINE_ERROR:
|
||||
return 5;
|
||||
|
||||
default:
|
||||
fprintf(stderr, "%s: internal error: unknown option -%c\n",
|
||||
progname, c);
|
||||
abort();
|
||||
}
|
||||
}
|
||||
|
||||
rs_set_verbose(verbose);
|
||||
|
||||
if (outfilename && (ptr = strrchr(outfilename, '.'))
|
||||
&& !rs_suffix_to_type(ptr + 1, NULL, NULL))
|
||||
flags &= ~RS_OUTPUT_HEX_ONLY;
|
||||
|
||||
|
||||
/* Read key file (if manually specified) */
|
||||
|
||||
key = rs_key_new();
|
||||
|
||||
if (keyfilename) {
|
||||
infile = fopen(keyfilename, "rb");
|
||||
if (!infile) {
|
||||
perror(keyfilename);
|
||||
rs_key_free(key);
|
||||
return 3;
|
||||
}
|
||||
if (rs_read_key_file(key, infile, keyfilename, 1)) {
|
||||
fclose(infile);
|
||||
rs_key_free(key);
|
||||
return 3;
|
||||
}
|
||||
fclose(infile);
|
||||
}
|
||||
else if (keyid) {
|
||||
if (rs_key_find_for_id(key, keyid, valmode)) {
|
||||
rs_key_free(key);
|
||||
return 3;
|
||||
}
|
||||
}
|
||||
|
||||
/* Process applications */
|
||||
|
||||
i = j = 1;
|
||||
while ((c = rs_parse_cmdline(argc, argv, optstring, &i, &j, &arg))) {
|
||||
if (c != RS_CMDLINE_FILENAME)
|
||||
continue;
|
||||
|
||||
/* Read input file */
|
||||
|
||||
if (strcmp(arg, "-")) {
|
||||
infilename = arg;
|
||||
infile = fopen(arg, "rb");
|
||||
if (!infile) {
|
||||
perror(arg);
|
||||
rs_key_free(key);
|
||||
return 4;
|
||||
}
|
||||
}
|
||||
else {
|
||||
infilename = "(standard input)";
|
||||
infile = stdin;
|
||||
}
|
||||
|
||||
prgm = rs_program_new();
|
||||
|
||||
if (ctype && dtype) {
|
||||
prgm->calctype = ctype;
|
||||
prgm->datatype = dtype;
|
||||
}
|
||||
else if ((ptr = strrchr(infilename, '.'))) {
|
||||
rs_suffix_to_type(ptr + 1, &prgm->calctype, &prgm->datatype);
|
||||
}
|
||||
|
||||
if (rs_read_program_file(prgm, infile, infilename, flags)) {
|
||||
rs_program_free(prgm);
|
||||
rs_key_free(key);
|
||||
if (infile != stdin)
|
||||
fclose(infile);
|
||||
return 4;
|
||||
}
|
||||
if (infile != stdin)
|
||||
fclose(infile);
|
||||
|
||||
/* Read key file (if automatic) */
|
||||
|
||||
if (!keyfilename && !keyid) {
|
||||
appkeyid = rs_program_get_key_id(prgm);
|
||||
if (!appkeyid) {
|
||||
fprintf(stderr, "%s: unable to determine key ID\n", infilename);
|
||||
rs_program_free(prgm);
|
||||
rs_key_free(key);
|
||||
return 3;
|
||||
}
|
||||
|
||||
if (appkeyid != key->id) {
|
||||
if (rs_key_find_for_id(key, appkeyid, valmode)) {
|
||||
rs_program_free(prgm);
|
||||
rs_key_free(key);
|
||||
return 3;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (valmode) {
|
||||
/* Validate application */
|
||||
if (verbose > 0)
|
||||
fprintf(stderr, "Validating %s %s %s...\n",
|
||||
rs_calc_type_to_string(prgm->calctype),
|
||||
rs_data_type_to_string(prgm->datatype),
|
||||
infilename);
|
||||
|
||||
if (rs_validate_program(prgm, key))
|
||||
invalidapps++;
|
||||
}
|
||||
else {
|
||||
/* Sign application */
|
||||
if (verbose > 0)
|
||||
fprintf(stderr, "Signing %s %s %s...\n",
|
||||
rs_calc_type_to_string(prgm->calctype),
|
||||
rs_data_type_to_string(prgm->datatype),
|
||||
infilename);
|
||||
|
||||
if (!rawmode) {
|
||||
if ((e = rs_repair_program(prgm, flags))) {
|
||||
if (!(flags & RS_IGNORE_ALL_WARNINGS)
|
||||
&& e < RS_ERR_CRITICAL)
|
||||
fprintf(stderr, "(use -f to override)\n");
|
||||
rs_program_free(prgm);
|
||||
rs_key_free(key);
|
||||
return 2;
|
||||
}
|
||||
}
|
||||
if (rs_sign_program(prgm, key, rootnum)) {
|
||||
rs_program_free(prgm);
|
||||
rs_key_free(key);
|
||||
return 2;
|
||||
}
|
||||
|
||||
/* Generate output file name */
|
||||
|
||||
if (outfilename) {
|
||||
if (strcmp(outfilename, "-")) {
|
||||
outfile = fopen(outfilename, "wb");
|
||||
if (!outfile) {
|
||||
perror(outfilename);
|
||||
rs_program_free(prgm);
|
||||
rs_key_free(key);
|
||||
return 4;
|
||||
}
|
||||
}
|
||||
else {
|
||||
outfile = stdout;
|
||||
}
|
||||
}
|
||||
else if (infile == stdin) {
|
||||
outfile = stdout;
|
||||
}
|
||||
else {
|
||||
ext = rs_type_to_suffix(prgm->calctype, prgm->datatype,
|
||||
(flags & RS_OUTPUT_HEX_ONLY));
|
||||
|
||||
tempname = rs_malloc(strlen(infilename) + 32);
|
||||
if (!tempname) {
|
||||
rs_program_free(prgm);
|
||||
rs_key_free(key);
|
||||
return 4;
|
||||
}
|
||||
strcpy(tempname, infilename);
|
||||
|
||||
ptr = strrchr(tempname, '.');
|
||||
if (!ptr) {
|
||||
strcat(tempname, ".");
|
||||
strcat(tempname, ext);
|
||||
}
|
||||
else if (strcasecmp(ptr + 1, ext)) {
|
||||
strcpy(ptr + 1, ext);
|
||||
}
|
||||
else {
|
||||
strcpy(ptr, "-signed.");
|
||||
strcat(ptr, ext);
|
||||
}
|
||||
|
||||
outfile = fopen(tempname, "wb");
|
||||
if (!outfile) {
|
||||
perror(tempname);
|
||||
rs_free(tempname);
|
||||
rs_program_free(prgm);
|
||||
rs_key_free(key);
|
||||
return 4;
|
||||
}
|
||||
rs_free(tempname);
|
||||
}
|
||||
|
||||
/* Write signed application to output file */
|
||||
|
||||
if (rs_write_program_file(prgm, outfile, 0, 0, 0, flags)) {
|
||||
if (outfile != stdout)
|
||||
fclose(outfile);
|
||||
rs_program_free(prgm);
|
||||
rs_key_free(key);
|
||||
return 4;
|
||||
}
|
||||
|
||||
if (outfile != stdout)
|
||||
fclose(outfile);
|
||||
}
|
||||
rs_program_free(prgm);
|
||||
}
|
||||
|
||||
rs_key_free(key);
|
||||
|
||||
if (invalidapps)
|
||||
return 1;
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
342
tool/rabbitsign-src/rabbitsign.h
Normal file
342
tool/rabbitsign-src/rabbitsign.h
Normal file
|
|
@ -0,0 +1,342 @@
|
|||
/*
|
||||
* RabbitSign - Tools for signing TI graphing calculator software
|
||||
* Copyright (C) 2009 Benjamin Moody
|
||||
*
|
||||
* This program 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.
|
||||
*
|
||||
* This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef __RABBITSIGN_H__
|
||||
#define __RABBITSIGN_H__
|
||||
|
||||
#ifdef HAVE_GMP_H
|
||||
# include <gmp.h>
|
||||
# define rs_snprintf gmp_snprintf
|
||||
# define rs_vsnprintf gmp_vsnprintf
|
||||
#else
|
||||
# include "mpz.h"
|
||||
#endif
|
||||
|
||||
#if __GNUC__ >= 3
|
||||
# define RS_ATTR_PURE __attribute__((pure))
|
||||
# define RS_ATTR_MALLOC __attribute__((malloc))
|
||||
# define RS_ATTR_UNUSED __attribute__((unused))
|
||||
# define RS_ATTR_PRINTF(f,i) __attribute__((format(printf,f,i)))
|
||||
#else
|
||||
# define RS_ATTR_PURE
|
||||
# define RS_ATTR_MALLOC
|
||||
# define RS_ATTR_UNUSED
|
||||
# define RS_ATTR_PRINTF(f,i)
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* Calculator types */
|
||||
typedef enum _RSCalcType {
|
||||
RS_CALC_UNKNOWN = 0,
|
||||
RS_CALC_TI73 = 0x74,
|
||||
RS_CALC_TI83P = 0x73,
|
||||
RS_CALC_TI89 = 0x98,
|
||||
RS_CALC_TI92P = 0x88
|
||||
} RSCalcType;
|
||||
|
||||
#define rs_calc_is_ti8x(ttt) ((ttt) == RS_CALC_TI73 || (ttt) == RS_CALC_TI83P)
|
||||
#define rs_calc_is_ti9x(ttt) ((ttt) == RS_CALC_TI89 || (ttt) == RS_CALC_TI92P)
|
||||
|
||||
/* Data types */
|
||||
typedef enum _RSDataType {
|
||||
RS_DATA_UNKNOWN = 0,
|
||||
RS_DATA_OS = 0x23,
|
||||
RS_DATA_APP = 0x24,
|
||||
RS_DATA_CERT = 0x25
|
||||
} RSDataType;
|
||||
|
||||
/* Flags for app signing */
|
||||
typedef enum _RSRepairFlags {
|
||||
RS_IGNORE_ALL_WARNINGS = 1,
|
||||
RS_REMOVE_OLD_SIGNATURE = 2, /* Remove existing signature */
|
||||
RS_FIX_PAGE_COUNT = 4, /* Fix page count header field */
|
||||
RS_FIX_OS_SIZE = 8, /* Fix size in OS header */
|
||||
RS_ZEALOUSLY_PAD_APP = 16 /* Pad application with an extra
|
||||
page if necessary */
|
||||
} RSRepairFlags;
|
||||
|
||||
/* Flags for file input */
|
||||
typedef enum _RSInputFlags {
|
||||
RS_INPUT_BINARY = 32, /* Assume input is raw binary
|
||||
data */
|
||||
RS_INPUT_SORTED = 64 /* Assume plain hex input is sorted
|
||||
(implicit page switch) */
|
||||
} RSInputFlags;
|
||||
|
||||
/* Flags for file output */
|
||||
typedef enum _RSOutputFlags {
|
||||
RS_OUTPUT_HEX_ONLY = 128, /* Write plain hex (.app) format */
|
||||
RS_OUTPUT_APPSIGN = 256 /* Write hex data in
|
||||
appsign-compatible format */
|
||||
} RSOutputFlags;
|
||||
|
||||
/* Encryption key structure */
|
||||
typedef struct _RSKey {
|
||||
char* filename; /* Filename */
|
||||
unsigned long id; /* Key ID */
|
||||
mpz_t n; /* Modulus (public key) */
|
||||
mpz_t p; /* First factor */
|
||||
mpz_t q; /* Second factor */
|
||||
mpz_t qinv; /* q^-1 mod p (for Rabin)
|
||||
(rs_sign_rabin() will calculate
|
||||
this based on p and q, if
|
||||
needed) */
|
||||
mpz_t d; /* Signing exponent (for RSA)
|
||||
(rs_sign_rsa() will calculate this
|
||||
based on p and q, if needed) */
|
||||
} RSKey;
|
||||
|
||||
/* Program data structure */
|
||||
typedef struct _RSProgram {
|
||||
char* filename; /* Filename */
|
||||
RSCalcType calctype; /* Calculator type */
|
||||
RSDataType datatype; /* Program data type */
|
||||
unsigned char* data; /* Program data */
|
||||
unsigned long length; /* Length of program data */
|
||||
unsigned long length_a; /* Size of buffer allocated */
|
||||
|
||||
/* Additional metadata (only used by TI-8x OS) */
|
||||
unsigned char* header; /* OS header */
|
||||
unsigned int header_length; /* Length of OS header */
|
||||
unsigned char* signature; /* OS signature */
|
||||
unsigned int signature_length; /* Length of OS signature */
|
||||
unsigned int* pagenums; /* List of page numbers */
|
||||
int npagenums; /* Number of page numbers */
|
||||
} RSProgram;
|
||||
|
||||
/* Status codes */
|
||||
typedef enum _RSStatus {
|
||||
RS_SUCCESS = 0,
|
||||
|
||||
RS_ERR_MISSING_PAGE_COUNT,
|
||||
RS_ERR_MISSING_KEY_ID,
|
||||
RS_ERR_MISSING_DATE_STAMP,
|
||||
RS_ERR_MISSING_PROGRAM_IMAGE,
|
||||
RS_ERR_MISALIGNED_PROGRAM_IMAGE,
|
||||
RS_ERR_INVALID_PROGRAM_DATA,
|
||||
RS_ERR_INVALID_PROGRAM_SIZE,
|
||||
RS_ERR_INCORRECT_PAGE_COUNT,
|
||||
RS_ERR_FINAL_PAGE_TOO_LONG,
|
||||
RS_ERR_FIELD_TOO_SMALL,
|
||||
|
||||
RS_ERR_CRITICAL = 1000,
|
||||
|
||||
RS_ERR_OUT_OF_MEMORY,
|
||||
RS_ERR_FILE_IO,
|
||||
RS_ERR_HEX_SYNTAX,
|
||||
RS_ERR_UNKNOWN_FILE_FORMAT,
|
||||
RS_ERR_UNKNOWN_PROGRAM_TYPE,
|
||||
RS_ERR_MISSING_HEADER,
|
||||
RS_ERR_MISSING_RABIN_SIGNATURE,
|
||||
RS_ERR_MISSING_RSA_SIGNATURE,
|
||||
RS_ERR_INCORRECT_PROGRAM_SIZE,
|
||||
RS_ERR_KEY_NOT_FOUND,
|
||||
RS_ERR_KEY_SYNTAX,
|
||||
RS_ERR_INVALID_KEY,
|
||||
RS_ERR_MISSING_PUBLIC_KEY,
|
||||
RS_ERR_MISSING_PRIVATE_KEY,
|
||||
RS_ERR_UNSUITABLE_RABIN_KEY,
|
||||
RS_ERR_UNSUITABLE_RSA_KEY,
|
||||
|
||||
RS_SIGNATURE_INCORRECT = -1
|
||||
} RSStatus;
|
||||
|
||||
|
||||
/**** Key handling (keys.c) ****/
|
||||
|
||||
/* Create a new key. */
|
||||
RSKey* rs_key_new (void) RS_ATTR_MALLOC;
|
||||
|
||||
/* Free a key. */
|
||||
void rs_key_free (RSKey* key);
|
||||
|
||||
/* Read key from a file. */
|
||||
RSStatus rs_read_key_file (RSKey* key, FILE* f,
|
||||
const char* fname, int verify);
|
||||
|
||||
/* Parse a number written in TI's hexadecimal key format. */
|
||||
RSStatus rs_parse_key_value (mpz_t dest, const char* str);
|
||||
|
||||
|
||||
/**** Program data manipulation (program.c) ****/
|
||||
|
||||
/* Create a new program. */
|
||||
RSProgram* rs_program_new (void) RS_ATTR_MALLOC;
|
||||
|
||||
/* Create a new program from an existing data buffer. */
|
||||
RSProgram* rs_program_new_with_data (RSCalcType ctype, RSDataType dtype,
|
||||
void* data, unsigned long length,
|
||||
unsigned long buffer_size)
|
||||
RS_ATTR_MALLOC;
|
||||
|
||||
/* Free program data. */
|
||||
void rs_program_free (RSProgram* prgm);
|
||||
|
||||
/* Truncate or extend program. */
|
||||
RSStatus rs_program_set_length (RSProgram* prgm, unsigned long length);
|
||||
|
||||
/* Add data to the end of the program. */
|
||||
RSStatus rs_program_append_data (RSProgram* prgm, const unsigned char* data,
|
||||
unsigned long length);
|
||||
|
||||
|
||||
/**** Search for key file (autokey.c) ****/
|
||||
|
||||
/* Get key ID for the given program. */
|
||||
unsigned long rs_program_get_key_id (const RSProgram* prgm) RS_ATTR_PURE;
|
||||
|
||||
/* Find key file for the given ID. */
|
||||
RSStatus rs_key_find_for_id (RSKey* key, unsigned long keyid, int publiconly);
|
||||
|
||||
|
||||
/**** Program signing and validation (apps.c) ****/
|
||||
|
||||
/* Check/fix program header and data. */
|
||||
RSStatus rs_repair_program (RSProgram* prgm, RSRepairFlags flags);
|
||||
|
||||
/* Add a signature to the program. */
|
||||
RSStatus rs_sign_program (RSProgram* prgm, RSKey* key, int rootnum);
|
||||
|
||||
/* Validate program signature. */
|
||||
RSStatus rs_validate_program (const RSProgram* prgm, const RSKey* key);
|
||||
|
||||
|
||||
/**** TI-73/83+/84+ app signing (app8x.c) ****/
|
||||
|
||||
/* Check/fix Flash app header and data. */
|
||||
RSStatus rs_repair_ti8x_app (RSProgram* app, RSRepairFlags flags);
|
||||
|
||||
/* Add a signature to a Flash app. */
|
||||
RSStatus rs_sign_ti8x_app (RSProgram* app, RSKey* key, int rootnum);
|
||||
|
||||
/* Validate Flash app signature. */
|
||||
RSStatus rs_validate_ti8x_app (const RSProgram* app, const RSKey* key);
|
||||
|
||||
|
||||
/**** TI-73/83+/84+ OS signing (os8x.c) ****/
|
||||
|
||||
/* Check/fix OS header and data. */
|
||||
RSStatus rs_repair_ti8x_os (RSProgram* os, RSRepairFlags flags);
|
||||
|
||||
/* Add a signature to an OS. */
|
||||
RSStatus rs_sign_ti8x_os (RSProgram* os, RSKey* key);
|
||||
|
||||
/* Validate OS signature. */
|
||||
RSStatus rs_validate_ti8x_os (const RSProgram* os, const RSKey* key);
|
||||
|
||||
|
||||
/**** TI-89/92+ app/OS signing (app9x.c) ****/
|
||||
|
||||
/* Check/fix Flash app header and data. */
|
||||
RSStatus rs_repair_ti9x_app (RSProgram* app, RSRepairFlags flags);
|
||||
|
||||
/* Check/fix OS header and data. */
|
||||
RSStatus rs_repair_ti9x_os (RSProgram* app, RSRepairFlags flags);
|
||||
|
||||
/* Add a signature to a 68k app/OS. */
|
||||
RSStatus rs_sign_ti9x_app (RSProgram* app, RSKey* key);
|
||||
|
||||
/* Validate app/OS signature. */
|
||||
RSStatus rs_validate_ti9x_app (const RSProgram* app, const RSKey* key);
|
||||
|
||||
#define rs_sign_ti9x_os rs_sign_ti9x_app
|
||||
#define rs_validate_ti9x_os rs_validate_ti9x_app
|
||||
|
||||
|
||||
/**** File input (input.c) ****/
|
||||
|
||||
/* Read program contents from a file. */
|
||||
RSStatus rs_read_program_file (RSProgram* prgm, FILE* f,
|
||||
const char* fname, RSInputFlags flags);
|
||||
|
||||
|
||||
/**** File output (output.c) ****/
|
||||
|
||||
/* Write program contents to a file. */
|
||||
RSStatus rs_write_program_file(const RSProgram* prgm, FILE* f,
|
||||
int month, int day, int year,
|
||||
RSOutputFlags flags);
|
||||
|
||||
|
||||
/**** Hex file output (output8x.c) ****/
|
||||
|
||||
/* Write program to a .73k/.73u/.8xk/.8xu or .app file. */
|
||||
RSStatus rs_write_ti8x_file (const RSProgram* prgm, FILE* f,
|
||||
int month, int day, int year,
|
||||
RSOutputFlags flags);
|
||||
|
||||
|
||||
/**** Binary file output (output9x.c) ****/
|
||||
|
||||
/* Write program to a .89k/.89u/.9xk/.9xu file. */
|
||||
RSStatus rs_write_ti9x_file (const RSProgram* prgm, FILE* f,
|
||||
int month, int day, int year,
|
||||
RSOutputFlags flags);
|
||||
|
||||
|
||||
/**** App header/certificate utility functions (header.c) ****/
|
||||
|
||||
/* Get length of a header field. */
|
||||
void rs_get_field_size (const unsigned char* data,
|
||||
unsigned long* fieldstart,
|
||||
unsigned long* fieldsize);
|
||||
|
||||
/* Set length of a header field. */
|
||||
int rs_set_field_size (unsigned char* data,
|
||||
unsigned long fieldsize);
|
||||
|
||||
/* Find a given header field in the data. */
|
||||
int rs_find_app_field (unsigned int type,
|
||||
const unsigned char* data,
|
||||
unsigned long length,
|
||||
unsigned long* fieldhead,
|
||||
unsigned long* fieldstart,
|
||||
unsigned long* fieldsize);
|
||||
|
||||
/* Get value of a numeric header field. */
|
||||
unsigned long rs_get_numeric_field (unsigned int type,
|
||||
const unsigned char* data,
|
||||
unsigned long length) RS_ATTR_PURE;
|
||||
|
||||
|
||||
/**** Error/message logging (error.c) ****/
|
||||
|
||||
typedef void (*RSMessageFunc) (const RSKey*, const RSProgram*,
|
||||
const char*, void*);
|
||||
|
||||
/* Set program name */
|
||||
void rs_set_progname (const char* s);
|
||||
|
||||
/* Set verbosity level */
|
||||
void rs_set_verbose (int v);
|
||||
|
||||
/* Set error logging function */
|
||||
void rs_set_error_func (RSMessageFunc func, void* data);
|
||||
|
||||
/* Set message logging function */
|
||||
void rs_set_message_func (RSMessageFunc func, void* data);
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* __RABBITSIGN_H__ */
|
||||
425
tool/rabbitsign-src/rabin.c
Normal file
425
tool/rabbitsign-src/rabin.c
Normal file
|
|
@ -0,0 +1,425 @@
|
|||
/*
|
||||
* RabbitSign - Tools for signing TI graphing calculator software
|
||||
* Copyright (C) 2009 Benjamin Moody
|
||||
*
|
||||
* This program 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.
|
||||
*
|
||||
* This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
# include <config.h>
|
||||
#endif
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#include "rabbitsign.h"
|
||||
#include "internal.h"
|
||||
|
||||
/*
|
||||
* Compute square root of x modulo p, where p === 3 (mod 4).
|
||||
*
|
||||
* (Assume that (x|p) = 1.)
|
||||
*
|
||||
* Notice that:
|
||||
*
|
||||
* p = 4k + 3
|
||||
*
|
||||
* x^[(p-1)/2] = x^(2k+1) = (x|p) = 1
|
||||
*
|
||||
* x^(2k+2) = x
|
||||
*
|
||||
* [x^(k+1)]^2 = x
|
||||
*
|
||||
* so x^(k+1) = x^[(p+1)/4] is a square root of x.
|
||||
*/
|
||||
static void mpz_sqrtm_3 (mpz_t res, /* mpz to store result */
|
||||
const mpz_t x, /* number to get square root of */
|
||||
const mpz_t p) /* prime modulus === 3 (mod 4) */
|
||||
{
|
||||
mpz_add_ui(res, p, 1);
|
||||
mpz_fdiv_q_2exp(res, res, 2); /* (p + 1)/4 */
|
||||
mpz_powm(res, x, res, p);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Compute square root of x modulo p, where p === 5 (mod 8).
|
||||
*
|
||||
* (Assume that (x|p) = 1.)
|
||||
*
|
||||
* Notice that:
|
||||
*
|
||||
* p = 4k + 1
|
||||
*
|
||||
* x^[(p-1)/2] = x^(2k) = (x|p) = 1
|
||||
*
|
||||
* x^[(k+1)/2]^2 * x^(4k-1) = x^(5k) = x^k
|
||||
*
|
||||
* Since x^k^2 = 1, x^k = +/- 1.
|
||||
*
|
||||
* CASE 1:
|
||||
* If x^k = 1, x^[(k+1)/2]^2 = x, so x^[(k+1)/2] = x^[(p+3)/8] is
|
||||
* the square root of x.
|
||||
*
|
||||
* CASE 2:
|
||||
* Otherwise, x^[(k+1)/2]^2 = -x; we need to find a square root of
|
||||
* -1.
|
||||
*
|
||||
* Since (2|p) = -1, 2^[(p-1)/2] = 2^(2k) = -1, so (2^k)^2 = -1
|
||||
*
|
||||
* (x^[(k+1)/2] * 2^k)^2 = -x * -1 = x
|
||||
*
|
||||
* so x^[(k+1)/2] * 2^k = x^[(p+3)/8] * 2^[(p-1)/4] is the square
|
||||
* root of x.
|
||||
*/
|
||||
static void mpz_sqrtm_5 (mpz_t res, /* mpz to store result */
|
||||
const mpz_t x, /* number to get square root of */
|
||||
const mpz_t p) /* prime modulus === 5 (mod 8) */
|
||||
{
|
||||
mpz_t a, b;
|
||||
mpz_init(a);
|
||||
mpz_init(b);
|
||||
|
||||
mpz_add_ui(a, p, 3);
|
||||
mpz_fdiv_q_2exp(b, a, 3);
|
||||
mpz_powm(res, x, b, p); /* x ^ (p+3)/8 */
|
||||
|
||||
/* Check if res^2 = x */
|
||||
mpz_mul(a, res, res);
|
||||
mpz_sub(b, a, x);
|
||||
mpz_mod(a, b, p);
|
||||
|
||||
if (0 != mpz_sgn(a)) {
|
||||
mpz_sub_ui(a, p, 1);
|
||||
mpz_fdiv_q_2exp(b, a, 2);
|
||||
mpz_set_ui(a, 2);
|
||||
mpz_powm(a, a, b, p); /* 2 ^ (p-1)/4 */
|
||||
mpz_mul(res, res, a);
|
||||
}
|
||||
|
||||
mpz_clear(a);
|
||||
mpz_clear(b);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Compute square root of x modulo p.
|
||||
*
|
||||
* This still won't work with p === 1 mod 8, but then, TI's system
|
||||
* won't work at all for 50% of apps if one of your factors is 1 mod
|
||||
* 8. (See the discussion of f values below.)
|
||||
*
|
||||
*/
|
||||
static void mpz_sqrtm (mpz_t res, /* mpz to store result */
|
||||
const mpz_t x, /* number to get square root of */
|
||||
const mpz_t p) /* prime modulus === 3, 5, or 7
|
||||
(mod 8) */
|
||||
{
|
||||
if ((mpz_get_ui(p) % 8) == 5)
|
||||
mpz_sqrtm_5(res, x, p);
|
||||
else
|
||||
mpz_sqrtm_3(res, x, p);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Compute x s.t. x === r (mod p) and x === s (mod q).
|
||||
*
|
||||
* We compute this as:
|
||||
*
|
||||
* [(r-s) * q^-1 mod p] * q + s
|
||||
*
|
||||
*/
|
||||
static void mpz_crt(mpz_t res, /* mpz to store result */
|
||||
const mpz_t r, /* root modulo p */
|
||||
const mpz_t s, /* root modulo q */
|
||||
const mpz_t p, /* first modulus */
|
||||
const mpz_t q, /* second modulus */
|
||||
const mpz_t qinv) /* q^(p-2) mod p */
|
||||
{
|
||||
/* ((r - s) */
|
||||
mpz_sub(res, r, s);
|
||||
|
||||
/* * q^-1) */
|
||||
mpz_mul(res, res, qinv);
|
||||
mpz_mod(res, res, p);
|
||||
|
||||
/* * q + s */
|
||||
mpz_mul(res, res, q);
|
||||
mpz_add(res, res, s);
|
||||
}
|
||||
|
||||
/*
|
||||
* Compute the T_f transform modulo n.
|
||||
*
|
||||
* Because only one quarter of the possible hashes can be signed with
|
||||
* a given key, we need to transform the hash. First, we want to
|
||||
* ensure that the result is nonzero, so we shift the hash by 8 bits
|
||||
* and add a 1 to the end. The resulting number is called m'.
|
||||
*
|
||||
* Second, we want to multiply it by a number k whose Legendre symbols
|
||||
* (k|p) and (k|q) are known, so that (km'|p) = (k|p)(m'|p) = 1 and
|
||||
* (km'|q) = (k|q)(km'|q) = 1. Since we need both to be true
|
||||
* simultaneously, regardless of the values of (m'|p) and (m'|q), we
|
||||
* clearly need four possible values of k.
|
||||
*
|
||||
* As it happens, TI's keys all follow a precise format: they all have
|
||||
* p === 3 and q === 7 (mod 8). As a result, we know that
|
||||
*
|
||||
* (-1|p) = (-1|q) = -1
|
||||
*
|
||||
* (2|p) = -1, (2|q) = 1
|
||||
*
|
||||
* So TI has defined the following transformation functions:
|
||||
*
|
||||
* T_0(x) = -2x'
|
||||
* T_1(x) = -x'
|
||||
* T_2(x) = x'
|
||||
* T_3(x) = 2x'
|
||||
*
|
||||
* where x' = 256x + 1.
|
||||
*
|
||||
* In the usual case of p === 3 and q === 7 (mod 8), then, two of the
|
||||
* possible (T_f(m)|p) will equal 1:
|
||||
*
|
||||
* If (m'|p) = 1, then (T_0(m)|p) = (T_2(m)|p) = 1.
|
||||
* If (m'|p) = -1, then (T_1(m)|p) = (T_3(m)|p) = 1.
|
||||
*
|
||||
* Two of the possible (T_f(m)|q) will equal 1:
|
||||
*
|
||||
* If (m'|q) = 1, then (T_2(m)|q) = (T_3(m)|q) = 1.
|
||||
* If (m'|q) = -1, then (T_0(m)|q) = (T_1(m)|q) = 1.
|
||||
*
|
||||
* Thus we can choose exactly one f value with
|
||||
* (T_f(m)|p) = (T_f(m)|q) = 1.
|
||||
*
|
||||
* If r === 5 (mod 8) is a prime, (-1|r) = 1, while (2|r) = -1. Thus
|
||||
* a similar logic holds:
|
||||
*
|
||||
* If (m'|r) = 1, then (T_1(m)|r) = (T_2(m)|r) = 1.
|
||||
* If (m'|r) = -1, then (T_0(m)|r) = (T_3(m)|r) = 1.
|
||||
*
|
||||
* So if {p,q} === {3,5}, {5,7}, or {3,7} (mod 8), given any m, we can
|
||||
* pick an f with (T_f(m)|p) = (T_f(m)|q) = 1.
|
||||
*
|
||||
*/
|
||||
static void applyf(mpz_t res, /* mpz to store result */
|
||||
const mpz_t m, /* MD5 hash */
|
||||
const mpz_t n, /* public key */
|
||||
int f) /* f (0, 1, 2, 3) */
|
||||
{
|
||||
mpz_mul_ui(res, m, 256);
|
||||
mpz_add_ui(res, res, 1);
|
||||
|
||||
switch (f) {
|
||||
case 0:
|
||||
mpz_add(res, res, res);
|
||||
case 1:
|
||||
mpz_sub(res, n, res);
|
||||
break;
|
||||
case 2:
|
||||
break;
|
||||
case 3:
|
||||
mpz_add(res, res, res);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Compute the Rabin signature with a given f.
|
||||
*/
|
||||
static void rabsigf(mpz_t res, /* mpz to store result */
|
||||
const mpz_t m, /* MD5 hash */
|
||||
const mpz_t n, /* public key */
|
||||
const mpz_t p, /* first factor */
|
||||
const mpz_t q, /* second factor */
|
||||
const mpz_t qinv, /* q^(p-2) mod p */
|
||||
int f, /* f (0, 1, 2, 3) */
|
||||
int rootnum) /* root number (0, 1, 2, 3) */
|
||||
{
|
||||
mpz_t mm;
|
||||
mpz_t r,s;
|
||||
|
||||
mpz_init(r);
|
||||
mpz_init(s);
|
||||
mpz_init(mm);
|
||||
|
||||
applyf(mm, m, n, f);
|
||||
|
||||
mpz_sqrtm(r, mm, p);
|
||||
mpz_sqrtm(s, mm, q);
|
||||
|
||||
if (rootnum & 1) {
|
||||
mpz_sub(r, p, r);
|
||||
}
|
||||
|
||||
if (rootnum & 2) {
|
||||
mpz_sub(s, q, s);
|
||||
}
|
||||
|
||||
mpz_crt(res, r, s, p, q, qinv);
|
||||
|
||||
mpz_clear(r);
|
||||
mpz_clear(s);
|
||||
mpz_clear(mm);
|
||||
}
|
||||
|
||||
/*
|
||||
* Table of f values.
|
||||
*
|
||||
* Remember that
|
||||
*
|
||||
* f = 0 corresponds to multiplying by -2
|
||||
* f = 1 corresponds to multiplying by -1
|
||||
* f = 2 corresponds to multiplying by 1
|
||||
* f = 3 corresponds to multiplying by 2
|
||||
*/
|
||||
static const int ftab[36] = {
|
||||
/************* (m'|p) = (m'|q) = 1 */
|
||||
/********** (m'|p) = -1, (m'|q) = 1 */
|
||||
/****** (m'|p) = 1, (m'|q) = -1 */
|
||||
/*** (m'|p) = (m'|q) = -1 */
|
||||
|
||||
/* p === 3, q === 3 */
|
||||
2, 99, 99,1, /* (-1|p) = (-1|q) = -1 ==> if both -1, multiply by -1 */
|
||||
|
||||
/* p === 3, q === 5 */
|
||||
2, 1, 0, 3, /* (-1|p) = -1, (-1|q) = 1 ==> if (m'|p) = -1, multiply by -1 */
|
||||
/* (-2|p) = 1, (-2|q) = -1 ==> if (m'|q) = -1, multiply by -2 */
|
||||
|
||||
/* p === 3, q === 7 */
|
||||
2, 3, 0, 1, /* (2|p) = -1, (2|q) = 1 ==> if (m'|p) = -1, multiply by 2 */
|
||||
/* (-2|p) = 1, (-2|q) = -1 ==> if (m'|q) = -1, multiply by -2 */
|
||||
|
||||
/* p === 5, q === 3 */
|
||||
2, 0, 1, 3,
|
||||
|
||||
/* p === 5, q === 5 */
|
||||
2, 99, 99,3, /* (2|p) = (2|q) = -1 ==> if both -1, multiply by 2 */
|
||||
|
||||
/* p === 5, q === 7 */
|
||||
2, 3, 1, 0, /* (2|p) = -1, (2|q) = 1 ==> if (m'|p) = -1, multiply by 2 */
|
||||
/* (-1|p) = 1, (-1|q) = -1 ==> if (m'|q) = -1, multiply by -1 */
|
||||
|
||||
/* p === 7, q === 3 */
|
||||
2, 0, 3, 1,
|
||||
|
||||
/* p === 7, q === 5 */
|
||||
2, 1, 3, 0,
|
||||
|
||||
/* p === 7, q === 7 */
|
||||
2, 99, 99,1 /* (-1|p) = (-1|q) = -1 ==> if both -1, multiply by -1 */
|
||||
};
|
||||
|
||||
/*
|
||||
* Compute the Rabin signature and the useful value of f.
|
||||
*/
|
||||
int rs_sign_rabin(mpz_t res, /* mpz to store signature */
|
||||
int* f, /* f value chosen */
|
||||
const mpz_t hash, /* MD5 hash of app */
|
||||
int rootnum, /* root number (0, 1, 2, 3) */
|
||||
RSKey* key) /* key structure */
|
||||
{
|
||||
mpz_t mm;
|
||||
int mLp, mLq;
|
||||
int pm8, qm8;
|
||||
|
||||
if (!mpz_sgn(key->n)) {
|
||||
rs_error(key, NULL, "unable to sign: public key missing");
|
||||
return RS_ERR_MISSING_PUBLIC_KEY;
|
||||
}
|
||||
|
||||
if (!mpz_sgn(key->p) || !mpz_sgn(key->q)) {
|
||||
rs_error(key, NULL, "unable to sign: private key missing");
|
||||
return RS_ERR_MISSING_PRIVATE_KEY;
|
||||
}
|
||||
|
||||
mpz_init(mm);
|
||||
|
||||
/* Calculate q^-1 if necessary */
|
||||
|
||||
if (!mpz_sgn(key->qinv)) {
|
||||
#ifndef USE_MPZ_GCDEXT
|
||||
mpz_sub_ui(mm, key->p, 2);
|
||||
mpz_powm(key->qinv, key->q, mm, key->p);
|
||||
#else
|
||||
mpz_gcdext(mm, key->qinv, NULL, key->q, key->p);
|
||||
if (mpz_cmp_ui(mm, 1)) {
|
||||
mpz_clear(mm);
|
||||
rs_error(key, NULL, "unable to sign: unsuitable key");
|
||||
return RS_ERR_UNSUITABLE_RABIN_KEY;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
applyf(mm, hash, key->n, 2);
|
||||
|
||||
mLp = mpz_legendre(mm, key->p);
|
||||
mLq = mpz_legendre(mm, key->q);
|
||||
|
||||
pm8 = mpz_get_ui(key->p) % 8;
|
||||
qm8 = mpz_get_ui(key->q) % 8;
|
||||
|
||||
if (pm8 == 1 || qm8 == 1 || (pm8 % 2) == 0 || (qm8 % 2) == 0) {
|
||||
mpz_clear(mm);
|
||||
rs_error(key, NULL, "unable to sign: unsuitable key");
|
||||
return RS_ERR_UNSUITABLE_RABIN_KEY;
|
||||
}
|
||||
|
||||
*f = ftab[(mLp == 1 ? 0 : 1) +
|
||||
(mLq == 1 ? 0 : 2) +
|
||||
(((qm8 - 3) / 2) * 4) +
|
||||
(((pm8 - 3) / 2) * 12)];
|
||||
|
||||
if (*f == 99) {
|
||||
mpz_clear(mm);
|
||||
rs_error(key, NULL, "unable to sign: unsuitable key");
|
||||
return RS_ERR_UNSUITABLE_RABIN_KEY;
|
||||
}
|
||||
|
||||
rabsigf(res, hash, key->n, key->p, key->q, key->qinv, *f, rootnum);
|
||||
mpz_clear(mm);
|
||||
return RS_SUCCESS;
|
||||
}
|
||||
|
||||
/* Check that the given Rabin signature is valid. */
|
||||
int rs_validate_rabin (const mpz_t sig, /* purported signature of app */
|
||||
int f, /* f value */
|
||||
const mpz_t hash, /* MD5 hash of app */
|
||||
const RSKey* key) /* key structure */
|
||||
{
|
||||
mpz_t a, b;
|
||||
int result;
|
||||
|
||||
if (!mpz_sgn(key->n)) {
|
||||
rs_error(key, NULL, "unable to validate: public key missing");
|
||||
return RS_ERR_MISSING_PUBLIC_KEY;
|
||||
}
|
||||
|
||||
if (f < 0 || f > 3)
|
||||
return RS_SIGNATURE_INCORRECT;
|
||||
|
||||
mpz_init(a);
|
||||
mpz_init(b);
|
||||
|
||||
mpz_mul(a, sig, sig);
|
||||
mpz_mod(a, a, key->n);
|
||||
|
||||
applyf(b, hash, key->n, f);
|
||||
|
||||
result = mpz_cmp(a, b);
|
||||
|
||||
mpz_clear(a);
|
||||
mpz_clear(b);
|
||||
return (result ? RS_SIGNATURE_INCORRECT : RS_SUCCESS);
|
||||
}
|
||||
137
tool/rabbitsign-src/rsa.c
Normal file
137
tool/rabbitsign-src/rsa.c
Normal file
|
|
@ -0,0 +1,137 @@
|
|||
/*
|
||||
* RabbitSign - Tools for signing TI graphing calculator software
|
||||
* Copyright (C) 2009 Benjamin Moody
|
||||
*
|
||||
* This program 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.
|
||||
*
|
||||
* This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
# include <config.h>
|
||||
#endif
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#include "rabbitsign.h"
|
||||
#include "internal.h"
|
||||
|
||||
#define VALIDATION_EXPONENT 17
|
||||
|
||||
/*
|
||||
* Calculate the RSA signing exponent.
|
||||
*
|
||||
* The validation exponent, e, is 17 for all TI-related RSA
|
||||
* signatures. The signing exponent, d, depends on n, and is
|
||||
* calculated so that e * d === 1 (mod (p-1)(q-1)).
|
||||
*
|
||||
* (This means that for any number x,
|
||||
*
|
||||
* x^(e * d) = x * x^[k0 * (p-1)] === x * 1 (mod p),
|
||||
*
|
||||
* and likewise
|
||||
*
|
||||
* x^(e * d) = x * x^[k1 * (q-1)] === x * 1 (mod q).
|
||||
*
|
||||
* Therefore (Chinese remainder theorem) x^(e * d) === x (mod n).
|
||||
*
|
||||
* Note that there is no way of calculating d without knowing the
|
||||
* factors of n; this is a key point in the security of RSA.)
|
||||
*/
|
||||
static int get_exponent(mpz_t res, /* mpz to store result */
|
||||
int e, /* validation exponent */
|
||||
const mpz_t p, /* first factor */
|
||||
const mpz_t q) /* second fatctor */
|
||||
{
|
||||
mpz_t a, b;
|
||||
mpz_init(a);
|
||||
mpz_init(b);
|
||||
|
||||
mpz_sub_ui(a, p, 1);
|
||||
mpz_sub_ui(b, q, 1);
|
||||
mpz_mul(a, a, b);
|
||||
|
||||
mpz_set_ui(b, e);
|
||||
|
||||
mpz_gcdext(b, res, NULL, b, a);
|
||||
if (mpz_cmp_ui(b, 1)) {
|
||||
mpz_clear(a);
|
||||
mpz_clear(b);
|
||||
return RS_ERR_UNSUITABLE_RSA_KEY;
|
||||
}
|
||||
|
||||
mpz_mod(res, res, a);
|
||||
|
||||
mpz_clear(a);
|
||||
mpz_clear(b);
|
||||
return RS_SUCCESS;
|
||||
}
|
||||
|
||||
/*
|
||||
* Compute an RSA signature.
|
||||
*
|
||||
* This is simply the hash raised to the d-th power mod n (where d is
|
||||
* defined above.)
|
||||
*/
|
||||
int rs_sign_rsa(mpz_t res, /* mpz to store signature */
|
||||
const mpz_t hash, /* MD5 hash of app */
|
||||
RSKey* key) /* key structure */
|
||||
{
|
||||
if (!mpz_sgn(key->n)) {
|
||||
rs_error(key, NULL, "unable to sign: public key missing");
|
||||
return RS_ERR_MISSING_PUBLIC_KEY;
|
||||
}
|
||||
|
||||
if (!mpz_sgn(key->d)) {
|
||||
if (!mpz_sgn(key->p) || !mpz_sgn(key->q)) {
|
||||
rs_error(key, NULL, "unable to sign: private key missing");
|
||||
return RS_ERR_MISSING_PRIVATE_KEY;
|
||||
}
|
||||
if (get_exponent(key->d, VALIDATION_EXPONENT, key->p, key->q)) {
|
||||
rs_error(key, NULL, "unable to sign: unsuitable key");
|
||||
return RS_ERR_UNSUITABLE_RSA_KEY;
|
||||
}
|
||||
}
|
||||
|
||||
mpz_powm(res, hash, key->d, key->n);
|
||||
return RS_SUCCESS;
|
||||
}
|
||||
|
||||
/*
|
||||
* Check that the given RSA signature is valid.
|
||||
*
|
||||
* To do this, we raise the signature to the 17th power mod n, and see
|
||||
* if it matches the hash.
|
||||
*/
|
||||
int rs_validate_rsa(const mpz_t sig, /* purported signature of app */
|
||||
const mpz_t hash, /* MD5 hash of app */
|
||||
const RSKey* key) /* key structure */
|
||||
{
|
||||
mpz_t e, m;
|
||||
int result;
|
||||
|
||||
if (!mpz_sgn(key->n)) {
|
||||
rs_error(key, NULL, "unable to validate: public key missing");
|
||||
return RS_ERR_MISSING_PUBLIC_KEY;
|
||||
}
|
||||
|
||||
mpz_init(e);
|
||||
mpz_init(m);
|
||||
|
||||
mpz_set_ui(e, VALIDATION_EXPONENT);
|
||||
mpz_powm(m, sig, e, key->n);
|
||||
result = mpz_cmp(hash, m);
|
||||
|
||||
mpz_clear(e);
|
||||
mpz_clear(m);
|
||||
return (result ? RS_SIGNATURE_INCORRECT : RS_SUCCESS);
|
||||
}
|
||||
161
tool/rabbitsign-src/typestr.c
Normal file
161
tool/rabbitsign-src/typestr.c
Normal file
|
|
@ -0,0 +1,161 @@
|
|||
/*
|
||||
* RabbitSign - Tools for signing TI graphing calculator software
|
||||
* Copyright (C) 2009 Benjamin Moody
|
||||
*
|
||||
* This program 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.
|
||||
*
|
||||
* This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
# include <config.h>
|
||||
#endif
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#ifdef HAVE_STRING_H
|
||||
# include <string.h>
|
||||
#else
|
||||
# ifdef HAVE_STRINGS_H
|
||||
# include <strings.h>
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#include "rabbitsign.h"
|
||||
#include "internal.h"
|
||||
|
||||
/*
|
||||
* Get default file suffix for a given calc/data type.
|
||||
*/
|
||||
const char* rs_type_to_suffix(RSCalcType calctype, /* calculator type */
|
||||
RSDataType datatype, /* program data type */
|
||||
int hexonly) /* 1 = plain hex output */
|
||||
{
|
||||
if (calctype == RS_CALC_TI73) {
|
||||
if (datatype == RS_DATA_APP)
|
||||
return (hexonly ? "app" : "73k");
|
||||
else if (datatype == RS_DATA_OS)
|
||||
return (hexonly ? "hex" : "73u");
|
||||
else if (datatype == RS_DATA_CERT)
|
||||
return "73q";
|
||||
}
|
||||
else if (calctype == RS_CALC_TI83P) {
|
||||
if (datatype == RS_DATA_APP)
|
||||
return (hexonly ? "app" : "8xk");
|
||||
else if (datatype == RS_DATA_OS)
|
||||
return (hexonly ? "hex" : "8xu");
|
||||
else if (datatype == RS_DATA_CERT)
|
||||
return "8xq";
|
||||
}
|
||||
else if (calctype == RS_CALC_TI89) {
|
||||
if (datatype == RS_DATA_APP)
|
||||
return "89k";
|
||||
else if (datatype == RS_DATA_OS)
|
||||
return "89u";
|
||||
else if (datatype == RS_DATA_CERT)
|
||||
return "89q";
|
||||
}
|
||||
else if (calctype == RS_CALC_TI92P) {
|
||||
if (datatype == RS_DATA_APP)
|
||||
return "9xk";
|
||||
else if (datatype == RS_DATA_OS)
|
||||
return "9xu";
|
||||
else if (datatype == RS_DATA_CERT)
|
||||
return "9xq";
|
||||
}
|
||||
|
||||
return "sig";
|
||||
}
|
||||
|
||||
/*
|
||||
* Get implied calc/data type for a given file suffix.
|
||||
*/
|
||||
int rs_suffix_to_type(const char* suff, /* file suffix (not
|
||||
including .) */
|
||||
RSCalcType* calctype, /* implied calculator
|
||||
type */
|
||||
RSDataType* datatype) /* implied program type */
|
||||
{
|
||||
int calc, data;
|
||||
|
||||
if (strlen(suff) != 3)
|
||||
return -1;
|
||||
|
||||
if (suff[0] == '7' && suff[1] == '3')
|
||||
calc = RS_CALC_TI73;
|
||||
else if (suff[0] == '8' && (suff[1] == 'x' || suff[1] == 'X'))
|
||||
calc = RS_CALC_TI83P;
|
||||
else if (suff[0] == '8' && suff[1] == '9')
|
||||
calc = RS_CALC_TI89;
|
||||
else if (suff[0] == '9' && (suff[1] == 'x' || suff[1] == 'X'))
|
||||
calc = RS_CALC_TI92P;
|
||||
else if ((suff[0] == 'v' || suff[0] == 'V') && suff[1] == '2')
|
||||
calc = RS_CALC_TI92P;
|
||||
else
|
||||
return -1;
|
||||
|
||||
if (suff[2] == 'k' || suff[2] == 'K')
|
||||
data = RS_DATA_APP;
|
||||
else if (suff[2] == 'u' || suff[2] == 'U')
|
||||
data = RS_DATA_OS;
|
||||
else if (suff[2] == 'q' || suff[2] == 'Q')
|
||||
data = RS_DATA_CERT;
|
||||
else
|
||||
return -1;
|
||||
|
||||
if (calctype) *calctype = calc;
|
||||
if (datatype) *datatype = data;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Get a human-readable description of a calculator type.
|
||||
*/
|
||||
const char* rs_calc_type_to_string(RSCalcType calctype)
|
||||
{
|
||||
switch (calctype) {
|
||||
case RS_CALC_TI73:
|
||||
return "TI-73";
|
||||
|
||||
case RS_CALC_TI83P:
|
||||
return "TI-83/84 Plus";
|
||||
|
||||
case RS_CALC_TI89:
|
||||
return "TI-89";
|
||||
|
||||
case RS_CALC_TI92P:
|
||||
return "TI-92 Plus/Voyage 200";
|
||||
|
||||
default:
|
||||
return "unknown";
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Get a human-readable description of a data type.
|
||||
*/
|
||||
const char* rs_data_type_to_string(RSDataType datatype)
|
||||
{
|
||||
switch (datatype) {
|
||||
case RS_DATA_OS:
|
||||
return "OS";
|
||||
|
||||
case RS_DATA_APP:
|
||||
return "application";
|
||||
|
||||
case RS_DATA_CERT:
|
||||
return "certificate";
|
||||
|
||||
default:
|
||||
return "program";
|
||||
}
|
||||
}
|
||||
316
tool/tilem-src/CHANGELOG
Normal file
316
tool/tilem-src/CHANGELOG
Normal file
|
|
@ -0,0 +1,316 @@
|
|||
/* This file only contains the changelog for the gui/doc/data, some things could be missing (core changes...)*/
|
||||
/* This changelog was started when I started to work on TilEm2 */
|
||||
|
||||
/* contra-sh :
|
||||
* ---18/08/09---
|
||||
* - Draw the TI83
|
||||
* - Copy from testemu.c : Create the savname, Open the Rom, Get the model, Draw the lcdscreen (no animation for the moment)
|
||||
* - Function event OnDestroy
|
||||
* - Modification of the Makefile (I hope it's good !? If you can control this... thx)
|
||||
* - LEARNING HOW COMMIT !! :D
|
||||
* ---19/08/09---
|
||||
* - New structure TilemCalcSkin : define the different filenames for the SkinSet (4 pieces).
|
||||
* - Draw the other models _automatically_ . ;D
|
||||
* ---20/08/09---
|
||||
* - Create skin.c
|
||||
* - Create gui.h (equivalent of tilem.h for the gui directory)
|
||||
* - Move the code struct in gui.h and TilemCalcSkin* tilem_guess_skin_set(TilemCalc* calc) into skin.c (only one call in the main file to define the skin set) ;D
|
||||
* - Detect a keyboard event (function keyboard_event() in skin.c actually).No treatment.
|
||||
* - Detect an event click on mouse
|
||||
* ---21/08/09---
|
||||
* - Get the x and y values when click on mouse (now it will be easy to know how key is click on the pixmap, todo in priority : detect right click)
|
||||
* ---24/08/09---
|
||||
* - Detect right click.
|
||||
* ---26/08/09---
|
||||
* - New function : TilemKeyMap* tilem_guess_key_map(int id).Choose a TilemKeyMap with an id given in parameter.
|
||||
* ---27/08/09---
|
||||
* - Extract the choice of the key_map from the mouse_event function.Execute only one time and it's more properly (and it will be easier to add the possibility to manage many skins and many keymaps).
|
||||
* ---01/09/09---
|
||||
* - Choose automatically the key_list. The TilemKeyList is already included in the TilemKeyMap structure...
|
||||
* - New structure TilemKeyCoord (old TilemKeyMap).TilemKeyMap already contains TilemKeyCoord and TilemKeyList...
|
||||
* ---08/09/09---
|
||||
* - New function tilem_set_coord to change the keypad coord.
|
||||
* - New file event.c to group the GDKevent handling.
|
||||
* - New function tilem_set_skin to change the skin.
|
||||
* ---10/09/09---
|
||||
* - Add the right click menu :D (0 signal connected without OnDestroy).Largely inspired from Tilem 0.973 and http://www.linux-france.org/article/devl/gtk/gtk_tut-11.html was a great inspiration too.
|
||||
* ---21/09/09---
|
||||
* - Aouch I had seen that the left click doesn't work now! Problem : two callback for the only one button_press_event. (sorry for this version...)
|
||||
* ---22/09/09---
|
||||
* - Correction : only one callback now. mouse_event contains the create_menu and the gtk_menu_popup. (lot of time was spent on this problem)*
|
||||
* ---23/09/09---
|
||||
* - Change TilemKeyCoord to the 82 stats skin.Change Event.c too.
|
||||
* ---06/10/09---
|
||||
* - Beginning the correction : change the method for testing coordinates clicks (one line now) . The coordinates will be imported from a file soon.
|
||||
* ---20/11/09---
|
||||
* - After 1 week to learn Tiemu skin format...I have made my own Tilem skin Generator.Inspired from skinedit.It just generate compatible file with 0 coordinates values, and an default lcd coordinates.Not really necessary but very useful for testing and for learning how this f****** skin format works.It will be called skintool for the moment.
|
||||
* ---27/11/09---
|
||||
* - After blocking a problem for a week grrr... I succeed to adapt the TiEmu skinloader to TilEm (skinops.c and skinops.h).Little modifications
|
||||
* ---28/11/09---
|
||||
* - The mouse_event function now use a SKIN_INFOS struct. So delete TilemKeyCoord struct.
|
||||
* ---02/12/09---
|
||||
* - Add a GtkFileSelection (access by right click menu) and try to load another skin with this method.
|
||||
* ---03/12/09---
|
||||
* - Create a GLOBAL_SKIN_INFOS that contains a KEY_LIST struct (old TilemKeyList) and a SKIN_INFOS struct.
|
||||
* ---04/12/09---
|
||||
* - Delete the TilemKeyCoord, TilemKeyMap, TilemCalcSkin and TilemKeyList structs...
|
||||
* ---05/12/09---
|
||||
* - The GtkWidget *pWindow creation was moved from testemu2.c to event.c .The function is called GtkWidget* Draw_Screen(GLOBAL_SKIN_INFOS *gsi);
|
||||
* ---07/12/09---
|
||||
* - New feature : TilEm could load a skin by the right_click_menu ! It use GtkWidget* ReDraw_Screen(GLOBAL_SKIN_INFOS *gsi) in event.c. WAOUH !
|
||||
* ---08/12/09---
|
||||
* - Move Draw_Screen, ReDraw_Screen and create_menus in a new screen.c file. Change Makefile.
|
||||
* ---14/12/09---
|
||||
* - New feature : add a popup rom type selector (radio button) at the start of tilem. Showed but not used for the moment.
|
||||
* - Connect the thread (no animation yet). Thanks to the "battle programming" 's spirit (hey bob ^^)
|
||||
* ---18/12/09---
|
||||
* - Launch the interactivity with emulation core. Could print into the draw area.
|
||||
* ---09/03/10---
|
||||
* - Restart working on this program ;D
|
||||
* ---11/03/10---
|
||||
* - I finally succeeded to connect the core. To print something into the lcd screen ! WahoOO ! This day is a great day !
|
||||
* - I succeded to type numbers etc...
|
||||
* - And now it works very well !! (the "button-release-event" is not catched by pWindow but by pLayout)
|
||||
* ---15/03/10---
|
||||
* - Create the scan_click function.Return wich keys was clicked.Print debug infos.
|
||||
* - Create the debuginfos.h to group the ifdef for debugging. (different level and different type of debug msg)
|
||||
* ---17/03/10---
|
||||
* - Create the rom_choose_popup function to replace choose_rom_type.It use GtkDialog instead of GtkWindow.
|
||||
* - rom_choose_popup _freeze_ the system... and get wich radio button is selected. So it will be easy to create the good emu.calc (and choose the default skin).
|
||||
* ---18/03/10---
|
||||
* - Resize the (printed) lcd area (gsi->emu->lcdwin) to fit(perfectly) into the skin.
|
||||
* - Replace a lot of printf by D****_L*_A* to easily switch what debug infos were printed.
|
||||
* - Try to make a nice debugging output (frames in ASCII ^^) :p
|
||||
* - WahooOO , load a skin works perfectly.You can easily change skin _while running_, no error, no warning.
|
||||
* - Could load automatically the good skin and run the good core using the choose_rom_popup() function and choose_skin_filename() function.
|
||||
* ---30/03/10---
|
||||
* - Create skin for following models : 73, 81, 82, 83+ and 84+.
|
||||
* - Fix bug in tool.c .Modification of tool.c to create radio button more properly.
|
||||
* ---31/03/10---
|
||||
* - Create skin for following model : 83 . Based on my own calc (take a foto with my iphone 3GS :D)
|
||||
* ---01/04/10---
|
||||
* - New feature : Save calc state and load state. State are stored in a separate dir called sav/ . (using benjamin 's function)
|
||||
* - New feature : Change view to see only the lcd. I finally choose to add it into a GtkLayout. So you can maximize it, but there was problem with add_event.
|
||||
* ---02/04/10---
|
||||
* - Add popup function to just print error message.You must give the message and gsi as parameter, and it run a modal dialog.
|
||||
* - Some cleaning.
|
||||
* ---23/04/10---
|
||||
* - Add config.c file to manage config.dat (create, read, modif etc...).
|
||||
* ---31/05/10---
|
||||
* - Start from scratch a totally new debugger :D.Just draw button with nice GtkImages.Actually in essai2 directory.
|
||||
* - Get and resize pixmaps (png) to 36 * 36 pixels for the debugger.
|
||||
* ---01/06/10---
|
||||
* - Add the debugger to tilem. Load registers values.
|
||||
* - Add a new feature : switch the top level window "borderless".It can be switch by clicking on right click menu entry.
|
||||
* ---02/06/10---
|
||||
* - Create the GtkTreeView (debugger).
|
||||
* - Refresh register on click.
|
||||
* ---05/08/10---
|
||||
* - More than one month without working on tilem...Only commit old modif, and skn/README file.
|
||||
* - Refresh stack on click (number of entry is correct but value not)
|
||||
* ---06/08/10---
|
||||
* - Working on a new system of configuration file.The config.dat is now a binary file (as .skn but totally differennt). At start, a CONFIG_INFOS struct is filling, then when clicking on right menu, this struct is modified, then when you stop tilem, config.dat is writed on disc.
|
||||
* ---09/08/10---
|
||||
* - Correction of the SEG_FAULT (never use sizeof(char*) inside malloc, strlen(char*) is better :P).
|
||||
* ---10/08/10---
|
||||
* - Working on a new config file called romconfig.dat (inspired from config.dat) using to do not ask for model each time tilem is started.
|
||||
* - It works :D
|
||||
* ---12/08/10---
|
||||
* - NEW feature : Can load a file using libticalcs2 (inspired from the wokr of Benjamin Moody). Basically it works, but it's not OK. (many bugs)
|
||||
* - Drop the deprecated GtkFileSelection.Use GtkFileChooser instead. :)
|
||||
* ---13/08/10---
|
||||
* - NEW feature : Add the screenshot feature.
|
||||
* ---17/08/10---
|
||||
* - Change the ti84plus.skn (old was really ugly).
|
||||
* - Add doc/ directory : add romconfig_file_format.txt and skinconfig_file_format.txt.
|
||||
* ---18/08/10---
|
||||
* - Correct the bug in link.c (unlock mutex ...)
|
||||
* - Start working on macro handling : Always do the same things to load and launch a file into an emulator become quickly noisy for the programmer (1 time, 10 times, 30 times, 50 times...argh!). Simply record a sequence and play it to test a program, this is one solution. (feature request from Guillaume Hoffman gh@gmail.com).
|
||||
* ---19/08/10---
|
||||
* - The macro feature works including loading file (very important). The implementation is very basic (record and read a text file) so many bug could (should?) appear. But I wait to see how it will be use.
|
||||
* ---20/08/10--
|
||||
* - Better implementation of GtkFileChooser (to be cleaner).
|
||||
* - Some work on macro (no seg fault now ^^).
|
||||
* - Add a Save state... entry in right click menu (no need to stop tilem to save state)
|
||||
* - Add a Play macro with GtkFileChooser (to play another macro than play.txt).
|
||||
* - Fix minor bug in GtkFileChooser (forget to init a char* to NULL).
|
||||
* ---23/08/10---
|
||||
* - Add a new args handler using getop library (add -m for macro and -k for skin).
|
||||
* ---06/09/10---
|
||||
* - NEW feature : could print the lcd content into the terminal. So useless but so funny ;) (feature request from Guillaume Hoffman).
|
||||
* - The output is saved into a file called lcd_content.txt.
|
||||
* ---08/09/10---
|
||||
* - Could choose wich char to display. This not really works as I want, but this is not a really important feature (works 1/2)
|
||||
* - Add an option at startup (-l). Could now start in skinless mode.
|
||||
* ---04/10/10---
|
||||
* - Start working on animated gif. Some research on GIF file format. Oops it will be hard, file is encoded (!).
|
||||
* ---09/10/10---
|
||||
* - Creation of 1 little static gif file seems working, but always no LZW encoding.
|
||||
* ---12/10/10---
|
||||
* - Finally I decided to use external source to encode the pix data.I use a file called "gifencode.c" by Hans Dinsen-Hansen and Michael A. Mayer. And it works !!!
|
||||
* ---14/10/10---
|
||||
* - It works ! It works !!! Tilem2 is now able to generate animated gif, functions are currently working (but totally buggy) and it successfully create animated gif :)
|
||||
* - Need to be integrated (and lot of debug).I commit it just to save it...Wait another commit to really use this feature :P
|
||||
* ---01/02/11---
|
||||
* - Starting to work on a new config file using glibc to do not hard code keypad values.
|
||||
* - And it works !!!! (but only load one keypad model currently)
|
||||
* - Add the other models into keylist.ini (but the content is completely false). Change scan_click method (correct a bug) to use kp->nb_of_buttons. Only need to give correct value into the keylist.ini file. For the rest it's seems ok.
|
||||
* ---07/02/11---
|
||||
* - Start to work on config.ini. A new generation config file using GKeyFile library (glib). Add some work in essai4 directory.
|
||||
* ---08/02/11---
|
||||
* - Remove romconfig.c romconfig.h config.c config.h (handle binary config file). Remove ROM_CONFIG_INFOS and CONFIG_INFOS from gsi.
|
||||
* - Add a new config.c and config.h file to handle config (last rom used, default skin to load, etc...). It uses glib GKeyFile library.
|
||||
* - Fix the macro bug pointed by Benjamin.
|
||||
* ---15/02/11---
|
||||
* - Replace correct copyright/licence informations into skinops.* .Sorry for the inconvenience.
|
||||
* ---16/02/11---
|
||||
* - Fix an important mistake into the gif creator function (palette should be before gif frame information).
|
||||
* ---18/02/11---
|
||||
* - Connect a timer to automatically add frame to a animated screenshot (using screenshot box).
|
||||
* ---14/03/11---
|
||||
* - Improve default skin choice.
|
||||
* - Define the skin's basedir into the config.ini. Add a universal getter into config.c .
|
||||
* ---19/03/11---
|
||||
* - Add a bouncy progress bar to show the link status (send file).
|
||||
* - Add a file saver.
|
||||
* - Create a new TilemCmdlineArgs structure.
|
||||
* ---07/04/11---
|
||||
* - Drop deprecated gtkitemfactory
|
||||
* - Prepare GT3 migration
|
||||
* ---10/04/11---
|
||||
* - Benjamin add a configure script and all associated things (Makefile.in, config.h etc...).
|
||||
* - Fix dependency and a lot of cleaning.
|
||||
* - Benjamin add a lot of function to handle data directory.
|
||||
* ---13/04/11---
|
||||
* - Completely refactoring the screenshot window. New preview possibility.
|
||||
* - Add some cool features for screenshot menu (replay from file, preview animation, preview screenshot, 2 gtkfilechooserbutton, change default folders etc...).
|
||||
* - Remove old pix directory.
|
||||
* - Benjamin begins to work on new debugger.Add a menu, some basic actions.
|
||||
* ---15/04/11---
|
||||
* - Benjamin add a set of function to handle user defined icons. A lot of improvement on the debugger (add step action, pause).
|
||||
* - Use tilem logo as default background in the screenshot menu, add some pix into the shared data directory.
|
||||
* - Remove old debugger pix.
|
||||
* - Add GtkSpinnerAnimation in the screenshot menu. Improve look and feel (fix fill/expand properties for the box, size of the widgets etc...).
|
||||
* ---17/04/11---
|
||||
* - Benjamin add a ti83p symbol file which allow to replace flag values by theirs labels in the debugger (and more other things). Debugger looks like very good.
|
||||
* ---19/04/11---
|
||||
* - I've added a ti83 symbol file (but it could contains some mistakes...). Flags are correctly printed for my loved ti83 regular ;)
|
||||
* ---27/04/11---
|
||||
* - Root window size could be forced (but the ratio could be strand if you specify stanges values ... Because ration is calculated on the start width and heigth).
|
||||
* ---02/05/11---
|
||||
* - Add the icons for the right click menu (stock icons currently).
|
||||
* - Export all menu related code in a separate file called menu.c. It could maybe be done by UI in the future, but it works fine as it for the moment ;)
|
||||
* - Add drag and drop support for loading files :) :) :) :) :) (code is currently really ugly)
|
||||
* ---09/05/11---
|
||||
* - Create a new TilemGuiStateFlags structure ot group the running state of the gui (skinless, recording macro, etc...) and export it into TilemCalcEmu instead GLOBAL_SKIN_INFOS.
|
||||
* - Completely remove GLOBAL_SKIN_INFOS structure from tilem2.
|
||||
* ---10/05/11---
|
||||
* - Change strutures to look like a object oriented model. But in some case it's not really well implemented.
|
||||
* ---11/05/11---
|
||||
* - Refactor a lot of gif header's code.
|
||||
* ---12/05/11---
|
||||
* - I finally found what's wrong in my gif creation. So I can do multicolor gif now.
|
||||
* ---14/05/11---
|
||||
* - We have finally completely reorganized the code to drop GLOBAL_SKIN_INFOS, and rename a lot of stuff including files (emuwin instead screen by example).
|
||||
* - Benjamin have imported his nice filedlg functions (filedlg.c) from flashbook ui (see it on SF.net). Now use it for the entire code.
|
||||
* ---14/05/11---
|
||||
* - Refactor the gif creation to separate clearly which value can be modified, which one are magic number etc... Create separate functions for each task.
|
||||
* - Benjamin begins to work on animation (instead of writing file while recording it). It provides a wonderful objects to handle screenshot.
|
||||
* ---15/05/11---
|
||||
* - Add a doxyfile for generating documentation including callgraphs.
|
||||
* - Improvement to keybindings (Benjamin).
|
||||
* ---16/05/11---
|
||||
* - Add some preliminary work on get var stuff. Only dirlist and allow user to retrieve a var using cmd line but it works. The list is printed in a tree view.
|
||||
* - Add multi drag and drop feature.
|
||||
* ---19/05/11---
|
||||
* - Add functions for animations (Benjamin). Could now save a animation into a gif file.
|
||||
* - Improve screenshot menu by setting some buttons inactives depending the current state of screenshot creation.
|
||||
* - Add combo box for size to screenshot menu.
|
||||
* ---21/05/11---
|
||||
* - A lot of improvement on screenshot menu (Benjamin). Settings are now independent of screenshot dialog. Default directory for output.
|
||||
* - Add mnemonic label to screenshot menu buttons (Benjamin).
|
||||
* ---22/05/11---
|
||||
* - Benjamin redesign the entire menu popup to use the better GtkAction system. Now there's keybindings for menu and code is really beautiful and shorter.
|
||||
* - Add grayscale option to screenshot menu (Benjamin).
|
||||
* ---23/05/11---
|
||||
* - Save the last rom opened and use it at startup if no rom is given.
|
||||
* - Allow user to load another rom while running.
|
||||
* - Refactor the entire macro creation to separate creation from writing as TilemAnimation does. Code is cleaner and simply better.
|
||||
* ---25/05/11---
|
||||
* - Add an option to change animation speed. The current printed animation is updated on change.
|
||||
* ---26/05/11---
|
||||
* - Add an option to change foreground and background color. No visual feedback.
|
||||
* ---27/05/11---
|
||||
* - Correct some stuff (see mailing list to know why). And add a palette setter in animation.c and a visual feedback when foreground/background color are changed.
|
||||
* - Some other minor improvement.
|
||||
* ---19/09/11---
|
||||
* - Restart working on tilem2 after holidays:)
|
||||
* - Add new file getvar.c to handle get var function (receiving var from calc to PC).
|
||||
* ---20/09/11---
|
||||
* - Some improvement to the rcvmenu.
|
||||
* ---22/09/11---
|
||||
* - Add the ti83pfr.skn file. This skin is for ti83plus.fr. The creator is Claude Clerc (aka claudiux). He donates the skin under GPL v3+ licence.Thanks to him !!!
|
||||
* ---11/10/11---
|
||||
* - Correct the getvar.c code to work correctly. Add columns to the tree view.
|
||||
* - Add app receive handling. Set index column invisible.
|
||||
* ---12/10/11---
|
||||
* - Some corrections : receive dialog is transcient. Receive dialog is not destroyed when closed just hided. New refresh button to refresh var/app list.
|
||||
* - Use a separate thread to receive files.
|
||||
* ---14/10/11---
|
||||
* - Add a feature to list ti82 and ti85 entries. User must prepare manually the link. Can't save a ti82 or ti85 entry (when selected in the rcvdialog).
|
||||
* - Lot of bug, code is really ugly. No error handling. The prepare_for_link_receive is not working. etc...
|
||||
* ---11/11/11---
|
||||
* - Benjamin add a totally new prefs dialog. Some unused function (print lcd in terminal by example) are deleted.
|
||||
* ---12/11/11---
|
||||
* - Working on ns silent get var.
|
||||
* ---14/11/11---
|
||||
* - New files : emucore.c and emucore.h .
|
||||
* - Benjamin adds a totally new core task manager in the gui. Begin to convert the send files function to use it.
|
||||
* - Use this task manager for macro. There's a little priority problem when a macro load a file. Load a file then run a macro at startup works fine.
|
||||
* ---15/11/11---
|
||||
* - Receive non silent vars : Benjamin get it working!
|
||||
* - Remove unused getvar.c file.
|
||||
* ---16/11/11---
|
||||
* - Allow multiple selection and multiple receive file. Need to fix a segfault (tomorow... xD).
|
||||
* ---17/11/11---
|
||||
* - Repare the file loading inside a macro (it was broken by new task manager).
|
||||
* - Delete a lot of unused functions/printf.
|
||||
* - Remove debuginfo.h file.
|
||||
* ---22/11/11---
|
||||
* - Benjamin finished the last things left to do on receive dialog. Nice!
|
||||
* ---25/11/11---
|
||||
* - New command line parser. Now tilem2 uses g_option from the glib instead of getopt. Easy handling of long options. Do not need to take care about correct parsing. A lot of new options are provided but not implemented !
|
||||
* - Delete args.c (old _but working well _ cmd line parser using getopt) and TilemCmdlineArgs structure from gui.h.
|
||||
* - Add the possibility to getvar a file at startup. I had to use a weird solution to do this with task manager. But it's working :)
|
||||
* ---12/12/11---
|
||||
* - Benjamin do a lot of improvements on file chooser (filters, ...).
|
||||
* ---22/12/11---
|
||||
* - Benjamin fix certificate patching.
|
||||
* ---19/03/12---
|
||||
* - Icons are finally commited into the trunk. These pictures are originaly designed by Scott Zeid and modified by me. No .desktop and icons installer for the moment.
|
||||
* - Scott, thank you a lot for these wonderful pictures!
|
||||
* ---21/03/12---
|
||||
* - Adding documentation (LaTeX). The documentation is not finished yet. Lot of pictures added.
|
||||
* ---24/04/12---
|
||||
* - Benjamin added some correction to install properly the icons.
|
||||
* ---27/04/12---
|
||||
* - Some modifications on the configure script because something was failing on my debian wheezy. It works fine yet (using squeeze and gtk/glib downgraded packages and some minor modifications on configure scripts).
|
||||
* ---03/05/12---
|
||||
* - Reverting changes on the configure script because it was not the fault of configure script.
|
||||
* ---07/05/12---
|
||||
* - Update doc (add "basic task" chapter).
|
||||
* - Update .desktop files.
|
||||
* ---08/05/12---
|
||||
* - Benjamin added a rule to install in the $HOME directory.
|
||||
* - Benjamin added MIME type files.
|
||||
* ---09/05/12---
|
||||
* - Benjamin added a piece of documentation about "getting ROM".
|
||||
* ---11/05/12---
|
||||
* - Add an huge explanation for debugger part into the documentation.
|
||||
* ---13/05/12---
|
||||
* - Add some screenshot documentation.
|
||||
* ---15/05/12---
|
||||
* - Benjamin add README, THANKS and COPYING file.
|
||||
* - Update screenshot doc.
|
||||
*/
|
||||
|
||||
674
tool/tilem-src/COPYING
Normal file
674
tool/tilem-src/COPYING
Normal file
|
|
@ -0,0 +1,674 @@
|
|||
GNU GENERAL PUBLIC LICENSE
|
||||
Version 3, 29 June 2007
|
||||
|
||||
Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
|
||||
Everyone is permitted to copy and distribute verbatim copies
|
||||
of this license document, but changing it is not allowed.
|
||||
|
||||
Preamble
|
||||
|
||||
The GNU General Public License is a free, copyleft license for
|
||||
software and other kinds of works.
|
||||
|
||||
The licenses for most software and other practical works are designed
|
||||
to take away your freedom to share and change the works. By contrast,
|
||||
the GNU General Public License is intended to guarantee your freedom to
|
||||
share and change all versions of a program--to make sure it remains free
|
||||
software for all its users. We, the Free Software Foundation, use the
|
||||
GNU General Public License for most of our software; it applies also to
|
||||
any other work released this way by its authors. You can apply it to
|
||||
your programs, too.
|
||||
|
||||
When we speak of free software, we are referring to freedom, not
|
||||
price. Our General Public Licenses are designed to make sure that you
|
||||
have the freedom to distribute copies of free software (and charge for
|
||||
them if you wish), that you receive source code or can get it if you
|
||||
want it, that you can change the software or use pieces of it in new
|
||||
free programs, and that you know you can do these things.
|
||||
|
||||
To protect your rights, we need to prevent others from denying you
|
||||
these rights or asking you to surrender the rights. Therefore, you have
|
||||
certain responsibilities if you distribute copies of the software, or if
|
||||
you modify it: responsibilities to respect the freedom of others.
|
||||
|
||||
For example, if you distribute copies of such a program, whether
|
||||
gratis or for a fee, you must pass on to the recipients the same
|
||||
freedoms that you received. You must make sure that they, too, receive
|
||||
or can get the source code. And you must show them these terms so they
|
||||
know their rights.
|
||||
|
||||
Developers that use the GNU GPL protect your rights with two steps:
|
||||
(1) assert copyright on the software, and (2) offer you this License
|
||||
giving you legal permission to copy, distribute and/or modify it.
|
||||
|
||||
For the developers' and authors' protection, the GPL clearly explains
|
||||
that there is no warranty for this free software. For both users' and
|
||||
authors' sake, the GPL requires that modified versions be marked as
|
||||
changed, so that their problems will not be attributed erroneously to
|
||||
authors of previous versions.
|
||||
|
||||
Some devices are designed to deny users access to install or run
|
||||
modified versions of the software inside them, although the manufacturer
|
||||
can do so. This is fundamentally incompatible with the aim of
|
||||
protecting users' freedom to change the software. The systematic
|
||||
pattern of such abuse occurs in the area of products for individuals to
|
||||
use, which is precisely where it is most unacceptable. Therefore, we
|
||||
have designed this version of the GPL to prohibit the practice for those
|
||||
products. If such problems arise substantially in other domains, we
|
||||
stand ready to extend this provision to those domains in future versions
|
||||
of the GPL, as needed to protect the freedom of users.
|
||||
|
||||
Finally, every program is threatened constantly by software patents.
|
||||
States should not allow patents to restrict development and use of
|
||||
software on general-purpose computers, but in those that do, we wish to
|
||||
avoid the special danger that patents applied to a free program could
|
||||
make it effectively proprietary. To prevent this, the GPL assures that
|
||||
patents cannot be used to render the program non-free.
|
||||
|
||||
The precise terms and conditions for copying, distribution and
|
||||
modification follow.
|
||||
|
||||
TERMS AND CONDITIONS
|
||||
|
||||
0. Definitions.
|
||||
|
||||
"This License" refers to version 3 of the GNU General Public License.
|
||||
|
||||
"Copyright" also means copyright-like laws that apply to other kinds of
|
||||
works, such as semiconductor masks.
|
||||
|
||||
"The Program" refers to any copyrightable work licensed under this
|
||||
License. Each licensee is addressed as "you". "Licensees" and
|
||||
"recipients" may be individuals or organizations.
|
||||
|
||||
To "modify" a work means to copy from or adapt all or part of the work
|
||||
in a fashion requiring copyright permission, other than the making of an
|
||||
exact copy. The resulting work is called a "modified version" of the
|
||||
earlier work or a work "based on" the earlier work.
|
||||
|
||||
A "covered work" means either the unmodified Program or a work based
|
||||
on the Program.
|
||||
|
||||
To "propagate" a work means to do anything with it that, without
|
||||
permission, would make you directly or secondarily liable for
|
||||
infringement under applicable copyright law, except executing it on a
|
||||
computer or modifying a private copy. Propagation includes copying,
|
||||
distribution (with or without modification), making available to the
|
||||
public, and in some countries other activities as well.
|
||||
|
||||
To "convey" a work means any kind of propagation that enables other
|
||||
parties to make or receive copies. Mere interaction with a user through
|
||||
a computer network, with no transfer of a copy, is not conveying.
|
||||
|
||||
An interactive user interface displays "Appropriate Legal Notices"
|
||||
to the extent that it includes a convenient and prominently visible
|
||||
feature that (1) displays an appropriate copyright notice, and (2)
|
||||
tells the user that there is no warranty for the work (except to the
|
||||
extent that warranties are provided), that licensees may convey the
|
||||
work under this License, and how to view a copy of this License. If
|
||||
the interface presents a list of user commands or options, such as a
|
||||
menu, a prominent item in the list meets this criterion.
|
||||
|
||||
1. Source Code.
|
||||
|
||||
The "source code" for a work means the preferred form of the work
|
||||
for making modifications to it. "Object code" means any non-source
|
||||
form of a work.
|
||||
|
||||
A "Standard Interface" means an interface that either is an official
|
||||
standard defined by a recognized standards body, or, in the case of
|
||||
interfaces specified for a particular programming language, one that
|
||||
is widely used among developers working in that language.
|
||||
|
||||
The "System Libraries" of an executable work include anything, other
|
||||
than the work as a whole, that (a) is included in the normal form of
|
||||
packaging a Major Component, but which is not part of that Major
|
||||
Component, and (b) serves only to enable use of the work with that
|
||||
Major Component, or to implement a Standard Interface for which an
|
||||
implementation is available to the public in source code form. A
|
||||
"Major Component", in this context, means a major essential component
|
||||
(kernel, window system, and so on) of the specific operating system
|
||||
(if any) on which the executable work runs, or a compiler used to
|
||||
produce the work, or an object code interpreter used to run it.
|
||||
|
||||
The "Corresponding Source" for a work in object code form means all
|
||||
the source code needed to generate, install, and (for an executable
|
||||
work) run the object code and to modify the work, including scripts to
|
||||
control those activities. However, it does not include the work's
|
||||
System Libraries, or general-purpose tools or generally available free
|
||||
programs which are used unmodified in performing those activities but
|
||||
which are not part of the work. For example, Corresponding Source
|
||||
includes interface definition files associated with source files for
|
||||
the work, and the source code for shared libraries and dynamically
|
||||
linked subprograms that the work is specifically designed to require,
|
||||
such as by intimate data communication or control flow between those
|
||||
subprograms and other parts of the work.
|
||||
|
||||
The Corresponding Source need not include anything that users
|
||||
can regenerate automatically from other parts of the Corresponding
|
||||
Source.
|
||||
|
||||
The Corresponding Source for a work in source code form is that
|
||||
same work.
|
||||
|
||||
2. Basic Permissions.
|
||||
|
||||
All rights granted under this License are granted for the term of
|
||||
copyright on the Program, and are irrevocable provided the stated
|
||||
conditions are met. This License explicitly affirms your unlimited
|
||||
permission to run the unmodified Program. The output from running a
|
||||
covered work is covered by this License only if the output, given its
|
||||
content, constitutes a covered work. This License acknowledges your
|
||||
rights of fair use or other equivalent, as provided by copyright law.
|
||||
|
||||
You may make, run and propagate covered works that you do not
|
||||
convey, without conditions so long as your license otherwise remains
|
||||
in force. You may convey covered works to others for the sole purpose
|
||||
of having them make modifications exclusively for you, or provide you
|
||||
with facilities for running those works, provided that you comply with
|
||||
the terms of this License in conveying all material for which you do
|
||||
not control copyright. Those thus making or running the covered works
|
||||
for you must do so exclusively on your behalf, under your direction
|
||||
and control, on terms that prohibit them from making any copies of
|
||||
your copyrighted material outside their relationship with you.
|
||||
|
||||
Conveying under any other circumstances is permitted solely under
|
||||
the conditions stated below. Sublicensing is not allowed; section 10
|
||||
makes it unnecessary.
|
||||
|
||||
3. Protecting Users' Legal Rights From Anti-Circumvention Law.
|
||||
|
||||
No covered work shall be deemed part of an effective technological
|
||||
measure under any applicable law fulfilling obligations under article
|
||||
11 of the WIPO copyright treaty adopted on 20 December 1996, or
|
||||
similar laws prohibiting or restricting circumvention of such
|
||||
measures.
|
||||
|
||||
When you convey a covered work, you waive any legal power to forbid
|
||||
circumvention of technological measures to the extent such circumvention
|
||||
is effected by exercising rights under this License with respect to
|
||||
the covered work, and you disclaim any intention to limit operation or
|
||||
modification of the work as a means of enforcing, against the work's
|
||||
users, your or third parties' legal rights to forbid circumvention of
|
||||
technological measures.
|
||||
|
||||
4. Conveying Verbatim Copies.
|
||||
|
||||
You may convey verbatim copies of the Program's source code as you
|
||||
receive it, in any medium, provided that you conspicuously and
|
||||
appropriately publish on each copy an appropriate copyright notice;
|
||||
keep intact all notices stating that this License and any
|
||||
non-permissive terms added in accord with section 7 apply to the code;
|
||||
keep intact all notices of the absence of any warranty; and give all
|
||||
recipients a copy of this License along with the Program.
|
||||
|
||||
You may charge any price or no price for each copy that you convey,
|
||||
and you may offer support or warranty protection for a fee.
|
||||
|
||||
5. Conveying Modified Source Versions.
|
||||
|
||||
You may convey a work based on the Program, or the modifications to
|
||||
produce it from the Program, in the form of source code under the
|
||||
terms of section 4, provided that you also meet all of these conditions:
|
||||
|
||||
a) The work must carry prominent notices stating that you modified
|
||||
it, and giving a relevant date.
|
||||
|
||||
b) The work must carry prominent notices stating that it is
|
||||
released under this License and any conditions added under section
|
||||
7. This requirement modifies the requirement in section 4 to
|
||||
"keep intact all notices".
|
||||
|
||||
c) You must license the entire work, as a whole, under this
|
||||
License to anyone who comes into possession of a copy. This
|
||||
License will therefore apply, along with any applicable section 7
|
||||
additional terms, to the whole of the work, and all its parts,
|
||||
regardless of how they are packaged. This License gives no
|
||||
permission to license the work in any other way, but it does not
|
||||
invalidate such permission if you have separately received it.
|
||||
|
||||
d) If the work has interactive user interfaces, each must display
|
||||
Appropriate Legal Notices; however, if the Program has interactive
|
||||
interfaces that do not display Appropriate Legal Notices, your
|
||||
work need not make them do so.
|
||||
|
||||
A compilation of a covered work with other separate and independent
|
||||
works, which are not by their nature extensions of the covered work,
|
||||
and which are not combined with it such as to form a larger program,
|
||||
in or on a volume of a storage or distribution medium, is called an
|
||||
"aggregate" if the compilation and its resulting copyright are not
|
||||
used to limit the access or legal rights of the compilation's users
|
||||
beyond what the individual works permit. Inclusion of a covered work
|
||||
in an aggregate does not cause this License to apply to the other
|
||||
parts of the aggregate.
|
||||
|
||||
6. Conveying Non-Source Forms.
|
||||
|
||||
You may convey a covered work in object code form under the terms
|
||||
of sections 4 and 5, provided that you also convey the
|
||||
machine-readable Corresponding Source under the terms of this License,
|
||||
in one of these ways:
|
||||
|
||||
a) Convey the object code in, or embodied in, a physical product
|
||||
(including a physical distribution medium), accompanied by the
|
||||
Corresponding Source fixed on a durable physical medium
|
||||
customarily used for software interchange.
|
||||
|
||||
b) Convey the object code in, or embodied in, a physical product
|
||||
(including a physical distribution medium), accompanied by a
|
||||
written offer, valid for at least three years and valid for as
|
||||
long as you offer spare parts or customer support for that product
|
||||
model, to give anyone who possesses the object code either (1) a
|
||||
copy of the Corresponding Source for all the software in the
|
||||
product that is covered by this License, on a durable physical
|
||||
medium customarily used for software interchange, for a price no
|
||||
more than your reasonable cost of physically performing this
|
||||
conveying of source, or (2) access to copy the
|
||||
Corresponding Source from a network server at no charge.
|
||||
|
||||
c) Convey individual copies of the object code with a copy of the
|
||||
written offer to provide the Corresponding Source. This
|
||||
alternative is allowed only occasionally and noncommercially, and
|
||||
only if you received the object code with such an offer, in accord
|
||||
with subsection 6b.
|
||||
|
||||
d) Convey the object code by offering access from a designated
|
||||
place (gratis or for a charge), and offer equivalent access to the
|
||||
Corresponding Source in the same way through the same place at no
|
||||
further charge. You need not require recipients to copy the
|
||||
Corresponding Source along with the object code. If the place to
|
||||
copy the object code is a network server, the Corresponding Source
|
||||
may be on a different server (operated by you or a third party)
|
||||
that supports equivalent copying facilities, provided you maintain
|
||||
clear directions next to the object code saying where to find the
|
||||
Corresponding Source. Regardless of what server hosts the
|
||||
Corresponding Source, you remain obligated to ensure that it is
|
||||
available for as long as needed to satisfy these requirements.
|
||||
|
||||
e) Convey the object code using peer-to-peer transmission, provided
|
||||
you inform other peers where the object code and Corresponding
|
||||
Source of the work are being offered to the general public at no
|
||||
charge under subsection 6d.
|
||||
|
||||
A separable portion of the object code, whose source code is excluded
|
||||
from the Corresponding Source as a System Library, need not be
|
||||
included in conveying the object code work.
|
||||
|
||||
A "User Product" is either (1) a "consumer product", which means any
|
||||
tangible personal property which is normally used for personal, family,
|
||||
or household purposes, or (2) anything designed or sold for incorporation
|
||||
into a dwelling. In determining whether a product is a consumer product,
|
||||
doubtful cases shall be resolved in favor of coverage. For a particular
|
||||
product received by a particular user, "normally used" refers to a
|
||||
typical or common use of that class of product, regardless of the status
|
||||
of the particular user or of the way in which the particular user
|
||||
actually uses, or expects or is expected to use, the product. A product
|
||||
is a consumer product regardless of whether the product has substantial
|
||||
commercial, industrial or non-consumer uses, unless such uses represent
|
||||
the only significant mode of use of the product.
|
||||
|
||||
"Installation Information" for a User Product means any methods,
|
||||
procedures, authorization keys, or other information required to install
|
||||
and execute modified versions of a covered work in that User Product from
|
||||
a modified version of its Corresponding Source. The information must
|
||||
suffice to ensure that the continued functioning of the modified object
|
||||
code is in no case prevented or interfered with solely because
|
||||
modification has been made.
|
||||
|
||||
If you convey an object code work under this section in, or with, or
|
||||
specifically for use in, a User Product, and the conveying occurs as
|
||||
part of a transaction in which the right of possession and use of the
|
||||
User Product is transferred to the recipient in perpetuity or for a
|
||||
fixed term (regardless of how the transaction is characterized), the
|
||||
Corresponding Source conveyed under this section must be accompanied
|
||||
by the Installation Information. But this requirement does not apply
|
||||
if neither you nor any third party retains the ability to install
|
||||
modified object code on the User Product (for example, the work has
|
||||
been installed in ROM).
|
||||
|
||||
The requirement to provide Installation Information does not include a
|
||||
requirement to continue to provide support service, warranty, or updates
|
||||
for a work that has been modified or installed by the recipient, or for
|
||||
the User Product in which it has been modified or installed. Access to a
|
||||
network may be denied when the modification itself materially and
|
||||
adversely affects the operation of the network or violates the rules and
|
||||
protocols for communication across the network.
|
||||
|
||||
Corresponding Source conveyed, and Installation Information provided,
|
||||
in accord with this section must be in a format that is publicly
|
||||
documented (and with an implementation available to the public in
|
||||
source code form), and must require no special password or key for
|
||||
unpacking, reading or copying.
|
||||
|
||||
7. Additional Terms.
|
||||
|
||||
"Additional permissions" are terms that supplement the terms of this
|
||||
License by making exceptions from one or more of its conditions.
|
||||
Additional permissions that are applicable to the entire Program shall
|
||||
be treated as though they were included in this License, to the extent
|
||||
that they are valid under applicable law. If additional permissions
|
||||
apply only to part of the Program, that part may be used separately
|
||||
under those permissions, but the entire Program remains governed by
|
||||
this License without regard to the additional permissions.
|
||||
|
||||
When you convey a copy of a covered work, you may at your option
|
||||
remove any additional permissions from that copy, or from any part of
|
||||
it. (Additional permissions may be written to require their own
|
||||
removal in certain cases when you modify the work.) You may place
|
||||
additional permissions on material, added by you to a covered work,
|
||||
for which you have or can give appropriate copyright permission.
|
||||
|
||||
Notwithstanding any other provision of this License, for material you
|
||||
add to a covered work, you may (if authorized by the copyright holders of
|
||||
that material) supplement the terms of this License with terms:
|
||||
|
||||
a) Disclaiming warranty or limiting liability differently from the
|
||||
terms of sections 15 and 16 of this License; or
|
||||
|
||||
b) Requiring preservation of specified reasonable legal notices or
|
||||
author attributions in that material or in the Appropriate Legal
|
||||
Notices displayed by works containing it; or
|
||||
|
||||
c) Prohibiting misrepresentation of the origin of that material, or
|
||||
requiring that modified versions of such material be marked in
|
||||
reasonable ways as different from the original version; or
|
||||
|
||||
d) Limiting the use for publicity purposes of names of licensors or
|
||||
authors of the material; or
|
||||
|
||||
e) Declining to grant rights under trademark law for use of some
|
||||
trade names, trademarks, or service marks; or
|
||||
|
||||
f) Requiring indemnification of licensors and authors of that
|
||||
material by anyone who conveys the material (or modified versions of
|
||||
it) with contractual assumptions of liability to the recipient, for
|
||||
any liability that these contractual assumptions directly impose on
|
||||
those licensors and authors.
|
||||
|
||||
All other non-permissive additional terms are considered "further
|
||||
restrictions" within the meaning of section 10. If the Program as you
|
||||
received it, or any part of it, contains a notice stating that it is
|
||||
governed by this License along with a term that is a further
|
||||
restriction, you may remove that term. If a license document contains
|
||||
a further restriction but permits relicensing or conveying under this
|
||||
License, you may add to a covered work material governed by the terms
|
||||
of that license document, provided that the further restriction does
|
||||
not survive such relicensing or conveying.
|
||||
|
||||
If you add terms to a covered work in accord with this section, you
|
||||
must place, in the relevant source files, a statement of the
|
||||
additional terms that apply to those files, or a notice indicating
|
||||
where to find the applicable terms.
|
||||
|
||||
Additional terms, permissive or non-permissive, may be stated in the
|
||||
form of a separately written license, or stated as exceptions;
|
||||
the above requirements apply either way.
|
||||
|
||||
8. Termination.
|
||||
|
||||
You may not propagate or modify a covered work except as expressly
|
||||
provided under this License. Any attempt otherwise to propagate or
|
||||
modify it is void, and will automatically terminate your rights under
|
||||
this License (including any patent licenses granted under the third
|
||||
paragraph of section 11).
|
||||
|
||||
However, if you cease all violation of this License, then your
|
||||
license from a particular copyright holder is reinstated (a)
|
||||
provisionally, unless and until the copyright holder explicitly and
|
||||
finally terminates your license, and (b) permanently, if the copyright
|
||||
holder fails to notify you of the violation by some reasonable means
|
||||
prior to 60 days after the cessation.
|
||||
|
||||
Moreover, your license from a particular copyright holder is
|
||||
reinstated permanently if the copyright holder notifies you of the
|
||||
violation by some reasonable means, this is the first time you have
|
||||
received notice of violation of this License (for any work) from that
|
||||
copyright holder, and you cure the violation prior to 30 days after
|
||||
your receipt of the notice.
|
||||
|
||||
Termination of your rights under this section does not terminate the
|
||||
licenses of parties who have received copies or rights from you under
|
||||
this License. If your rights have been terminated and not permanently
|
||||
reinstated, you do not qualify to receive new licenses for the same
|
||||
material under section 10.
|
||||
|
||||
9. Acceptance Not Required for Having Copies.
|
||||
|
||||
You are not required to accept this License in order to receive or
|
||||
run a copy of the Program. Ancillary propagation of a covered work
|
||||
occurring solely as a consequence of using peer-to-peer transmission
|
||||
to receive a copy likewise does not require acceptance. However,
|
||||
nothing other than this License grants you permission to propagate or
|
||||
modify any covered work. These actions infringe copyright if you do
|
||||
not accept this License. Therefore, by modifying or propagating a
|
||||
covered work, you indicate your acceptance of this License to do so.
|
||||
|
||||
10. Automatic Licensing of Downstream Recipients.
|
||||
|
||||
Each time you convey a covered work, the recipient automatically
|
||||
receives a license from the original licensors, to run, modify and
|
||||
propagate that work, subject to this License. You are not responsible
|
||||
for enforcing compliance by third parties with this License.
|
||||
|
||||
An "entity transaction" is a transaction transferring control of an
|
||||
organization, or substantially all assets of one, or subdividing an
|
||||
organization, or merging organizations. If propagation of a covered
|
||||
work results from an entity transaction, each party to that
|
||||
transaction who receives a copy of the work also receives whatever
|
||||
licenses to the work the party's predecessor in interest had or could
|
||||
give under the previous paragraph, plus a right to possession of the
|
||||
Corresponding Source of the work from the predecessor in interest, if
|
||||
the predecessor has it or can get it with reasonable efforts.
|
||||
|
||||
You may not impose any further restrictions on the exercise of the
|
||||
rights granted or affirmed under this License. For example, you may
|
||||
not impose a license fee, royalty, or other charge for exercise of
|
||||
rights granted under this License, and you may not initiate litigation
|
||||
(including a cross-claim or counterclaim in a lawsuit) alleging that
|
||||
any patent claim is infringed by making, using, selling, offering for
|
||||
sale, or importing the Program or any portion of it.
|
||||
|
||||
11. Patents.
|
||||
|
||||
A "contributor" is a copyright holder who authorizes use under this
|
||||
License of the Program or a work on which the Program is based. The
|
||||
work thus licensed is called the contributor's "contributor version".
|
||||
|
||||
A contributor's "essential patent claims" are all patent claims
|
||||
owned or controlled by the contributor, whether already acquired or
|
||||
hereafter acquired, that would be infringed by some manner, permitted
|
||||
by this License, of making, using, or selling its contributor version,
|
||||
but do not include claims that would be infringed only as a
|
||||
consequence of further modification of the contributor version. For
|
||||
purposes of this definition, "control" includes the right to grant
|
||||
patent sublicenses in a manner consistent with the requirements of
|
||||
this License.
|
||||
|
||||
Each contributor grants you a non-exclusive, worldwide, royalty-free
|
||||
patent license under the contributor's essential patent claims, to
|
||||
make, use, sell, offer for sale, import and otherwise run, modify and
|
||||
propagate the contents of its contributor version.
|
||||
|
||||
In the following three paragraphs, a "patent license" is any express
|
||||
agreement or commitment, however denominated, not to enforce a patent
|
||||
(such as an express permission to practice a patent or covenant not to
|
||||
sue for patent infringement). To "grant" such a patent license to a
|
||||
party means to make such an agreement or commitment not to enforce a
|
||||
patent against the party.
|
||||
|
||||
If you convey a covered work, knowingly relying on a patent license,
|
||||
and the Corresponding Source of the work is not available for anyone
|
||||
to copy, free of charge and under the terms of this License, through a
|
||||
publicly available network server or other readily accessible means,
|
||||
then you must either (1) cause the Corresponding Source to be so
|
||||
available, or (2) arrange to deprive yourself of the benefit of the
|
||||
patent license for this particular work, or (3) arrange, in a manner
|
||||
consistent with the requirements of this License, to extend the patent
|
||||
license to downstream recipients. "Knowingly relying" means you have
|
||||
actual knowledge that, but for the patent license, your conveying the
|
||||
covered work in a country, or your recipient's use of the covered work
|
||||
in a country, would infringe one or more identifiable patents in that
|
||||
country that you have reason to believe are valid.
|
||||
|
||||
If, pursuant to or in connection with a single transaction or
|
||||
arrangement, you convey, or propagate by procuring conveyance of, a
|
||||
covered work, and grant a patent license to some of the parties
|
||||
receiving the covered work authorizing them to use, propagate, modify
|
||||
or convey a specific copy of the covered work, then the patent license
|
||||
you grant is automatically extended to all recipients of the covered
|
||||
work and works based on it.
|
||||
|
||||
A patent license is "discriminatory" if it does not include within
|
||||
the scope of its coverage, prohibits the exercise of, or is
|
||||
conditioned on the non-exercise of one or more of the rights that are
|
||||
specifically granted under this License. You may not convey a covered
|
||||
work if you are a party to an arrangement with a third party that is
|
||||
in the business of distributing software, under which you make payment
|
||||
to the third party based on the extent of your activity of conveying
|
||||
the work, and under which the third party grants, to any of the
|
||||
parties who would receive the covered work from you, a discriminatory
|
||||
patent license (a) in connection with copies of the covered work
|
||||
conveyed by you (or copies made from those copies), or (b) primarily
|
||||
for and in connection with specific products or compilations that
|
||||
contain the covered work, unless you entered into that arrangement,
|
||||
or that patent license was granted, prior to 28 March 2007.
|
||||
|
||||
Nothing in this License shall be construed as excluding or limiting
|
||||
any implied license or other defenses to infringement that may
|
||||
otherwise be available to you under applicable patent law.
|
||||
|
||||
12. No Surrender of Others' Freedom.
|
||||
|
||||
If conditions are imposed on you (whether by court order, agreement or
|
||||
otherwise) that contradict the conditions of this License, they do not
|
||||
excuse you from the conditions of this License. If you cannot convey a
|
||||
covered work so as to satisfy simultaneously your obligations under this
|
||||
License and any other pertinent obligations, then as a consequence you may
|
||||
not convey it at all. For example, if you agree to terms that obligate you
|
||||
to collect a royalty for further conveying from those to whom you convey
|
||||
the Program, the only way you could satisfy both those terms and this
|
||||
License would be to refrain entirely from conveying the Program.
|
||||
|
||||
13. Use with the GNU Affero General Public License.
|
||||
|
||||
Notwithstanding any other provision of this License, you have
|
||||
permission to link or combine any covered work with a work licensed
|
||||
under version 3 of the GNU Affero General Public License into a single
|
||||
combined work, and to convey the resulting work. The terms of this
|
||||
License will continue to apply to the part which is the covered work,
|
||||
but the special requirements of the GNU Affero General Public License,
|
||||
section 13, concerning interaction through a network will apply to the
|
||||
combination as such.
|
||||
|
||||
14. Revised Versions of this License.
|
||||
|
||||
The Free Software Foundation may publish revised and/or new versions of
|
||||
the GNU General Public License from time to time. Such new versions will
|
||||
be similar in spirit to the present version, but may differ in detail to
|
||||
address new problems or concerns.
|
||||
|
||||
Each version is given a distinguishing version number. If the
|
||||
Program specifies that a certain numbered version of the GNU General
|
||||
Public License "or any later version" applies to it, you have the
|
||||
option of following the terms and conditions either of that numbered
|
||||
version or of any later version published by the Free Software
|
||||
Foundation. If the Program does not specify a version number of the
|
||||
GNU General Public License, you may choose any version ever published
|
||||
by the Free Software Foundation.
|
||||
|
||||
If the Program specifies that a proxy can decide which future
|
||||
versions of the GNU General Public License can be used, that proxy's
|
||||
public statement of acceptance of a version permanently authorizes you
|
||||
to choose that version for the Program.
|
||||
|
||||
Later license versions may give you additional or different
|
||||
permissions. However, no additional obligations are imposed on any
|
||||
author or copyright holder as a result of your choosing to follow a
|
||||
later version.
|
||||
|
||||
15. Disclaimer of Warranty.
|
||||
|
||||
THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
|
||||
APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
|
||||
HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
|
||||
OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
|
||||
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
|
||||
IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
|
||||
ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
|
||||
|
||||
16. Limitation of Liability.
|
||||
|
||||
IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
|
||||
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
|
||||
THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
|
||||
GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
|
||||
USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
|
||||
DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
|
||||
PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
|
||||
EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
|
||||
SUCH DAMAGES.
|
||||
|
||||
17. Interpretation of Sections 15 and 16.
|
||||
|
||||
If the disclaimer of warranty and limitation of liability provided
|
||||
above cannot be given local legal effect according to their terms,
|
||||
reviewing courts shall apply local law that most closely approximates
|
||||
an absolute waiver of all civil liability in connection with the
|
||||
Program, unless a warranty or assumption of liability accompanies a
|
||||
copy of the Program in return for a fee.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
How to Apply These Terms to Your New Programs
|
||||
|
||||
If you develop a new program, and you want it to be of the greatest
|
||||
possible use to the public, the best way to achieve this is to make it
|
||||
free software which everyone can redistribute and change under these terms.
|
||||
|
||||
To do so, attach the following notices to the program. It is safest
|
||||
to attach them to the start of each source file to most effectively
|
||||
state the exclusion of warranty; and each file should have at least
|
||||
the "copyright" line and a pointer to where the full notice is found.
|
||||
|
||||
<one line to give the program's name and a brief idea of what it does.>
|
||||
Copyright (C) <year> <name of author>
|
||||
|
||||
This program 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.
|
||||
|
||||
This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
Also add information on how to contact you by electronic and paper mail.
|
||||
|
||||
If the program does terminal interaction, make it output a short
|
||||
notice like this when it starts in an interactive mode:
|
||||
|
||||
<program> Copyright (C) <year> <name of author>
|
||||
This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
|
||||
This is free software, and you are welcome to redistribute it
|
||||
under certain conditions; type `show c' for details.
|
||||
|
||||
The hypothetical commands `show w' and `show c' should show the appropriate
|
||||
parts of the General Public License. Of course, your program's commands
|
||||
might be different; for a GUI interface, you would use an "about box".
|
||||
|
||||
You should also get your employer (if you work as a programmer) or school,
|
||||
if any, to sign a "copyright disclaimer" for the program, if necessary.
|
||||
For more information on this, and how to apply and follow the GNU GPL, see
|
||||
<http://www.gnu.org/licenses/>.
|
||||
|
||||
The GNU General Public License does not permit incorporating your program
|
||||
into proprietary programs. If your program is a subroutine library, you
|
||||
may consider it more useful to permit linking proprietary applications with
|
||||
the library. If this is what you want to do, use the GNU Lesser General
|
||||
Public License instead of this License. But first, please read
|
||||
<http://www.gnu.org/philosophy/why-not-lgpl.html>.
|
||||
53
tool/tilem-src/INSTALL
Normal file
53
tool/tilem-src/INSTALL
Normal file
|
|
@ -0,0 +1,53 @@
|
|||
Installing TilEm
|
||||
------------------
|
||||
|
||||
To compile TilEm, you will need:
|
||||
|
||||
* a standard C compiler
|
||||
|
||||
* the GTK+ library, version 2.6.0 or later
|
||||
|
||||
* the libticalcs2 library (part of the TiLP project), and its
|
||||
dependencies (libticables2, libtifiles2, and libticonv)
|
||||
|
||||
Some OS distributions package the "development files" separately from
|
||||
the libraries themselves; you need both. If you are using Debian (or
|
||||
a related distribution, such as Ubuntu or Mint), install the packages
|
||||
'build-essential', 'libticalcs-dev', and 'libgtk2.0-dev'.
|
||||
|
||||
If these packages aren't available from your package manager, you'll
|
||||
need to compile them yourself; see the TiLP website for more
|
||||
information (http://lpg.ticalc.org/prj_tilp/).
|
||||
|
||||
Mac OS X has not been tested by the TilEm team, but if TiLP works,
|
||||
TilEm should, too. Please let us know if you do get it to work.
|
||||
|
||||
Once the above dependencies are installed, open a terminal and 'cd' to
|
||||
the directory containing this INSTALL file. Then run
|
||||
|
||||
./configure
|
||||
|
||||
which will check whether you have all of the necessary software
|
||||
installed, and figure out how to compile TilEm for your particular
|
||||
system. If configure is successful, you can then run
|
||||
|
||||
make
|
||||
|
||||
to compile TilEm. Finally, you can run
|
||||
|
||||
sudo make install
|
||||
|
||||
to install it (or run 'make install' as the superuser.) The program
|
||||
will be installed in '/usr/local/bin/', and data files will be
|
||||
installed in '/usr/local/share/tilem2/'. Alternatively, you can run
|
||||
|
||||
make install-home
|
||||
|
||||
to install TilEm in your own home directory ('$HOME/bin/', with data
|
||||
files stored in '$HOME/.local/share/tilem2/'), which does not require
|
||||
superuser privileges. (If $HOME/bin didn't exist already, you might
|
||||
have to run 'export PATH=$HOME/bin:$PATH', or log out and log back in,
|
||||
before running TilEm.)
|
||||
|
||||
Once TilEm is installed, start it by running 'tilem2', or through your
|
||||
system's applications menu.
|
||||
270
tool/tilem-src/KEYS
Normal file
270
tool/tilem-src/KEYS
Normal file
|
|
@ -0,0 +1,270 @@
|
|||
KEYBOARD BINDINGS
|
||||
|
||||
This list shows the default keyboard controls for TilEm. You can
|
||||
modify these, if you like, by editing 'keybindings.ini'. (Place the
|
||||
modified version of keybindings.ini in your TilEm configuration
|
||||
directory - $HOME/.config/tilem2/ on Unix, or
|
||||
$PROFILE\Local Settings\Application Data\tilem2 on Windows.)
|
||||
|
||||
In the following list:
|
||||
S = Shift
|
||||
C = Control
|
||||
↑ = 2nd
|
||||
α = Alpha
|
||||
|
||||
² in the TI-82/83 column indicates that the key is only for the TI-82.
|
||||
³ indicates that it is only for the TI-83/TI-83 Plus/TI-84 Plus.
|
||||
|
||||
Key TI-73 TI-76.fr TI-81 TI-82/83 TI-85/86
|
||||
──────────────────────────────────────────────────────────────────────────────
|
||||
F12 ON ON ON ON ON
|
||||
S+F12 ↑ [OFF] ↑ [OFF] ↑ [OFF] ↑ [OFF] ↑ [OFF]
|
||||
|
||||
Up Up Up Up Up Up
|
||||
Down Down Down Down Down Down
|
||||
Left Left Left Left Left Left
|
||||
Right Right Right Right Right Right
|
||||
S+Up ↑ Up ↑ Up ↑ Up ↑ Up ↑ Up
|
||||
S+Down ↑ Down ↑ Down ↑ Down ↑ Down ↑ Down
|
||||
Home ↑ Left ↑ Left ↑ Left ↑ Left
|
||||
End ↑ Right ↑ Right ↑ Right ↑ Right
|
||||
PageUp α Up ³
|
||||
PageDown α Down ³
|
||||
|
||||
F1 Y= f(x)= Y= Y= F1
|
||||
F2 WINDOW fenêtre RANGE WINDOW F2
|
||||
F3 ZOOM zoom ZOOM ZOOM F3
|
||||
F4 TRACE trace TRACE TRACE F4
|
||||
F5 GRAPH graphe GRAPH GRAPH F5
|
||||
S+F1 ↑ [PLOT] ↑ [gr stat] ↑ Y= ↑ [STAT PLT] ↑ [M1]
|
||||
S+F2 ↑ [TBLSET] ↑ [déf tab] ↑ RANGE ↑ [TBLSET] ↑ [M2]
|
||||
S+F3 ↑ [FORMAT] ↑ [format] ↑ ZOOM ↑ [FORMAT] ↑ [M3]
|
||||
S+F4 ↑ TRACE ↑ [calculs] ↑ TRACE ↑ [CALC] ↑ [M4]
|
||||
S+F5 ↑ [TABLE] ↑ [table] ↑ GRAPH ↑ [TABLE] ↑ [M5]
|
||||
PageDown MORE
|
||||
|
||||
Tab 2nd 2nde 2nd 2nd 2nd
|
||||
' or Menu ↑ [TEXT] texte Alpha Alpha Alpha
|
||||
|
||||
Insert ↑ [INS] ↑ [insérer] INS ↑ [INS] ↑ [INS]
|
||||
Delete DEL suppr DEL DEL DEL
|
||||
Backspace Left, DEL Left, suppr Left, DEL Left, DEL Left, DEL
|
||||
C+Backspace CLEAR annul CLEAR CLEAR CLEAR
|
||||
or C+Delete
|
||||
|
||||
Escape CLEAR annul CLEAR CLEAR EXIT
|
||||
S+Escape ↑ [QUIT] ↑ [quitter] ↑ [QUIT] ↑ [QUIT] ↑ [QUIT]
|
||||
|
||||
F6 math MATH MATH GRAPH
|
||||
F7 APPS angle MATRX MATRX/APPS STAT
|
||||
F8 PRGM prgm PRGM PRGM PRGM
|
||||
F9 var VARS VARS CUSTOM
|
||||
F10 stats STAT
|
||||
F11 MODE mode MODE MODE ↑ [MODE]
|
||||
c CONST
|
||||
d DRAW
|
||||
l LIST
|
||||
m MATH
|
||||
p prgm PRGM PRGM
|
||||
C+Tab ↑ [CATALOG] ↑ [catalog] ↑ [CATALOG]³ ↑ [CATALOG]
|
||||
|
||||
_ UNIT
|
||||
| or ½ a/b
|
||||
f F◂▸D
|
||||
a Ab/c◂▸d/e
|
||||
s SIMP
|
||||
% %
|
||||
|
||||
| ↑ [ABS] ↑ [ABS] ²
|
||||
s sin SIN SIN
|
||||
c cos COS COS
|
||||
t tan TAN TAN
|
||||
o log LOG LOG
|
||||
l ln LN LN
|
||||
|
||||
u ↑ [uₙ] ↑ [u] ³
|
||||
v ↑ [vₙ] ↑ [v] ³
|
||||
w ↑ [wₙ] ↑ [w] ³
|
||||
u ↑ [Uₙ₋₁] ²
|
||||
v ↑ [Vₙ₋₁] ²
|
||||
n ↑ [n] ²
|
||||
|
||||
C+1 or \ ↑ [x⁻¹] x⁻¹ x⁻¹ x⁻¹ ↑ [x⁻¹]
|
||||
C+2 or ² x² x² x² x² x²
|
||||
( ( ( ( ( (
|
||||
) ) ( ) ) )
|
||||
{ ↑ [{] ↑ [{]
|
||||
} ↑ [}] ↑ [}]
|
||||
[ ↑ [[] ↑ [[]
|
||||
] ↑ []] ↑ []]
|
||||
^ ^ ^ ^ ^ ^
|
||||
/ ÷ ÷ ÷ ÷ ÷
|
||||
* × × × × ×
|
||||
- - - - - -
|
||||
+ + + + + +
|
||||
, , , α [,] , ,
|
||||
|
||||
> STO▸ STO▸ STO▸ STO▸ STO▸
|
||||
< ↑ [RCL] ↑ [rappel] ↑ STO▸ ↑ [RCL] ↑ [RCL]
|
||||
|
||||
0 - 9 0 - 9 0 - 9 0 - 9 0 - 9 0 - 9
|
||||
. . . . . .
|
||||
~ or ± (-) (-) (-) (-) (-)
|
||||
& or € ↑ [EE] ↑ […×10ⁿ] EE ↑ [EE] EE
|
||||
|
||||
x X x,n X|T X,T,θ,n
|
||||
$ ↑ [ANS] ↑ [rép] ↑ [ANS] ↑ [ANS] ↑ [ANS]
|
||||
# ↑ [π] ↑ [π] ↑ [π] ↑ [π] ↑ [π]
|
||||
e ↑ [e] ↑ [e] ³
|
||||
i ↑ [i] ³
|
||||
|
||||
A - Z α [A]-[Z] α [A]-[Z] α [A]-[Z]
|
||||
a - z ↑α [a]-[z]
|
||||
Space α [space] α [space] α [space]
|
||||
@ α [θ] α [θ]
|
||||
" α ["] α ["]
|
||||
? α [?] α [?]
|
||||
: α [:] ↑ [:]
|
||||
= α [=]
|
||||
|
||||
Return ENTER entrer ENTER ENTER ENTER
|
||||
S+Return ↑ [ENTRY] ↑ [précéd] ↑ [ENTRY] ↑ [ENTRY] ↑ [ENTRY]
|
||||
──────────────────────────────────────────────────────────────────────────────
|
||||
|
||||
For the TI-83 Plus and TI-84 Plus, in addition to the keys listed
|
||||
above for the TI-83, pressing Shift+letter while Caps Lock is enabled
|
||||
will type a lowercase letter (Alpha, Alpha, letter.) Lowercase mode
|
||||
will need to be enabled on the calculator for this to work; it's not
|
||||
enabled by default, but there are many assembly programs that can do
|
||||
so.
|
||||
|
||||
|
||||
KEYPAD CHARTS
|
||||
|
||||
TI-73 TI-76.fr
|
||||
|
||||
╭──────┬──────┬──────┬──────┬──────╮ ╭──────┬──────┬──────┬──────┬──────╮
|
||||
│S+F1 │S+F2 │S+F3 │S+F4 │S+F5 │ │S+F1 │S+F2 │S+F3 │S+F4 │S+F5 │
|
||||
│F1 │F2 │F3 │F4 │F5 │ │F1 │F2 │F3 │F4 │F5 │
|
||||
╰──────┴──────┴──────┴────┬─┴──┬───╯ ╰──────┴──────┴──────┴────┬─┴──┬───╯
|
||||
╭──────┬──────┬──────╮ │S+Up│ ╭──────┬──────┬──────╮ │S+Up│
|
||||
│ │S+Esc │Ins ├────┤Up ├─────╮ │ │S+Esc │Ins ├────┤Up ├─────╮
|
||||
│Tab │F11 │Del │Home├────┤End │ │Tab │F11 │Del │Home├────┤End │
|
||||
├──────┼──────┼──────┤Left├────┤Right│ ├──────┼──────┼──────┤Left├────┤Right│
|
||||
│' │ │ ├────┤S+Dn├─────╯ │ │ │ ├────┤S+Dn├─────╯
|
||||
│m │d │l │ │Down│ │' │x │F10 │ │Down│
|
||||
├──────┼──────┼──────┼────┴─┬──┴───╮ ├──────┼──────┼──────┼────┴─┬──┴───╮
|
||||
│ │& │C+Tab │ │ │ │ │ │ │ │ │
|
||||
│C+2 │^ │F8 │F7 │Esc │ │F6 │F7 │F8 │F9 │Esc │
|
||||
├──────┼──────┼──────┼──────┼──────┤ ├──────┼──────┼──────┼──────┼──────┤
|
||||
│ │\ │# │ │ │ │ │ │ │ │# │
|
||||
│_ │| │f │a │c │ │\ │s │c │t │^ │
|
||||
├──────┼──────┼──────┼──────┼──────┤ ├──────┼──────┼──────┼──────┼──────┤
|
||||
│ │ │ │ │ │ │ │& │{ │} │e │
|
||||
│s │% │( │) │/ │ │C+2 │, │( │) │/ │
|
||||
├──────┼──────┼──────┼──────┼──────┤ ├──────┼──────┼──────┼──────┼──────┤
|
||||
│ │ │ │ │ │ │ │u │v │w │ │
|
||||
│x │7 │8 │9 │* │ │o │7 │8 │9 │* │
|
||||
├──────┼──────┼──────┼──────┼──────┤ ├──────┼──────┼──────┼──────┼──────┤
|
||||
│ │ │ │ │ │ │ │ │ │ │ │
|
||||
│, │4 │5 │6 │- │ │l │4 │5 │6 │- │
|
||||
├──────┼──────┼──────┼──────┼──────┤ ├──────┼──────┼──────┼──────┼──────┤
|
||||
│< │ │ │ │ │ │< │ │ │ │ │
|
||||
│> │1 │2 │3 │+ │ │> │1 │2 │3 │+ │
|
||||
├──────┼──────┼──────┼──────┼──────┤ ├──────┼──────┼──────┼──────┼──────┤
|
||||
│S+F12 │ │ │$ │S+Ret │ │S+F12 │C+Tab │ │$ │S+Ret │
|
||||
│F12 │0 │. │~ │Ret │ │F12 │0 │. │~ │Ret │
|
||||
╰──────┴──────┴──────┴──────┴──────╯ ╰──────┴──────┴──────┴──────┴──────╯
|
||||
|
||||
|
||||
TI-81 TI-82
|
||||
|
||||
╭──────┬──────┬──────┬──────┬──────╮ ╭──────┬──────┬──────┬──────┬──────╮
|
||||
│S+F1 │S+F2 │S+F3 │S+F4 │S+F5 │ │S+F1 │S+F2 │S+F3 │S+F4 │S+F5 │
|
||||
│F1 │F2 │F3 │F4 │F5 │ │F1 │F2 │F3 │F4 │F5 │
|
||||
╰──────┴──────┴──────┴────┬─┴──┬───╯ ╰──────┴──────┴──────┴────┬─┴──┬───╯
|
||||
╭──────┬──────┬──────╮ │S+Up│ ╭──────┬──────┬──────╮ │S+Up│
|
||||
│ │ │ ├────┤Up ├─────╮ │ │S+Esc │Ins ├────┤Up ├─────╮
|
||||
│Tab │Ins │Del │ ├────┤ │ │Tab │F11 │Del │Home├────┤End │
|
||||
├──────┼──────┼──────┤Left├────┤Right│ ├──────┼──────┼──────┤Left├────┤Right│
|
||||
│ │ │ ├────┤S+Dn├─────╯ │ │ │ ├────┤S+Dn├─────╯
|
||||
│' │x │F11 │ │Down│ │' │x │F10 │ │Down│
|
||||
├──────┼──────┼──────┼────┴─┬──┴───╮ ├──────┼──────┼──────┼────┴─┬──┴───╮
|
||||
│ │ │ │ │S+Esc │ │ │ │ │ │ │
|
||||
│F6 │F7 │F8 │F9 │Esc │ │F6 │F7 │F8 │F9 │Esc │
|
||||
├──────┼──────┼──────┼──────┼──────┤ ├──────┼──────┼──────┼──────┼──────┤
|
||||
│| │ │ │ │# │ │| │ │ │ │# │
|
||||
│\ │s │c │t │^ │ │\ │s │c │t │^ │
|
||||
├──────┼──────┼──────┼──────┼──────┤ ├──────┼──────┼──────┼──────┼──────┤
|
||||
│ │ │ │ │ │ │ │& │{ │} │ │
|
||||
│C+2 │& │( │) │/ │ │C+2 │, │( │) │/ │
|
||||
├──────┼──────┼──────┼──────┼──────┤ ├──────┼──────┼──────┼──────┼──────┤
|
||||
│ │ │ │ │ │ │ │u │v │n │[ │
|
||||
│o │7 │8 │9 │* │ │o │7 │8 │9 │* │
|
||||
├──────┼──────┼──────┼──────┼──────┤ ├──────┼──────┼──────┼──────┼──────┤
|
||||
│ │ │ │ │ │ │ │ │ │ │] │
|
||||
│l │4 │5 │6 │- │ │l │4 │5 │6 │- │
|
||||
├──────┼──────┼──────┼──────┼──────┤ ├──────┼──────┼──────┼──────┼──────┤
|
||||
│< │ │ │ │ │ │< │ │ │ │ │
|
||||
│> │1 │2 │3 │+ │ │> │1 │2 │3 │+ │
|
||||
├──────┼──────┼──────┼──────┼──────┤ ├──────┼──────┼──────┼──────┼──────┤
|
||||
│S+F12 │ │ │$ │S+Ret │ │S+F12 │ │ │$ │S+Ret │
|
||||
│F12 │0 │. │~ │Ret │ │F12 │0 │. │~ │Ret │
|
||||
╰──────┴──────┴──────┴──────┴──────╯ ╰──────┴──────┴──────┴──────┴──────╯
|
||||
|
||||
Not shown: Not shown:
|
||||
A-Z Alpha, [A]-[Z] A-Z Alpha, [A]-[Z]
|
||||
@ Alpha, 3 @ Alpha, 3
|
||||
" Alpha, + " Alpha, +
|
||||
Space Alpha, 0 Space Alpha, 0
|
||||
, Alpha, . : Alpha, .
|
||||
? Alpha, (-) ? Alpha, (-)
|
||||
|
||||
|
||||
TI-83 / TI-83 Plus / TI-84 Plus TI-85 / TI-86
|
||||
|
||||
╭──────┬──────┬──────┬──────┬──────╮ ╭──────┬──────┬──────┬──────┬──────╮
|
||||
│S+F1 │S+F2 │S+F3 │S+F4 │S+F5 │ │S+F1 │S+F2 │S+F3 │S+F4 │S+F5 │
|
||||
│F1 │F2 │F3 │F4 │F5 │ │F1 │F2 │F3 │F4 │F5 │
|
||||
╰──────┴──────┴──────┴────┬─┴──┬───╯ ╰──────┴──────┴──────┴────┬─┴──┬───╯
|
||||
╭──────┬──────┬──────╮ │S+Up│ ╭──────┬──────┬──────╮ │S+Up│
|
||||
│ │S+Esc │Ins ├────┤Up ├─────╮ │ │S+Esc │F11 ├────┤Up ├─────╮
|
||||
│Tab │F11 │Del │Home├────┤End │ │Tab │Esc │PgDn │Home├────┤End │
|
||||
├──────┼──────┼──────┤Left├────┤Right│ ├──────┼──────┼──────┤Left├────┤Right│
|
||||
│ │ │ ├────┤S+Dn├─────╯ │ │ │Ins ├────┤S+Dn├─────╯
|
||||
│' │x │F10 │ │Down│ │' │ │Del │ │Down│
|
||||
├──────┼──────┼──────┼────┴─┬──┴───╮ ├──────┼──────┼──────┼────┴─┬──┴───╮
|
||||
│ │ │ │ │ │ │ │ │ │C+Tab │ │
|
||||
│F6 │F7 │F8 │F9 │Esc │ │F6 │F7 │F8 │F9 │C+BkSp│
|
||||
├──────┼──────┼──────┼──────┼──────┤ ├──────┼──────┼──────┼──────┼──────┤
|
||||
│ │ │ │ │# │ │ │ │ │ │# │
|
||||
│\ │s │c │t │^ │ │ │ │ │ │^ │
|
||||
├──────┼──────┼──────┼──────┼──────┤ ├──────┼──────┼──────┼──────┼──────┤
|
||||
│ │& │{ │} │e │ │ │\ │[ │] │ │
|
||||
│C+2 │, │( │) │/ │ │ │& │( │) │/ │
|
||||
├──────┼──────┼──────┼──────┼──────┤ ├──────┼──────┼──────┼──────┼──────┤
|
||||
│ │u │v │w │[ │ │ │ │ │ │ │
|
||||
│o │7 │8 │9 │* │ │C+2 │7 │8 │9 │* │
|
||||
├──────┼──────┼──────┼──────┼──────┤ ├──────┼──────┼──────┼──────┼──────┤
|
||||
│ │ │ │ │] │ │ │ │ │ │ │
|
||||
│l │4 │5 │6 │- │ │, │4 │5 │6 │- │
|
||||
├──────┼──────┼──────┼──────┼──────┤ ├──────┼──────┼──────┼──────┼──────┤
|
||||
│< │ │ │ │ │ │< │ │ │ │ │
|
||||
│> │1 │2 │3 │+ │ │> │1 │2 │3 │+ │
|
||||
├──────┼──────┼──────┼──────┼──────┤ ├──────┼──────┼──────┼──────┼──────┤
|
||||
│S+F12 │C+Tab │i │$ │S+Ret │ │S+F12 │ │: │$ │S+Ret │
|
||||
│F12 │0 │. │~ │Ret │ │F12 │0 │. │~ │Ret │
|
||||
╰──────┴──────┴──────┴──────┴──────╯ ╰──────┴──────┴──────┴──────┴──────╯
|
||||
|
||||
Not shown: Not shown:
|
||||
PageUp Alpha, Up A-Z Alpha, [A]-[Z]
|
||||
PageDown Alpha, Down a-z 2nd, Alpha, [a]-[z]
|
||||
A-Z Alpha, [A]-[Z] Space Alpha, (-)
|
||||
@ Alpha, 3 = Alpha, Sto▸
|
||||
" Alpha, +
|
||||
Space Alpha, 0
|
||||
: Alpha, .
|
||||
? Alpha, (-)
|
||||
|
||||
TI-83 Plus / TI-84 Plus only:
|
||||
CapsLock + Shift + a-z = Alpha, Alpha, [a]-[z]
|
||||
91
tool/tilem-src/Makefile.in
Normal file
91
tool/tilem-src/Makefile.in
Normal file
|
|
@ -0,0 +1,91 @@
|
|||
prefix = @prefix@
|
||||
exec_prefix = @exec_prefix@
|
||||
datarootdir = @datarootdir@
|
||||
bindir = @bindir@
|
||||
datadir = @datadir@
|
||||
pkgdatadir = @datadir@/tilem2
|
||||
mandir = @mandir@
|
||||
|
||||
top_builddir = @top_builddir@
|
||||
top_srcdir = @top_srcdir@
|
||||
srcdir = @srcdir@
|
||||
VPATH = @srcdir@
|
||||
@SET_MAKE@
|
||||
SHELL = @SHELL@
|
||||
|
||||
INSTALL = @INSTALL@
|
||||
|
||||
distname = @PACKAGE_TARNAME@-@PACKAGE_VERSION@
|
||||
|
||||
distfiles = CHANGELOG COPYING INSTALL KEYS NEWS README THANKS TODO \
|
||||
aclocal.m4 config.h.in configure configure.ac install-sh \
|
||||
Makefile.in \
|
||||
data/Makefile.in \
|
||||
data/keybindings.ini \
|
||||
data/desktop/*.desktop data/desktop/*.xml \
|
||||
data/icons/hicolor/index.theme data/icons/hicolor/*/*/*.png \
|
||||
data/icons-svg/*.svg \
|
||||
data/skins/README data/skins/*.skn \
|
||||
data/symbols/*.sym \
|
||||
db/Makefile.in db/*.c db/*.h \
|
||||
emu/Makefile.in emu/*.c emu/*.h emu/x*/*.c emu/x*/*.h \
|
||||
gui/Makefile.in gui/*.c gui/*.h gui/*.ico gui/*.rc.in \
|
||||
installer/win32/Makefile.in \
|
||||
installer/win32/installer.nsi.in installer/win32/gtkrc \
|
||||
installer/win32/COPYING-ZLIB installer/win32/COPYING-PIXMAN
|
||||
|
||||
all:
|
||||
cd emu && $(MAKE)
|
||||
cd db && $(MAKE)
|
||||
cd gui && $(MAKE)
|
||||
|
||||
clean:
|
||||
cd emu && $(MAKE) clean
|
||||
cd db && $(MAKE) clean
|
||||
cd gui && $(MAKE) clean
|
||||
cd installer/win32 && $(MAKE) clean
|
||||
|
||||
install: all
|
||||
cd gui && $(MAKE) install
|
||||
cd data && $(MAKE) install
|
||||
|
||||
uninstall:
|
||||
cd gui && $(MAKE) uninstall
|
||||
cd data && $(MAKE) uninstall
|
||||
|
||||
install-home: all
|
||||
$(MAKE) install \
|
||||
bindir=$(HOME)/bin \
|
||||
datarootdir=$${XDG_DATA_HOME:-$(HOME)/.local/share}
|
||||
|
||||
uninstall-home:
|
||||
$(MAKE) uninstall \
|
||||
bindir=$(HOME)/bin \
|
||||
datarootdir=$${XDG_DATA_HOME:-$(HOME)/.local/share}
|
||||
|
||||
distclean: clean
|
||||
rm -f config.status config.log config.h configure.lineno
|
||||
rm -rf autom4te.cache
|
||||
rm -f installer/win32/Makefile installer/win32/installer.nsi
|
||||
rm -f gui/tilem2.rc
|
||||
rm -f Makefile emu/Makefile db/Makefile gui/Makefile data/Makefile
|
||||
|
||||
dist:
|
||||
rm -rf $(distname)
|
||||
mkdir $(distname)
|
||||
set -e ; files=`cd $(srcdir) ; echo $(distfiles)` ; \
|
||||
for f in $$files ; do \
|
||||
dir=`echo $(distname)/$$f | sed 's,/[^/]*$$,,'` ; \
|
||||
[ -d $$dir ] || $(INSTALL) -d $$dir ; \
|
||||
cp -p $(srcdir)/$$f $$dir ; \
|
||||
done
|
||||
tar cv $(distname) | bzip2 -c -9 > $(distname).tar.bz2
|
||||
|
||||
Makefile: Makefile.in config.status
|
||||
$(SHELL) ./config.status
|
||||
|
||||
config.status: configure
|
||||
$(SHELL) ./config.status --recheck
|
||||
|
||||
.PRECIOUS: Makefile config.status
|
||||
.PHONY: all clean dist distclean install install-home uninstall uninstall-home
|
||||
73
tool/tilem-src/NEWS
Normal file
73
tool/tilem-src/NEWS
Normal file
|
|
@ -0,0 +1,73 @@
|
|||
Version History
|
||||
-----------------
|
||||
|
||||
2012-06-07 -- version 2.0
|
||||
|
||||
This is the first official release of the "new" TilEm. Much of the
|
||||
old TilEm code has been rewritten, and there are many improvements
|
||||
(and probably some new bugs.)
|
||||
|
||||
Please note, if you have used older versions of TilEm:
|
||||
|
||||
* Your existing ROM files and settings in ~/.TilEm will not be
|
||||
used (in fact, you can keep TilEm 0.97x installed alongside
|
||||
TilEm 2.0 if you wish.) TilEm 2.0 no longer uses a "library" of
|
||||
ROM files; you can store ROM files anywhere you like.
|
||||
|
||||
* TilEm 2.0 uses a new format for calculator state (SAV) files.
|
||||
State files created by TilEm 0.97x can be loaded by TilEm 2.0,
|
||||
but if you then save the state, it will be stored in the new
|
||||
format, which older versions of TilEm will not support.
|
||||
|
||||
New features and bugs fixed since version 0.975 include:
|
||||
|
||||
* All code that was covered by the Z80em license has been removed.
|
||||
|
||||
* Support for the TI-81 (both hardware versions) and TI-76.fr, and
|
||||
experimental support for the TI-Nspire's TI-84 Plus emulation
|
||||
mode.
|
||||
|
||||
* Many hardware emulation improvements for all calculator models.
|
||||
In particular, major improvements have been made concerning Z80
|
||||
interrupts, timers, the LCD driver, and the link port.
|
||||
|
||||
* The emulator window uses TiEmu-format skin files.
|
||||
|
||||
* Greatly improved grayscale emulation.
|
||||
|
||||
* Commands for saving still screenshots (in PNG, BMP, JPEG, or GIF
|
||||
format) and animations (GIF format only.)
|
||||
|
||||
* Keypad macros can be recorded and replayed.
|
||||
|
||||
* Programs and/or ROM files can be loaded from the command line.
|
||||
|
||||
* Link I/O uses libticalcs2, which allows all types of variables,
|
||||
as well as Flash apps and OSes, to be transferred through the
|
||||
link port. For the TI-81, PRG files can be transferred to and
|
||||
from the calculator memory directly.
|
||||
|
||||
* TilEm does not consume 100% of the host CPU when idle.
|
||||
|
||||
* Improved disassembler (macros; distinct "labels" and "romcalls";
|
||||
named IY flags.)
|
||||
|
||||
* The debugger offers a "Finish Subroutine" command. In addition,
|
||||
the "Step Over" command behaves more sensibly.
|
||||
|
||||
* Breakpoints can be set on absolute memory addresses, and on Z80
|
||||
opcodes.
|
||||
|
||||
* Many minor improvements.
|
||||
|
||||
Features of 0.975 that are not yet supported in TilEm 2.0 include:
|
||||
|
||||
* External link cables.
|
||||
|
||||
* Custom symbol files in the disassembler.
|
||||
|
||||
* Program counter history tracking.
|
||||
|
||||
Most of the new code is due to Benjamin Moody (floppusmaximus) and
|
||||
Thibault Duponchelle (contra-sh). See THANKS for a full list of
|
||||
contributors.
|
||||
92
tool/tilem-src/README
Normal file
92
tool/tilem-src/README
Normal file
|
|
@ -0,0 +1,92 @@
|
|||
TilEm
|
||||
-------
|
||||
|
||||
TilEm is an emulator and debugger for Texas Instruments Z80-based
|
||||
graphing calculators. It can emulate any of the following calculator
|
||||
models:
|
||||
|
||||
TI-73 / TI-73 Explorer
|
||||
TI-76.fr
|
||||
TI-81
|
||||
TI-82
|
||||
TI-82 STATS / TI-82 STATS.fr
|
||||
TI-83
|
||||
TI-83 Plus / TI-83 Plus Silver Edition / TI-83 Plus.fr
|
||||
TI-84 Plus / TI-84 Plus Silver Edition / TI-84 pocket.fr
|
||||
TI-85
|
||||
TI-86
|
||||
|
||||
TilEm fully supports all known versions of the above calculators (as
|
||||
of 2012), and attempts to reproduce the behavior of the original
|
||||
calculator hardware as faithfully as possible.
|
||||
|
||||
In addition, TilEm can emulate the TI-Nspire's virtual TI-84 Plus
|
||||
mode. This is currently experimental, and some programs may not work
|
||||
correctly.
|
||||
|
||||
TilEm runs on the X Window System on GNU/Linux and other Unix-like
|
||||
platforms, as well as on Microsoft Windows, and any other platform
|
||||
supported by the GTK+ library.
|
||||
|
||||
|
||||
Installation
|
||||
--------------
|
||||
Packages for Microsoft Windows are available from the TilEm project
|
||||
website (http://lpg.ticalc.org/prj_tilem/). For other platforms, you
|
||||
will need to compile TilEm from source; please see the file 'INSTALL'
|
||||
in the source package.
|
||||
|
||||
|
||||
Using TilEm
|
||||
-------------
|
||||
TilEm requires a copy of the operating system from the calculator
|
||||
model(s) you wish to emulate. This file is called a "ROM image",
|
||||
since the calculator OS was traditionally stored in Read-Only Memory.
|
||||
ROM images are copyrighted by TI and may not be distributed without
|
||||
permission. See the TilEm User's Manual for more information about
|
||||
how to create a ROM image.
|
||||
|
||||
The main TilEm window shows an image of the calculator (if possible -
|
||||
we are still missing background images for a few models.) Clicking
|
||||
with the left mouse button presses a key; clicking with the middle
|
||||
button presses a key and holds it down. Clicking with the right
|
||||
button, or pressing Shift+F10, opens the menu.
|
||||
|
||||
When you run TilEm for the first time, it will ask you to select a ROM
|
||||
image to use. The file you select will be used by default the next
|
||||
time you run TilEm. You can switch to a different ROM image by
|
||||
right-clicking and selecting "Open Calculator".
|
||||
|
||||
The state of the emulated calculator is not saved by default; to save
|
||||
the state, right-click and select "Save Calculator". The state is
|
||||
saved to a ".sav" file, stored in the same directory as the ROM image.
|
||||
|
||||
You can send program and variable files to the emulated calculator,
|
||||
either by dragging and dropping them from your file manager, or by
|
||||
right-clicking and selecting "Send File". To retrieve program or
|
||||
variable files from the calculator, select "Receive File".
|
||||
|
||||
Other features of TilEm include:
|
||||
|
||||
- A debugger for assembly programs
|
||||
- Capturing screenshots, both normal and animated
|
||||
- Recording and replaying keystroke macros
|
||||
|
||||
For more information, see the TilEm User's Manual:
|
||||
http://lpg.ticalc.org/prj_tilem2/doc.html
|
||||
|
||||
|
||||
About this program
|
||||
--------------------
|
||||
Many people deserve credit for helping to make this program possible.
|
||||
See the file 'THANKS'.
|
||||
|
||||
This program is free software, which means that you are allowed to
|
||||
modify it, and to distribute it (or your modified version) to others.
|
||||
When you received this program, you should also have been offered a
|
||||
complete copy of its source code. For more information, see the file
|
||||
'COPYING'.
|
||||
|
||||
You can contact the authors at <tilem-devel@lists.sourceforge.net>.
|
||||
Please let us know of any problems you encounter, or ideas for how we
|
||||
could make TilEm better.
|
||||
37
tool/tilem-src/THANKS
Normal file
37
tool/tilem-src/THANKS
Normal file
|
|
@ -0,0 +1,37 @@
|
|||
Thanks
|
||||
--------
|
||||
The current maintainers of TilEm are Thibault Duponchelle and Benjamin
|
||||
Moody, but many other people have played a part in making this program
|
||||
possible.
|
||||
|
||||
The original TilEm was written in 2001 by Julien Solignac. The
|
||||
current version is partially based on the original, but large portions
|
||||
have been rewritten, starting in 2009, by Benjamin Moody and Thibault
|
||||
Duponchelle. Portions of the hardware emulation code are also due to
|
||||
Luc Bruant.
|
||||
|
||||
The code for reading skin files is based on code from TiEmu, written
|
||||
by Julien Blache. The GIF compression code is based on whirlgif,
|
||||
written by Hans Dinsen-Hansen and Michael A. Mayer.
|
||||
|
||||
Thanks to Claude Clerc for the photo of his TI-83 Plus, and to Danilo
|
||||
Šegan for the photo of his TI-86, which we have used as skins. Thanks
|
||||
to Scott Zeid for the design of the program icon.
|
||||
|
||||
TilEm uses the TiLP libraries (libticalcs2, libticables2, libtifiles2,
|
||||
and libticonv) to send and receive variables. Thanks are due to the
|
||||
current maintainer of TiLP, Lionel Debroux, for his assistance, as
|
||||
well as to all of the past maintainers of TiLP, including Romain
|
||||
Liévin, Kevin Kofler, and Julien Blache.
|
||||
|
||||
Finally, this program would never have been possible without the
|
||||
efforts of countless programmers and researchers over the years to
|
||||
discover and document the inner workings of the calculator hardware.
|
||||
The following people deserve special recognition for their research:
|
||||
Randy Compton, Tijl Coosemans, Brian Coventry, Dan Eble, Dan
|
||||
Englender, Dines Justesen, Julien Lasson, Mattias Lindqvist, James
|
||||
Montelongo, Michael Vincent, Brandon Wilson, and Joerg Woerner.
|
||||
|
||||
(Thibault) In addition of above:
|
||||
Thanks to Michael Nock and Guillaume Hoffman for testing, feature request and encouragement.
|
||||
Thanks to Xavier Andreani for his encouragement.
|
||||
7
tool/tilem-src/TODO
Normal file
7
tool/tilem-src/TODO
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
- Linking between 2 tilem instances
|
||||
- Sound
|
||||
- Rewrite macro (parser and tokens).
|
||||
- Add scripting (lua or something else?)
|
||||
- Teacher mode (record keys pressed and produce a picture file with keys icons)
|
||||
|
||||
|
||||
173
tool/tilem-src/aclocal.m4
vendored
Normal file
173
tool/tilem-src/aclocal.m4
vendored
Normal file
|
|
@ -0,0 +1,173 @@
|
|||
# generated automatically by aclocal 1.11.1 -*- Autoconf -*-
|
||||
|
||||
# Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004,
|
||||
# 2005, 2006, 2007, 2008, 2009 Free Software Foundation, Inc.
|
||||
# This file is free software; the Free Software Foundation
|
||||
# gives unlimited permission to copy and/or distribute it,
|
||||
# with or without modifications, as long as this notice is preserved.
|
||||
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
|
||||
# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
|
||||
# PARTICULAR PURPOSE.
|
||||
|
||||
# pkg.m4 - Macros to locate and utilise pkg-config. -*- Autoconf -*-
|
||||
# serial 1 (pkg-config-0.24)
|
||||
#
|
||||
# Copyright © 2004 Scott James Remnant <scott@netsplit.com>.
|
||||
#
|
||||
# This program 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 2 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# This program 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 this program; if not, write to the Free Software
|
||||
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
#
|
||||
# As a special exception to the GNU General Public License, if you
|
||||
# distribute this file as part of a program that contains a
|
||||
# configuration script generated by Autoconf, you may include it under
|
||||
# the same distribution terms that you use for the rest of that program.
|
||||
|
||||
# PKG_PROG_PKG_CONFIG([MIN-VERSION])
|
||||
# ----------------------------------
|
||||
AC_DEFUN([PKG_PROG_PKG_CONFIG],
|
||||
[m4_pattern_forbid([^_?PKG_[A-Z_]+$])
|
||||
m4_pattern_allow([^PKG_CONFIG(_(PATH|LIBDIR|SYSROOT_DIR|ALLOW_SYSTEM_(CFLAGS|LIBS)))?$])
|
||||
m4_pattern_allow([^PKG_CONFIG_(DISABLE_UNINSTALLED|TOP_BUILD_DIR|DEBUG_SPEW)$])
|
||||
AC_ARG_VAR([PKG_CONFIG], [path to pkg-config utility])
|
||||
AC_ARG_VAR([PKG_CONFIG_PATH], [directories to add to pkg-config's search path])
|
||||
AC_ARG_VAR([PKG_CONFIG_LIBDIR], [path overriding pkg-config's built-in search path])
|
||||
|
||||
if test "x$ac_cv_env_PKG_CONFIG_set" != "xset"; then
|
||||
AC_PATH_TOOL([PKG_CONFIG], [pkg-config])
|
||||
fi
|
||||
if test -n "$PKG_CONFIG"; then
|
||||
_pkg_min_version=m4_default([$1], [0.9.0])
|
||||
AC_MSG_CHECKING([pkg-config is at least version $_pkg_min_version])
|
||||
if $PKG_CONFIG --atleast-pkgconfig-version $_pkg_min_version; then
|
||||
AC_MSG_RESULT([yes])
|
||||
else
|
||||
AC_MSG_RESULT([no])
|
||||
PKG_CONFIG=""
|
||||
fi
|
||||
fi[]dnl
|
||||
])# PKG_PROG_PKG_CONFIG
|
||||
|
||||
# PKG_CHECK_EXISTS(MODULES, [ACTION-IF-FOUND], [ACTION-IF-NOT-FOUND])
|
||||
#
|
||||
# Check to see whether a particular set of modules exists. Similar
|
||||
# to PKG_CHECK_MODULES(), but does not set variables or print errors.
|
||||
#
|
||||
# Please remember that m4 expands AC_REQUIRE([PKG_PROG_PKG_CONFIG])
|
||||
# only at the first occurence in configure.ac, so if the first place
|
||||
# it's called might be skipped (such as if it is within an "if", you
|
||||
# have to call PKG_CHECK_EXISTS manually
|
||||
# --------------------------------------------------------------
|
||||
AC_DEFUN([PKG_CHECK_EXISTS],
|
||||
[AC_REQUIRE([PKG_PROG_PKG_CONFIG])dnl
|
||||
if test -n "$PKG_CONFIG" && \
|
||||
AC_RUN_LOG([$PKG_CONFIG --exists --print-errors "$1"]); then
|
||||
m4_default([$2], [:])
|
||||
m4_ifvaln([$3], [else
|
||||
$3])dnl
|
||||
fi])
|
||||
|
||||
# _PKG_CONFIG([VARIABLE], [COMMAND], [MODULES])
|
||||
# ---------------------------------------------
|
||||
m4_define([_PKG_CONFIG],
|
||||
[if test -n "$$1"; then
|
||||
pkg_cv_[]$1="$$1"
|
||||
elif test -n "$PKG_CONFIG"; then
|
||||
PKG_CHECK_EXISTS([$3],
|
||||
[pkg_cv_[]$1=`$PKG_CONFIG --[]$2 "$3" 2>/dev/null`
|
||||
test "x$?" != "x0" && pkg_failed=yes ],
|
||||
[pkg_failed=yes])
|
||||
else
|
||||
pkg_failed=untried
|
||||
fi[]dnl
|
||||
])# _PKG_CONFIG
|
||||
|
||||
# _PKG_SHORT_ERRORS_SUPPORTED
|
||||
# -----------------------------
|
||||
AC_DEFUN([_PKG_SHORT_ERRORS_SUPPORTED],
|
||||
[AC_REQUIRE([PKG_PROG_PKG_CONFIG])
|
||||
if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then
|
||||
_pkg_short_errors_supported=yes
|
||||
else
|
||||
_pkg_short_errors_supported=no
|
||||
fi[]dnl
|
||||
])# _PKG_SHORT_ERRORS_SUPPORTED
|
||||
|
||||
|
||||
# PKG_CHECK_MODULES(VARIABLE-PREFIX, MODULES, [ACTION-IF-FOUND],
|
||||
# [ACTION-IF-NOT-FOUND])
|
||||
#
|
||||
#
|
||||
# Note that if there is a possibility the first call to
|
||||
# PKG_CHECK_MODULES might not happen, you should be sure to include an
|
||||
# explicit call to PKG_PROG_PKG_CONFIG in your configure.ac
|
||||
#
|
||||
#
|
||||
# --------------------------------------------------------------
|
||||
AC_DEFUN([PKG_CHECK_MODULES],
|
||||
[AC_REQUIRE([PKG_PROG_PKG_CONFIG])dnl
|
||||
AC_ARG_VAR([$1][_CFLAGS], [C compiler flags for $1, overriding pkg-config])dnl
|
||||
AC_ARG_VAR([$1][_LIBS], [linker flags for $1, overriding pkg-config])dnl
|
||||
|
||||
pkg_failed=no
|
||||
AC_MSG_CHECKING([for $1])
|
||||
|
||||
_PKG_CONFIG([$1][_CFLAGS], [cflags], [$2])
|
||||
_PKG_CONFIG([$1][_LIBS], [libs], [$2])
|
||||
|
||||
m4_define([_PKG_TEXT], [Alternatively, you may set the environment variables $1[]_CFLAGS
|
||||
and $1[]_LIBS to avoid the need to call pkg-config.
|
||||
See the pkg-config man page for more details.])
|
||||
|
||||
if test $pkg_failed = yes; then
|
||||
AC_MSG_RESULT([no])
|
||||
_PKG_SHORT_ERRORS_SUPPORTED
|
||||
if test $_pkg_short_errors_supported = yes; then
|
||||
$1[]_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors --cflags --libs "$2" 2>&1`
|
||||
else
|
||||
$1[]_PKG_ERRORS=`$PKG_CONFIG --print-errors --cflags --libs "$2" 2>&1`
|
||||
fi
|
||||
# Put the nasty error message in config.log where it belongs
|
||||
echo "$$1[]_PKG_ERRORS" >&AS_MESSAGE_LOG_FD
|
||||
|
||||
m4_default([$4], [AC_MSG_ERROR(
|
||||
[Package requirements ($2) were not met:
|
||||
|
||||
$$1_PKG_ERRORS
|
||||
|
||||
Consider adjusting the PKG_CONFIG_PATH environment variable if you
|
||||
installed software in a non-standard prefix.
|
||||
|
||||
_PKG_TEXT])[]dnl
|
||||
])
|
||||
elif test $pkg_failed = untried; then
|
||||
AC_MSG_RESULT([no])
|
||||
m4_default([$4], [AC_MSG_FAILURE(
|
||||
[The pkg-config script could not be found or is too old. Make sure it
|
||||
is in your PATH or set the PKG_CONFIG environment variable to the full
|
||||
path to pkg-config.
|
||||
|
||||
_PKG_TEXT
|
||||
|
||||
To get pkg-config, see <http://pkg-config.freedesktop.org/>.])[]dnl
|
||||
])
|
||||
else
|
||||
$1[]_CFLAGS=$pkg_cv_[]$1[]_CFLAGS
|
||||
$1[]_LIBS=$pkg_cv_[]$1[]_LIBS
|
||||
AC_MSG_RESULT([yes])
|
||||
$3
|
||||
fi[]dnl
|
||||
])# PKG_CHECK_MODULES
|
||||
|
||||
91
tool/tilem-src/config.h.in
Normal file
91
tool/tilem-src/config.h.in
Normal file
|
|
@ -0,0 +1,91 @@
|
|||
/* config.h.in. Generated from configure.ac by autoheader. */
|
||||
|
||||
/* Define if building universal (internal helper macro) */
|
||||
#undef AC_APPLE_UNIVERSAL_BUILD
|
||||
|
||||
/* Define to 1 if you have the <inttypes.h> header file. */
|
||||
#undef HAVE_INTTYPES_H
|
||||
|
||||
/* Define to 1 if you have the <memory.h> header file. */
|
||||
#undef HAVE_MEMORY_H
|
||||
|
||||
/* Define to 1 if you have the <stdint.h> header file. */
|
||||
#undef HAVE_STDINT_H
|
||||
|
||||
/* Define to 1 if you have the <stdlib.h> header file. */
|
||||
#undef HAVE_STDLIB_H
|
||||
|
||||
/* Define to 1 if you have the <strings.h> header file. */
|
||||
#undef HAVE_STRINGS_H
|
||||
|
||||
/* Define to 1 if you have the <string.h> header file. */
|
||||
#undef HAVE_STRING_H
|
||||
|
||||
/* Define to 1 if you have the <sys/stat.h> header file. */
|
||||
#undef HAVE_SYS_STAT_H
|
||||
|
||||
/* Define to 1 if you have the <sys/types.h> header file. */
|
||||
#undef HAVE_SYS_TYPES_H
|
||||
|
||||
/* Define to 1 if the system has the type `uintptr_t'. */
|
||||
#undef HAVE_UINTPTR_T
|
||||
|
||||
/* Define to 1 if you have the <unistd.h> header file. */
|
||||
#undef HAVE_UNISTD_H
|
||||
|
||||
/* Define to the address where bug reports for this package should be sent. */
|
||||
#undef PACKAGE_BUGREPORT
|
||||
|
||||
/* Define to the full name of this package. */
|
||||
#undef PACKAGE_NAME
|
||||
|
||||
/* Define to the full name and version of this package. */
|
||||
#undef PACKAGE_STRING
|
||||
|
||||
/* Define to the one symbol short name of this package. */
|
||||
#undef PACKAGE_TARNAME
|
||||
|
||||
/* Define to the home page for this package. */
|
||||
#undef PACKAGE_URL
|
||||
|
||||
/* Define to the version of this package. */
|
||||
#undef PACKAGE_VERSION
|
||||
|
||||
/* Define to 1 if you have the ANSI C header files. */
|
||||
#undef STDC_HEADERS
|
||||
|
||||
/* Define WORDS_BIGENDIAN to 1 if your processor stores words with the most
|
||||
significant byte first (like Motorola and SPARC, unlike Intel). */
|
||||
#if defined AC_APPLE_UNIVERSAL_BUILD
|
||||
# if defined __BIG_ENDIAN__
|
||||
# define WORDS_BIGENDIAN 1
|
||||
# endif
|
||||
#else
|
||||
# ifndef WORDS_BIGENDIAN
|
||||
# undef WORDS_BIGENDIAN
|
||||
# endif
|
||||
#endif
|
||||
|
||||
/* Define to `__inline__' or `__inline' if that's what the C compiler
|
||||
calls it, or to nothing if 'inline' is not supported under any name. */
|
||||
#ifndef __cplusplus
|
||||
#undef inline
|
||||
#endif
|
||||
|
||||
/* Define to the equivalent of the C99 'restrict' keyword, or to
|
||||
nothing if this is not supported. Do not define if restrict is
|
||||
supported directly. */
|
||||
#undef restrict
|
||||
/* Work around a bug in Sun C++: it does not support _Restrict or
|
||||
__restrict__, even though the corresponding Sun C compiler ends up with
|
||||
"#define restrict _Restrict" or "#define restrict __restrict__" in the
|
||||
previous line. Perhaps some future version of Sun C++ will work with
|
||||
restrict; if so, hopefully it defines __RESTRICT like Sun C does. */
|
||||
#if defined __SUNPRO_CC && !defined __RESTRICT
|
||||
# define _Restrict
|
||||
# define __restrict__
|
||||
#endif
|
||||
|
||||
/* Define to the type of an unsigned integer type wide enough to hold a
|
||||
pointer, if such a type exists, and if the system does not define it. */
|
||||
#undef uintptr_t
|
||||
6127
tool/tilem-src/configure
vendored
Executable file
6127
tool/tilem-src/configure
vendored
Executable file
File diff suppressed because it is too large
Load Diff
172
tool/tilem-src/configure.ac
Normal file
172
tool/tilem-src/configure.ac
Normal file
|
|
@ -0,0 +1,172 @@
|
|||
AC_PREREQ(2.67)
|
||||
AC_INIT([TilEm], [2.0], [tilem-devel@lists.sourceforge.net],
|
||||
[tilem], [http://tilem.sourceforge.net/])
|
||||
AC_CONFIG_SRCDIR([emu/tilem.h])
|
||||
|
||||
# Checks for programs
|
||||
|
||||
AC_PROG_CC
|
||||
AC_PROG_CPP
|
||||
AC_ARG_VAR(OPT_CFLAGS,
|
||||
[Additional C compiler flags used for optimizing critical areas of
|
||||
the code (default: -O3 if using GCC)])
|
||||
if test "x$GCC" = "xyes" ; then
|
||||
CFLAGS="$CFLAGS -W -Wall -Wwrite-strings"
|
||||
if test "x$OPT_CFLAGS" = "x" ; then
|
||||
OPT_CFLAGS="-O3"
|
||||
fi
|
||||
fi
|
||||
|
||||
AC_CHECK_TOOL(AR, [ar], [false])
|
||||
AC_ARG_VAR(AR, [Static library archiver])
|
||||
AC_ARG_VAR(AR_FLAGS, [Flags to pass to ar to build a static library])
|
||||
if test "x$AR_FLAGS" = "x" ; then
|
||||
AR_FLAGS=cru
|
||||
fi
|
||||
|
||||
AC_PROG_RANLIB
|
||||
AC_ARG_VAR(RANLIB, [Program to make a static library linkable])
|
||||
|
||||
AC_PROG_INSTALL
|
||||
AC_PROG_MAKE_SET
|
||||
|
||||
AC_CHECK_PROG([UPDATE_DESKTOP_DATABASE],
|
||||
[update-desktop-database], [update-desktop-database], [:])
|
||||
AC_CHECK_PROG([UPDATE_MIME_DATABASE],
|
||||
[update-mime-database], [update-mime-database], [:])
|
||||
|
||||
# Checks for libraries
|
||||
|
||||
m4_define(with_flags, [
|
||||
save_cflags="$CFLAGS"
|
||||
save_libs="$LIBS"
|
||||
CFLAGS="$CFLAGS $$1_CFLAGS"
|
||||
LIBS="$LIBS $$1_LIBS"
|
||||
$2
|
||||
CFLAGS="$save_cflags"
|
||||
LIBS="$save_libs"
|
||||
])
|
||||
|
||||
# GLib and GTK+
|
||||
|
||||
PKG_CHECK_MODULES(GTK, gtk+-2.0 >= 2.6.0
|
||||
glib-2.0 >= 2.12.0
|
||||
gthread-2.0)
|
||||
|
||||
AC_ARG_ENABLE([gtk-deprecated],
|
||||
AS_HELP_STRING([--disable-gtk-deprecated], [Disable deprecated GTK+ API]),
|
||||
[ enable_gtk_deprecated=$enableval ], [ enable_gtk_deprecated=yes ])
|
||||
if test "x$enable_gtk_deprecated" = "xno" ; then
|
||||
GTK_CFLAGS="$GTK_CFLAGS -DG_DISABLE_DEPRECATED -DGTK_DISABLE_DEPRECATED -DGDK_DISABLE_DEPRECATED -DGSEAL_ENABLE"
|
||||
fi
|
||||
|
||||
# If using the native Windows version of GTK+, be sure to use
|
||||
# -mms-bitfields for all compilation. Also, use -mwindows for linking
|
||||
# GUI programs.
|
||||
|
||||
# (If not using pkg-config, you're on your own)
|
||||
|
||||
if test "x$PKG_CONFIG" != "x" ; then
|
||||
gtk_target=`$PKG_CONFIG --variable=target gtk+-2.0`
|
||||
fi
|
||||
|
||||
if test "x$gtk_target" = "xwin32" && test "x$GCC" = "xyes" ; then
|
||||
CFLAGS="$CFLAGS -mms-bitfields"
|
||||
GUI_LDFLAGS="-mwindows"
|
||||
LIBS="-lcomdlg32 -lshell32 -lole32 $LIBS"
|
||||
gui_extra_objects="tilem2rc.o"
|
||||
else
|
||||
GUI_LDFLAGS=""
|
||||
gui_extra_objects=""
|
||||
fi
|
||||
|
||||
AC_SUBST(GUI_LDFLAGS)
|
||||
AC_SUBST(gui_extra_objects)
|
||||
|
||||
with_flags(GTK,
|
||||
[ AC_CHECK_FUNC(gtk_init, [ have_gtk=yes ], [ have_gtk=no ]) ])
|
||||
if test "x$have_gtk" != "xyes" ; then
|
||||
AC_MSG_ERROR([GTK+ 2.x libraries not found or not usable.
|
||||
You must install a recent version of GTK+ 2.x, including the
|
||||
-dev/-devel packages if appropriate.])
|
||||
fi
|
||||
|
||||
# Libticalcs2 and related libraries
|
||||
|
||||
PKG_CHECK_MODULES(TICALCS, ticalcs2 ticables2 tifiles2 ticonv,
|
||||
[ have_ticalcs=maybe ], [ have_ticalcs=no ])
|
||||
|
||||
if test "x$have_ticalcs" = "xmaybe" ; then
|
||||
with_flags(TICALCS,
|
||||
[ AC_CHECK_FUNC(ticalcs_library_init, [ have_ticalcs=yes ], [ have_ticalcs=no ]) ])
|
||||
fi
|
||||
|
||||
if test "x$have_ticalcs" != "xyes" ; then
|
||||
AC_MSG_ERROR([libticalcs2 not found or not usable.
|
||||
|
||||
$TICALCS_PKG_ERRORS
|
||||
|
||||
You must install libticalcs2, libticables2, libtifiles2, and libticonv
|
||||
(including the -dev/-devel packages if appropriate.) These libraries
|
||||
are available from <http://lpg.ticalc.org/prj_tilp/>.
|
||||
|
||||
If you have installed the libraries in a non-standard location (or if
|
||||
you're cross-compiling), you will need to add the location of
|
||||
ticalcs2.pc to your PKG_CONFIG_PATH environment variable, or set the
|
||||
TICALCS_CFLAGS and TICALCS_LIBS environment variables by hand.])
|
||||
fi
|
||||
|
||||
# Tools used for building the Windows installer
|
||||
|
||||
if test "x$gtk_target" = "xwin32" ; then
|
||||
AC_CHECK_TOOL([STRIP], [strip], [:])
|
||||
AC_CHECK_TOOL([OBJDUMP], [objdump], [objdump])
|
||||
AC_CHECK_TOOL([WINDRES], [windres], [windres])
|
||||
AC_CHECK_PROG([MAKENSIS], [makensis], [makensis])
|
||||
AC_PROG_LN_S
|
||||
|
||||
AC_MSG_CHECKING([where to find GTK+ runtime libraries])
|
||||
if test "x$GTK_BINDIR" = "x" ; then
|
||||
prefix=`$PKG_CONFIG --variable=exec_prefix gtk+-2.0`
|
||||
test "x$prefix" != "x" && GTK_BINDIR="$prefix/bin"
|
||||
fi
|
||||
AC_MSG_RESULT([$GTK_BINDIR])
|
||||
|
||||
AC_MSG_CHECKING([where to find ticalcs2 runtime libraries])
|
||||
if test "x$TICALCS_BINDIR" = "x" ; then
|
||||
prefix=`$PKG_CONFIG --variable=exec_prefix ticalcs2`
|
||||
test "x$prefix" != "x" && TICALCS_BINDIR="$prefix/bin"
|
||||
fi
|
||||
AC_MSG_RESULT([$TICALCS_BINDIR])
|
||||
|
||||
if test "x$DLLPATH" = "x" ; then
|
||||
DLLPATH='${GTK_BINDIR}'$PATH_SEPARATOR'${TICALCS_BINDIR}'
|
||||
fi
|
||||
AC_SUBST(GTK_BINDIR)
|
||||
AC_SUBST(TICALCS_BINDIR)
|
||||
AC_SUBST(DLLPATH)
|
||||
fi
|
||||
|
||||
# Checks for header files
|
||||
|
||||
AC_HEADER_STDC
|
||||
|
||||
# Checks for system and compiler characteristics
|
||||
|
||||
AC_C_BIGENDIAN
|
||||
AC_C_INLINE
|
||||
AC_C_RESTRICT
|
||||
AC_TYPE_UINTPTR_T
|
||||
|
||||
# Output
|
||||
|
||||
AC_CONFIG_HEADERS([config.h])
|
||||
AC_CONFIG_FILES([Makefile
|
||||
emu/Makefile
|
||||
db/Makefile
|
||||
data/Makefile
|
||||
gui/Makefile
|
||||
gui/tilem2.rc
|
||||
installer/win32/Makefile
|
||||
installer/win32/installer.nsi])
|
||||
AC_OUTPUT
|
||||
114
tool/tilem-src/data/Makefile.in
Normal file
114
tool/tilem-src/data/Makefile.in
Normal file
|
|
@ -0,0 +1,114 @@
|
|||
prefix = @prefix@
|
||||
exec_prefix = @exec_prefix@
|
||||
datarootdir = @datarootdir@
|
||||
bindir = @bindir@
|
||||
datadir = @datadir@
|
||||
pkgdatadir = @datadir@/tilem2
|
||||
mandir = @mandir@
|
||||
icondir = @datadir@/icons
|
||||
applicationsdir = @datadir@/applications
|
||||
mimedir = @datadir@/mime
|
||||
|
||||
top_builddir = @top_builddir@
|
||||
top_srcdir = @top_srcdir@
|
||||
srcdir = @srcdir@
|
||||
VPATH = @srcdir@
|
||||
@SET_MAKE@
|
||||
|
||||
INSTALL = @INSTALL@
|
||||
INSTALL_DATA = @INSTALL_DATA@
|
||||
SHELL = @SHELL@
|
||||
UPDATE_DESKTOP_DATABASE = @UPDATE_DESKTOP_DATABASE@
|
||||
UPDATE_MIME_DATABASE = @UPDATE_MIME_DATABASE@
|
||||
|
||||