Skip to content

Instantly share code, notes, and snippets.

@Estella
Created April 10, 2018 20:15
Show Gist options
  • Save Estella/17aafb60b67b229102bed620be9a9f95 to your computer and use it in GitHub Desktop.
Save Estella/17aafb60b67b229102bed620be9a9f95 to your computer and use it in GitHub Desktop.
/*******************************************************************************************************/
// PRINCESS - Metamorphic Cipher (64bit WORDS, 18 Rounds, 1024bit key, 512bit block), based on RC5
/*******************************************************************************************************/
// Written for fun, dedicated to girlfriend named Princess, who I love dearly. -Estella Mystagic
// Requries 64bit platform
// gcc -O2 princess_v1.c -o princess
/*******************************************************************************************************/
#include <stdio.h>
#include <time.h>
/*******************************************************************************************************/
// Debug Config
/*******************************************************************************************************/
#define DEBUG_DUMPKEY 1
#define DEBUG_KEYSETUP 1
#define DEBUG_META 1
#define DEBUG_META2 1
#define DEBUG_ROUNDS 2 // one higher then actual amount.
/*******************************************************************************************************/
typedef unsigned long long int WORD;
/*******************************************************************************************************/
// Tweakable Configuration
/*******************************************************************************************************/
WORD P = 0xb7e151628aed2a6a, Q = 0x9e3779b97f4a7c15, I = 0x243f6a8885a308d3; // constants (PHI,PI,E)
/*******************************************************************************************************/
#define w 64 // word size in bits
#define r 18 // number of rounds
#define b 128 // number of bytes in 1024bit key
#define c 16 // number words in key = ceil(8*b/w)
#define t 152 // size of table S = 8*(r+1) words
/*******************************************************************************************************/
WORD S[t]; // expanded key table
/*******************************************************************************************************/
#define ROL(x,y) (((x)<<(y&(w-1))) | ((x)>>(w-(y&(w-1)))))
#define ROR(x,y) (((x)>>(y&(w-1))) | ((x)<<(w-(y&(w-1)))))
#define XOR(x,y) (x^y)
#define NOP(x) (x)
#define INV(x) (~x)
/*******************************************************************************************************/
// Metamorphic Crypto Logic Unit (CLU)
/*******************************************************************************************************/
WORD PRINCESS_CLU(WORD AA, WORD BB, int MODE) {
int meta = (BB % 5);
switch(meta) {
case 0:
if (MODE) { AA = ROL(AA,BB); } else { AA = ROR(AA,BB); }
break;
case 1:
if (MODE) { AA = ROR(AA,BB); } else { AA = ROL(AA,BB); }
break;
case 2:
if (MODE) { AA = XOR(AA,BB); } else { AA = XOR(BB,AA); }
break;
case 3:
AA = INV(AA);
break;
case 4:
AA = NOP(AA);
break;
}
if (DEBUG_META) { printf("M: %d CLU %d: AA = %016llX, BB = %016llX\n",MODE,meta,AA,BB); }
return AA;
}
/*******************************************************************************************************/
void PRINCESS_ENCRYPT(WORD *pt, WORD *ct) {
WORD i,j,AA,BB,
A=pt[0]+S[0], B=pt[1]+S[1], C=pt[2]+S[2], D=pt[3]+S[3],
E=pt[4]+S[4], F=pt[5]+S[5], G=pt[6]+S[6], H=pt[7]+S[7];
for (i=1; i<=r; i++) {
A = ROL(A^B,B)+S[2*i];
B = ROL(B^A,A)+S[2*i+1];
C = ROR(C^D,D)+S[2*i+2];
D = ROR(D^C,C)+S[2*i+3];
E = ROR(E^F,F)+S[2*i+4];
F = ROR(F^E,E)+S[2*i+5];
G = ROL(G^H,H)+S[2*i+6];
H = ROL(H^G,G)+S[2*i+7];
A = PRINCESS_CLU(A,S[i],0);
B = PRINCESS_CLU(B,S[i],0);
C = PRINCESS_CLU(C,S[i],0);
D = PRINCESS_CLU(D,S[i],0);
E = PRINCESS_CLU(E,S[i],0);
F = PRINCESS_CLU(F,S[i],0);
G = PRINCESS_CLU(G,S[i],0);
H = PRINCESS_CLU(H,S[i],0);
}
ct[0] = A; ct[1] = B; ct[2] = C; ct[3] = D;
ct[4] = E; ct[5] = F; ct[6] = G; ct[7] = H;
for (i=1; i<=r; i++) {
for (j=0; j<8;j++) {
AA = ct[j];
BB = S[i];
ct[j] = PRINCESS_CLU(ct[j],S[i],0);
if (DEBUG_META2) { printf("%lld - ENC MUTATE: %lld:%016llX <= %016llX , %016llX\n",i,j,ct[j],AA,BB); }
i++;
}
}
}
/*******************************************************************************************************/
void PRINCESS_DECRYPT(WORD *ct, WORD *pt) {
WORD i,j,AA,BB;
for (i=r; i>0; i--) {
for (j=8; j>0;j--) {
AA = ct[j-1];
BB = S[i-1];
ct[j-1] = PRINCESS_CLU(ct[j-1],S[i-1],1);
if (DEBUG_META) { printf("%lld - DEC MUTATE: %lld:%016llX <= %016llX , %016llX\n",i-1,j-1,ct[j-1],AA,BB); }
i--;
}
}
WORD H=ct[7], G=ct[6], F=ct[5], E=ct[4],
D=ct[3], C=ct[2], B=ct[1], A=ct[0];
for (i=r; i>0; i--) {
H = PRINCESS_CLU(H,S[i],1);
G = PRINCESS_CLU(G,S[i],1);
F = PRINCESS_CLU(F,S[i],1);
E = PRINCESS_CLU(E,S[i],1);
D = PRINCESS_CLU(D,S[i],1);
C = PRINCESS_CLU(C,S[i],1);
B = PRINCESS_CLU(B,S[i],1);
A = PRINCESS_CLU(A,S[i],1);
H = ROR(H-S[2*i+7],G)^G;
G = ROR(G-S[2*i+6],H)^H;
F = ROL(F-S[2*i+5],E)^E;
E = ROL(E-S[2*i+4],F)^F;
D = ROL(D-S[2*i+3],C)^C;
C = ROL(C-S[2*i+2],D)^D;
B = ROR(B-S[2*i+1],A)^A;
A = ROR(A-S[2*i],B)^B;
}
pt[7] = H-S[7]; pt[6] = G-S[6]; pt[5] = F-S[5]; pt[4] = E-S[4],
pt[3] = D-S[3]; pt[2] = C-S[2]; pt[1] = B-S[1]; pt[0] = A-S[0];
}
/*******************************************************************************************************/
// Silly Overly Complex Key Expansion with metamorphic functions.
/*******************************************************************************************************/
void PRINCESS_SETUP(unsigned char *K) {
WORD i, j, jj, jc ,jd, k, u=w/8, A, B, C, D, L[c];
for (i=b-1,L[c-1]=0; i!=-1; i--) {
L[i/u] = (L[i/u]<<8)+K[i];
}
if (DEBUG_KEYSETUP) { printf("keysetup stage1 (metamorphic constants):\n"); }
for (S[0]=P,i=1; i<t; i++) {
int meta = ((I^(Q^i^S[i])+P) % 3);
if (meta == 0) {
S[i] = S[i-1]+Q;
} else if (meta == 1) {
S[i] = S[i-1]+P;
} else if (meta == 2) {
S[i] = S[i-1]+I;
}
if (DEBUG_KEYSETUP) { printf("S1: %d: S[%lld] = %016llX\n",meta,i,S[i]); }
}
if (DEBUG_KEYSETUP) { printf("keysetup stage2 (metamorphic mixer):\n"); }
for (A=B=i=j=k=0; k<3*t; k++,i=(i+1)%t,j=(j+1)%c) {
int meta = ((A^B^k^i^j) % 4);
if (meta == 0) {
A = S[i] = ROL(S[i]+(A+B),3);
B = L[j] = ROL(L[j]+(A+B),(A+B));
} else if (meta == 1) {
A = S[i] = ROL(S[i]+(A+B)^P,3);
B = L[j] = ROL(L[j]+(A+B)^Q,(A+B));
} else if (meta == 2) {
A = S[i] = ROR(S[i]+(A+B)+Q,3);
B = L[j] = ROR(L[j]+(A+B)+P,(A+B));
} else if (meta == 3) {
A = S[i] = ROR(S[i]+(A+B)-Q,3);
B = L[j] = ROR(L[j]+(A+B)-P,(A+B));
}
A = S[i] = PRINCESS_CLU(A,B,((A^B) % 2));
B = L[j] = PRINCESS_CLU(B,A,((A^B) % 2));
if (DEBUG_KEYSETUP) { printf("S2: %d: S[%lld] = %016llX, L[%lld] = %016llX\n",meta,i,S[i],j,L[j]); }
}
if (DEBUG_KEYSETUP) { printf("keysetup stage3 (key array order - metamorphic mixer):\n"); }
for (i=0; i<t; i++) {
jc = (S[i % t] + S[(i + 1) % t]) % t;
jd = (S[i % t] + S[(i + 2) % t]) % t;
C = S[jc];
D = S[jd];
jj = (jc+jd) % t;
int meta = ((i^jc^jd^C^D^jj) % 5);
if (meta == 0) {
S[jj] = PRINCESS_CLU(C,D, (S[i % t] ^ C) % 2);
} else if (meta == 1) {
S[jj] = PRINCESS_CLU(D,C, (S[i % t] ^ D) % 2);
} else if (meta == 2) {
S[i] = PRINCESS_CLU((D+Q),(D+I), (S[i % t] ^ (C+P)) % 2);
} else if (meta == 3) {
S[i] = PRINCESS_CLU((C^D+Q),(D^I-P), (S[i % t] ^ D-Q) % 2);
} else if (meta == 4) {
S[jj] = PRINCESS_CLU((D+Q^I),(D+I-Q+P^C), (S[i % t] ^ (C+P^Q+I)) % 2);
}
if (DEBUG_KEYSETUP) { printf("S3: %d - %lld: S[%lld] = %016llX <= C: S[%lld] = %016llX, D: S[%lld] = %016llX\n",meta,i,jj,S[i],jc,C,jd,D); }
}
if (DEBUG_KEYSETUP) { printf("keysetup stage4 (metamorphic mixer):\n"); }
for (A=B=i=j=k=0; k<3*t; k++,i=(i+1)%t,j=(j+1)%c) {
int meta = ((A^B^k^i^j) % 4);
if (meta == 0) {
A = S[i] = ROL(S[i]+(A+B)+P^Q,3);
B = L[j] = ROL(L[j]+(A+B)+Q^I,(A+B));
} else if (meta == 1) {
A = S[i] = ROL(S[i]+(A+B)-P^I,3);
B = L[j] = ROL(L[j]+(A+B)^Q+I,(A+B));
} else if (meta == 2) {
A = S[i] = ROR(S[i]+(A+B)+Q^I,3);
B = L[j] = ROR(L[j]+(A+B)^I+P,(A+B));
} else if (meta == 3) {
A = S[i] = ROR(S[i]+(A+B)-Q-I,3);
B = L[j] = ROR(L[j]+(A+B)^P+I,(A+B));
}
A = S[i] = PRINCESS_CLU(A,B,((A^B^S[i]) % 2));
B = L[j] = PRINCESS_CLU(B,A,((A^B^L[j]) % 2));
if (DEBUG_KEYSETUP) { printf("S4: %d: S[%lld] = %016llX, L[%lld] = %016llX\n",meta,i,S[i],j,L[j]); }
}
if (DEBUG_DUMPKEY) {
printf("Dumping expanded keysetup:\n");
for (jj=0; jj<t; jj += 8) {
//printf("S[%lld] = %016llX\n",jj,S[jj]);
printf("%016llX %016llX %016llX %016llX %016llX %016llX %016llX %016llX\n",S[jj],S[jj+1],S[jj+2],S[jj+3],S[jj+4],S[jj+5],S[jj+6],S[jj+7]);
}
printf("Dumping expanded keysetup (short form):\n");
for (jj=0; jj<t; jj++) {
printf("%016llX\n",S[jj]);
}
}
}
/*******************************************************************************************************/
int main() {
WORD i, j, pt1[8], pt2[8], ct[8] = {0,0};
unsigned char key[b];
time_t t0, t1;
printf("PRINCESS - Metamorphic Cipher (64bit WORDS, 18 Rounds, 1024bit key, 512bit block):\n");
for (i=1;i<DEBUG_ROUNDS;i++) {
pt1[0]=ct[0]; pt1[1]=ct[1]; pt1[2]=ct[2]; pt1[3]=ct[3], pt1[4]=ct[4]; pt1[5]=ct[5]; pt1[6]=ct[6]; pt1[7]=ct[7];
for (j=0;j<b;j++) { key[j] = ct[0]%(255-j); }
PRINCESS_SETUP(key);
PRINCESS_ENCRYPT(pt1,ct);
PRINCESS_DECRYPT(ct,pt2);
printf("\n%lld. key:\n ",i);
for (j=0; j<64; j++) { printf("%.2X",key[j]); }
printf("\n ");
for (j=64; j<128; j++) { printf("%.2X",key[j]); }
printf("\n");
printf("\n P: %016llX %016llX %016llX %016llX %016llX %016llX %016llX %016llX\n C: %016llX %016llX %016llX %016llX %016llX %016llX %016llX %016llX\n",
pt1[0], pt1[1], pt1[2], pt1[3], pt1[4], pt1[5], pt1[6], pt1[7],
ct[0], ct[1], ct[2], ct[3], ct[4], ct[5], ct[6], ct[7]);
if (pt1[0] != pt2[0] || pt1[1] != pt2[1] || pt1[2] != pt2[2] || pt1[3] != pt2[3] || pt1[4] != pt2[4] || pt1[5] != pt2[5] || pt1[6] != pt2[6] || pt1[7] != pt2[7]) {
printf("\n DECRYPT ERROR:\n %016llX %016llX %016llX %016llX %016llX %016llX %016llX %016llX\n %016llX %016llX %016llX %016llX %016llX %016llX %016llX %016llX\n",
pt1[0], pt1[1], pt1[2], pt1[3], pt1[4], pt1[5], pt1[6], pt1[7],
pt2[0], pt2[1], pt2[2], pt2[3], pt2[4], pt2[5], pt2[6], pt2[7]);
}
}
/*
// Timing tests, make sure to turn off debug outputs, before doing a million iterations.
time (&t0);
for (i=1;i<1000000;i++) { PRINCESS_ENCRYPT(ct,ct); }
time (&t1);
printf ("\n Time_t for 1 mil blocks: %ld \n", t1-t0);
*/
return 0;
}
/*******************************************************************************************************/
// EOF
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment