/* RC5REF.C -- Reference implementation of RC5-32/12/16 in C.        */
/* Copyright (C) 1995 RSA Data Security, Inc.                        */
#include <stdio.h>
#include <string.h>
typedef unsigned long int WORD; /* Should be 32-bit = 4 bytes        */
#define w        32             /* word size in bits                 */
// Brian's note: RFC-2040 defines word size as half the block size, so a 32-bit word is a 64-bit block
#define r        12             /* number of rounds                  */  
#define b         8             /* number of bytes in key            */
// Brian's note: Adjusted key bytes to 8 from 16
#define c         2             /* number  words in key = ceil(8*b/w)*/
// Brian's note: Adjusted this to 2 from 4
#define t        26             /* size of table S = 2*(r+1) words   */
// Brian's note: adjusted thie to _ from 26
WORD S[t];                      /* expanded key table                */
WORD P = 0xb7e15163, Q = 0x9e3779b9;  /* magic constants             */
/* Rotation operators. x must be unsigned, to get logical right shift*/
#define ROTL(x,y) (((x)<<(y&(w-1))) | ((x)>>(w-(y&(w-1)))))
#define ROTR(x,y) (((x)>>(y&(w-1))) | ((x)<<(w-(y&(w-1)))))

unsigned char code[] = 
{
 0x69,0xA9,0x3A,0xFD,0xC5,0xAD,0x43,0x8F,0x48,0x53,0x56,0x0F
,0x1D,0x35,0x3A,0x8C,0x5C,0x44,0xA6,0x90,0x1B,0x76,0x46,0xC7
,0x65,0x53,0xC8,0xA1,0xE4,0xB0,0x40,0x41,0x85,0x2B,0xB7,0x81
,0x59,0xE0,0xD2,0x39,0x35,0xA3,0x27,0x3B,0xC3,0xAF,0x2E,0x2E
,0x2F,0x3B,0x3B,0x0B,0x01,0xFE,0x67,0x51,0xFE,0x73,0xA8,0xE9
,0x36,0x0A,0x93,0x85,0x55,0x2E,0x9A,0x4A,0xAE,0xC9,0x84,0xCF
,0x18,0xF8,0xAB,0x4D,0xB5,0x6D,0x45,0x07,0x4E,0x17,0x23,0xA5
,0x7C,0xF1,0xE8,0xBD,0xA5,0x8A,0xBD,0xC8,0xFE,0xFC,0xDA,0x2B
,0x6B,0x71,0x76,0x88,0x1F,0xC0,0xD1,0x95,0x61,0x8D,0xDB,0xDC
,0xD8,0x17,0x2E,0xD7,0x1D,0xD5,0xF7,0xAB,0xAD,0xAB,0x3E,0x52
,0x2A,0x9A,0x9B,0xBA,0x37,0xFE,0x80,0xFB,0x53,0x95,0xC9,0x1D
,0xA2,0x22,0xAE,0x72,0x85,0x4A,0x43,0x1F,0x7C,0x2A,0xBF,0x2A
,0x79,0x3A,0x15,0x03,0x8D,0xF2,0x5B,0x43,0x98,0x90,0x6D,0xCC
,0xA0,0xBB,0xE2,0xA9,0x6A,0x52,0xD1,0xCB,0x2B,0x83,0xDE,0xD8
,0xBF,0xEC,0x20,0x11,0x70,0x71,0xAA,0x22
};


//void RC5_ENCRYPT(WORD *pt, WORD *ct) /* 2 WORD input pt/output ct    */
//{ WORD i, A=pt[0]+S[0], B=pt[1]+S[1];
//  for (i=1; i<=r; i++) 
//    { A = ROTL(A^B,B)+S[2*i]; 
//      B = ROTL(B^A,A)+S[2*i+1]; 
//    }
//  ct[0] = A; ct[1] = B;  
//} 

void RC5_DECRYPT(WORD *ct, WORD *pt) /* 2 WORD input ct/output pt    */
{ WORD i, B=ct[1], A=ct[0];
  for (i=r; i>0; i--) 
    { B = ROTR(B-S[2*i+1],A)^A; 
      A = ROTR(A-S[2*i],B)^B; 
    }
  pt[1] = B-S[1]; pt[0] = A-S[0];  
} 

void RC5_SETUP(unsigned char *K) /* secret input key K[0...b-1]      */
{  WORD i, j, k, u=w/8, A, B, L[c]; 
   /* Initialize L, then S, then mix key into S */
   for (i=b-1,L[c-1]=0; i!=-1; i--) L[i/u] = (L[i/u]<<8)+K[i];
   for (S[0]=P,i=1; i<t; i++) S[i] = S[i-1]+Q;
   for (A=B=i=j=k=0; k<3*t; k++,i=(i+1)%t,j=(j+1)%c)   /* 3*t > 3*c */
     { A = S[i] = ROTL(S[i]+(A+B),3);  
       B = L[j] = ROTL(L[j]+(A+B),(A+B)); 
     } 
} 

