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 */

Reply via email to