Received: (from cpunk@localhost) by slack.lne.com (8.11.0/8.11.0) id
g4R9crb01035 for [EMAIL PROTECTED]; Mon, 27 May 2002 02:38:53 -0700
Received: from weltregierung.koeln.ccc.de (w11g.ff.c0re.23.nu
[213.221.113.45]) by slack.lne.com (8.11.0/8.11.0) with ESMTP id
g4R9cZe01019 for <[EMAIL PROTECTED]>; Mon, 27 May 2002 02:38:36 -0700
Received: (qmail 9955 invoked by uid 900); 27 May 2002 09:33:53 -0000
X-Mailsort: cypherpunks
Received: (qmail 9937 invoked by uid 0); 27 May 2002 09:33:50 -0000
Received: from unknown (HELO einstein.ssz.com) ([EMAIL PROTECTED]) by
w11g.ff.c0re.23.nu with SMTP; 27 May 2002 09:33:50 -0000
Received: (from cpunks@localhost) by einstein.ssz.com (8.8.8/8.8.8) id
EAA19338 for [EMAIL PROTECTED]; Mon, 27 May 2002
04:55:40 -0500
Received: (from mdom@localhost) by einstein.ssz.com (8.8.8/8.8.8) id
EAA19320 for cypherpunks-outgoing; Mon, 27 May 2002 04:55:31 -0500
Received: (from cpunks_anon@localhost) by einstein.ssz.com (8.8.8/8.8.8)
id EAA19315 for [EMAIL PROTECTED]; Mon, 27 May 2002 04:55:29 -0500
From: CDR Anonymizer <[EMAIL PROTECTED]>
Message-Id: <[EMAIL PROTECTED]>
Subject: Meganet VME decryptor
Date: Mon, 27 May 2002 11:18:05 +0200 (CEST)
To: [EMAIL PROTECTED]
Sender: [EMAIL PROTECTED]
Precedence: bulk
X-Unsubscription-Info: http://einstein.ssz.com/cdr
/*
* You might have heard of Meganet's "Virtual Matrix Encryption." They've
* had a series of "crack this code" contests, but won't tell us how
* their code works. The program below was reverse-engineered from the
* shareware software which is available on their web site, and can
* decrypt VME files. It's very different from Meganet's software, but
* produces exactly the same results in all my tests. This is not a
* cracking program (you need to supply the required secret information
* in order to decrypt) but maybe someone can use it to build one.
*
* I've added the ability to decode the VME98 file header. I couldn't
* find an executable to work with, so my only source of information was
* a few encrypted (probably garbage) files. Only the header is decoded,
* not the file contents.
*
* Meganet claims that the "Targeted Delivery System" increases security
* by limiting decryption to copies of VME with certain serial numbers.
* It's possible for anyone to compute the required decryption
* parameters, though, as the program below demonstrates. It can decrypt
* messages targeted to any serial number (provided you know the proper
* passwords and such, of course).
*
* The "Date Limiting Algorithm" is supposed to prevent decryption after
* a certain date. Meganet's VME software extracts the date limit from
* the encrypted file, compares it to the current date, and refuses to
* decrypt the file if the date isn't right. This program has no such
* limitation, so it can decrypt regardless of the date limit.
*
* VME computes a "Transaction Code" and "Authentication Number" to
* verify file integrity. These are basically dressed-up 8-bit checksums.
*
* VME has an alternate encryption mode which tries to be faster by doing
* fewer computations per character. You can access this mode by typing
& "av" in the "Link Parameter" field of their shareware program. This
* program supports both modes.
*
* If you try to decrypt Meganet's old encrypted challenge files with
* this code (using the passwords given on their web site), you'll get
* garbage. However, it's exactly the same garbage that you'll get if
* you decrypt the files with their shareware software. Apparantly
* either a) the shareware version is broken, or b) Meganet decided to
* make certain nobody would win the challenge by encrypting random
* numbers instead of a meaningful file. This code can correctly decrypt
* files that were encrypted with the shareware version.
*/
#include <stdio.h>
#include <string.h>
#include <ctype.h>
int vme_decrypt(FILE *data_file, char *passwords[], FILE *config_file,
FILE *secret_file, FILE *out_file);
/* Test driver. Sorry there isn't a proper user interface here. */
int main()
{
FILE *data_file, *config_file, *secret_file, *out_file;
char *passwords[] = {
"[EMAIL PROTECTED]", /* source user */
"[EMAIL PROTECTED]", /* target user */
"VME Challenge 2001", /* description */
"", /* password */
};
data_file = fopen("vme2001.vme", "rb");
config_file = fopen("vme2001.cfg", "rb");
secret_file = fopen("vme2001.txt", "rb");
out_file = fopen("decrypt.out", "wb");
if (vme_decrypt(data_file,passwords,config_file,secret_file,out_file))
printf("Decryption failed\n");
return 0;
} /* main */
#define VME_NUM_PASS 4
#define VME_PASS_SIZE 0x40
#define VME_KEY_SIZE 0x10
#define VME_MAX_FUNCS 100
#define VME_BUF_SIZE 0x100
#define VME_MBK_SIZE 0x8000
#define VME_MAXINT 0xffffffffu
#define SWAP(x,y) { int temp = (x); (x) = (y); (y) = temp; }
#define LROT(x,y) ( ((x)<<(y) | (x)>>(8-(y))) & 0xff )
#define RROT(x,y) ( ((x)>>(y) | (x)<<(8-(y))) & 0xff )
#define VME_RAND(r) ( (r)=((r)*0x19660du+0x3c6ef35fu)&VME_MAXINT )
#define VME_RAND4(r) ( (r)=((r)*(-3)-1)&0xf )
#define VME_RAND8(r) ( (r)=((r)*0x0d+0x5f)&0xff )
#define VME_RAND15(r) ( (r)=((r)*0x660d+0x735f)&0x7fff )
#define VME98_RAND8(r) ( ((r)=((r)*5+1)&0x1ff)>>1 )
struct vme_state {
int version, fast_mode, num_funcs, secret_size;
int stk_xor, stk_sum, key_sum;
int rand_byte1, rand_byte2;
unsigned main_key;
unsigned char recipient[VME_KEY_SIZE], key3[VME_KEY_SIZE];
unsigned char func_order[VME_MAX_FUNCS], key_order[VME_MAX_FUNCS];
unsigned char key1[VME_BUF_SIZE], key2[VME_BUF_SIZE];
unsigned char stk[VME_BUF_SIZE], mul[VME_BUF_SIZE];
unsigned char perm1[VME_BUF_SIZE];
unsigned char perm2[VME_BUF_SIZE], invperm2[VME_BUF_SIZE];
unsigned char rmbk1[VME_BUF_SIZE], rmbk2[VME_BUF_SIZE];
unsigned char rmbk3[VME_BUF_SIZE], rmbk4[VME_BUF_SIZE];
unsigned char mbk1[VME_MBK_SIZE], mbk2[VME_MBK_SIZE];
unsigned char mbk3[VME_MBK_SIZE], mbk4[VME_MBK_SIZE];
};
static int vme_load_config(FILE *config_file, struct vme_state *vme);
static int vme_load_stk(FILE *data_file, struct vme_state *vme);
static int vme_main_init(FILE *data_file, char *passwords[],
FILE *secret_file, struct vme_state *vme);
static void vme_key_init(struct vme_state *vme);
static void vme_mbk_init(FILE *secret_file, struct vme_state *vme);
static void vme_calc_code(char *label, int sum);
static void vme00_decrypt(FILE *data_file, FILE *out_file,
struct vme_state *vme);
static void vme00_fastdecrypt(FILE *data_file, FILE *out_file,
struct vme_state *vme);
static void vme02_decrypt(FILE *data_file, FILE *out_file,
struct vme_state *vme);
static void vme02_fastdecrypt(FILE *data_file, FILE *out_file,
struct vme_state *vme);
static int vme_table1(int c, int n, int k, struct vme_state *vme);
static int vme_table2(int c, int n, unsigned rand);
/* Main decryption function */
int vme_decrypt(FILE *data_file, char *passwords[], FILE *config_file,
FILE *secret_file, FILE *out_file)
{
struct vme_state vme;
if ( vme_load_config(config_file, &vme) ) return 1;
if ( vme_load_stk(data_file, &vme) ) return 1;
if ( vme_main_init(data_file, passwords, secret_file, &vme) )
return 1;
vme_key_init(&vme);
vme_mbk_init(secret_file, &vme);
if (vme.version > 2000) {
if (vme.fast_mode) vme02_fastdecrypt(data_file, out_file, &vme);
else vme02_decrypt(data_file, out_file, &vme);
}
else {
if (vme.fast_mode) vme00_fastdecrypt(data_file, out_file, &vme);
else vme00_decrypt(data_file, out_file, &vme);
}
return 0;
} /* vme_decrypt */
/*
* The configuration file gives the initial order of the functions
* applied to the data as it is encrypted.
*/
static int vme_load_config(FILE *config_file, struct vme_state *vme)
{
int i, c, f, n, rand_state;
if (config_file == NULL) {
vme->func_order[0] = vme->key_order[0] = 0xf;
vme->num_funcs = 1;
}
else {
fseek(config_file, 0, SEEK_SET);
rand_state = 0xff;
n = 0;
for (i = 0; i < VME_MAX_FUNCS; i++) {
c = getc(config_file);
if (c == EOF) return 1;
c ^= VME_RAND8(rand_state);
f = c >> 4;
vme->func_order[i] = f;
vme->key_order[i] = (f == 0xe) ? 0xe : c & 0xf;
if (f != 0xf) n = i;
}
vme->num_funcs = n + 1;
}
return 0;
} /* vme_load_config */
/*
* The encrypted file is prefixed with a 256-byte header which makes up
* the Specific Transaction Key (STK). Note that the STK is only one of
* several "keys" you need to know in order to decrypt the rest of the
* file. There are several encoded pieces of information encoded into
* the STK. Instead of using the manufacturer-recommended procedure to
* decode the header information using the passwords, this code just
* does an exhaustive key search. You're going to bust a gut laughing
* when you see this.
*/
static int vme_load_stk(FILE *data_file, struct vme_state *vme)
{
int i, j, r, s, c;
int found, isgood, pos, xor, sum, rand_state;
char date[VME_KEY_SIZE], file_id[VME_KEY_SIZE], recip[VME_KEY_SIZE];
char serial[VME_KEY_SIZE], time[VME_KEY_SIZE];
if (data_file == NULL) return 1;
fseek(data_file, 0, SEEK_SET);
for (i = 0; i < VME_BUF_SIZE; i++) {
c = getc(data_file);
if (c == EOF) return 1;
vme->stk[i] = c;
}
/* Search the entire 7-bit keyspace */
found = 0;
for (i = 0; i < 0xff; i += 2) {
rand_state = i;
for (j = 0; j < VME_KEY_SIZE; j++) {
pos = j << 4;
r = VME_RAND8(rand_state); s = VME_RAND8(rand_state) & 3;
date[j] = vme->stk[pos+s] ^ r;
file_id[j] = vme->stk[pos + ((s+1)&3)] ^ ((pos+0x7f)&0xff);
r = VME_RAND8(rand_state); s = VME_RAND8(rand_state) & 3;
recip[j] = vme->stk[pos+s+4] ^ r;
r = VME_RAND8(rand_state); s = VME_RAND8(rand_state) & 3;
serial[j] = vme->stk[pos+s+8] ^ r;
r = VME_RAND8(rand_state); s = VME_RAND8(rand_state) & 3;
time[j] = vme->stk[pos+s+12] ^ r;
}
isgood = 1;
for (j = 0; isgood && j < VME_KEY_SIZE; j++)
if (!isdigit(date[j]))
isgood = 0;
for (j = 0; isgood && j < 14; j++)
if (!isdigit(time[j]))
isgood = 0;
if (!isgood) continue;
if (strncmp(file_id, "VVVVVVVVVVVVVVVV", 16) == 0)
vme->fast_mode = 0;
else if (strncmp(file_id, "vvvvvvvvvvvvvvvv", 16) == 0)
vme->fast_mode = 1;
else
continue;
found = 1;
vme->version = time[14]*100 + time[15];
memcpy(vme->recipient, recip, VME_KEY_SIZE);
printf("Guessed header key: 0x%02x\n", i);
printf("Date limit: from %.4s/%.2s/%.2s ", date, date+4, date+6);
printf("to %.4s/%.2s/%.2s\n", date+8, date+12, date+14);
printf("Recipient: %.16s\n", recip);
printf("Encryptor serial number: %.4s-%.4s-%.4s-%.4s\n",
serial, serial+4, serial+8, serial+12);
printf("Encryption time: %.4s/%.2s/%.2s ", time, time+4, time+6);
printf("%.2s:%.2s:%.2s\n", time+8, time+10, time+12);
printf("VME version: %d\n", vme->version);
if (vme->fast_mode) printf("Encrypted in fast mode\n");
}
if (!found) {
/* Try to decode a VME98 header. 4-bit keyspace, it seems. */
for (i = 1; i < 0x1ff; i += 0x20) {
rand_state = i;
for (j = 0; j < VME_KEY_SIZE; j++) {
pos = j << 4;
r = VME98_RAND8(rand_state); s = VME98_RAND8(rand_state) & 3;
date[j] = vme->stk[pos+s] ^ r;
r = VME98_RAND8(rand_state); s = VME98_RAND8(rand_state) & 3;
recip[j] = vme->stk[pos+s+4] ^ r;
r = VME98_RAND8(rand_state); s = VME98_RAND8(rand_state) & 3;
serial[j] = vme->stk[pos+s+8] ^ r;
r = VME98_RAND8(rand_state); s = VME98_RAND8(rand_state) & 3;
time[j] = vme->stk[pos+s+12] ^ r;
}
isgood = 1;
for (j = 0; isgood && j < VME_KEY_SIZE; j++)
if (!isdigit(date[j]))
isgood = 0;
for (j = 0; isgood && j < 14; j++)
if (!isdigit(time[j]))
isgood = 0;
if (!isgood) continue;
found = 1;
vme->fast_mode = 0;
vme->version = time[14]*100 + time[15];
memcpy(vme->recipient, recip, VME_KEY_SIZE);
printf("Guessed header key: 0x%03x\n", i);
printf("Date limit: from %.4s/%.2s/%.2s ", date, date+4, date+6);
printf("to %.4s/%.2s/%.2s\n", date+8, date+12, date+14);
printf("Recipient: %.16s\n", recip);
printf("Encryptor serial number: %.4s-%.4s-%.4s-%.4s\n",
serial, serial+4, serial+8, serial+12);
printf("Encryption time: %.4s/%.2s/%.2s ", time, time+4, time+6);
printf("%.2s:%.2s:%.2s\n", time+8, time+10, time+12);
printf("VME version: %d\n", vme->version);
}
if (!found) {
printf("Warning: couldn't find header key\n");
vme->fast_mode = 0;
vme->version = 2000;
memset(vme->recipient, 0, VME_KEY_SIZE);
}
}
rand_state = 0x2d;
xor = 0x7b;
sum = 0;
for (i = 0; i < VME_BUF_SIZE; i++) {
c = vme->stk[i];
sum += c;
c ^= VME_RAND8(rand_state);
xor ^= c;
vme->stk[i] = c;
}
vme->stk_xor = xor;
vme->stk_sum = sum & 0xff;
return 0;
} /* vme_load_stk */
/*
* Use the passwords and file sizes to determine the 32-bit main_key
* and two other 256-byte keys.
*/
static int vme_main_init(FILE *data_file, char *passwords[],
FILE *secret_file, struct vme_state *vme)
{
int i, j, r;
int xor1, xor2, data_size;
unsigned sum, recip_sum, pass_sum;
unsigned main_key, header_key, rand_state, rand_state2;
unsigned char key_str[VME_PASS_SIZE];
unsigned char pass[VME_NUM_PASS][VME_PASS_SIZE];
unsigned char fixed_key[VME_NUM_PASS][VME_PASS_SIZE];
if (data_file == NULL) return 1;
rand_state = 3;
pass_sum = 0;
for (i = 0; i < VME_NUM_PASS; i++) {
for (j = 0; j < VME_PASS_SIZE && passwords[i][j] != '\0'; j++)
pass_sum += pass[i][j] = passwords[i][j];
for (; j < VME_PASS_SIZE; j++)
pass_sum += pass[i][j] = VME_RAND8(rand_state);
}
rand_state = 0x30;
for (i = 0; i < VME_NUM_PASS; i++)
for (j = 0; j < VME_PASS_SIZE; j++)
fixed_key[i][j] = VME_RAND8(rand_state);
/* Recompute the header key to validate the key search above. */
rand_state = pass_sum & 0xff;
sum = 0;
header_key = 0;
for (j = 0; j < VME_PASS_SIZE; j++) {
for (i = 0; i < VME_NUM_PASS; i++)
sum += VME_RAND8(rand_state) * pass[i][j];
rand_state = (sum + j) & 0xff;
header_key += VME_RAND8(rand_state);
}
rand_state = (header_key + 0x61) & 0xff;
header_key = VME_RAND8(rand_state);
header_key *= VME_RAND8(rand_state);
printf("Computed header key: 0x%02x\n", header_key & 0xff);
fseek(data_file, 0, SEEK_END);
data_size = ftell(data_file) - VME_BUF_SIZE;
if (data_size < 0) return 1;
if (secret_file == NULL)
vme->secret_size = 0;
else {
fseek(secret_file, 0, SEEK_END);
vme->secret_size = ftell(secret_file);
}
if (strncmp(vme->recipient, "Global ", 16) == 0) {
sprintf(key_str, " %d %d ", data_size, vme->secret_size);
recip_sum = 0xdf2;
}
else if (strncmp(vme->recipient+8, "Local ", 8) == 0) {
sprintf(key_str, " %d %d %.8s", data_size, vme->secret_size,
vme->recipient);
rand_state = 0xe;
recip_sum = 0x1c0;
for (i = 0; i < 8; i++)
recip_sum += VME_RAND4(rand_state) * vme->recipient[i];
}
else { /* specific recipient */
sprintf(key_str, " %d %d %.16s", data_size, vme->secret_size,
vme->recipient);
rand_state = 0x76593361;
for (i = 0; i < 8; i++) {
VME_RAND(rand_state);
rand_state = (rand_state % 0x7919) * vme->recipient[i]
* vme->recipient[(VME_KEY_SIZE - 1) - i];
VME_RAND(rand_state);
while (rand_state >= 0x7fffffff)
rand_state -= 0x7fffffff;
}
rand_state2 = 0xe;
recip_sum = 0xdf2;
for (i = 0; i < VME_KEY_SIZE; i++) {
VME_RAND(rand_state);
rand_state = (rand_state % 32767001) + 0xe4a03;
r = vme->recipient[i];
for (j = 0; j < r; j++) VME_RAND(rand_state);
recip_sum += (VME_RAND(rand_state) & 0xff)
* VME_RAND4(rand_state2);
for (j++; j < 0x100; j++) VME_RAND(rand_state);
}
}
rand_state = 0x67;
for (i = strlen(key_str); i < VME_PASS_SIZE; i++)
key_str[i] = VME_RAND8(rand_state);
sum = pass_sum + 0x7f80;
for (i = 0; i < VME_PASS_SIZE; i++) sum += key_str[i];
for (i = 0; i < VME_BUF_SIZE; i++) sum += vme->stk[i];
rand_state = sum;
sum = vme->stk_xor;
main_key = vme->stk_xor << 6;
for (i = 0; i < VME_PASS_SIZE; i++) {
for (j = i; j < VME_BUF_SIZE; j += VME_PASS_SIZE)
sum += (VME_RAND(rand_state) & 0xfffff) * vme->stk[j];
sum += (VME_RAND(rand_state) & 0xfffff) * key_str[i];
for (j = 0; j < VME_NUM_PASS; j++) {
sum += (VME_RAND(rand_state) & 0xfffff) * pass[j][i];
sum += (VME_RAND(rand_state) & 0xfffff) * fixed_key[j][i];
}
rand_state = sum + i;
main_key += VME_RAND(rand_state) & 0x1ffffff;
for (j = 0; j < VME_NUM_PASS; j++) {
r = VME_RAND(rand_state) & 0xff;
vme->key1[j<<6 | i] = pass[j][i] ^ r;
vme->key2[j<<6 | i] = fixed_key[j][i] ^ r;
}
}
vme->main_key = main_key & VME_MAXINT;
rand_state = (main_key + 0x7f) & 0xff;
xor1 = 0x9b;
xor2 = 0xa7;
for (i = 0; i < VME_BUF_SIZE; i++) {
r = VME_RAND8(rand_state);
xor1 ^= vme->key1[i] ^= r;
xor2 ^= vme->key2[i] ^= r;
}
vme->key_sum = vme->stk_xor + recip_sum + xor1 + xor2;
return 0;
} /* vme_main_init */
/* Initialize some other keys */
static void vme_key_init(struct vme_state *vme)
{
int i, j, rand_state;
rand_state = (vme->main_key + 0x4d) & 0xff;
for (i = 0; i < VME_BUF_SIZE; i++)
vme->perm1[i] = i;
for (i = 0; i < VME_BUF_SIZE; i++) {
j = VME_RAND8(rand_state);
SWAP(vme->perm1[i], vme->perm1[j]);
}
rand_state = (vme->main_key + 0x4e) & 0xff;
for (i = 0; i < VME_BUF_SIZE; i++)
vme->perm2[i] = i;
for (i = 0; i < VME_BUF_SIZE; i++) {
j = VME_RAND8(rand_state);
SWAP(vme->perm2[i], vme->perm2[j]);
}
for (i = 0; i < VME_BUF_SIZE; i++)
vme->invperm2[ vme->perm2[i] ] = i;
/* This generates a permutation of two copies of
the multiplicative units of Z/256 */
rand_state = (vme->main_key + vme->key_sum) & 0xff;
for (i = 1; i < VME_BUF_SIZE; i += 2) {
j = 1;
while ( (i*j & 0xff) != 1 ) j += 2;
vme->mul[VME_RAND8(rand_state)] = j;
vme->mul[VME_RAND8(rand_state)] = j;
}
} /* vme_key_init */
/*
* Initialize the infamous Million Bit Key using the main_key and
* secret_file. Also compute a reduced version.
*/
static void vme_mbk_init(FILE *secret_file, struct vme_state *vme)
{
int i, j, c, rand_state;
rand_state = (vme->main_key + 0xbd) & 0xff;
for (i = 0; i < VME_MBK_SIZE; i++) {
vme->mbk1[i] = VME_RAND8(rand_state);
vme->mbk2[i] = VME_RAND8(rand_state);
vme->mbk3[i] = VME_RAND8(rand_state);
vme->mbk4[i] = VME_RAND8(rand_state);
}
if (secret_file != NULL)
fseek(secret_file, 0, SEEK_SET);
if (vme->version > 2000) {
if (vme->secret_size <= 0)
;
else if (vme->secret_size <= 4*VME_MBK_SIZE) {
for (i = 0; i < 4*VME_MBK_SIZE; i++) {
c = getc(secret_file);
if (c == EOF) {
fseek(secret_file, 0, SEEK_SET);
c = getc(secret_file);
}
j = i & (VME_MBK_SIZE - 1);
vme->mbk1[j] ^= c;
vme->mbk2[j] ^= c;
vme->mbk3[j] ^= c;
vme->mbk4[j] ^= c;
}
}
else { /* big secret file */
i = 0;
while ( (c = getc(secret_file)) != EOF ) {
vme->mbk1[i] ^= c;
vme->mbk2[i] ^= c;
vme->mbk3[i] ^= c;
vme->mbk4[i] ^= c;
i = (i + 1) & (VME_MBK_SIZE - 1);
}
}
}
else { /* VME 2000 */
if (vme->secret_size <= 0)
;
else if (vme->secret_size <= VME_MBK_SIZE) {
for (i = 0; i < VME_MBK_SIZE; i++) {
c = getc(secret_file);
if (c == EOF) {
fseek(secret_file, 0, SEEK_SET);
c = getc(secret_file);
}
vme->mbk4[i] ^= vme->mbk3[i] ^= vme->mbk2[i] ^= vme->mbk1[i] ^= c;
}
}
else { /* big secret file */
i = 0;
while ( (c = getc(secret_file)) != EOF ) {
vme->mbk4[i] ^= vme->mbk3[i] ^= vme->mbk2[i] ^= vme->mbk1[i] ^= c;
i = (i + 1) & (VME_MBK_SIZE - 1);
}
}
}
for (i = 0; i < VME_BUF_SIZE; i++) {
vme->rmbk1[i] = vme->mbk1[i];
vme->rmbk2[i] = vme->mbk2[i];
vme->rmbk3[i] = vme->mbk3[i];
vme->rmbk4[i] = vme->mbk4[i];
for (j = i + VME_BUF_SIZE; j < VME_MBK_SIZE; j += VME_BUF_SIZE) {
vme->rmbk1[i] ^= vme->mbk1[j];
vme->rmbk2[i] ^= vme->mbk2[j];
vme->rmbk3[i] ^= vme->mbk3[j];
vme->rmbk4[i] ^= vme->mbk4[j];
}
}
} /* vme_mbk_init */
/* Calculate transaction code / authentication number */
static void vme_calc_code(char *label, int sum)
{
int i, rand_state;
char code[8];
rand_state = sum & 0xff;
for (i = 0; i < 8; i++)
code[i] = VME_RAND8(rand_state) % 10 + '0';
printf("%s: %.4s-%.4s\n", label, code, code+4);
} /* vme_calc_code */
/* VME 2000 normal decrypt */
static void vme00_decrypt(FILE *data_file, FILE *out_file,
struct vme_state *vme)
{
int c, i, r, buf_pos, mbk_pos;
int curr_cipher_byte, last_cipher_byte, last_plain_byte;
int auth_sum, trans_sum;
unsigned rand_state;
unsigned char rand_byte[8], rand_func[4];
unsigned short rand_word[8];
fseek(data_file, VME_BUF_SIZE, SEEK_SET);
buf_pos = 0;
last_plain_byte = 0xaa;
last_cipher_byte = 0x55;
auth_sum = trans_sum = vme->stk_sum;
while ( (c = getc(data_file)) != EOF ) {
curr_cipher_byte = c;
trans_sum += c;
rand_state = vme->main_key + vme->key_sum
+ last_plain_byte + last_cipher_byte;
r = VME_RAND(rand_state) & 1;
for (i = 1; i < 8; i++)
r |= VME_RAND(rand_state) & (1 << i);
vme->rand_byte2 = r;
vme->rand_byte1 = VME_RAND(rand_state) & 0xff;
for (i = 0; i < 8; i++)
rand_byte[i] = VME_RAND(rand_state) & 0xff;
for (i = 0; i < 4; i++)
rand_func[i] = VME_RAND(rand_state) % vme->num_funcs;
for (i = 0; i < 8; i++)
rand_word[i] = VME_RAND15(rand_state);
vme->key3[0] = last_plain_byte;
vme->key3[1] = last_cipher_byte;
vme->key3[2] = vme->rand_byte2;
vme->key3[3] = vme->rand_byte1;
vme->key3[4] = rand_byte[0];
vme->key3[5] = rand_byte[3];
vme->key3[6] = rand_byte[4];
vme->key3[7] = rand_byte[2];
vme->key3[8] = rand_byte[1];
vme->key3[9] = vme->stk[buf_pos];
vme->key3[10] = vme->key1[buf_pos];
vme->key3[11] = vme->key2[buf_pos];
vme->key3[12] = vme->rmbk1[buf_pos] ^ vme->mbk1[rand_word[0]];
vme->key3[13] = vme->rmbk2[buf_pos] ^ vme->mbk2[rand_word[1]];
vme->key3[14] = vme->rmbk3[buf_pos] ^ vme->mbk3[rand_word[2]];
vme->key3[15] = vme->rmbk4[buf_pos] ^ vme->mbk4[rand_word[3]];
for (i = vme->num_funcs - 1; i >= 0; i--)
c = vme_table1(c, vme->func_order[i], vme->key_order[i], vme);
c = vme->invperm2[c];
r = rand_byte[0];
SWAP(vme->perm2[r], vme->perm2[c]);
vme->invperm2[ vme->perm2[c] ] = c;
vme->invperm2[ vme->perm2[r] ] = r;
c ^= vme->rmbk1[buf_pos] ^ vme->rmbk2[buf_pos] ^ vme->rmbk3[buf_pos]
^ vme->rmbk4[buf_pos] ^ vme->rand_byte2 ^ rand_byte[2] ^ 0xff;
i = (rand_byte[1]%7 - rand_byte[4]%7) & 7; c = LROT(c, i);
c ^= 1 << (rand_byte[3] & 7);
c = vme_table1(c, rand_byte[0] >> 4, vme->rand_byte1 & 0xf, vme);
c = vme_table1(c, last_plain_byte >> 4, last_plain_byte & 0xf, vme);
c = ((c + last_cipher_byte) * vme->mul[vme->key2[buf_pos]]) & 0xff;
mbk_pos = (vme->rand_byte1<<8 | vme->stk[buf_pos]) & (VME_MBK_SIZE - 1);
c ^= vme->mbk1[mbk_pos] ^ vme->mbk2[mbk_pos] ^ vme->mbk3[mbk_pos]
^ vme->mbk4[mbk_pos] ^ vme->key1[buf_pos] ^ vme->rand_byte2 ^ 0xff;
c = vme_table2(c, last_plain_byte, vme->main_key);
r = vme->rand_byte1;
SWAP(vme->perm1[r], vme->perm1[c]);
c = vme->perm1[r];
SWAP(vme->stk[buf_pos], vme->stk[rand_byte[5]]);
SWAP(vme->key1[buf_pos], vme->key1[rand_byte[6]]);
SWAP(vme->key2[buf_pos], vme->key2[rand_byte[7]]);
SWAP(vme->func_order[rand_func[0]], vme->func_order[rand_func[1]]);
SWAP(vme->key_order[rand_func[2]], vme->key_order[rand_func[3]]);
SWAP(vme->mbk1[mbk_pos], vme->mbk1[rand_word[4]]);
SWAP(vme->mbk2[mbk_pos], vme->mbk2[rand_word[5]]);
SWAP(vme->mbk3[mbk_pos], vme->mbk3[rand_word[6]]);
SWAP(vme->mbk4[mbk_pos], vme->mbk4[rand_word[7]]);
auth_sum += c;
last_plain_byte = c;
last_cipher_byte = curr_cipher_byte;
buf_pos = (buf_pos + 1) & (VME_BUF_SIZE - 1);
vme->main_key++;
putc(c, out_file);
}
vme_calc_code("Transaction Code", trans_sum);
vme_calc_code("Authentication Number", auth_sum);
} /* vme00_decrypt */
/* VME 2000 fast mode decrypt */
static void vme00_fastdecrypt(FILE *data_file, FILE *out_file,
struct vme_state *vme)
{
int c, i, r, buf_pos, mbk_pos;
int curr_cipher_byte, last_cipher_byte, last_plain_byte;
int auth_sum, trans_sum;
unsigned rand_state;
unsigned char rand_byte[8], rand_func[4];
unsigned short rand_word[8];
fseek(data_file, VME_BUF_SIZE, SEEK_SET);
buf_pos = mbk_pos = 0;
last_plain_byte = 0xaa;
last_cipher_byte = 0x55;
auth_sum = trans_sum = vme->stk_sum;
while ( (c = getc(data_file)) != EOF ) {
trans_sum += c;
if (buf_pos == 0) {
rand_state = vme->main_key + vme->key_sum
+ last_plain_byte + last_cipher_byte;
r = VME_RAND(rand_state) & 1;
for (i = 1; i < 8; i++)
r |= VME_RAND(rand_state) & (1 << i);
vme->rand_byte2 = r;
vme->rand_byte1 = VME_RAND(rand_state) & 0xff;
for (i = 0; i < 8; i++)
rand_byte[i] = VME_RAND(rand_state) & 0xff;
for (i = 0; i < 4; i++)
rand_func[i] = VME_RAND(rand_state) % vme->num_funcs;
for (i = 0; i < 8; i++)
rand_word[i] = VME_RAND15(rand_state);
vme->key3[0] = last_plain_byte;
vme->key3[1] = last_cipher_byte;
vme->key3[2] = vme->rand_byte2;
vme->key3[3] = vme->rand_byte1;
vme->key3[4] = rand_byte[0];
vme->key3[5] = rand_byte[3];
vme->key3[6] = rand_byte[4];
vme->key3[7] = rand_byte[2];
vme->key3[8] = rand_byte[1];
vme->key3[9] = vme->stk[0];
vme->key3[10] = vme->key1[0];
vme->key3[11] = vme->key2[0];
vme->key3[12] = vme->rmbk1[0] ^ vme->mbk1[rand_word[0]];
vme->key3[13] = vme->rmbk2[0] ^ vme->mbk2[rand_word[1]];
vme->key3[14] = vme->rmbk3[0] ^ vme->mbk3[rand_word[2]];
vme->key3[15] = vme->rmbk4[0] ^ vme->mbk4[rand_word[3]];
}
for (i = vme->num_funcs - 1; i >= 0; i--)
c = vme_table1(c, vme->func_order[i], vme->key_order[i], vme);
r = vme->rand_byte1;
SWAP(vme->perm1[r], vme->perm1[c]);
c = vme->perm1[r];
auth_sum += c; vme->main_key++; putc(c, out_file);
SWAP(vme->stk[buf_pos], vme->stk[rand_byte[5]]);
SWAP(vme->key1[buf_pos], vme->key1[rand_byte[6]]);
SWAP(vme->key2[buf_pos], vme->key2[rand_byte[7]]);
SWAP(vme->func_order[rand_func[0]], vme->func_order[rand_func[1]]);
SWAP(vme->key_order[rand_func[2]], vme->key_order[rand_func[3]]);
SWAP(vme->mbk1[mbk_pos], vme->mbk1[rand_word[4]]);
SWAP(vme->mbk2[mbk_pos], vme->mbk2[rand_word[5]]);
SWAP(vme->mbk3[mbk_pos], vme->mbk3[rand_word[6]]);
SWAP(vme->mbk4[mbk_pos], vme->mbk4[rand_word[7]]);
if ((c = getc(data_file)) == EOF) break; trans_sum += c;
for (i = vme->num_funcs - 1; i >= 0; i--)
c = vme_table1(c, vme->func_order[i], vme->key_order[i], vme);
c = vme_table2(c, last_plain_byte, vme->main_key);
auth_sum += c; vme->main_key++; putc(c, out_file);
if ((c = getc(data_file)) == EOF) break; trans_sum += c;
for (i = vme->num_funcs - 1; i >= 0; i--)
c = vme_table1(c, vme->func_order[i], vme->key_order[i], vme);
mbk_pos = (vme->rand_byte1<<8 | vme->stk[rand_byte[5]])
& (VME_MBK_SIZE - 1);
c ^= vme->mbk1[mbk_pos] ^ vme->mbk2[mbk_pos]
^ vme->mbk3[mbk_pos] ^ vme->mbk4[mbk_pos];
auth_sum += c; vme->main_key++; putc(c, out_file);
if ((c = getc(data_file)) == EOF) break; trans_sum += c;
for (i = vme->num_funcs - 1; i >= 0; i--)
c = vme_table1(c, vme->func_order[i], vme->key_order[i], vme);
c ^= vme->key1[rand_byte[6]] ^ vme->rand_byte2 ^ 0xff;
auth_sum += c; vme->main_key++; putc(c, out_file);
if ((c = getc(data_file)) == EOF) break; trans_sum += c;
for (i = vme->num_funcs - 1; i >= 0; i--)
c = vme_table1(c, vme->func_order[i], vme->key_order[i], vme);
c = (c * vme->mul[vme->key2[rand_byte[7]]]) & 0xff;
auth_sum += c; vme->main_key++; putc(c, out_file);
if ((c = getc(data_file)) == EOF) break; trans_sum += c;
for (i = vme->num_funcs - 1; i >= 0; i--)
c = vme_table1(c, vme->func_order[i], vme->key_order[i], vme);
c = (c + last_cipher_byte) & 0xff;
auth_sum += c; vme->main_key++; putc(c, out_file);
if ((c = getc(data_file)) == EOF) break; trans_sum += c;
for (i = vme->num_funcs - 1; i >= 0; i--)
c = vme_table1(c, vme->func_order[i], vme->key_order[i], vme);
c = vme_table1(c, last_plain_byte >> 4, last_plain_byte & 0xf, vme);
auth_sum += c; vme->main_key++; putc(c, out_file);
if ((c = getc(data_file)) == EOF) break; trans_sum += c;
for (i = vme->num_funcs - 1; i >= 0; i--)
c = vme_table1(c, vme->func_order[i], vme->key_order[i], vme);
c = vme_table1(c, rand_byte[0] >> 4, vme->rand_byte1 & 0xf, vme);
auth_sum += c; vme->main_key++; putc(c, out_file);
if ((c = getc(data_file)) == EOF) break; trans_sum += c;
for (i = vme->num_funcs - 1; i >= 0; i--)
c = vme_table1(c, vme->func_order[i], vme->key_order[i], vme);
c ^= 1 << (rand_byte[3] & 7);
auth_sum += c; vme->main_key++; putc(c, out_file);
if ((c = getc(data_file)) == EOF) break; trans_sum += c;
for (i = vme->num_funcs - 1; i >= 0; i--)
c = vme_table1(c, vme->func_order[i], vme->key_order[i], vme);
r = rand_byte[4] % 7 + 1; c = RROT(c, r);
auth_sum += c; vme->main_key++; putc(c, out_file);
if ((c = getc(data_file)) == EOF) break; trans_sum += c;
for (i = vme->num_funcs - 1; i >= 0; i--)
c = vme_table1(c, vme->func_order[i], vme->key_order[i], vme);
r = rand_byte[1] % 7 + 1; c = LROT(c, r);
auth_sum += c; vme->main_key++; putc(c, out_file);
if ((c = getc(data_file)) == EOF) break; trans_sum += c;
for (i = vme->num_funcs - 1; i >= 0; i--)
c = vme_table1(c, vme->func_order[i], vme->key_order[i], vme);
c ^= rand_byte[2];
auth_sum += c; vme->main_key++; putc(c, out_file);
if ((c = getc(data_file)) == EOF) break; trans_sum += c;
for (i = vme->num_funcs - 1; i >= 0; i--)
c = vme_table1(c, vme->func_order[i], vme->key_order[i], vme);
c ^= vme->rand_byte2 ^ 0xff;
auth_sum += c; vme->main_key++; putc(c, out_file);
if ((c = getc(data_file)) == EOF) break; trans_sum += c;
for (i = vme->num_funcs - 1; i >= 0; i--)
c = vme_table1(c, vme->func_order[i], vme->key_order[i], vme);
i = buf_pos + 13; c ^= vme->rmbk1[i] ^ vme->rmbk2[i];
auth_sum += c; vme->main_key++; putc(c, out_file);
if ((c = getc(data_file)) == EOF) break; trans_sum += c;
for (i = vme->num_funcs - 1; i >= 0; i--)
c = vme_table1(c, vme->func_order[i], vme->key_order[i], vme);
i = buf_pos + 14; c ^= vme->rmbk3[i] ^ vme->rmbk4[i];
auth_sum += c; vme->main_key++; putc(c, out_file);
if ((c = getc(data_file)) == EOF) break; trans_sum += c;
curr_cipher_byte = c;
for (i = vme->num_funcs - 1; i >= 0; i--)
c = vme_table1(c, vme->func_order[i], vme->key_order[i], vme);
c = vme->invperm2[c];
r = rand_byte[0];
SWAP(vme->perm2[r], vme->perm2[c]);
vme->invperm2[ vme->perm2[r] ] = r;
vme->invperm2[ vme->perm2[c] ] = c;
last_plain_byte = c;
last_cipher_byte = curr_cipher_byte;
auth_sum += c; vme->main_key++; putc(c, out_file);
buf_pos = (buf_pos + 0x10) & (VME_BUF_SIZE - 1);
}
vme_calc_code("Transaction Code", trans_sum);
vme_calc_code("Authentication Number", auth_sum);
} /* vme00_fastdecrypt */
/* VME 2002 normal decrypt */
static void vme02_decrypt(FILE *data_file, FILE *out_file,
struct vme_state *vme)
{
int c, i, r, buf_pos, mbk_pos;
int curr_cipher_byte, last_cipher_byte, last_plain_byte;
int auth_sum, trans_sum;
unsigned rand_state;
unsigned char rand_byte[8], rand_func[4];
unsigned short rand_word[8];
fseek(data_file, VME_BUF_SIZE, SEEK_SET);
buf_pos = 0;
last_plain_byte = 0xaa;
last_cipher_byte = 0x55;
auth_sum = trans_sum = vme->stk_sum;
while ( (c = getc(data_file)) != EOF ) {
curr_cipher_byte = c;
trans_sum += c;
rand_state = vme->main_key + vme->key_sum
+ last_plain_byte + last_cipher_byte;
vme->rand_byte1 = VME_RAND(rand_state) & 0xff;
for (i = 0; i < 8; i++)
rand_byte[i] = VME_RAND(rand_state) & 0xff;
r = vme->rand_byte1 & 1;
for (i = 0; i < 7; i++)
r = (rand_byte[i] + r) & (2 << i);
vme->rand_byte2 = rand_byte[7] ^ r;
if (vme->num_funcs > 1)
for (i = 0; i < 4; i++)
rand_func[i] = VME_RAND(rand_state) % vme->num_funcs;
r = (vme->secret_size > 0) ? 8 : 4;
for (i = 0; i < r; i++)
rand_word[i] = VME_RAND15(rand_state);
vme->key3[0] = vme->rmbk1[buf_pos] ^ vme->mbk1[rand_word[0]];
vme->key3[1] = last_plain_byte ^ vme->rand_byte2;
vme->key3[2] = vme->stk[buf_pos];
vme->key3[3] = vme->key1[buf_pos];
vme->key3[4] = vme->key2[buf_pos];
vme->key3[5] = last_cipher_byte ^ vme->rand_byte2;
vme->key3[6] = rand_byte[4] & 0xf;
vme->key3[7] = vme->rand_byte1 & 0xf;
vme->key3[8] = rand_byte[3];
vme->key3[9] = rand_byte[4];
vme->key3[10] = rand_byte[1];
vme->key3[11] = rand_byte[2];
vme->key3[12] = vme->rand_byte2;
vme->key3[13] = vme->rmbk1[buf_pos] ^ vme->mbk2[rand_word[1]];
vme->key3[14] = vme->rmbk1[buf_pos] ^ vme->mbk3[rand_word[2]];
vme->key3[15] = vme->rmbk1[buf_pos] ^ vme->mbk4[rand_word[3]];
for (i = vme->num_funcs - 1; i >= 0; i--)
c = vme_table1(c, vme->func_order[i], vme->key_order[i], vme);
c = vme->invperm2[c ^ vme->key3[15]];
r = rand_byte[0];
SWAP(vme->perm2[r], vme->perm2[c]);
vme->invperm2[ vme->perm2[c] ] = c;
vme->invperm2[ vme->perm2[r] ] = r;
c ^= vme->key3[14] ^ vme->key3[13]
^ vme->key3[12] ^ vme->key3[11] ^ 0xff;
i = (vme->key3[10]%7 - vme->key3[9]%7) & 7; c = LROT(c, i);
c ^= 1 << (vme->key3[8] & 7);
c = vme_table2(c, vme->key3[vme->key3[7]], vme->main_key);
c = vme_table2(c, vme->key3[vme->key3[6]], vme->main_key);
c = ((c + vme->key3[5]) * vme->mul[vme->key3[4]]) & 0xff;
mbk_pos = (vme->rand_byte1<<8 | vme->key3[2]) & (VME_MBK_SIZE - 1);
c ^= vme->mbk1[mbk_pos] ^ vme->mbk2[mbk_pos] ^ vme->mbk3[mbk_pos]
^ vme->mbk4[mbk_pos] ^ vme->key3[3] ^ vme->rand_byte2 ^ 0xff;
c = vme_table2(c, vme->key3[1], vme->main_key);
c ^= vme->key3[0];
r = vme->rand_byte1;
SWAP(vme->perm1[r], vme->perm1[c]);
c = vme->perm1[r];
SWAP(vme->stk[buf_pos], vme->stk[rand_byte[5]]);
SWAP(vme->key1[buf_pos], vme->key1[rand_byte[6]]);
SWAP(vme->key2[buf_pos], vme->key2[rand_byte[7]]);
if (vme->num_funcs > 1) {
SWAP(vme->func_order[rand_func[0]], vme->func_order[rand_func[1]]);
SWAP(vme->key_order[rand_func[2]], vme->key_order[rand_func[3]]);
}
if (vme->secret_size > 0) {
SWAP(vme->mbk1[mbk_pos], vme->mbk1[rand_word[4]]);
SWAP(vme->mbk2[mbk_pos], vme->mbk2[rand_word[5]]);
SWAP(vme->mbk3[mbk_pos], vme->mbk3[rand_word[6]]);
SWAP(vme->mbk4[mbk_pos], vme->mbk4[rand_word[7]]);
}
auth_sum += c;
last_plain_byte = c;
last_cipher_byte = curr_cipher_byte;
buf_pos = (buf_pos + 1) & (VME_BUF_SIZE - 1);
vme->main_key++;
putc(c, out_file);
}
vme_calc_code("Transaction Code", trans_sum);
vme_calc_code("Authentication Number", auth_sum);
} /* vme02_decrypt */
/* VME 2002 fast mode decrypt */
static void vme02_fastdecrypt(FILE *data_file, FILE *out_file,
struct vme_state *vme)
{
int c, i, r, buf_pos, mbk_pos, file_pos;
int curr_cipher_byte, last_cipher_byte, last_plain_byte;
int auth_sum, trans_sum;
unsigned rand_state;
unsigned char rand_byte[8], rand_func[4];
unsigned short rand_word[8];
fseek(data_file, VME_BUF_SIZE, SEEK_SET);
file_pos = mbk_pos = 0;
last_plain_byte = 0xaa;
last_cipher_byte = 0x55;
auth_sum = trans_sum = vme->stk_sum;
while ( (c = getc(data_file)) != EOF ) {
trans_sum += c;
rand_state = vme->main_key + vme->key_sum
+ last_plain_byte + last_cipher_byte;
vme->rand_byte1 = VME_RAND(rand_state) & 0xff;
for (i = 0; i < 7; i++)
rand_byte[i] = VME_RAND(rand_state) & 0xff;
vme->rand_byte2 = VME_RAND(rand_state) & 0xff;
if (vme->num_funcs > 1)
for (i = 0; i < 4; i++)
rand_func[i] = VME_RAND(rand_state) % vme->num_funcs;
if (vme->secret_size > 0) {
for (i = 0; i < 8; i++)
rand_word[i] = VME_RAND15(rand_state);
}
else {
for (i = 0; i < 4; i++)
rand_word[i] = file_pos;
}
buf_pos = file_pos & (VME_BUF_SIZE - 1);
vme->key3[0] = vme->rmbk1[buf_pos] ^ vme->mbk1[rand_word[0]];
vme->key3[1] = last_plain_byte ^ vme->rand_byte2;
vme->key3[2] = vme->stk[buf_pos];
vme->key3[3] = vme->key1[buf_pos];
vme->key3[4] = vme->key2[buf_pos];
vme->key3[5] = last_cipher_byte ^ vme->rand_byte2;
vme->key3[6] = rand_byte[4] & 0xf;
vme->key3[7] = vme->rand_byte1 & 0xf;
vme->key3[8] = rand_byte[3];
vme->key3[9] = rand_byte[4];
vme->key3[10] = rand_byte[1];
vme->key3[11] = rand_byte[2];
vme->key3[12] = vme->rand_byte2;
vme->key3[13] = vme->rmbk1[buf_pos] ^ vme->mbk2[rand_word[1]];
vme->key3[14] = vme->rmbk1[buf_pos] ^ vme->mbk3[rand_word[2]];
vme->key3[15] = vme->rmbk1[buf_pos] ^ vme->mbk4[rand_word[3]];
for (i = vme->num_funcs - 1; i >= 0; i--)
c = vme_table1(c, vme->func_order[i], vme->key_order[i], vme);
c ^= vme->key3[0];
r = vme->rand_byte1;
SWAP(vme->perm1[r], vme->perm1[c]);
c = vme->perm1[r];
auth_sum += c; vme->main_key++; putc(c, out_file);
SWAP(vme->stk[buf_pos], vme->stk[rand_byte[5]]);
SWAP(vme->key1[buf_pos], vme->key1[rand_byte[6]]);
if (vme->num_funcs > 1) {
SWAP(vme->func_order[rand_func[0]], vme->func_order[rand_func[1]]);
SWAP(vme->key_order[rand_func[2]], vme->key_order[rand_func[3]]);
}
if (vme->secret_size > 0) {
SWAP(vme->mbk1[mbk_pos], vme->mbk1[rand_word[4]]);
SWAP(vme->mbk2[mbk_pos], vme->mbk2[rand_word[5]]);
SWAP(vme->mbk3[mbk_pos], vme->mbk3[rand_word[6]]);
SWAP(vme->mbk4[mbk_pos], vme->mbk4[rand_word[7]]);
}
if ((c = getc(data_file)) == EOF) break; trans_sum += c;
for (i = vme->num_funcs - 1; i >= 0; i--)
c = vme_table1(c, vme->func_order[i], vme->key_order[i], vme);
c = vme_table2(c, vme->key3[1], vme->main_key);
auth_sum += c; vme->main_key++; putc(c, out_file);
if ((c = getc(data_file)) == EOF) break; trans_sum += c;
for (i = vme->num_funcs - 1; i >= 0; i--)
c = vme_table1(c, vme->func_order[i], vme->key_order[i], vme);
mbk_pos = (vme->rand_byte1<<8 | vme->key3[2]) & (VME_MBK_SIZE - 1);
c ^= vme->mbk1[mbk_pos] ^ vme->mbk2[mbk_pos]
^ vme->mbk3[mbk_pos] ^ vme->mbk4[mbk_pos];
auth_sum += c; vme->main_key++; putc(c, out_file);
if ((c = getc(data_file)) == EOF) break; trans_sum += c;
for (i = vme->num_funcs - 1; i >= 0; i--)
c = vme_table1(c, vme->func_order[i], vme->key_order[i], vme);
c ^= vme->rand_byte2 ^ vme->key3[3] ^ 0xff;
auth_sum += c; vme->main_key++; putc(c, out_file);
if ((c = getc(data_file)) == EOF) break; trans_sum += c;
for (i = vme->num_funcs - 1; i >= 0; i--)
c = vme_table1(c, vme->func_order[i], vme->key_order[i], vme);
c = (c * vme->mul[vme->key3[4]]) & 0xff;
auth_sum += c; vme->main_key++; putc(c, out_file);
if ((c = getc(data_file)) == EOF) break; trans_sum += c;
for (i = vme->num_funcs - 1; i >= 0; i--)
c = vme_table1(c, vme->func_order[i], vme->key_order[i], vme);
c = (c + vme->key3[5]) & 0xff;
auth_sum += c; vme->main_key++; putc(c, out_file);
if ((c = getc(data_file)) == EOF) break; trans_sum += c;
for (i = vme->num_funcs - 1; i >= 0; i--)
c = vme_table1(c, vme->func_order[i], vme->key_order[i], vme);
c = vme_table2(c, vme->key3[vme->key3[6]], vme->main_key);
auth_sum += c; vme->main_key++; putc(c, out_file);
if ((c = getc(data_file)) == EOF) break; trans_sum += c;
for (i = vme->num_funcs - 1; i >= 0; i--)
c = vme_table1(c, vme->func_order[i], vme->key_order[i], vme);
c = vme_table2(c, vme->key3[vme->key3[7]], vme->main_key);
auth_sum += c; vme->main_key++; putc(c, out_file);
if ((c = getc(data_file)) == EOF) break; trans_sum += c;
for (i = vme->num_funcs - 1; i >= 0; i--)
c = vme_table1(c, vme->func_order[i], vme->key_order[i], vme);
c ^= 1 << (vme->key3[8] & 0x7);
auth_sum += c; vme->main_key++; putc(c, out_file);
if ((c = getc(data_file)) == EOF) break; trans_sum += c;
for (i = vme->num_funcs - 1; i >= 0; i--)
c = vme_table1(c, vme->func_order[i], vme->key_order[i], vme);
r = vme->key3[9] % 7 + 1; c = RROT(c, r);
auth_sum += c; vme->main_key++; putc(c, out_file);
if ((c = getc(data_file)) == EOF) break; trans_sum += c;
for (i = vme->num_funcs - 1; i >= 0; i--)
c = vme_table1(c, vme->func_order[i], vme->key_order[i], vme);
r = vme->key3[10] % 7 + 1; c = LROT(c, r);
auth_sum += c; vme->main_key++; putc(c, out_file);
if ((c = getc(data_file)) == EOF) break; trans_sum += c;
for (i = vme->num_funcs - 1; i >= 0; i--)
c = vme_table1(c, vme->func_order[i], vme->key_order[i], vme);
c ^= vme->key3[11];
auth_sum += c; vme->main_key++; putc(c, out_file);
if ((c = getc(data_file)) == EOF) break; trans_sum += c;
for (i = vme->num_funcs - 1; i >= 0; i--)
c = vme_table1(c, vme->func_order[i], vme->key_order[i], vme);
c ^= vme->key3[12] ^ 0xff;
auth_sum += c; vme->main_key++; putc(c, out_file);
if ((c = getc(data_file)) == EOF) break; trans_sum += c;
for (i = vme->num_funcs - 1; i >= 0; i--)
c = vme_table1(c, vme->func_order[i], vme->key_order[i], vme);
c ^= vme->key3[13];
auth_sum += c; vme->main_key++; putc(c, out_file);
if ((c = getc(data_file)) == EOF) break; trans_sum += c;
for (i = vme->num_funcs - 1; i >= 0; i--)
c = vme_table1(c, vme->func_order[i], vme->key_order[i], vme);
c ^= vme->key3[14];
auth_sum += c; vme->main_key++; putc(c, out_file);
if ((c = getc(data_file)) == EOF) break; trans_sum += c;
curr_cipher_byte = c;
for (i = vme->num_funcs - 1; i >= 0; i--)
c = vme_table1(c, vme->func_order[i], vme->key_order[i], vme);
c = vme->invperm2[c ^ vme->key3[15]];
r = rand_byte[0];
SWAP(vme->perm2[r], vme->perm2[c]);
vme->invperm2[ vme->perm2[c] ] = c;
vme->invperm2[ vme->perm2[r] ] = r;
last_plain_byte = c;
last_cipher_byte = curr_cipher_byte;
auth_sum += c; vme->main_key++; putc(c, out_file);
file_pos = (file_pos + 0x10) & (VME_MBK_SIZE - 1);
}
vme_calc_code("Transaction Code", trans_sum);
vme_calc_code("Authentication Number", auth_sum);
} /* vme02_fastdecrypt */
/* A small table of functions */
static int vme_table1(int c, int n, int k, struct vme_state *vme)
{
int i;
k = vme->key3[k];
if (n == 9) {
n = k >> 4;
k = vme->key3[k & 0xf];
}
switch (n) {
case 0: c = vme_table2(c, k, vme->main_key); break;
case 1:
i = (vme->rand_byte1<<8 | k) & (VME_MBK_SIZE - 1);
c ^= vme->mbk1[i] ^ vme->mbk2[i] ^ vme->mbk3[i] ^ vme->mbk4[i];
break;
case 2: c ^= k ^ vme->rand_byte2 ^ 0xff; break;
case 3: c = (c * vme->mul[k]) & 0xff; break;
case 4: c = (c + k) & 0xff; break;
case 5: c ^= 1 << (k & 7); break;
case 6: i = k % 7 + 1; c = RROT(c, i); break;
case 7: i = k % 7 + 1; c = LROT(c, i); break;
case 8: case 9: case 13: case 14: c ^= k; break;
case 10: case 11: case 12: c ^= k ^ 0xff; break;
case 15: break;
}
return c;
} /* vme_table1 */
/* A big table of functions */
static int vme_table2(int c, int n, unsigned rand)
{
int i;
rand += n;
VME_RAND(rand);
switch (n) {
case 1: c ^= 0x20 << (rand % 3); break;
case 2: c ^= (rand & 0x1f) + 2; break;
case 5: c ^= (rand & 0x0f) ^ 0x7f; break;
case 7: c ^= (rand & 0x3f) + 8; break;
case 8: c ^= (rand & 3) ^ 0x7f; break;
case 9: c ^= (rand & 1) ^ 0x3f; break;
case 11: c ^= (rand & 7) ^ 0x7f; break;
case 12: c ^= 4 << (rand % 6); break;
case 13: c ^= rand & 0x7f; break;
case 14: c ^= (rand & 0x1f) ^ 0xff; break;
case 16: c ^= 1 << (rand % 6); break;
case 17: c ^= 2 >> (rand & 1); break;
case 18: c ^= (rand & 0x0f) ^ 0x3f; break;
case 19: c ^= (rand & 0x3f) << 2; break;
case 20: c ^= rand & 0xff; break;
case 21: c ^= 0x20 >> (rand & 1); break;
case 23: c ^= (rand & 0x0f) ^ 0x80; break;
case 26: c ^= 0x80 >> (rand % 7); break;
case 27: c ^= (rand & 3) ^ 8; break;
case 28: c ^= rand & 1; break;
case 29: c ^= (rand & 0x3f) + 0x10; break;
case 31: c ^= (rand & 0x3f) + 0x20; break;
case 32: c ^= (rand & 0x0f) << 1; break;
case 33: c ^= 1 << (rand & 1); break;
case 34: c ^= (rand & 3) ^ 7; break;
case 35: c ^= 2 << (rand % 5); break;
case 36: c ^= (rand & 1) ^ 0x80; break;
case 37: c ^= 0x20 >> (rand % 6); break;
case 38: c ^= (rand & 1) ^ 0x20; break;
case 43: c ^= (rand & 0x1f) << 1; break;
case 45: c ^= (rand & 7) ^ 0x10; break;
case 48: c ^= (rand & 0x0f) << 2; break;
case 50: c ^= (rand & 1) ^ 0x40; break;
case 51: c ^= (rand & 1) ^ 0x0f; break;
case 52: c ^= (rand & 1) ^ 0x1f; break;
case 53: c ^= (rand & 7) ^ 0x3f; break;
case 55: c ^= 0x80 >> (rand & 7); break;
case 57: c ^= 0x80 >> (rand & 3); break;
case 58: c ^= rand & 0x1f; break;
case 59: c ^= (rand & 7) << 3; break;
case 60: c ^= (rand & 3) ^ 0x80; break;
case 61: c ^= (rand & 0x7f) ^ 0xff; break;
case 62: c ^= rand & 7; break;
case 63: c ^= 4 << (rand % 3); break;
case 65: c ^= 4 << (rand & 1); break;
case 66: c ^= (rand & 0x7f) + 8; break;
case 67: c ^= (rand & 0x1f) + 4; break;
case 68: c ^= (rand & 3) << 1; break;
case 69: c ^= (rand & 0x1f) ^ 0x7f; break;
case 70: c ^= (rand & 3) ^ 4; break;
case 71: c ^= (rand & 7) ^ 0x80; break;
case 74: c ^= (rand & 3) << 2; break;
case 75: c ^= (rand & 0x7f) + 0x20; break;
case 76: c ^= 4 << (rand & 3); break;
case 79: c ^= (rand & 7) << 1; break;
case 80: c ^= (rand & 0x7f) << 1; break;
case 81: c ^= 1 << (rand % 5); break;
case 84: c ^= (rand & 7) ^ 0xff; break;
case 87: c ^= (rand & 3) ^ 3; break;
case 88: c ^= (rand & 0x7f) + 2; break;
case 91: c ^= (rand & 1) ^ 1; break;
case 92: c ^= (rand & 3) ^ 0xff; break;
case 93: c ^= (rand & 0x3f) << 1; break;
case 94: c ^= (rand & 3) ^ 0x40; break;
case 95: c ^= (rand & 3) << 3; break;
case 97: c ^= 0x40 >> (rand % 5); break;
case 98: c ^= (rand & 3) + 2; break;
case 100: c ^= 1 << (rand % 3); break;
case 101: c ^= (rand & 7) ^ 0x1f; break;
case 102: c ^= 2 << (rand & 3); break;
case 103: c ^= (rand & 0x0f) + 2; break;
case 104: c ^= 0x20 >> (rand & 3); break;
case 105: c ^= 0x40 >> (rand % 3); break;
case 106: c ^= 1 << (rand & 7); break;
case 107: c ^= (rand & 0x0f) + 4; break;
case 108: c ^= (rand & 0x7f) + 4; break;
case 109: c ^= (rand & 0x1f) << 3; break;
case 111: c ^= 8 << (rand & 3); break;
case 113: c ^= rand & 0x0f; break;
case 116: c ^= 2 << (rand & 1); break;
case 117: c ^= (rand & 3) ^ 0x3f; break;
case 119: c ^= 0x10 >> (rand % 5); break;
case 120: c ^= (rand & 1) ^ 0x10; break;
case 121: c ^= 0x10 >> (rand & 3); break;
case 124: c ^= 0x10 << (rand & 1); break;
case 125: c ^= (rand & 0x0f) + 8; break;
case 126: c ^= (rand & 0x0f) << 4; break;
case 128: c ^= 0x10 << (rand % 3); break;
case 129: c ^= (rand & 1) << 1; break;
case 130: c ^= (rand & 0x7f) ^ 0x7f; break;
case 131: c ^= (rand & 0x1f) ^ 0x80; break;
case 132: c ^= 8 << (rand % 5); break;
case 133: c ^= (rand & 0x0f) ^ 0x1f; break;
case 135: c ^= 0x20 >> (rand % 5); break;
case 137: c ^= (rand & 0x3f) ^ 0x40; break;
case 138: c ^= rand & 3; break;
case 139: c ^= (rand & 1) ^ 4; break;
case 140: c ^= (rand & 3) ^ 0x0f; break;
case 141: c ^= (rand & 3) ^ 0x20; break;
case 142: c ^= (rand & 7) ^ 0x0f; break;
case 143: c ^= (rand & 1) << 4; break;
case 144: c ^= (rand & 0x1f) + 0x10; break;
case 145: c ^= (rand & 7) ^ 0x20; break;
case 147: c ^= 0x20 >> (rand % 3); break;
case 152: c ^= (rand & 0x0f) << 3; break;
case 153: c ^= 8 << (rand % 3); break;
case 156: c ^= 0x40 << (rand & 1); break;
case 157: c ^= (rand & 0x1f) ^ 0x40; break;
case 158: c ^= 8 << (rand & 1); break;
case 159: c ^= 0x80 >> (rand % 3); break;
case 160: c ^= (rand & 1) << 3; break;
case 161: c ^= (rand & 0x0f) ^ 0x20; break;
case 166: c ^= 0x80 >> (rand % 6); break;
case 167: c ^= (rand & 0x3f) ^ 0xff; break;
case 168: c ^= (rand & 7) + 4; break;
case 169: c ^= (rand & 0x7f) ^ 0x80; break;
case 170: c ^= 8 >> (rand & 1); break;
case 171: c ^= (rand & 3) ^ 0x1f; break;
case 172: c ^= 4 << (rand % 5); break;
case 173: c ^= (rand & 7) << 2; break;
case 175: c ^= (rand & 1) ^ 8; break;
case 177: c ^= (rand & 0xff) ^ 0xff; break;
case 179: c ^= (rand & 0x1f) ^ 0x20; break;
case 181: c ^= 2 << (rand % 3); break;
case 182: c ^= (rand & 3) << 4; break;
case 188: c ^= 0x40 >> (rand % 7); break;
case 189: c ^= (rand & 3) ^ 0x10; break;
case 190: c ^= (rand & 1) ^ 0x7f; break;
case 193: c ^= (rand & 7) << 4; break;
case 194: c ^= 8 >> (rand % 3); break;
case 195: c ^= (rand & 1) ^ 2; break;
case 196: c ^= 0x10 >> (rand & 1); break;
case 197: c ^= 0x40 >> (rand % 6); break;
case 199: c ^= (rand & 7) + 2; break;
case 200: c ^= (rand & 0x7f) + 0x40; break;
case 201: c ^= 2 << (rand % 6); break;
case 204: c ^= 0x40 >> (rand & 1); break;
case 205: c ^= (rand & 7) ^ 8; break;
case 206: c ^= 1 << (rand & 3); break;
case 208: c ^= (rand & 1) ^ 3; break;
case 209: c ^= rand & 0x3f; break;
case 211: c ^= 0x20 << (rand & 1); break;
case 212: c ^= (rand & 0x3f) ^ 0x7f; break;
case 214: c ^= (rand & 0x1f) << 2; break;
case 215: c ^= (rand & 0x1f) ^ 0x3f; break;
case 216: c ^= 2 << (rand % 7); break;
case 218: c ^= (rand & 0x1f) ^ 0x1f; break;
case 221: c ^= (rand & 0x0f) ^ 0xff; break;
case 223: c ^= (rand & 0x3f) + 2; break;
case 224: c ^= (rand & 0x1f) + 8; break;
case 225: c ^= (rand & 0x7f) + 0x10; break;
case 226: c ^= (rand & 1) ^ 7; break;
case 228: c ^= 0x40 >> (rand & 3); break;
case 230: c ^= (rand & 0x3f) + 4; break;
case 232: c ^= 0x80 >> (rand & 1); break;
case 233: c ^= 0x10 << (rand & 3); break;
case 235: c ^= (rand & 0x0f) ^ 0x10; break;
case 236: c ^= 4 >> (rand % 3); break;
case 237: c ^= (rand & 7) << 5; break;
case 238: c ^= 0x10 >> (rand % 3); break;
case 240: c ^= (rand & 1) << 2; break;
case 241: c ^= (rand & 0x0f) ^ 0x40; break;
case 242: c ^= (rand & 0x3f) ^ 0x80; break;
case 243: c ^= (rand & 1) ^ 0xff; break;
case 244: c ^= 1 << (rand % 7); break;
case 246: c ^= (rand & 0x0f) ^ 0x0f; break;
case 248: c ^= 4 >> (rand & 1); break;
case 249: c ^= (rand & 7) ^ 0x40; break;
case 250: c ^= 0x80 >> (rand % 5); break;
case 252: c ^= (rand & 7) ^ 7; break;
case 253: c ^= (rand & 0x3f) ^ 0x3f; break;
case 255: c ^= 8 >> (rand & 3); break;
case 0: case 180: i = 3 - (rand % 3); c = LROT(c, i); break;
case 3: case 202: i = 4 - (rand & 1); c = LROT(c, i); break;
case 4: case 89: i = 4 - (rand & 3); c = LROT(c, i); break;
case 6: case 184: i = 6 + (rand & 1); c = LROT(c, i); break;
case 10: case 64: i = 1 + (rand % 6); c = LROT(c, i); break;
case 15: case 46: i = 3 + (rand % 3); c = LROT(c, i); break;
case 22: case 176: i = 3 + (rand % 5); c = LROT(c, i); break;
case 24: case 40: i = 2 + (rand % 5); c = LROT(c, i); break;
case 25: case 164: i = 7 - (rand & 3); c = LROT(c, i); break;
case 30: case 220: i = 2 + (rand & 3); c = LROT(c, i); break;
case 39: case 44: i = 1 + (rand % 3); c = LROT(c, i); break;
case 41: case 155: i = 2 + (rand % 3); c = LROT(c, i); break;
case 42: case 146: i = 4 + (rand % 3); c = LROT(c, i); break;
case 47: case 56: i = 3 - (rand & 1); c = LROT(c, i); break;
case 49: case 186: i = 6 - (rand % 5); c = LROT(c, i); break;
case 54: case 251: i = 6 - (rand & 1); c = LROT(c, i); break;
case 72: case 77: i = 3 + (rand & 3); c = LROT(c, i); break;
case 73: case 149: i = 5 - (rand & 1); c = LROT(c, i); break;
case 78: case 90: i = 7 - (rand & 1); c = LROT(c, i); break;
case 82: case 165: i = 5 + (rand & 1); c = LROT(c, i); break;
case 83: case 198: i = 7 - (rand % 3); c = LROT(c, i); break;
case 85: case 191: i = 2 + (rand % 6); c = LROT(c, i); break;
case 86: case 187: i = 1 + (rand % 5); c = LROT(c, i); break;
case 96: case 162: i = 4 + (rand & 3); c = LROT(c, i); break;
case 99: case 254: i = 1 + (rand & 3); c = LROT(c, i); break;
case 110: case 245: i = 4 + (rand & 1); c = LROT(c, i); break;
case 112: case 234: i = 1 + (rand % 7); c = LROT(c, i); break;
case 114: case 154: i = 3 + (rand & 1); c = LROT(c, i); break;
case 115: case 150: i = 6 - (rand % 6); c = LROT(c, i); break;
case 118: case 148: i = 4 - (rand % 3); c = LROT(c, i); break;
case 122: case 227: i = 6 - (rand & 3); c = LROT(c, i); break;
case 123: case 127: i = 2 - (rand & 1); c = LROT(c, i); break;
case 134: case 247: i = 6 - (rand % 3); c = LROT(c, i); break;
case 136: case 231: i = 5 - (rand % 3); c = LROT(c, i); break;
case 151: case 207: i = 7 - (rand % 6); c = LROT(c, i); break;
case 163: case 219: i = 5 + (rand % 3); c = LROT(c, i); break;
case 174: case 222: i = 7 - (rand % 7); c = LROT(c, i); break;
case 178: case 239: i = 5 - (rand % 5); c = LROT(c, i); break;
case 183: case 185: i = 2 + (rand & 1); c = LROT(c, i); break;
case 192: case 210: i = 1 + (rand & 1); c = LROT(c, i); break;
case 203: case 213: i = 7 - (rand % 5); c = LROT(c, i); break;
case 217: case 229: i = 5 - (rand & 3); c = LROT(c, i); break;
}
return c;
} /* vme_table2 */