RosettaCodeData/Task/The-ISAAC-Cipher/C-sharp/the-isaac-cipher.cs
2015-02-20 09:02:09 -05:00

159 lines
4 KiB
C#

using System;
namespace cipher {
static class Cipher {
// external results
static uint[] randrsl = new uint[256];
static uint randcnt;
// internal state
static uint[] mm = new uint[256];
static uint aa=0, bb=0, cc=0;
static void isaac() {
uint i,x,y;
cc++; // cc just gets incremented once per 256 results
bb+=cc; // then combined with bb
for (i=0; i<=255; i++) {
x = mm[i];
switch (i & 3) {
case 0: aa = aa ^ (aa << 13); break;
case 1: aa = aa ^ (aa >> 6); break;
case 2: aa = aa ^ (aa << 2); break;
case 3: aa = aa ^ (aa >> 16); break;
}
aa = mm[(i+128) & 255] + aa;
y = mm[(x >> 2) & 255] + aa + bb;
mm[i] = y;
bb = mm[(y >> 10) & 255] + x;
randrsl[i]= bb;
}
}
// if (flag==TRUE), then use the contents of randrsl[] to initialize mm[].
static void mix(ref uint a, ref uint b, ref uint c, ref uint d, ref uint e, ref uint f, ref uint g, ref uint h) {
a = a ^ b << 11; d+=a; b+=c;
b = b ^ c >> 2; e+=b; c+=d;
c = c ^ d << 8; f+=c; d+=e;
d = d ^ e >> 16; g+=d; e+=f;
e = e ^ f << 10; h+=e; f+=g;
f = f ^ g >> 4; a+=f; g+=h;
g = g ^ h << 8; b+=g; h+=a;
h = h ^ a >> 9; c+=h; a+=b;
}
static void Init(bool flag) {
short i; uint a,b,c,d,e,f,g,h;
aa=0; bb=0; cc=0;
a=0x9e3779b9; b=a; c=a; d=a;
e=a; f=a; g=a; h=a;
for (i=0; i<=3; i++) // scramble it
mix(ref a,ref b,ref c,ref d,ref e,ref f,ref g,ref h);
i=0;
do { // fill in mm[] with messy stuff
if (flag) { // use all the information in the seed
a+=randrsl[i ]; b+=randrsl[i+1]; c+=randrsl[i+2]; d+=randrsl[i+3];
e+=randrsl[i+4]; f+=randrsl[i+5]; g+=randrsl[i+6]; h+=randrsl[i+7];
} // if flag
mix(ref a,ref b,ref c,ref d,ref e,ref f,ref g,ref h);
mm[i ]=a; mm[i+1]=b; mm[i+2]=c; mm[i+3]=d;
mm[i+4]=e; mm[i+5]=f; mm[i+6]=g; mm[i+7]=h;
i+=8;
}
while (i<255);
if (flag) {
// do a second pass to make all of the seed affect all of mm
i=0;
do {
a+=mm[i ]; b+=mm[i+1]; c+=mm[i+2]; d+=mm[i+3];
e+=mm[i+4]; f+=mm[i+5]; g+=mm[i+6]; h+=mm[i+7];
mix(ref a,ref b,ref c,ref d,ref e,ref f,ref g,ref h);
mm[i ]=a; mm[i+1]=b; mm[i+2]=c; mm[i+3]=d;
mm[i+4]=e; mm[i+5]=f; mm[i+6]=g; mm[i+7]=h;
i+=8;
}
while (i<255);
}
isaac(); // fill in the first set of results
randcnt=0; // prepare to use the first set of results
}
// Seed ISAAC with a string
static void Seed(string seed, bool flag) {
for (int i=0; i<256; i++) mm[i]=0;
for (int i=0; i<256; i++) randrsl[i]=0;
int m = seed.Length;
for (int i=0; i<m; i++) {
randrsl[i] = seed[i];
}
// initialize ISAAC with seed
Init(flag);
}
// Get a random 32-bit value
static uint Random() {
uint result = randrsl[randcnt];
randcnt++;
if (randcnt>255) {
isaac(); randcnt=0;
}
return result;
}
// Get a random character in printable ASCII range
static byte RandA() {
return (byte)(Random() % 95 + 32);
}
// XOR encrypt on random stream. Output: ASCII byte array
static byte[] Vernam(string msg)
{
int n,l;
byte[] v = new byte[msg.Length];
l = msg.Length;
// XOR message
for (n=0; n<l; n++) {
v[n] = (byte) (RandA() ^ (byte)msg[n]);
}
return v;
}
public static void Main() {
string msg = "a Top Secret secret";
string key = "this is my secret key";
byte[] xctx= new byte[msg.Length];
byte[] xptx= new byte[msg.Length];
string xtcx= "*******************";
string xtpx= "*******************";
Seed(key,true);
// XOR encrypt
xctx = Vernam(msg);
xtcx = System.Text.Encoding.ASCII.GetString(xctx);
// XOR decrypt
Seed(key,true);
xptx = Vernam(xtcx);
xtpx = System.Text.Encoding.ASCII.GetString(xptx);
Console.WriteLine("Message: "+msg);
Console.WriteLine("Key : "+key);
Console.Write ("XOR : ");
// output ciphertext as a string of hexadecimal digits
for (int n=0; n<xctx.Length; n++) Console.Write("{0:X2}", xctx[n]);
Console.WriteLine("\nXOR dcr: "+xtpx);
}
}
}