/*
* 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.
*
* I've added support for the "Targeted Delivery System." Meganet claims
* that this 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.
*
* 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]",      /* 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;
} /* main */

/* 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_RAND4(r)  ( (r)=((r)*0xd+0xf)&0xf )
#define VME_RAND8(r)  ( (r)=((r)*0x0d+0x5f)&0xff )

struct vme_state {
  int num_funcs, have_secret, stk_xor, key_sum, randb1, randb10;
  unsigned main_key;
  unsigned char func_order[VME_KEY_SIZE], key_order[VME_KEY_SIZE];
  unsigned char key3[VME_KEY_SIZE], recipient[VME_KEY_SIZE];
  unsigned char stk[VME_BUF_SIZE], key1[VME_BUF_SIZE];
  unsigned char key2[VME_BUF_SIZE], perm1[VME_BUF_SIZE];
  unsigned char perm2[VME_BUF_SIZE], invperm2[VME_BUF_SIZE];
  unsigned char mul[VME_BUF_SIZE], rmbk[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 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;
    found = 1;

    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 verion: %02d%02d\n", time[14], time[15]);

    memcpy(vme->recipient, recip, VME_KEY_SIZE);
    if (strncmp(file_id, "VVVVVVVVVVVVVVVV", 16) != 0)
      printf("Warning: unsupported encryption mode\n");
  }
  if (!found) {
    printf("Warning: couldn't find header key\n");
    memset(vme->recipient, 0, VME_KEY_SIZE);
  }

  rand_state = 0x2d;
  xor = 0x7b;
  for (i = 0; i < VME_BUF_SIZE; i++)
    xor ^= vme->stk[i] ^= VME_RAND8(rand_state);
  vme->stk_xor = xor;
  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, recip_sum;
  int data_size, secret_size;
  unsigned sum, 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;
  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);
  }

  if (strncmp(vme->recipient, "Global          ", 16) == 0) {
    sprintf(key_str, " %d %d ", data_size, secret_size);
    recip_sum = 0xdf2;
  }
  else if (strncmp(vme->recipient+8, "Local   ", 8) == 0) {
    sprintf(key_str, " %d %d %.8s", data_size, 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, secret_size,
        vme->recipient);
    rand_state = 0x76593361;
    for (i = 0; i < 8; i++) {
      VME_RAND(rand_state);
      rand_state = vme->recipient[i]
          * vme->recipient[(VME_KEY_SIZE - 1) - i]
          * (rand_state % 0x7919);
      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 = 0x7f80;
  for (i = 0; i < VME_PASS_SIZE; i++) {
    sum += key_str[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->stk_xor;
  main_key = vme->stk_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) * 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;
  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;
  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_sum;
  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++) {
    c = vme->mbk1[i];
    for (j = VME_BUF_SIZE; j < VME_MBK_SIZE; j += VME_BUF_SIZE)
      c ^= vme->mbk1[i + j];
    vme->rmbk[i] = c;
  }
} /* vme_mbk_init */

/*
* Actual decryption 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_sum
        + last_plain_byte + last_cipher_byte;

#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;
    if (vme->num_funcs > 1)
#endif
    {
      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->rmbk[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->rmbk[buf_pos] ^ vme->mbk2[randw2];
    vme->key3[14] = vme->rmbk[buf_pos] ^ vme->mbk3[randw3];
    vme->key3[15] = vme->rmbk[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->rmbk[buf_pos] ^ vme->mbk1[randw1];
    vme->key3[13] = vme->rmbk[buf_pos] ^ vme->mbk2[randw2];
    vme->key3[14] = vme->rmbk[buf_pos] ^ vme->mbk3[randw3];
    vme->key3[15] = vme->rmbk[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]);
#ifdef VME_2002
    if (vme->num_funcs > 1)
#endif
    {
      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 */

Reply via email to