mirror of
https://git.zap.org.au/git/trader.git
synced 2025-02-02 15:08:13 -05:00
Completely rewrite the scramble() and unscramble() functions
The file output is now completely in ASCII---and will be much harder to break for casual cheating!
This commit is contained in:
parent
3d20e0b307
commit
9cb3a46693
100
src/fileio.c
100
src/fileio.c
@ -32,32 +32,22 @@
|
||||
|
||||
|
||||
/************************************************************************
|
||||
* Module-specific constants and macros *
|
||||
* Module-specific macros *
|
||||
************************************************************************/
|
||||
|
||||
// Game loading and saving constants
|
||||
|
||||
static const unsigned char game_file_crypt_key[] = {
|
||||
0x50, 0x52, 0x55, 0x59, 0x5A, 0x5C, 0x5F,
|
||||
0x90, 0x92, 0x95, 0x99, 0x9A, 0x9C, 0x9F,
|
||||
0xA0, 0xA2, 0xA5, 0xA9, 0xAA, 0xAC, 0xAF,
|
||||
0xD0, 0xD2, 0xD5, 0xD9, 0xDA, 0xDC, 0xDF
|
||||
};
|
||||
|
||||
#define GAME_FILE_CRYPT_KEY_SIZE (sizeof(game_file_crypt_key) / sizeof(game_file_crypt_key[0]))
|
||||
|
||||
|
||||
// Macros used in load_game()
|
||||
|
||||
#define load_game_scanf(_fmt, _var, _cond) \
|
||||
do { \
|
||||
if (fgets(bigbuf, BIGBUFSIZE, file) == NULL) { \
|
||||
if (fgets(inbuf, BIGBUFSIZE, file) == NULL) { \
|
||||
err_exit(_("%s: missing field on line %d"), \
|
||||
filename, lineno); \
|
||||
} \
|
||||
if (sscanf(unscramble(&crypt_key, bigbuf, BIGBUFSIZE, \
|
||||
buf, BUFSIZE), _fmt "\n", &(_var)) \
|
||||
!= 1) { \
|
||||
if (unscramble(buf, inbuf, BUFSIZE, crypt_key_p) == NULL) { \
|
||||
err_exit(_("%s: illegal field on line %d"), \
|
||||
filename, lineno); \
|
||||
} \
|
||||
if (sscanf(buf, _fmt "\n", &(_var)) != 1) { \
|
||||
err_exit(_("%s: illegal field on line %d: `%s'"), \
|
||||
filename, lineno, buf); \
|
||||
} \
|
||||
@ -89,12 +79,15 @@ static const unsigned char game_file_crypt_key[] = {
|
||||
char *s; \
|
||||
int len; \
|
||||
\
|
||||
if (fgets(bigbuf, BIGBUFSIZE, file) == NULL) { \
|
||||
if (fgets(inbuf, BIGBUFSIZE, file) == NULL) { \
|
||||
err_exit(_("%s: missing field on line %d"), \
|
||||
filename, lineno); \
|
||||
} \
|
||||
if (strlen(unscramble(&crypt_key, bigbuf, BIGBUFSIZE, \
|
||||
buf, BUFSIZE)) == 0) { \
|
||||
if (unscramble(buf, inbuf, BUFSIZE, crypt_key_p) == NULL) { \
|
||||
err_exit(_("%s: illegal field on line %d"), \
|
||||
filename, lineno); \
|
||||
} \
|
||||
if (strlen(buf) == 0) { \
|
||||
err_exit(_("%s: illegal value on line %d"), \
|
||||
filename, lineno); \
|
||||
} \
|
||||
@ -129,12 +122,15 @@ static const unsigned char game_file_crypt_key[] = {
|
||||
char *s; \
|
||||
int len; \
|
||||
\
|
||||
if (fgets(bigbuf, BIGBUFSIZE, file) == NULL) { \
|
||||
if (fgets(inbuf, BIGBUFSIZE, file) == NULL) { \
|
||||
err_exit(_("%s: missing field on line %d"), \
|
||||
filename, lineno); \
|
||||
} \
|
||||
if (strlen(unscramble(&crypt_key, bigbuf, BIGBUFSIZE, \
|
||||
buf, BUFSIZE)) == 0) { \
|
||||
if (unscramble(buf, inbuf, BUFSIZE, crypt_key_p) == NULL) { \
|
||||
err_exit(_("%s: illegal field on line %d"), \
|
||||
filename, lineno); \
|
||||
} \
|
||||
if (strlen(buf) == 0) { \
|
||||
err_exit(_("%s: illegal value on line %d"), \
|
||||
filename, lineno); \
|
||||
} \
|
||||
@ -160,8 +156,8 @@ static const unsigned char game_file_crypt_key[] = {
|
||||
#define save_game_printf(_fmt, _var) \
|
||||
do { \
|
||||
snprintf(buf, BUFSIZE, _fmt "\n", _var); \
|
||||
scramble(&crypt_key, buf, BUFSIZE, bigbuf, BIGBUFSIZE); \
|
||||
fprintf(file, "%s", bigbuf); \
|
||||
scramble(encbuf, buf, BIGBUFSIZE, crypt_key_p); \
|
||||
fprintf(file, "%s", encbuf); \
|
||||
} while (0)
|
||||
|
||||
#define save_game_write_int(_var) \
|
||||
@ -227,11 +223,12 @@ bool load_game (int num)
|
||||
int saved_errno, lineno;
|
||||
char *prev_locale;
|
||||
|
||||
char *buf, *bigbuf;
|
||||
char *buf, *inbuf;
|
||||
wchar_t *wcbuf;
|
||||
|
||||
unsigned char crypt_key;
|
||||
int crypt_key_input;
|
||||
unsigned int crypt_key;
|
||||
unsigned int *crypt_key_p;
|
||||
int is_encrypted_input;
|
||||
int n, i, j;
|
||||
|
||||
#ifdef USE_UTF8_GAME_FILE
|
||||
@ -243,7 +240,7 @@ bool load_game (int num)
|
||||
assert(num >= 1 && num <= 9);
|
||||
|
||||
buf = xmalloc(BUFSIZE);
|
||||
bigbuf = xmalloc(BIGBUFSIZE);
|
||||
inbuf = xmalloc(BIGBUFSIZE);
|
||||
wcbuf = xmalloc(BUFSIZE * sizeof(wchar_t));
|
||||
|
||||
filename = game_filename(num);
|
||||
@ -272,7 +269,7 @@ bool load_game (int num)
|
||||
}
|
||||
|
||||
free(buf);
|
||||
free(bigbuf);
|
||||
free(inbuf);
|
||||
free(wcbuf);
|
||||
free(filename);
|
||||
return false;
|
||||
@ -341,13 +338,15 @@ bool load_game (int num)
|
||||
|
||||
lineno = 4;
|
||||
|
||||
// Read in the game file encryption key
|
||||
if (fscanf(file, "%i\n", &crypt_key_input) != 1) {
|
||||
// Read in the game file encryption status
|
||||
if (fscanf(file, "%i\n", &is_encrypted_input) != 1) {
|
||||
err_exit(_("%s: illegal or missing field on line %d"), filename, lineno);
|
||||
}
|
||||
crypt_key = (unsigned char) crypt_key_input;
|
||||
lineno++;
|
||||
|
||||
crypt_key = 0;
|
||||
crypt_key_p = is_encrypted_input ? &crypt_key : NULL;
|
||||
|
||||
// Read in various game variables
|
||||
load_game_read_int(n, n == MAX_X);
|
||||
load_game_read_int(n, n == MAX_Y);
|
||||
@ -384,11 +383,13 @@ bool load_game (int num)
|
||||
|
||||
// Read in galaxy map
|
||||
for (int x = 0; x < MAX_X; x++) {
|
||||
if (fgets(bigbuf, BIGBUFSIZE, file) == NULL) {
|
||||
if (fgets(inbuf, BIGBUFSIZE, file) == NULL) {
|
||||
err_exit(_("%s: missing field on line %d"), filename, lineno);
|
||||
}
|
||||
if (strlen(unscramble(&crypt_key, bigbuf, BIGBUFSIZE, buf, BUFSIZE))
|
||||
!= MAX_Y + 1) {
|
||||
if (unscramble(buf, inbuf, BUFSIZE, crypt_key_p) == NULL) {
|
||||
err_exit(_("%s: illegal field on line %d"), filename, lineno);
|
||||
}
|
||||
if (strlen(buf) != MAX_Y + 1) {
|
||||
err_exit(_("%s: illegal field on line %d"), filename, lineno);
|
||||
}
|
||||
|
||||
@ -422,7 +423,7 @@ bool load_game (int num)
|
||||
#endif
|
||||
|
||||
free(buf);
|
||||
free(bigbuf);
|
||||
free(inbuf);
|
||||
free(wcbuf);
|
||||
free(filename);
|
||||
free(prev_locale);
|
||||
@ -437,15 +438,16 @@ bool load_game (int num)
|
||||
bool save_game (int num)
|
||||
{
|
||||
const char *data_dir;
|
||||
char *buf, *bigbuf;
|
||||
char *buf, *encbuf;
|
||||
char *filename;
|
||||
FILE *file;
|
||||
char *codeset;
|
||||
int saved_errno;
|
||||
char *prev_locale;
|
||||
struct stat statbuf;
|
||||
unsigned char crypt_key;
|
||||
int i, j, x, y;
|
||||
unsigned int crypt_key;
|
||||
unsigned int *crypt_key_p;
|
||||
|
||||
#ifdef USE_UTF8_GAME_FILE
|
||||
iconv_t icd;
|
||||
@ -456,10 +458,10 @@ bool save_game (int num)
|
||||
assert(num >= 1 && num <= 9);
|
||||
|
||||
buf = xmalloc(BUFSIZE);
|
||||
bigbuf = xmalloc(BIGBUFSIZE);
|
||||
encbuf = xmalloc(BIGBUFSIZE);
|
||||
|
||||
crypt_key = option_dont_encrypt ? 0 :
|
||||
game_file_crypt_key[randi(GAME_FILE_CRYPT_KEY_SIZE)];
|
||||
crypt_key = 0;
|
||||
crypt_key_p = option_dont_encrypt ? NULL : &crypt_key;
|
||||
|
||||
// Create the data directory, if needed
|
||||
data_dir = data_directory();
|
||||
@ -480,7 +482,7 @@ bool save_game (int num)
|
||||
strerror(saved_errno));
|
||||
|
||||
free(buf);
|
||||
free(bigbuf);
|
||||
free(encbuf);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@ -501,7 +503,7 @@ bool save_game (int num)
|
||||
"^{File %s: %s^}"), num, filename, strerror(saved_errno));
|
||||
|
||||
free(buf);
|
||||
free(bigbuf);
|
||||
free(encbuf);
|
||||
free(filename);
|
||||
return false;
|
||||
}
|
||||
@ -534,9 +536,9 @@ bool save_game (int num)
|
||||
prev_locale = xstrdup(setlocale(LC_NUMERIC, NULL));
|
||||
setlocale(LC_NUMERIC, "C");
|
||||
|
||||
// Write out the game file header and encryption key
|
||||
// Write out the game file header and encryption status
|
||||
fprintf(file, "%s\n" "%s\n", GAME_FILE_HEADER, GAME_FILE_API_VERSION);
|
||||
fprintf(file, "%s\n" "%d\n", codeset, crypt_key);
|
||||
fprintf(file, "%s\n" "%d\n", codeset, ! option_dont_encrypt);
|
||||
|
||||
// Write out various game variables
|
||||
save_game_write_int(MAX_X);
|
||||
@ -581,8 +583,8 @@ bool save_game (int num)
|
||||
*p++ = '\n';
|
||||
*p = '\0';
|
||||
|
||||
scramble(&crypt_key, buf, BUFSIZE, bigbuf, BIGBUFSIZE);
|
||||
fprintf(file, "%s", bigbuf);
|
||||
scramble(encbuf, buf, BIGBUFSIZE, crypt_key_p);
|
||||
fprintf(file, "%s", encbuf);
|
||||
}
|
||||
|
||||
// Write out a dummy sentinal value
|
||||
@ -602,7 +604,7 @@ bool save_game (int num)
|
||||
#endif
|
||||
|
||||
free(buf);
|
||||
free(bigbuf);
|
||||
free(encbuf);
|
||||
free(filename);
|
||||
free(prev_locale);
|
||||
return true;
|
||||
|
@ -53,7 +53,7 @@
|
||||
************************************************************************/
|
||||
|
||||
#define GAME_FILE_HEADER "Star Traders Saved Game"
|
||||
#define GAME_FILE_API_VERSION "File API 7.2" // For game loads and saves
|
||||
#define GAME_FILE_API_VERSION "File API 7.5" // For game loads and saves
|
||||
#define GAME_FILE_SENTINEL 42 // End of game file sentinel
|
||||
|
||||
#ifdef USE_UTF8_GAME_FILE
|
||||
@ -62,7 +62,7 @@
|
||||
#endif
|
||||
|
||||
#define BUFSIZE 1024 // For various string buffers
|
||||
#define BIGBUFSIZE 4096 // For buffers known to be larger
|
||||
#define BIGBUFSIZE 2048 // For buffers known to be larger
|
||||
|
||||
|
||||
#endif /* included_TRADER_H */
|
||||
|
525
src/utils.c
525
src/utils.c
@ -50,7 +50,7 @@ wchar_t *mon_thousands_sep; // Local monetary thousands separator
|
||||
|
||||
|
||||
/************************************************************************
|
||||
* Module-specific constants and variable definitions *
|
||||
* Module-specific constants and macros *
|
||||
************************************************************************/
|
||||
|
||||
#define GAME_FILENAME_PROTO "game%d"
|
||||
@ -63,25 +63,120 @@ wchar_t *mon_thousands_sep; // Local monetary thousands separator
|
||||
#define MOD_POSIX_P_SEP_BY_SPACE 0
|
||||
|
||||
// Constants used for scrambling and unscrambling game data
|
||||
#define SCRAMBLE_PAD_CHAR '.'
|
||||
#define UNSCRAMBLE_INVALID (-1)
|
||||
#define UNSCRAMBLE_PAD_CHAR (-2)
|
||||
#define SCRAMBLE_CRC_LEN 8 // Length of CRC in ASCII (excl NUL)
|
||||
#define SCRAMBLE_CHKSUM_LEN 3 // For checksum, excluding NUL byte
|
||||
#define SCRAMBLE_CRC_MASK 0xFFFFFFFF // Bits of CRC to keep
|
||||
#define SCRAMBLE_CHKSUM_MASK 0x0FFF // Bits of checksum to keep
|
||||
|
||||
static const char scramble_index[] =
|
||||
#define SCRAMBLE_PAD_CHAR '*'
|
||||
#define SCRAMBLE_IGNORE_CHAR '~'
|
||||
#define UNSCRAMBLE_INVALID (-1)
|
||||
#define UNSCRAMBLE_IGNORE (-2)
|
||||
#define UNSCRAMBLE_PAD_CHAR (-3)
|
||||
|
||||
static const char scramble_table[] =
|
||||
"0123456789AaBbCcDdEeFfGgHhIiJjKkLlMmNnOoPpQqRrSsTtUuVvWwXxYyZz-_";
|
||||
|
||||
static const char unscramble_index[] = {
|
||||
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
||||
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
||||
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 62, -2, -1,
|
||||
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, -1, -1, -1, -1, -1, -1,
|
||||
-1, 10, 12, 14, 16, 18, 20, 22, 24, 26, 28, 30, 32, 34, 36, 38,
|
||||
40, 42, 44, 46, 48, 50, 52, 54, 56, 58, 60, -1, -1, -1, -1, 63,
|
||||
-1, 11, 13, 15, 17, 19, 21, 23, 25, 27, 29, 31, 33, 35, 37, 39,
|
||||
41, 43, 45, 47, 49, 51, 53, 55, 57, 59, 61, -1, -1, -1, -1, -1
|
||||
#define _b(n) \
|
||||
((n) == '0' ? 0 : (n) == '1' ? 1 : (n) == '2' ? 2 : (n) == '3' ? 3 : \
|
||||
(n) == '4' ? 4 : (n) == '5' ? 5 : (n) == '6' ? 6 : (n) == '7' ? 7 : \
|
||||
(n) == '8' ? 8 : (n) == '9' ? 9 : (n) == 'A' ? 10 : (n) == 'a' ? 11 : \
|
||||
(n) == 'B' ? 12 : (n) == 'b' ? 13 : (n) == 'C' ? 14 : (n) == 'c' ? 15 : \
|
||||
(n) == 'D' ? 16 : (n) == 'd' ? 17 : (n) == 'E' ? 18 : (n) == 'e' ? 19 : \
|
||||
(n) == 'F' ? 20 : (n) == 'f' ? 21 : (n) == 'G' ? 22 : (n) == 'g' ? 23 : \
|
||||
(n) == 'H' ? 24 : (n) == 'h' ? 25 : (n) == 'I' ? 26 : (n) == 'i' ? 27 : \
|
||||
(n) == 'J' ? 28 : (n) == 'j' ? 29 : (n) == 'K' ? 30 : (n) == 'k' ? 31 : \
|
||||
(n) == 'L' ? 32 : (n) == 'l' ? 33 : (n) == 'M' ? 34 : (n) == 'm' ? 35 : \
|
||||
(n) == 'N' ? 36 : (n) == 'n' ? 37 : (n) == 'O' ? 38 : (n) == 'o' ? 39 : \
|
||||
(n) == 'P' ? 40 : (n) == 'p' ? 41 : (n) == 'Q' ? 42 : (n) == 'q' ? 43 : \
|
||||
(n) == 'R' ? 44 : (n) == 'r' ? 45 : (n) == 'S' ? 46 : (n) == 's' ? 47 : \
|
||||
(n) == 'T' ? 48 : (n) == 't' ? 49 : (n) == 'U' ? 50 : (n) == 'u' ? 51 : \
|
||||
(n) == 'V' ? 52 : (n) == 'v' ? 53 : (n) == 'W' ? 54 : (n) == 'w' ? 55 : \
|
||||
(n) == 'X' ? 56 : (n) == 'x' ? 57 : (n) == 'Y' ? 58 : (n) == 'y' ? 59 : \
|
||||
(n) == 'Z' ? 60 : (n) == 'z' ? 61 : (n) == '-' ? 62 : (n) == '_' ? 63 : \
|
||||
(n) == ' ' ? UNSCRAMBLE_IGNORE : \
|
||||
(n) == '\t' ? UNSCRAMBLE_IGNORE : \
|
||||
(n) == '\n' ? UNSCRAMBLE_IGNORE : \
|
||||
(n) == '\r' ? UNSCRAMBLE_IGNORE : \
|
||||
(n) == SCRAMBLE_IGNORE_CHAR ? UNSCRAMBLE_IGNORE : \
|
||||
(n) == SCRAMBLE_PAD_CHAR ? UNSCRAMBLE_PAD_CHAR : \
|
||||
UNSCRAMBLE_INVALID)
|
||||
|
||||
static const signed char unscramble_table[] = {
|
||||
_b(0), _b(1), _b(2), _b(3), _b(4), _b(5), _b(6), _b(7),
|
||||
_b(8), _b(9), _b(10) , _b(11), _b(12), _b(13), _b(14), _b(15),
|
||||
_b(16), _b(17), _b(18), _b(19), _b(20), _b(21), _b(22), _b(23),
|
||||
_b(24), _b(25), _b(26), _b(27), _b(28), _b(29), _b(30), _b(31),
|
||||
_b(32), _b(33), _b(34), _b(35), _b(36), _b(37), _b(38), _b(39),
|
||||
_b(40), _b(41), _b(42), _b(43), _b(44), _b(45), _b(46), _b(47),
|
||||
_b(48), _b(49), _b(50), _b(51), _b(52), _b(53), _b(54), _b(55),
|
||||
_b(56), _b(57), _b(58), _b(59), _b(60), _b(61), _b(62), _b(63),
|
||||
_b(64), _b(65), _b(66), _b(67), _b(68), _b(69), _b(70), _b(71),
|
||||
_b(72), _b(73), _b(74), _b(75), _b(76), _b(77), _b(78), _b(79),
|
||||
_b(80), _b(81), _b(82), _b(83), _b(84), _b(85), _b(86), _b(87),
|
||||
_b(88), _b(89), _b(90), _b(91), _b(92), _b(93), _b(94), _b(95),
|
||||
_b(96), _b(97), _b(98), _b(99), _b(100), _b(101), _b(102), _b(103),
|
||||
_b(104), _b(105), _b(106), _b(107), _b(108), _b(109), _b(110), _b(111),
|
||||
_b(112), _b(113), _b(114), _b(115), _b(116), _b(117), _b(118), _b(119),
|
||||
_b(120), _b(121), _b(122), _b(123), _b(124), _b(125), _b(126), _b(127),
|
||||
_b(128), _b(129), _b(130), _b(131), _b(132), _b(133), _b(134), _b(135),
|
||||
_b(136), _b(137), _b(138), _b(139), _b(140), _b(141), _b(142), _b(143),
|
||||
_b(144), _b(145), _b(146), _b(147), _b(148), _b(149), _b(150), _b(151),
|
||||
_b(152), _b(153), _b(154), _b(155), _b(156), _b(157), _b(158), _b(159),
|
||||
_b(160), _b(161), _b(162), _b(163), _b(164), _b(165), _b(166), _b(167),
|
||||
_b(168), _b(169), _b(170), _b(171), _b(172), _b(173), _b(174), _b(175),
|
||||
_b(176), _b(177), _b(178), _b(179), _b(180), _b(181), _b(182), _b(183),
|
||||
_b(184), _b(185), _b(186), _b(187), _b(188), _b(189), _b(190), _b(191),
|
||||
_b(192), _b(193), _b(194), _b(195), _b(196), _b(197), _b(198), _b(199),
|
||||
_b(200), _b(201), _b(202), _b(203), _b(204), _b(205), _b(206), _b(207),
|
||||
_b(208), _b(209), _b(210), _b(211), _b(212), _b(213), _b(214), _b(215),
|
||||
_b(216), _b(217), _b(218), _b(219), _b(220), _b(221), _b(222), _b(223),
|
||||
_b(224), _b(225), _b(226), _b(227), _b(228), _b(229), _b(230), _b(231),
|
||||
_b(232), _b(233), _b(234), _b(235), _b(236), _b(237), _b(238), _b(239),
|
||||
_b(240), _b(241), _b(242), _b(243), _b(244), _b(245), _b(246), _b(247),
|
||||
_b(248), _b(249), _b(250), _b(251), _b(252), _b(253), _b(254), _b(255)
|
||||
};
|
||||
|
||||
#define UNSCRAMBLE_INDEX_SIZE (sizeof(unscramble_index) / sizeof(unscramble_index[0]))
|
||||
#define UNSCRAMBLE_TABLE_SIZE (sizeof(unscramble_table) / sizeof(unscramble_table[0]))
|
||||
|
||||
static const unsigned char xor_table[] = {
|
||||
/* Set of bytes 0x00 to 0xFF in random order; each byte in an input
|
||||
string is XORed with successive bytes in this table. */
|
||||
0x00, 0xCE, 0xB1, 0x9F, 0xE4, 0xE0, 0xE3, 0x79,
|
||||
0xA1, 0x3B, 0x4E, 0x89, 0x81, 0x84, 0x43, 0xC8,
|
||||
0xBE, 0x0F, 0x67, 0x2A, 0xB4, 0xD8, 0xBA, 0x5D,
|
||||
0x94, 0x06, 0x69, 0x0E, 0x1C, 0x48, 0x9E, 0x0A,
|
||||
0x1D, 0x09, 0x02, 0xCD, 0xD4, 0xF6, 0x5B, 0x8A,
|
||||
0xAE, 0x65, 0xB3, 0xB5, 0xA7, 0x13, 0x03, 0xF2,
|
||||
0x42, 0xF0, 0xA6, 0xAA, 0x35, 0xCB, 0x2C, 0x55,
|
||||
0xF5, 0xC7, 0x32, 0xB7, 0x6B, 0xEA, 0xC3, 0x6F,
|
||||
0x41, 0xFF, 0xD1, 0x24, 0x54, 0xA9, 0xC6, 0xC2,
|
||||
0x74, 0xEE, 0xBC, 0x99, 0x59, 0x71, 0x3D, 0x85,
|
||||
0x0B, 0xF7, 0x3A, 0x7E, 0xDB, 0x45, 0xE8, 0x96,
|
||||
0xD0, 0xC1, 0xE6, 0xFD, 0x86, 0x8C, 0x9B, 0x0C,
|
||||
0x66, 0x5F, 0xE5, 0x14, 0x98, 0x3C, 0xBD, 0xE2,
|
||||
0x88, 0xA3, 0x30, 0x38, 0x2F, 0xA2, 0x37, 0x70,
|
||||
0xB8, 0x11, 0x61, 0x93, 0x52, 0x1B, 0xDD, 0x20,
|
||||
0x60, 0x19, 0xEF, 0xD2, 0xEC, 0x73, 0x07, 0x92,
|
||||
0x4C, 0x6A, 0xA8, 0x9D, 0x34, 0x04, 0x87, 0x2E,
|
||||
0x1E, 0xA4, 0xCA, 0x72, 0x63, 0xD7, 0x7F, 0xFB,
|
||||
0x68, 0xE1, 0xBF, 0x10, 0x8E, 0xAF, 0x9A, 0xFA,
|
||||
0xA0, 0xDE, 0x1F, 0x31, 0x15, 0x97, 0xED, 0x2B,
|
||||
0x36, 0x8D, 0x12, 0xC5, 0x23, 0x95, 0x33, 0x56,
|
||||
0x4F, 0xE7, 0xAD, 0x5C, 0x4B, 0x83, 0xDC, 0x29,
|
||||
0xE9, 0xCF, 0x8F, 0x58, 0x4D, 0x5A, 0x08, 0x49,
|
||||
0xFC, 0x6D, 0x7C, 0xB6, 0xD3, 0x7B, 0xD6, 0x53,
|
||||
0x57, 0x82, 0x0D, 0xD9, 0x7D, 0xDA, 0x4A, 0xDF,
|
||||
0x27, 0x40, 0x1A, 0x22, 0xC9, 0x51, 0x3E, 0x6C,
|
||||
0xC4, 0x18, 0xCC, 0xAC, 0xEB, 0xA5, 0xF4, 0x44,
|
||||
0xFE, 0x76, 0xF8, 0x75, 0xF3, 0x2D, 0xB0, 0xB9,
|
||||
0x9C, 0x47, 0x7A, 0x28, 0xBB, 0xF1, 0x16, 0x64,
|
||||
0x46, 0x21, 0x78, 0x90, 0xD5, 0x80, 0x3F, 0x39,
|
||||
0x25, 0xB2, 0x6E, 0x8B, 0x77, 0xC0, 0x05, 0x50,
|
||||
0x17, 0xF9, 0x01, 0x26, 0x91, 0x5E, 0x62, 0xAB
|
||||
};
|
||||
|
||||
#define XOR_TABLE_SIZE (sizeof(xor_table) / sizeof(xor_table[0]))
|
||||
|
||||
|
||||
/************************************************************************
|
||||
@ -94,6 +189,69 @@ static char *data_directory_str = NULL; // Writable data dir pathname
|
||||
static bool add_currency_symbol = false; // Do we need to add "$"?
|
||||
|
||||
|
||||
/************************************************************************
|
||||
* Module-specific function prototypes *
|
||||
************************************************************************/
|
||||
|
||||
/*
|
||||
Function: apply_xor - Scramble a buffer using xor_table
|
||||
Parameters: dest - Location of destination buffer
|
||||
src - Location of source buffer
|
||||
n - Number of bytes to scramble
|
||||
key - Pointer to xor_table index
|
||||
Returns: (nothing)
|
||||
|
||||
This function copies n bytes from *src into *dest, applying a XOR with
|
||||
the contents of xor_table in the process. It is a reversable function:
|
||||
apply_xor(apply_xor(buffer)) == buffer. It is used by both scramble()
|
||||
and unscramble().
|
||||
*/
|
||||
static void apply_xor (void *restrict dest, const void *restrict src,
|
||||
size_t n, unsigned int *restrict key);
|
||||
|
||||
|
||||
/*
|
||||
Function: b64encode - Convert a block to non-standard Base64 encoding
|
||||
Parameters: in - Location of input buffer
|
||||
inlen - Size of input buffer
|
||||
out - Location of output buffer
|
||||
outlen - Size of output buffer
|
||||
Returns: size_t - Number of bytes placed in output buffer
|
||||
|
||||
This function encodes inlen bytes in the input buffer into the output
|
||||
buffer using a non-standard Base64 encoding (as contained above in
|
||||
scramble_table[]). The resulting encoded string length is returned
|
||||
(including trailing '\n' but NOT including trailing NUL).
|
||||
|
||||
Note that the output buffer must be at least 4/3 the size of the input
|
||||
buffer; if not, an assert is generated.
|
||||
|
||||
This function is used by scramble().
|
||||
*/
|
||||
static size_t b64encode (const void *restrict in, size_t inlen,
|
||||
void *restrict out, size_t outlen);
|
||||
|
||||
|
||||
/*
|
||||
Function: b64decode - Convert a block from non-standard Base64 encoding
|
||||
Parameters: in - Location of input buffer
|
||||
inlen - Size of input buffer
|
||||
out - Location of output buffer
|
||||
outlen - Size of output buffer
|
||||
Returns: ssize_t - Number of bytes placed in output buffer, or -1
|
||||
|
||||
This function decodes up to inlen bytes in the input buffer into the
|
||||
output buffer using a non-standard Base64 encoding (as contained above
|
||||
in unscramble_table[]). The resulting decoded buffer length is
|
||||
returned; that buffer may contain NUL bytes. If an error occurs during
|
||||
decoding, -1 is returned instead.
|
||||
|
||||
This function is used by unscramble().
|
||||
*/
|
||||
static ssize_t b64decode (const void *restrict in, size_t inlen,
|
||||
void *restrict out, size_t outlen);
|
||||
|
||||
|
||||
/************************************************************************
|
||||
* Initialisation and environment function definitions *
|
||||
************************************************************************/
|
||||
@ -436,53 +594,336 @@ ssize_t l_strfmon (char *restrict buf, size_t maxsize,
|
||||
* Encryption function definitions *
|
||||
************************************************************************/
|
||||
|
||||
// These functions are documented in the file "utils.h"
|
||||
/* These functions are documented in the file "utils.h" or in the
|
||||
comments above. */
|
||||
|
||||
|
||||
/***********************************************************************/
|
||||
// scramble: Scramble (encrypt) the buffer
|
||||
|
||||
char *scramble (unsigned char *restrict key,
|
||||
char *restrict inbuf, int inbufsize,
|
||||
char *restrict outbuf, int outbufsize)
|
||||
char *scramble (char *restrict dest, const char *restrict src,
|
||||
size_t size, unsigned int *restrict key)
|
||||
{
|
||||
/* The algorithm used here is reversable: scramble(scramble(...))
|
||||
will (or, at least, should!) return the same as the original
|
||||
buffer. Problematic characters are ignored; however, this
|
||||
function assumes all other characters are permitted in files.
|
||||
This is true on all POSIX systems. */
|
||||
unsigned long int crc;
|
||||
unsigned int chksum;
|
||||
size_t srclen;
|
||||
char *xorbuf, *midxor;
|
||||
char *middest;
|
||||
char crcbuf[SCRAMBLE_CRC_LEN + 1];
|
||||
char chksumbuf[SCRAMBLE_CHKSUM_LEN + 1];
|
||||
|
||||
assert(outbuf != NULL);
|
||||
|
||||
if (inbuf != NULL && key != NULL && *key != 0) {
|
||||
char *p = inbuf;
|
||||
unsigned char k = ~*key;
|
||||
assert(dest != NULL);
|
||||
assert(src != NULL);
|
||||
assert(size > 0);
|
||||
|
||||
for (int i = 0; i < inbufsize && *p != '\0'; i++, k++, p++) {
|
||||
char c = *p;
|
||||
char r = c ^ k; // Simple encryption: XOR on a moving key
|
||||
srclen = strlen(src);
|
||||
|
||||
if (c != '\r' && c != '\n'
|
||||
&& r != '\r' && r != '\n' && r != '\0') {
|
||||
*p = r;
|
||||
}
|
||||
if (key == NULL) {
|
||||
// No encryption required
|
||||
assert(size >= srclen + 2); // Enough room to add "\n"?
|
||||
|
||||
strcpy(dest, src);
|
||||
|
||||
// Add "\n" if needed
|
||||
if (dest[srclen - 1] != '\n') {
|
||||
dest[srclen] = '\n';
|
||||
dest[srclen + 1] = '\0';
|
||||
}
|
||||
} else {
|
||||
// Scramble the input
|
||||
|
||||
xorbuf = xmalloc(srclen + SCRAMBLE_CRC_LEN + 1);
|
||||
|
||||
// Scramble src using *key, leaving room for CRC32 in front
|
||||
midxor = xorbuf + SCRAMBLE_CRC_LEN;
|
||||
apply_xor(midxor, src, srclen, key);
|
||||
|
||||
// Calculate CRC32 checksum of XORed buffer
|
||||
crc = crc32(midxor, srclen) & SCRAMBLE_CRC_MASK;
|
||||
snprintf(crcbuf, SCRAMBLE_CRC_LEN + 1, "%08lx", crc);
|
||||
memcpy(xorbuf, crcbuf, SCRAMBLE_CRC_LEN);
|
||||
|
||||
// Encode whole buffer (including CRC32) using Base64
|
||||
middest = dest + SCRAMBLE_CHKSUM_LEN;
|
||||
b64encode(xorbuf, srclen + SCRAMBLE_CRC_LEN,
|
||||
middest, size - SCRAMBLE_CHKSUM_LEN);
|
||||
|
||||
// Calculate simple checksum
|
||||
chksum = 0;
|
||||
for (char *p = middest; *p != '\0' && *p != '\n'; p++) {
|
||||
chksum += *p;
|
||||
}
|
||||
chksum &= SCRAMBLE_CHKSUM_MASK;
|
||||
|
||||
// Place checksum in front of Base64 string
|
||||
snprintf(chksumbuf, SCRAMBLE_CHKSUM_LEN + 1, "%03x", chksum);
|
||||
memcpy(dest, chksumbuf, SCRAMBLE_CHKSUM_LEN);
|
||||
|
||||
free(xorbuf);
|
||||
}
|
||||
|
||||
strcpy(outbuf, inbuf);
|
||||
|
||||
return outbuf;
|
||||
return dest;
|
||||
}
|
||||
|
||||
|
||||
/***********************************************************************/
|
||||
// unscramble: Unscramble (decrypt) the buffer
|
||||
|
||||
char *unscramble (unsigned char *restrict key,
|
||||
char *restrict inbuf, int inbufsize,
|
||||
char *restrict outbuf, int outbufsize)
|
||||
char *unscramble (char *restrict dest, const char *restrict src,
|
||||
size_t size, unsigned int *restrict key)
|
||||
{
|
||||
return scramble(key, inbuf, inbufsize, outbuf, outbufsize);
|
||||
unsigned long int crc, crc_input;
|
||||
unsigned int chksum, chksum_input;
|
||||
size_t srclen;
|
||||
char *xorbuf, *midxor;
|
||||
ssize_t xorlen;
|
||||
const char *midsrc;
|
||||
char crcbuf[SCRAMBLE_CRC_LEN + 2]; // Leave room for '\n\0'
|
||||
char chksumbuf[SCRAMBLE_CHKSUM_LEN + 2];
|
||||
|
||||
|
||||
assert(dest != NULL);
|
||||
assert(src != NULL);
|
||||
assert(size > 0);
|
||||
|
||||
srclen = strlen(src);
|
||||
|
||||
if (key == NULL) {
|
||||
// No decryption required
|
||||
assert(size >= srclen + 1);
|
||||
strcpy(dest, src);
|
||||
} else {
|
||||
// Unscramble the input
|
||||
|
||||
// Copy out simple checksum from input
|
||||
memcpy(chksumbuf, src, SCRAMBLE_CHKSUM_LEN);
|
||||
chksumbuf[SCRAMBLE_CHKSUM_LEN] = '\n';
|
||||
chksumbuf[SCRAMBLE_CHKSUM_LEN + 1] = '\0';
|
||||
if (sscanf(chksumbuf, "%x\n", &chksum_input) != 1) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// Calculate and compare checksums
|
||||
midsrc = src + SCRAMBLE_CHKSUM_LEN;
|
||||
chksum = 0;
|
||||
for (const char *p = midsrc; *p != '\0' && *p != '\n'; p++) {
|
||||
chksum += *p;
|
||||
}
|
||||
chksum &= SCRAMBLE_CHKSUM_MASK;
|
||||
|
||||
if (chksum != chksum_input) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
xorbuf = xmalloc(size + SCRAMBLE_CRC_LEN);
|
||||
|
||||
// Decode buffer sans checksum using Base64
|
||||
xorlen = b64decode(midsrc, srclen - SCRAMBLE_CHKSUM_LEN,
|
||||
xorbuf, size + SCRAMBLE_CRC_LEN);
|
||||
if (xorlen < SCRAMBLE_CRC_LEN) {
|
||||
free(xorbuf);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// Copy out CRC32 checksum
|
||||
memcpy(crcbuf, xorbuf, SCRAMBLE_CRC_LEN);
|
||||
crcbuf[SCRAMBLE_CRC_LEN] = '\n';
|
||||
crcbuf[SCRAMBLE_CRC_LEN + 1] = '\0';
|
||||
if (sscanf(crcbuf, "%lx\n", &crc_input) != 1) {
|
||||
free(xorbuf);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// Calculate and compare CRC32 checksums
|
||||
midxor = xorbuf + SCRAMBLE_CRC_LEN;
|
||||
crc = crc32(midxor, xorlen - SCRAMBLE_CRC_LEN) & SCRAMBLE_CRC_MASK;
|
||||
if (crc != crc_input) {
|
||||
free(xorbuf);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// Descramble xorbuf using *key, ignoring CRC32 in front
|
||||
apply_xor(dest, midxor, xorlen - SCRAMBLE_CRC_LEN, key);
|
||||
|
||||
// Convert the output to a C string
|
||||
assert(size >= xorlen - SCRAMBLE_CRC_LEN + 1);
|
||||
dest[xorlen - SCRAMBLE_CRC_LEN] = '\0';
|
||||
|
||||
free(xorbuf);
|
||||
}
|
||||
|
||||
return dest;
|
||||
}
|
||||
|
||||
|
||||
/***********************************************************************/
|
||||
// apply_xor: Scramble a buffer using xor_table
|
||||
|
||||
void apply_xor (void *restrict dest, const void *restrict src,
|
||||
size_t n, unsigned int *restrict key)
|
||||
{
|
||||
assert(dest != NULL);
|
||||
assert(src != NULL);
|
||||
assert(key != NULL);
|
||||
assert(*key < XOR_TABLE_SIZE);
|
||||
|
||||
for (size_t i = 0; i < n; i++, dest++, src++) {
|
||||
*(unsigned char *) dest = *(unsigned char *) src ^ xor_table[*key];
|
||||
*key = (*key + 1) % XOR_TABLE_SIZE;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/***********************************************************************/
|
||||
// b64encode: Convert a block to non-standard Base64 encoding
|
||||
|
||||
size_t b64encode (const void *restrict in, size_t inlen,
|
||||
void *restrict out, size_t outlen)
|
||||
{
|
||||
size_t count;
|
||||
size_t padding;
|
||||
|
||||
// Note that bit manipulations on strings require unsigned char!
|
||||
const unsigned char *u_in = in;
|
||||
unsigned char *u_out = out;
|
||||
|
||||
|
||||
assert(u_in != NULL);
|
||||
assert(u_out != NULL);
|
||||
assert(outlen > 0);
|
||||
assert(outlen > inlen);
|
||||
|
||||
count = 0;
|
||||
padding = inlen % 3;
|
||||
|
||||
for (size_t i = 0; i < inlen; i += 3, u_in += 3) {
|
||||
unsigned long int n;
|
||||
unsigned char n0, n1, n2, n3;
|
||||
|
||||
// Convert three input bytes into a 24-bit number
|
||||
n = u_in[0] << 16;
|
||||
if (i + 1 < inlen) {
|
||||
n += u_in[1] << 8;
|
||||
}
|
||||
if (i + 2 < inlen) {
|
||||
n += u_in[2];
|
||||
}
|
||||
|
||||
// Convert the 24-bit number into four Base64 bytes
|
||||
n0 = (unsigned char) (n >> 18) & 0x3F;
|
||||
n1 = (unsigned char) (n >> 12) & 0x3F;
|
||||
n2 = (unsigned char) (n >> 6) & 0x3F;
|
||||
n3 = (unsigned char) n & 0x3F;
|
||||
|
||||
assert(count + 3 < outlen);
|
||||
|
||||
*u_out++ = scramble_table[n0];
|
||||
*u_out++ = scramble_table[n1];
|
||||
count += 2;
|
||||
|
||||
if (i + 1 < inlen) {
|
||||
*u_out++ = scramble_table[n2];
|
||||
count++;
|
||||
}
|
||||
if (i + 2 < inlen) {
|
||||
*u_out++ = scramble_table[n3];
|
||||
count++;
|
||||
}
|
||||
}
|
||||
|
||||
if (padding > 0) {
|
||||
assert(count + 2 < outlen);
|
||||
for (; padding < 3; padding++) {
|
||||
*u_out++ = SCRAMBLE_PAD_CHAR;
|
||||
count++;
|
||||
}
|
||||
}
|
||||
|
||||
assert(count + 2 <= outlen);
|
||||
|
||||
*u_out++ = '\n';
|
||||
*u_out = '\0';
|
||||
count++;
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
|
||||
/***********************************************************************/
|
||||
// b64decode: Convert a block from non-standard Base64 encoding
|
||||
|
||||
ssize_t b64decode (const void *restrict in, size_t inlen,
|
||||
void *restrict out, size_t outlen)
|
||||
{
|
||||
size_t count;
|
||||
unsigned long int n;
|
||||
|
||||
// Note that bit manipulations on strings require unsigned char!
|
||||
// Using char * results in very subtle bugs indeed...
|
||||
const unsigned char *u_in = in;
|
||||
unsigned char *u_out = out;
|
||||
|
||||
|
||||
assert(u_in != NULL);
|
||||
assert(u_out != NULL);
|
||||
assert(outlen > 0);
|
||||
|
||||
count = 0;
|
||||
n = 1;
|
||||
|
||||
for (size_t i = 0; i < inlen && *u_in != '\0'; i++, u_in++) {
|
||||
char c = *u_in > UNSCRAMBLE_TABLE_SIZE ?
|
||||
UNSCRAMBLE_INVALID : unscramble_table[*u_in];
|
||||
|
||||
switch (c) {
|
||||
case UNSCRAMBLE_INVALID:
|
||||
return -1;
|
||||
|
||||
case UNSCRAMBLE_IGNORE:
|
||||
continue;
|
||||
|
||||
case UNSCRAMBLE_PAD_CHAR:
|
||||
// Assume end of data
|
||||
i = inlen;
|
||||
continue;
|
||||
|
||||
default:
|
||||
n = n << 6 | c; // c is 0 .. 63
|
||||
|
||||
if (n & 0x1000000) {
|
||||
// Convert 24-bit number into three output bytes
|
||||
count += 3;
|
||||
if (count > outlen) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
*u_out++ = n >> 16;
|
||||
*u_out++ = n >> 8;
|
||||
*u_out++ = n;
|
||||
n = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (n & 0x40000) {
|
||||
count += 2;
|
||||
if (count > outlen) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
*u_out++ = n >> 10;
|
||||
*u_out++ = n >> 2;
|
||||
} else if (n & 0x1000) {
|
||||
count += 1;
|
||||
if (count > outlen) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
*u_out++ = n >> 4;
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
|
||||
|
75
src/utils.h
75
src/utils.h
@ -260,59 +260,58 @@ extern ssize_t l_strfmon (char *restrict buf, size_t maxsize,
|
||||
************************************************************************/
|
||||
|
||||
/*
|
||||
The functions described here are simple in the extreme: they are only
|
||||
designed to stop casual cheating!
|
||||
The functions described here are NOT cryptographically secure: they are
|
||||
only designed to stop casual cheating!
|
||||
*/
|
||||
|
||||
/*
|
||||
Function: scramble - Scramble (encrypt) the buffer
|
||||
Parameters: key - Pointer to encryption/decryption key
|
||||
inbuf - Pointer to input buffer to encrypt
|
||||
inbufsize - Size of input buffer
|
||||
outbuf - Pointer to output buffer
|
||||
outbufsize - Size of output buffer
|
||||
Returns: char * - Pointer to output buffer
|
||||
Function: scramble - Scramble (encrypt) the buffer
|
||||
Parameters: dest - Pointer to output buffer
|
||||
src - Pointer to input buffer to encrypt
|
||||
size - Size of output buffer
|
||||
key - Pointer to encryption/decryption key
|
||||
Returns: char * - Pointer to output buffer
|
||||
|
||||
This function scrambles (encrypts) the buffer *inbuf using a trivial
|
||||
encryption algorithm and places the result in *outbuf. If key is NULL
|
||||
or *key is zero, no encryption takes place: the input buffer is copied
|
||||
to the output buffer as-is.
|
||||
This function scrambles (encrypts) the buffer *src and places the
|
||||
result in *dest. It uses *key to keep a running encryption key. If
|
||||
the key is NULL, no encryption is performed.
|
||||
|
||||
The input buffer should contain a C-style string terminated by '\0'.
|
||||
The characters '\r', '\n' and '\0' are guaranteed to remain the same
|
||||
before and after encryption. Note that inbuf and outbuf MUST point to
|
||||
different buffers, and that outbuf typically must be four times larger
|
||||
than inbuf. At most inbufsize bytes are encrypted; outbuf is returned
|
||||
as the result.
|
||||
The output buffer will be terminated with '\n\0', even if the input
|
||||
does not have a terminating '\n'. The pointer dest is returned as the
|
||||
output.
|
||||
|
||||
Note that src and dest MUST point to different buffers, and that *dest
|
||||
typically must be twice as large as *src. In addition, *key MUST be
|
||||
initialised to zero before calling scramble() for the first time.
|
||||
*/
|
||||
extern char *scramble (unsigned char *restrict key,
|
||||
char *restrict inbuf, int inbufsize,
|
||||
char *restrict outbuf, int outbufsize);
|
||||
extern char *scramble (char *restrict dest, const char *restrict src,
|
||||
size_t size, unsigned int *restrict key);
|
||||
|
||||
|
||||
/*
|
||||
Function: unscramble - Unscramble (decrypt) the buffer
|
||||
Parameters: key - Pointer to encryption/decryption key
|
||||
inbuf - Pointer to input buffer to decrypt
|
||||
inbufsize - Size of input buffer
|
||||
outbuf - Pointer to output buffer
|
||||
outbufsize - Size of output buffer
|
||||
Returns: char * - Pointer to output buffer
|
||||
Parameters: dest - Pointer to output buffer
|
||||
src - Pointer to input buffer to decrypt
|
||||
size - Size of output buffer
|
||||
key - Pointer to encryption/decryption key
|
||||
Returns: char * - Pointer to output buffer or NULL on error
|
||||
|
||||
This function does the reverse of scramble(): it unscrambles (decrypts)
|
||||
the buffer *inbuf using a trivial algorithm and places the result in
|
||||
*outbuf. If key is NULL or *key is zero, no decryption takes place:
|
||||
the input buffer is copied to the output buffer as-is.
|
||||
the buffer *src and places the result in *dest. If key is NULL, no
|
||||
decryption takes place: the input buffer is copied to the output buffer
|
||||
without changes.
|
||||
|
||||
The buffer should contain a C-style string terminated by '\0'. As for
|
||||
scramble(), the characters '\r', '\n' and '\0' will not be changed (nor
|
||||
will any encrypted character map back to these values). Note that
|
||||
inbuf and outbuf MUST point to different buffers. At most bufsize
|
||||
bytes are decrypted; outbuf is returned as the result.
|
||||
The buffer should contain a C-style string terminated by '\0'. Note
|
||||
that src and dest MUST point to different buffers. The pointer dest is
|
||||
returned as the output, unless there is an error in the data (such as a
|
||||
corrupted checksum), in which case NULL is returned.
|
||||
|
||||
Note that *key MUST be initialised to zero before calling unscramble()
|
||||
for the first time.
|
||||
*/
|
||||
extern char *unscramble (unsigned char *restrict key,
|
||||
char *restrict inbuf, int inbufsize,
|
||||
char *restrict outbuf, int outbufsize);
|
||||
extern char *unscramble (char *restrict dest, const char *restrict src,
|
||||
size_t size, unsigned int *restrict key);
|
||||
|
||||
|
||||
/************************************************************************
|
||||
|
Loading…
x
Reference in New Issue
Block a user