/*
* 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.
* 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.
*
* If you try to decrypt Meganet's old encrypted challenge files with this
* code, you'll get garbage. However, it's exactly the same garbage that
* you'll get if you decrypt the files with their shareware software. This
* is not due to the much-hyped "Date Limiting Algorithm" (see below for
* details). 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]", /* sender */
"[EMAIL PROTECTED]", /* recipient */
"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;
}
/* There are a number of incompatible changes between
the 2000 and 2002 versions. */
/* #define VME_2002 1 */
#define VME_NUM_PASS 4
#define VME_PASS_SIZE 0x40
#define VME_KEY_SIZE 0x10
#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_RAND8(r) ( (r)=((r)*0x0d+0x5f)&0xff )
struct vme_state {
int num_funcs, have_secret, key_xor, randb1, randb10;
unsigned main_key;
unsigned char func_order[VME_KEY_SIZE], key_order[VME_KEY_SIZE];
unsigned char key3[VME_KEY_SIZE];
unsigned char stk[VME_BUF_SIZE], key1[VME_BUF_SIZE], key2[VME_BUF_SIZE];
unsigned char perm1[VME_BUF_SIZE], perm2[VME_BUF_SIZE];
unsigned char invperm2[VME_BUF_SIZE], mul[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_decrypt_loop(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);
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);
vme_decrypt_loop(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) return 1;
fseek(config_file, 0, SEEK_SET);
rand_state = 0xff;
n = 0;
for (i = 0; i < VME_KEY_SIZE; 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 enrypted file is prefixed with a 256-byte header which contains
* the Specific Transaction Key (STK) and some encoded information.
* Instead of using the manufacturer-recommended procedure to decode
* the 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, 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 whole 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; j < VME_KEY_SIZE; j++)
if (!isdigit(date[j]))
isgood = 0;
for (j = 0; j < 14; j++)
if (!isdigit(time[j]))
isgood = 0;
if (!isgood) continue;
found = 1;
printf("Guessed header key: 0x%02x\n", i);
/* Meganet's VME software deliberately trashes the STK if it discovers
that the current date is not within the date limit. I don't. */
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 verion: %02d%02d\n", time[14], time[15]);
if (strncmp(file_id, "VVVVVVVVVVVVVVVV", 16) != 0)
printf("Warning: unsupported encryption mode\n");
if (strncmp(recip, "Global ", 16) != 0)
printf("Warning: unsupported recipient type\n");
}
if (!found) printf("Warning: couldn't find header key\n");
rand_state = 0x2d;
xor = 0x7b;
for (i = 0; i < VME_BUF_SIZE; i++)
xor ^= vme->stk[i] ^= VME_RAND8(rand_state);
vme->key_xor = xor;
return 0;
} /* vme_load_stk */
/*
* Use the passwords and file sizes to determine the 32-bit main_key
* and two other 16-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;
int data_size, secret_size;
unsigned sum, main_key, header_key, rand_state;
unsigned char sizes[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;
for (i = 0; i < VME_NUM_PASS; i++) {
for (j = 0; j < VME_PASS_SIZE && passwords[i][j] != '\0'; j++)
pass[i][j] = passwords[i][j];
for (; j < VME_PASS_SIZE; j++)
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. */
sum = 0;
for (i = 0; i < VME_NUM_PASS; i++)
for (j = 0; j < VME_PASS_SIZE; j++)
sum += pass[i][j];
rand_state = sum;
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;
header_key += VME_RAND8(rand_state);
}
rand_state = header_key + 0x61;
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)
secret_size = 0;
else {
fseek(secret_file, 0, SEEK_END);
secret_size = ftell(secret_file);
}
rand_state = 0x67;
sprintf(sizes, " %d %d ", data_size, secret_size);
for (i = strlen(sizes); i < VME_PASS_SIZE; i++)
sizes[i] = VME_RAND8(rand_state);
sum = 0x7f80;
for (i = 0; i < VME_PASS_SIZE; i++) {
sum += sizes[i];
for (j = 0; j < VME_NUM_PASS; j++)
sum += pass[j][i];
}
for (i = 0; i < VME_BUF_SIZE; i++)
sum += vme->stk[i];
rand_state = sum;
sum = vme->key_xor;
main_key = vme->key_xor << 6;
for (i = 0; i < VME_PASS_SIZE; i++) {
sum += (VME_RAND(rand_state) & 0xfffff) * vme->stk[i];
sum += (VME_RAND(rand_state) & 0xfffff) * vme->stk[i+0x40];
sum += (VME_RAND(rand_state) & 0xfffff) * vme->stk[i+0x80];
sum += (VME_RAND(rand_state) & 0xfffff) * vme->stk[i+0xc0];
sum += (VME_RAND(rand_state) & 0xfffff) * sizes[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;
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_xor += 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;
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;
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_xor + 0xf2;
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
* the secret_file. Also compute a reduced version.
*/
static void vme_mbk_init(FILE *secret_file, struct vme_state *vme)
{
int i, j, c;
int secret_size, rand_state;
rand_state = vme->main_key + 0xbd;
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)
secret_size = 0;
else {
fseek(secret_file, 0, SEEK_END);
secret_size = ftell(secret_file);
fseek(secret_file, 0, SEEK_SET);
}
#ifdef VME_2002
if (secret_size <= 0)
vme->have_secret = 0;
else if (secret_size <= 4*VME_MBK_SIZE) {
vme->have_secret = 1;
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 {
vme->have_secret = 1;
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 */
vme->have_secret = 1;
if (secret_size <= 0)
;
else if (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 {
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);
}
}
#endif
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 = VME_BUF_SIZE; j < VME_MBK_SIZE; j += VME_BUF_SIZE) {
vme->rmbk1[i] ^= vme->mbk1[i + j];
vme->rmbk2[i] ^= vme->mbk2[i + j];
vme->rmbk3[i] ^= vme->mbk3[i + j];
vme->rmbk4[i] ^= vme->mbk4[i + j];
}
}
} /* vme_mbk_init */
/*
* Actual encryption happens here.
*/
static void vme_decrypt_loop(FILE *data_file, FILE *out_file,
struct vme_state *vme)
{
int c, i;
int buf_pos, mbk_pos;
int curr_cipher_byte, last_cipher_byte, last_plain_byte;
int randb1, randb2, randb3, randb4, randb5;
int randb6, randb7, randb8, randb9, randb10;
int randf1, randf2, randf3, randf4;
int randw1, randw2, randw3, randw4;
int randw5, randw6, randw7, randw8;
unsigned rand_state;
fseek(data_file, VME_BUF_SIZE, SEEK_SET);
buf_pos = 0;
last_plain_byte = 0xaa;
last_cipher_byte = 0x55;
while ( (c = getc(data_file)) != EOF ) {
curr_cipher_byte = c;
rand_state = vme->main_key + vme->key_xor
+ last_plain_byte + last_cipher_byte + 0xdf2;
#ifndef VME_2002
randb10 = 0;
for (i = 0; i < 8; i++)
randb10 |= VME_RAND(rand_state) & (1 << i);
vme->randb10 = randb10;
#endif
vme->randb1 = randb1 = VME_RAND(rand_state) & 0xff;
randb2 = VME_RAND(rand_state) & 0xff;
randb3 = VME_RAND(rand_state) & 0xff;
randb4 = VME_RAND(rand_state) & 0xff;
randb5 = VME_RAND(rand_state) & 0xff;
randb6 = VME_RAND(rand_state) & 0xff;
randb7 = VME_RAND(rand_state) & 0xff;
randb8 = VME_RAND(rand_state) & 0xff;
randb9 = VME_RAND(rand_state) & 0xff;
#ifdef VME_2002
randb10 = randb1 & 1;
randb10 = (randb2 + randb10) & 2;
randb10 = (randb3 + randb10) & 4;
randb10 = (randb4 + randb10) & 8;
randb10 = (randb5 + randb10) & 0x10;
randb10 = (randb6 + randb10) & 0x20;
randb10 = (randb7 + randb10) & 0x40;
randb10 = (randb8 + randb10) & 0x80;
vme->randb10 = randb10 ^= randb9;
#endif
if (vme->num_funcs > 1) {
randf1 = VME_RAND(rand_state) % vme->num_funcs;
randf2 = VME_RAND(rand_state) % vme->num_funcs;
randf3 = VME_RAND(rand_state) % vme->num_funcs;
randf4 = VME_RAND(rand_state) % vme->num_funcs;
}
randw1 = VME_RAND(rand_state) & (VME_MBK_SIZE - 1);
randw2 = VME_RAND(rand_state) & (VME_MBK_SIZE - 1);
randw3 = VME_RAND(rand_state) & (VME_MBK_SIZE - 1);
randw4 = VME_RAND(rand_state) & (VME_MBK_SIZE - 1);
if (vme->have_secret) {
randw5 = VME_RAND(rand_state) & (VME_MBK_SIZE - 1);
randw6 = VME_RAND(rand_state) & (VME_MBK_SIZE - 1);
randw7 = VME_RAND(rand_state) & (VME_MBK_SIZE - 1);
randw8 = VME_RAND(rand_state) & (VME_MBK_SIZE - 1);
}
#ifdef VME_2002
vme->key3[0] = vme->rmbk1[buf_pos] ^ vme->mbk1[randw1];
vme->key3[1] = last_plain_byte ^ randb10;
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 ^ randb10;
vme->key3[6] = randb6 & 0xf;
vme->key3[7] = randb1 & 0xf;
vme->key3[8] = randb5;
vme->key3[9] = randb6;
vme->key3[10] = randb3;
vme->key3[11] = randb4;
vme->key3[12] = randb10;
vme->key3[13] = vme->rmbk2[buf_pos] ^ vme->mbk2[randw2];
vme->key3[14] = vme->rmbk3[buf_pos] ^ vme->mbk3[randw3];
vme->key3[15] = vme->rmbk4[buf_pos] ^ vme->mbk4[randw4];
#else /* VME 2000 */
vme->key3[0] = last_plain_byte;
vme->key3[1] = last_cipher_byte;
vme->key3[2] = randb10;
vme->key3[3] = randb1;
vme->key3[4] = randb2;
vme->key3[5] = randb5;
vme->key3[6] = randb6;
vme->key3[7] = randb4;
vme->key3[8] = randb3;
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[randw1];
vme->key3[13] = vme->rmbk2[buf_pos] ^ vme->mbk2[randw2];
vme->key3[14] = vme->rmbk3[buf_pos] ^ vme->mbk3[randw3];
vme->key3[15] = vme->rmbk4[buf_pos] ^ vme->mbk4[randw4];
#endif
for (i = vme->num_funcs - 1; i >= 0; i--)
c = vme_table1(c, vme->func_order[i], vme->key_order[i], vme);
#ifdef VME_2002
c = vme->invperm2[c ^ vme->key3[15]];
SWAP(vme->perm2[randb2], vme->perm2[c]);
vme->invperm2[ vme->perm2[c] ] = c;
vme->invperm2[ vme->perm2[randb2] ] = randb2;
c ^= vme->key3[14] ^ vme->key3[13] ^ randb10 ^ randb4 ^ 0xff;
i = randb3 % 7; c = LROT(c, i);
i = randb6 % 7; c = RROT(c, i);
c ^= 1 << (randb5 & 7);
c = vme_table2(c, vme->key3[randb1 & 0xf], vme->main_key);
c = vme_table2(c, vme->key3[randb6 & 0xf], vme->main_key);
c = ((c + vme->key3[5]) * vme->mul[vme->key3[4]]) & 0xff;
mbk_pos = (randb1<<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] ^ randb10 ^ 0xff;
c = vme_table2(c, vme->key3[1], vme->main_key);
c ^= vme->key3[0];
SWAP(vme->perm1[randb1], vme->perm1[c]);
c = vme->perm1[randb1];
#else /* VME 2000 */
c = vme->invperm2[c];
SWAP(vme->perm2[randb2], vme->perm2[c]);
vme->invperm2[ vme->perm2[c] ] = c;
vme->invperm2[ vme->perm2[randb2] ] = randb2;
c ^= randb10 ^ randb4 ^ 0xff;
i = randb3 % 7; c = LROT(c, i);
i = randb6 % 7; c = RROT(c, i);
c ^= 1 << (randb5 & 7);
c = vme_table1(c, randb2 >> 4, randb1 & 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 = (randb1<<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] ^ randb10 ^ 0xff;
c = vme_table2(c, last_plain_byte, vme->main_key);
SWAP(vme->perm1[randb1], vme->perm1[c]);
c = vme->perm1[randb1];
#endif
SWAP(vme->stk[buf_pos], vme->stk[randb7]);
SWAP(vme->key1[buf_pos], vme->key1[randb8]);
SWAP(vme->key2[buf_pos], vme->key2[randb9]);
if (vme->num_funcs > 1) {
SWAP(vme->func_order[randf1], vme->func_order[randf2]);
SWAP(vme->key_order[randf3], vme->key_order[randf4]);
}
if (vme->have_secret) {
SWAP(vme->mbk1[mbk_pos], vme->mbk1[randw5]);
SWAP(vme->mbk2[mbk_pos], vme->mbk2[randw6]);
SWAP(vme->mbk3[mbk_pos], vme->mbk3[randw7]);
SWAP(vme->mbk4[mbk_pos], vme->mbk4[randw8]);
}
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_decrypt_loop */
/*
* 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->randb1<<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->randb10 ^ 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 0: i = 3 - (rand % 3); c = LROT(c, i); break;
case 1: c ^= 1 << (5 + (rand % 3)); break;
case 2: c ^= 2 + (rand & 0x1f); break;
case 3: i = 4 - (rand & 1); c = LROT(c, i); break;
case 4: i = 4 + (rand & 3); c = RROT(c, i); break;
case 5: c ^= 127 - (rand & 0xf); break;
case 6: i = 2 - (rand & 1); c = RROT(c, i); break;
case 7: c ^= 8 + (rand & 0x3f); break;
case 8: c ^= 127 - (rand & 3); break;
case 9: c ^= 63 - (rand & 1); break;
case 10: i = 7 - (rand % 6); c = RROT(c, i); break;
case 11: c ^= 127 - (rand & 7); break;
case 12: c ^= 1 << (2 + (rand % 6)); break;
case 13: c ^= (rand & 0x7f); break;
case 14: c ^= 255 - (rand & 0x1f); break;
case 15: i = 3 + (rand % 3); c = LROT(c, i); break;
case 16: c ^= 1 << (rand % 6); break;
case 17: c ^= 1 << (1 - (rand & 1)); break;
case 18: c ^= 63 - (rand & 0xf); break;
case 19: c ^= (rand & 0x3f) << 2; break;
case 20: c ^= (rand & 0xff); break;
case 21: c ^= 1 << (5 - (rand & 1)); break;
case 22: i = 3 + (rand % 5); c = LROT(c, i); break;
case 23: c ^= 128 + (rand & 0xf); break;
case 24: i = 2 + (rand % 5); c = LROT(c, i); break;
case 25: i = 7 - (rand & 3); c = LROT(c, i); break;
case 26: c ^= 1 << (7 - (rand % 7)); break;
case 27: c ^= 8 + (rand & 3); break;
case 28: c ^= (rand & 1); break;
case 29: c ^= 16 + (rand & 0x3f); break;
case 30: i = 2 + (rand & 3); c = LROT(c, i); break;
case 31: c ^= 32 + (rand & 0x3f); break;
case 32: c ^= (rand & 0xf) << 1; break;
case 33: c ^= 1 << (rand & 1); break;
case 34: c ^= 7 - (rand & 3); break;
case 35: c ^= 1 << (1 + (rand % 5)); break;
case 36: c ^= 128 + (rand & 1); break;
case 37: c ^= 1 << (5 - (rand % 6)); break;
case 38: c ^= 32 + (rand & 1); break;
case 39: i = 7 - (rand % 3); c = RROT(c, i); break;
case 40: i = 6 - (rand % 5); c = RROT(c, i); break;
case 41: i = 2 + (rand % 3); c = LROT(c, i); break;
case 42: i = 4 + (rand % 3); c = LROT(c, i); break;
case 43: c ^= (rand & 0x1f) << 1; break;
case 44: i = 1 + (rand % 3); c = LROT(c, i); break;
case 45: c ^= 16 + (rand & 7); break;
case 46: i = 5 - (rand % 3); c = RROT(c, i); break;
case 47: i = 3 - (rand & 1); c = LROT(c, i); break;
case 48: c ^= (rand & 0xf) << 2; break;
case 49: i = 6 - (rand % 5); c = LROT(c, i); break;
case 50: c ^= 64 + (rand & 1); break;
case 51: c ^= 15 - (rand & 1); break;
case 52: c ^= 31 - (rand & 1); break;
case 53: c ^= 63 - (rand & 7); break;
case 54: i = 2 + (rand & 1); c = RROT(c, i); break;
case 55: c ^= 1 << (7 - (rand & 7)); break;
case 56: i = 5 + (rand & 1); c = RROT(c, i); break;
case 57: c ^= 1 << (7 - (rand & 3)); break;
case 58: c ^= (rand & 0x1f); break;
case 59: c ^= (rand & 7) << 3; break;
case 60: c ^= 128 + (rand & 3); break;
case 61: c ^= 255 - (rand & 0x7f); break;
case 62: c ^= (rand & 7); break;
case 63: c ^= 1 << (2 + (rand % 3)); break;
case 64: i = 1 + (rand % 6); c = LROT(c, i); break;
case 65: c ^= 1 << (2 + (rand & 1)); break;
case 66: c ^= 8 + (rand & 0x7f); break;
case 67: c ^= 4 + (rand & 0x1f); break;
case 68: c ^= (rand & 3) << 1; break;
case 69: c ^= 127 - (rand & 0x1f); break;
case 70: c ^= 4 + (rand & 3); break;
case 71: c ^= 128 + (rand & 7); break;
case 72: i = 5 - (rand & 3); c = RROT(c, i); break;
case 73: i = 5 - (rand & 1); c = LROT(c, i); break;
case 74: c ^= (rand & 3) << 2; break;
case 75: c ^= 32 + (rand & 0x7f); break;
case 76: c ^= 1 << (2 + (rand & 3)); break;
case 77: i = 3 + (rand & 3); c = LROT(c, i); break;
case 78: i = 1 + (rand & 1); c = RROT(c, i); break;
case 79: c ^= (rand & 7) << 1; break;
case 80: c ^= (rand & 0x7f) << 1; break;
case 81: c ^= 1 << (rand % 5); break;
case 82: i = 5 + (rand & 1); c = LROT(c, i); break;
case 83: i = 1 + (rand % 3); c = RROT(c, i); break;
case 84: c ^= 255 - (rand & 7); break;
case 85: i = 6 - (rand % 6); c = RROT(c, i); break;
case 86: i = 1 + (rand % 5); c = LROT(c, i); break;
case 87: c ^= 3 - (rand & 3); break;
case 88: c ^= 2 + (rand & 0x7f); break;
case 89: i = 4 - (rand & 3); c = LROT(c, i); break;
case 90: i = 7 - (rand & 1); c = LROT(c, i); break;
case 91: c ^= 1 - (rand & 1); break;
case 92: c ^= 255 - (rand & 3); break;
case 93: c ^= (rand & 0x3f) << 1; break;
case 94: c ^= 64 + (rand & 3); break;
case 95: c ^= (rand & 3) << 3; break;
case 96: i = 4 + (rand & 3); c = LROT(c, i); break;
case 97: c ^= 1 << (6 - (rand % 5)); break;
case 98: c ^= 2 + (rand & 3); break;
case 99: i = 7 - (rand & 3); c = RROT(c, i); break;
case 100: c ^= 1 << (rand % 3); break;
case 101: c ^= 31 - (rand & 7); break;
case 102: c ^= 1 << (1 + (rand & 3)); break;
case 103: c ^= 2 + (rand & 0xf); break;
case 104: c ^= 1 << (5 - (rand & 3)); break;
case 105: c ^= 1 << (6 - (rand % 3)); break;
case 106: c ^= 1 << (rand & 7); break;
case 107: c ^= 4 + (rand & 0xf); break;
case 108: c ^= 4 + (rand & 0x7f); break;
case 109: c ^= (rand & 0x1f) << 3; break;
case 110: i = 4 - (rand & 1); c = RROT(c, i); break;
case 111: c ^= 1 << (3 + (rand & 3)); break;
case 112: i = 1 + (rand % 7); c = LROT(c, i); break;
case 113: c ^= (rand & 0xf); break;
case 114: i = 5 - (rand & 1); c = RROT(c, i); break;
case 115: i = 6 - (rand % 6); c = LROT(c, i); break;
case 116: c ^= 1 << (1 + (rand & 1)); break;
case 117: c ^= 63 - (rand & 3); break;
case 118: i = 4 - (rand % 3); c = LROT(c, i); break;
case 119: c ^= 1 << (4 - (rand % 5)); break;
case 120: c ^= 16 + (rand & 1); break;
case 121: c ^= 1 << (4 - (rand & 3)); break;
case 122: i = 6 - (rand & 3); c = LROT(c, i); break;
case 123: i = 6 + (rand & 1); c = RROT(c, i); break;
case 124: c ^= 1 << (4 + (rand & 1)); break;
case 125: c ^= 8 + (rand & 0xf); break;
case 126: c ^= (rand & 0xf) << 4; break;
case 127: i = 2 - (rand & 1); c = LROT(c, i); break;
case 128: c ^= 1 << (4 + (rand % 3)); break;
case 129: c ^= (rand & 1) << 1; break;
case 130: c ^= 127 - (rand & 0x7f); break;
case 131: c ^= 128 + (rand & 0x1f); break;
case 132: c ^= 1 << (3 + (rand % 5)); break;
case 133: c ^= 31 - (rand & 0xf); break;
case 134: i = 2 + (rand % 3); c = RROT(c, i); break;
case 135: c ^= 1 << (5 - (rand % 5)); break;
case 136: i = 5 - (rand % 3); c = LROT(c, i); break;
case 137: c ^= 64 + (rand & 0x3f); break;
case 138: c ^= (rand & 3); break;
case 139: c ^= 4 + (rand & 1); break;
case 140: c ^= 15 - (rand & 3); break;
case 141: c ^= 32 + (rand & 3); break;
case 142: c ^= 15 - (rand & 7); break;
case 143: c ^= (rand & 1) << 4; break;
case 144: c ^= 16 + (rand & 0x1f); break;
case 145: c ^= 32 + (rand & 7); break;
case 146: i = 4 - (rand % 3); c = RROT(c, i); break;
case 147: c ^= 1 << (5 - (rand % 3)); break;
case 148: i = 4 + (rand % 3); c = RROT(c, i); break;
case 149: i = 3 + (rand & 1); c = RROT(c, i); break;
case 150: i = 2 + (rand % 6); c = RROT(c, i); break;
case 151: i = 1 + (rand % 6); c = RROT(c, i); break;
case 152: c ^= (rand & 0xf) << 3; break;
case 153: c ^= 1 << (3 + (rand % 3)); break;
case 154: i = 3 + (rand & 1); c = LROT(c, i); break;
case 155: i = 6 - (rand % 3); c = RROT(c, i); break;
case 156: c ^= 1 << (6 + (rand & 1)); break;
case 157: c ^= 64 + (rand & 0x1f); break;
case 158: c ^= 1 << (3 + (rand & 1)); break;
case 159: c ^= 1 << (7 - (rand % 3)); break;
case 160: c ^= (rand & 1) << 3; break;
case 161: c ^= 32 + (rand & 0xf); break;
case 162: i = 4 - (rand & 3); c = RROT(c, i); break;
case 163: i = 3 - (rand % 3); c = RROT(c, i); break;
case 164: i = 1 + (rand & 3); c = RROT(c, i); break;
case 165: i = 3 - (rand & 1); c = RROT(c, i); break;
case 166: c ^= 1 << (7 - (rand % 6)); break;
case 167: c ^= 255 - (rand & 0x3f); break;
case 168: c ^= 4 + (rand & 7); break;
case 169: c ^= 128 + (rand & 0x7f); break;
case 170: c ^= 1 << (3 - (rand & 1)); break;
case 171: c ^= 31 - (rand & 3); break;
case 172: c ^= 1 << (2 + (rand % 5)); break;
case 173: c ^= (rand & 7) << 2; break;
case 174: i = 1 + (rand % 7); c = RROT(c, i); break;
case 175: c ^= 8 + (rand & 1); break;
case 176: i = 5 - (rand % 5); c = RROT(c, i); break;
case 177: c ^= 255 - (rand & 0xff); break;
case 178: i = 5 - (rand % 5); c = LROT(c, i); break;
case 179: c ^= 32 + (rand & 0x1f); break;
case 180: i = 5 + (rand % 3); c = RROT(c, i); break;
case 181: c ^= 1 << (1 + (rand % 3)); break;
case 182: c ^= (rand & 3) << 4; break;
case 183: i = 2 + (rand & 1); c = LROT(c, i); break;
case 184: i = 6 + (rand & 1); c = LROT(c, i); break;
case 185: i = 6 - (rand & 1); c = RROT(c, i); break;
case 186: i = 2 + (rand % 5); c = RROT(c, i); break;
case 187: i = 7 - (rand % 5); c = RROT(c, i); break;
case 188: c ^= 1 << (6 - (rand % 7)); break;
case 189: c ^= 16 + (rand & 3); break;
case 190: c ^= 127 - (rand & 1); break;
case 191: i = 2 + (rand % 6); c = LROT(c, i); break;
case 192: i = 7 - (rand & 1); c = RROT(c, i); break;
case 193: c ^= (rand & 7) << 4; break;
case 194: c ^= 1 << (3 - (rand % 3)); break;
case 195: c ^= 2 + (rand & 1); break;
case 196: c ^= 1 << (4 - (rand & 1)); break;
case 197: c ^= 1 << (6 - (rand % 6)); break;
case 198: i = 7 - (rand % 3); c = LROT(c, i); break;
case 199: c ^= 2 + (rand & 7); break;
case 200: c ^= 64 + (rand & 0x7f); break;
case 201: c ^= 1 << (1 + (rand % 6)); break;
case 202: i = 4 + (rand & 1); c = RROT(c, i); break;
case 203: i = 1 + (rand % 5); c = RROT(c, i); break;
case 204: c ^= 1 << (6 - (rand & 1)); break;
case 205: c ^= 8 + (rand & 7); break;
case 206: c ^= 1 << (rand & 3); break;
case 207: i = 7 - (rand % 6); c = LROT(c, i); break;
case 208: c ^= 3 - (rand & 1); break;
case 209: c ^= (rand & 0x3f); break;
case 210: i = 1 + (rand & 1); c = LROT(c, i); break;
case 211: c ^= 1 << (5 + (rand & 1)); break;
case 212: c ^= 127 - (rand & 0x3f); break;
case 213: i = 7 - (rand % 5); c = LROT(c, i); break;
case 214: c ^= (rand & 0x1f) << 2; break;
case 215: c ^= 63 - (rand & 0x1f); break;
case 216: c ^= 1 << (1 + (rand % 7)); break;
case 217: i = 5 - (rand & 3); c = LROT(c, i); break;
case 218: c ^= 31 - (rand & 0x1f); break;
case 219: i = 5 + (rand % 3); c = LROT(c, i); break;
case 220: i = 6 - (rand & 3); c = RROT(c, i); break;
case 221: c ^= 255 - (rand & 0xf); break;
case 222: i = 7 - (rand % 7); c = LROT(c, i); break;
case 223: c ^= 2 + (rand & 0x3f); break;
case 224: c ^= 8 + (rand & 0x1f); break;
case 225: c ^= 16 + (rand & 0x7f); break;
case 226: c ^= 7 - (rand & 1); break;
case 227: i = 2 + (rand & 3); c = RROT(c, i); break;
case 228: c ^= 1 << (6 - (rand & 3)); break;
case 229: i = 3 + (rand & 3); c = RROT(c, i); break;
case 230: c ^= 4 + (rand & 0x3f); break;
case 231: i = 3 + (rand % 3); c = RROT(c, i); break;
case 232: c ^= 1 << (7 - (rand & 1)); break;
case 233: c ^= 1 << (4 + (rand & 3)); break;
case 234: i = 7 - (rand % 7); c = RROT(c, i); break;
case 235: c ^= 16 + (rand & 0xf); break;
case 236: c ^= 1 << (2 - (rand % 3)); break;
case 237: c ^= (rand & 7) << 5; break;
case 238: c ^= 1 << (4 - (rand % 3)); break;
case 239: i = 3 + (rand % 5); c = RROT(c, i); break;
case 240: c ^= (rand & 1) << 2; break;
case 241: c ^= 64 + (rand & 0xf); break;
case 242: c ^= 128 + (rand & 0x3f); break;
case 243: c ^= 255 - (rand & 1); break;
case 244: c ^= 1 << (rand % 7); break;
case 245: i = 4 + (rand & 1); c = LROT(c, i); break;
case 246: c ^= 15 - (rand & 0xf); break;
case 247: i = 6 - (rand % 3); c = LROT(c, i); break;
case 248: c ^= 1 << (2 - (rand & 1)); break;
case 249: c ^= 64 + (rand & 7); break;
case 250: c ^= 1 << (7 - (rand % 5)); break;
case 251: i = 6 - (rand & 1); c = LROT(c, i); break;
case 252: c ^= 7 - (rand & 7); break;
case 253: c ^= 63 - (rand & 0x3f); break;
case 254: i = 1 + (rand & 3); c = LROT(c, i); break;
case 255: c ^= 1 << (3 - (rand & 3)); break;
}
return c;
} /* vme_table2 */