/* FILE : mmpc_rec.c
** AUTHOR : Jim Shapiro
** DATE : 19 March, 1999
** DISCLAIMER : No liability is assumed by the author for any use
** made of this program.
** DISTRIBUTION: Any use may be made of this program, as long as the
** clear acknowledgment is made to the author in code
** and runtime executables. The author retains
** copyright.
*/
#define THIS_IS_MAIN
#include <stdio.h>
#include <stdlib.h>
#include <strings.h>
#include <sys/stat.h>
#include "msg_dgst_rsa.h"
/* must come before package.h for typedef of ARRAYS */
#include "blowfish.h"
#include "package.h"
#include "hash.h"
enum { KEEP_INDICES, CB_HASH_COUNT };
static void help(char *program);
/* (m)ulti-(m)essage (p)ackage (c)haffing - receiver */
/* MD5 (the default) or SHA */
#define SHA
#ifndef SHA
const int Digest_bytes = 16;
const int Block_bytes = 24;
#else
const int Digest_bytes = 20;
const int Block_bytes = 28;
#endif
int main(int argc, char **argv)
{
char buf[11];
char byte_s[3] = { '\0', '\0', '\0' };
unsigned char *key_p;
unsigned char block_p[8];
unsigned char previous_block_p[8];
unsigned char build_p[8]; /* to build key via xor's */
unsigned char plain_p[8]; /* plaintext */
unsigned char act_digest_p[Digest_bytes];
unsigned char file_digest_p[Digest_bytes];
int i;
int j;
int len; /* key length when in hex */
int key_len; /* key length when in bytes */
int rv = EXIT_FAILURE;
unsigned long ul;
unsigned long matches;
unsigned long data_bytes;
/* initialized to suppress benign warning */
unsigned long next_to_last_match_index = 0;
/* initialized to suppress benign warning */
unsigned long last_match_index = 0;
unsigned long total_blocks;
FILE *fin_p;
struct stat stat_struct;
ARRAYS r_array; /* for the random key */
do {
if((argc == 2) && (strcmp(argv[1], "-h") == 0)) {
help(argv[0]);
break;
}
if(argc != 3) {
(void)printf("Usage: %s <HMAC key> <chaff file>\n", argv[0]);
break;
}
#ifndef SHA
(void)fputs("Expecting hmac_md5 for digest.\n", stderr);
#else
(void)fputs("Expecting hmac_sha for digest.\n", stderr);
#endif
len = strlen(argv[1]);
if((len % 2) != 0) {
(void)puts("Sorry, you did not enter an even number of "
"(hex) characters for the key!...");
exit(EXIT_FAILURE);
}
if((fin_p = fopen(argv[2], "rb")) == NULL) {
(void)printf("Cannot open chaff file \"%s\"!...\n", argv[2]);
break;
}
if(stat(argv[2], &stat_struct) == -1) {
(void)printf("Cannot stat \"%s\"!...\n", argv[2]);
break;
}
key_len = len >> 1; /* convert from hex to byte count */
if((key_p = (unsigned char *)malloc(key_len *
sizeof(unsigned char))) == NULL) {
(void)fprintf(stderr, "Could not malloc %d bytes for key!...\n",
len);
exit(EXIT_FAILURE);
}
for(i = j = 0; i < len; i += 2) {
bcopy(argv[1] + i, byte_s, 2);
key_p[j++] = (unsigned char)strtol(byte_s, (char **)NULL, 16);
}
Endian = check_byte_order();
data_bytes = stat_struct.st_size;
if((data_bytes % Block_bytes) != 0) {
(void)printf("Chaffed file size is not n * %u !...\n",
Block_bytes);
break;
}
total_blocks = data_bytes / Block_bytes;
initialize_cb_hash_count(CB_HASH_COUNT);
initialize_cb_hash_size(KEEP_INDICES, Primes[SMALL_HASH]);
initialize_cb_hashes(CB_HASH_COUNT);
(void)fprintf(stderr,
"There are %lu blocks each containing 8 bytes of "
"data and a %d byte HMAC.\n",
total_blocks, Digest_bytes);
/* set (internal) public key arrays */
package_one_time_set(123450, 678900);
rev_package_initialize(build_p); /* zero out for xor's */
for(ul = matches = 0lu; ul < total_blocks; ul++) { /* 1st pass */
if(fread(block_p, sizeof(unsigned char), 8, fin_p) != 8) {
(void)printf("Error 0 reading block %lu!...\n", ul);
break;
}
#ifndef SHA
hmac_md5_string(block_p, 8, key_p, key_len, act_digest_p);
#else
hmac_sha_string(block_p, 8, key_p, key_len, act_digest_p);
#endif
if(fread(file_digest_p, sizeof(unsigned char), Digest_bytes,
fin_p) != Digest_bytes) {
(void)puts("Could not read HMAC from chaff file!...");
exit(EXIT_FAILURE);
}
for(i = 0; i < Digest_bytes; i++) {
if(act_digest_p[i] != file_digest_p[i]) {
break; /* HMACs do not match */
}
}
if(i == Digest_bytes) {
(void)sprintf(buf, "%lu", ul);
if(cb_new_pair(KEEP_INDICES, buf, TRUE) != INSERT_OK) {
(void)printf("Cannot insert key %s into hash!...\n", buf);
exit(EXIT_FAILURE);
}
if(matches > 0lu) {
rev_package_build_kp(build_p, matches, previous_block_p);
}
next_to_last_match_index = last_match_index;
last_match_index = ul;
matches++;
bcopy(block_p, previous_block_p, 8);
}
}
if(last_match_index == 0lu) {
(void)printf(
"Sorry, there is no match for \"%s\" in file \"%s\".\n",
argv[1], argv[2]);
break;
}
rev_package_set_key(build_p, previous_block_p, &r_array);
rewind(fin_p);
/* 2nd pass -- note that we quit after index of NEXT to last
match */
for(ul = matches = 0lu; ul <= next_to_last_match_index; ul++) {
(void)sprintf(buf, "%lu", ul);
if(cb_exists(KEEP_INDICES, buf) == FALSE) {
fseek(fin_p, Block_bytes, SEEK_CUR); /* skip data and HMAC */
} else {
if(fread(block_p, sizeof(unsigned char), 8, fin_p) != 8) {
(void)printf("Error 1 reading block %lu!...\n", ul);
break;
}
rev_package_finalize(&r_array, ++matches, block_p, plain_p);
if(ul < next_to_last_match_index) { /* data block */
j = 8;
} else { /* last data block with sentinel */
j = 8 - (int)plain_p[7]; /* number of bytes to print */
}
for(i = 0; i < j; i++) {
(void)putchar(plain_p[i]);
}
fseek(fin_p, Digest_bytes, SEEK_CUR); /* skip HMAC */
}
}
(void)fclose(fin_p);
rv = EXIT_SUCCESS;
} while(0);
return rv;
}
static void help(char *program)
{
(void)printf(
"\n\"%s\" is a companion program to \"mmpc_snd\", the latter of which\n"
"package-chaffs any number of files using a different HMAC for each\n"
"file and optionally \"randomly\" adds chaff blocks of \"random\" bytes.\n"
"This program is executed by supplying the key entered as a string of\n"
"hexadecimal characters followed by the name of a package-chaffed file\n"
"from mmpc_snd.\n\n", program);
}