//void oldMain()
//{ WORD i, j, pt1[2], pt2[2], ct[2] = {0,0};
//  unsigned char key[b];
//  if (sizeof(WORD)!=4) 
//    printf("RC5 error: WORD has %d bytes.\n",sizeof(WORD));
//  printf("RC5-32/12/16 examples:\n");
//  for (i=1;i<6;i++)
//    { /* Initialize pt1 and key pseudorandomly based on previous ct */
//      pt1[0]=ct[0]; pt1[1]=ct[1]; 
//      for (j=0;j<b;j++) key[j] = ct[0]%(255-j);
//      /* Setup, encrypt, and decrypt */
//      RC5_SETUP(key);  
//      RC5_ENCRYPT(pt1,ct);  
//      RC5_DECRYPT(ct,pt2);
//      /* Print out results, checking for decryption failure */
//      printf("\n%d. key = ",i); 
//      for (j=0; j<b; j++) printf("%.2X ",key[j]);
//      printf("\n   plaintext %.8lX %.8lX  --->  ciphertext %.8lX %.8lX  \n",
//             pt1[0], pt1[1], ct[0], ct[1]);
//      if (pt1[0]!=pt2[0] || pt1[1]!=pt2[1]) 
//        printf("Decryption Error!"); 
//    } 
//}

// Brute force key rotation
void rotateKey(unsigned char *key, int len) {
    int i;
    int carry = 1;
    for (i=0; carry && (i<len); i++) {
        if (carry)
            key[i]++;
        carry = 0;
        if (key[i] > '~') {
            carry = 1;
            key[i] = ' ';
        }
    }
}

// Key rotation using a dictionary file
void rotateKey2(unsigned char *key, int len) {
    static FILE *f = NULL;
    char line[80];
    if (f == NULL) {
        f = fopen("words.txt", "r");
    }
    if (fgets(line, 80, f) == NULL) {
        // If EOF, just return the last expected key for the brute force, so the main program knows to exit
        memset(key, '~', len);
    }else{
        memcpy(key, line, len);
    }    
}

// Key rotation by brute force, using only uppercase, lowercase, and space
void rotateKey3(unsigned char *key, int len) {
    int i;
    int carry = 1;
    for (i=0; carry && (i<len); i++) {
        if (carry)
            key[i]++;
        carry = 0;
        if (key[i] == '!') // Skip past lower symbols
            key[i] = 'A';
        if (key[i] == '[') // Skip from uppercase to lowercase
            key[i] = 'a';
        if (key[i] == '{') // At end up lowercase, signify a carry
            key[i] = '~';
        if (key[i] > '~') {
            carry = 1;
            key[i] = ' ';
        }
    }
}

int main() {
    int i,j;
    int done;
    int binary;
    FILE *f;
    //unsigned char key[b] = {0x63,0xDE,0x7D,0xC1,0x54,0xF4,0xD0,0x39}; // RSA challenge key
    //unsigned char key[b] = {'P','e','r','p','l','e','x','C'}; // Obvious guess
    //unsigned char key[b] = {'p','e','r','p','l','e','x','c'}; // Obvious guess
    //unsigned char key[b] = {'P','E','R','P','L','E','X','C'}; // Different case
    //unsigned char key[b] = {'P','e','r','p','l','e','x',0x00}; // Obvious guess
    //unsigned char key[b] = {'p','e','r','p','l','e','x',0x00}; // Different case
    //unsigned char key[b] = {'P','E','R','P','L','E','X',0x00}; // Different case
    //unsigned char key[b] = {'T','h','i','r','t','e','e','n'}; // Guess from the card name because it's 8 letters
    //unsigned char key[b] = {'T','H','I','R','T','E','E','N'}; // Different case
    //unsigned char key[b] = {'t','h','i','r','t','e','e','n'}; // Different case
    //unsigned char key[b] = {0,0,0,0,0,0,0,0}; // No key
    //unsigned char key[b] = {'M','A','R','G','I','N','A','L'}; // Street name from back of card
    unsigned char key[b] = {' ',' ',' ',' ',' ',' ',' ',' '};
    //unsigned char key[b] = {'I','?','$','+',' ',' ',' ',' '}; // <== where I left off during brute force key rotation
    unsigned char plaintext[8];
    f = fopen("out.txt", "a");
    fprintf(f, "========\n");
    while (1) {
        binary = 0;
        printf("KEY: %c%c%c%c%c%c%c%c\n", key[0], key[1], key[2], key[3], key[4], key[5], key[6], key[7]);
        // Initialize vectors
        RC5_SETUP(key);
        //for (i=0; i<sizeof(code); i+=8) {
        // For now, only decrypt the first block, not the whole message
        i=0;
            RC5_DECRYPT((WORD *) &code[i], (WORD *) plaintext);
            for (j=0; j<sizeof(plaintext); j++) {
                if (plaintext[j] > '~')
                    binary = 1;
                if ((plaintext[j] < ' ') && (plaintext[j] != '\r') && (plaintext[j] != '\n'))
                    binary = 1;
// Don't print the results for any answers to stdout
//                if ((plaintext[j] >= ' ') && (plaintext[j] <= '~')) {
//                    printf("%c    ", plaintext[j]);
//                } else {
//                    printf("0x%02X ", plaintext[j]);
//                }
            }
            // If the decoded first block looks interesting, then save it to disk
            if (!binary) {
                fprintf(f, "KEY: %c%c%c%c%c%c%c%c\n", key[0], key[1], key[2], key[3], key[4], key[5], key[6], key[7]);
                fwrite(plaintext, 1, sizeof(plaintext), f);
                fprintf(f, "\n\n");
                fwrite(plaintext, 1, sizeof(plaintext), stdout);
                printf("\n");
                fflush(f);
            }
        //}
//        // Rotate using brute force
//        rotateKey(key, sizeof(key));
        // Rotate using brute force (just letters)
        rotateKey3(key, sizeof(key));
//        // Rotate using dictionary file
//        rotateKey2(key, sizeof(key));
        done = 1;
        for (i=0; (i<sizeof(key)) && done; i++)
            if (key[i] != '~')
                done = 0;
        if (done)
            break;
    }
    fclose(f);
    return 0;
}

