WARNING: Wiki content is an archive, no promise about quality!
This page is about the various cryptographic and hashing functions used by Warden.
SHA1
Warden uses a very similar version of SHA1 to Lockdown, with minor changes. The only changes, in fact, are the reversal of the endianness in a few places:
- sha1_transform() -- the 0x40 bytes of data to be hashed (not the "state", just the new data) have the endianness reversed in 0x10 4-byte blocks. So basically:
- 112233445566778899aabbcc.….
- becomes
- 4433221188776655ccbbaa99.….
- sha1_final() -- the endianness of the first 8 bytes are reversed (as a 64-bit integer). So:
- 1122334455667788
- becomes
- 8877665544332211
Those are the only changes.
I have no good code to demonstrate with, only some hacking code, but feel free to use my C code or Java code if you have nothing better.
SHA1 Test Strings
* eea339da 0d4b6b5e efbf5532 90186095 0907d8af: ""
* c6e1d42f fc282d7a e19e84ed 39e776bb 12eb931b: "The quick brown fox jumps over the lazy dog":
* 4d64e33a f5a17767 eaef1d6a 9caf74bc 493e314b: "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA":
* df847112 54412b8d 7cf95a20 c8e1622c 598e0878: "~!@#$%^&*()_+QWERTYUIOP{}|ASDFGHJKL:\"ZXCVBNM<>?1234567890-=qwertyuiop[]\\asdfghjkl;'zxcvbnm,./"
* bdd61649 688ef7b7 ab8c6903 6e58d132 c8df57a4: "\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f\x20\x21\x22\x23\x24\x25\x26\x27\x28\x29\x2a\x2b\x2c\x2d\x2e\x2f\x30\x31\x32\x33\x34\x35\x36\x37\x38\x39\x3a\x3b\x3c\x3d\x3e\x3f\x40\x41\x42\x43\x44\x45\x46\x47\x48\x49\x4a\x4b\x4c\x4d\x4e\x4f\x50\x51\x52\x53\x54\x55\x56\x57\x58\x59\x5a\x5b\x5c\x5d\x5e\x5f\x60\x61\x62\x63\x64\x65\x66\x67\x68\x69\x6a\x6b\x6c\x6d\x6e\x6f\x70\x71\x72\x73\x74\x75\x76\x77\x78\x79\x7a\x7b\x7c\x7d\x7e\x7f\x80\x81\x82\x83\x84\x85\x86\x87\x88\x89\x8a\x8b\x8c\x8d\x8e\x8f\x90\x91\x92\x93\x94\x95\x96\x97\x98\x99\x9a\x9b\x9c\x9d\x9e\x9f\xa0\xa1\xa2\xa3\xa4\xa5\xa6\xa7\xa8\xa9\xaa\xab\xac\xad\xae\xaf\xb0\xb1\xb2\xb3\xb4\xb5\xb6\xb7\xb8\xb9\xba\xbb\xbc\xbd\xbe\xbf\xc0\xc1\xc2\xc3\xc4\xc5\xc6\xc7\xc8\xc9\xca\xcb\xcc\xcd\xce\xcf\xd0\xd1\xd2\xd3\xd4\xd5\xd6\xd7\xd8\xd9\xda\xdb\xdc\xdd\xde\xdf\xe0\xe1\xe2\xe3\xe4\xe5\xe6\xe7\xe8\xe9\xea\xeb\xec\xed\xee\xef\xf0\xf1\xf2\xf3\xf4\xf5\xf6\xf7\xf8\xf9\xfa\xfb\xfc\xfd\xfe\xff":
MD5
You can optionally use MD5 for one step in the Warden verification. It is 100% standard MD5.
RSA
You can optionally use RSA for one step in the Warden validation. In particular, it is the algorithm:
m = c^d^ mod n
Again, this is completely standard.
Where c is the encrypted buffer, d is the key, and n is a known modulus value.
Xor Encryption
Warden uses a very simple symmetric encryption algorithm in at least two places. Although I haven't confirmed it myself, I'm told that the algorithm is RC4. The algorithm has two parts:
- Take an arbitrary-length buffer and generate a 0x100-byte key
- Encrypt or decrypt data using that 0x100-byte key
Implementation in C
#define SWAP(a,b) (((a) == (b)) ? ((a)=(a)) : ((char)(a) ^= (char)(b) ^= (char)(a) ^= (char)(b)))
/** Generates the key based on "base" */
void generate_key(unsigned char *key_buffer, unsigned char *base, unsigned int base_length)
{
unsigned char val = 0;
unsigned int i;
unsigned int position = 0;
for(i = 0; i < 0x100; i++)
key_buffer[i] = i;
key_buffer[0x100] = 0;
key_buffer[0x101] = 0;
for(i = 1; i <= 0x40; i++)
{
val += key_buffer[(i * 4) - 4] + base[position++ % base_length];
SWAP(key_buffer[(i * 4) - 4], key_buffer[val & 0x0FF]);
val += key_buffer[(i * 4) - 3] + base[position++ % base_length];
SWAP(key_buffer[(i * 4) - 3], key_buffer[val & 0x0FF]);
val += key_buffer[(i * 4) - 2] + base[position++ % base_length];
SWAP(key_buffer[(i * 4) - 2], key_buffer[val & 0x0FF]);
val += key_buffer[(i * 4) - 1] + base[position++ % base_length];
SWAP(key_buffer[(i * 4) - 1], key_buffer[val & 0x0FF]);
}
}
void do_crypt(unsigned char *key, unsigned char *data, int length)
{
int i;
for(i = 0; i < length; i++)
{
key[0x100]++;
key[0x101] += key[key[0x100]];
SWAP(key[key[0x101]], key[key[0x100]]);
data[i] = data[i] ^ key[(key[key[0x101]] + key[key[0x100]]) & 0x0FF];
}
}
Implementation in Java
(the requirement for util.Buffer is only for the main() function, you don't need it.)
package warden;
import util.Buffer;
/** Implements a very simple crypto system used by Warden. I'm told it's RC4, but I haven't bothered confirming. */
public class SimpleCrypto
{
private byte[] key;
/** Generates the key based on "base" */
public SimpleCrypto(byte[] base)
{
char val = 0;
int i;
int position = 0;
byte temp;
key = new byte[0x102];
for (i = 0; i < 0x100; i++)
key[i] = (byte) i;
key[0x100] = 0;
key[0x101] = 0;
for (i = 1; i <= 0x40; i++)
{
val += key[(i * 4) - 4] + base[position++ % base.length];
temp = key[(i * 4) - 4];
key[(i * 4) - 4] = key[val & 0x0FF];
key[val & 0x0FF] = temp;
val += key[(i * 4) - 3] + base[position++ % base.length];
temp = key[(i * 4) - 3];
key[(i * 4) - 3] = key[val & 0x0FF];
key[val & 0x0FF] = temp;
val += key[(i * 4) - 2] + base[position++ % base.length];
temp = key[(i * 4) - 2];
key[(i * 4) - 2] = key[val & 0x0FF];
key[val & 0x0FF] = temp;
val += key[(i * 4) - 1] + base[position++ % base.length];
temp = key[(i * 4) - 1];
key[(i * 4) - 1] = key[val & 0x0FF];
key[val & 0x0FF] = temp;
}
}
/** Encrypts or decrypts. */
public byte[] do_crypt(byte[] data)
{
int i;
byte temp;
for (i = 0; i < data.length; i++)
{
key[0x100]++;
key[0x101] += key[key[0x100] & 0x0FF];
temp = key[key[0x101] & 0x0FF];
key[key[0x101] & 0x0FF] = key[key[0x100] & 0x0FF];
key[key[0x100] & 0x0FF] = temp;
data[i] = (byte) (data[i] ^ key[(key[key[0x101] & 0x0FF] + key[key[0x100] & 0x0FF]) & 0x0FF]);
}
return data;
}
/** More for debugging than anything. */
public byte[] getKey()
{
return key;
}
public static void main(String[] args)
{
SimpleCrypto c = new SimpleCrypto("This is my key. Don't hurt it!!".getBytes());
String str = "This is not a test Of the emergency broadcast system Where malibu fires and radio towers Conspire to dance again And I cannot believe the media Mecca They're only trying to peddle reality, Catch it on prime time, story at nine The whole world is going insane";
byte []out = c.do_crypt(str.getBytes());
Buffer b = new Buffer(out);
System.out.println(b);
System.out.println("Proper output:");
System.out.println("04 11 56 52 3b d5 86 ee 86 55 a7 f7 b5 a7 ae 18");
System.out.println("e3 0a 97 7e 16 cf c8 cf 62 d7 3a 5c 26 ff 16 4b");
System.out.println("f1 c9 a6 ef 1a f8 bd 89 9b 67 3e bb 34 31 35 1e");
System.out.println("79 91 3b d2 f1 c1 b4 65 c3 6d 08 56 73 6c 53 c1");
System.out.println("6d e9 76 06 4f b9 ba 5b 89 17 69 02 36 9a 14 48");
System.out.println("04 e8 d6 a8 36 c3 a5 31 8c 2c d1 bf b7 75 e1 a2");
System.out.println("89 61 ac 66 a0 44 09 bc e5 b1 59 71 cd 6f e3 ce");
System.out.println("32 2c ca 95 7d 41 a3 17 08 e8 f6 bf 27 46 6a 9c");
System.out.println("f3 89 f5 0d 32 9e 88 88 3d f8 bd 39 23 85 2c 4b");
System.out.println("58 58 f8 2b e2 fd ee 4d 34 7f 4f 73 6d 9b d2 8f");
System.out.println("37 58 23 1f ad 67 7b 07 9e c4 54 66 25 0c f2 7f");
System.out.println("24 f0 4f 46 34 5d 1b b7 45 7b b8 30 fa 2d c0 2a");
System.out.println("5f c0 4b 3d ce 4d 39 21 87 28 5a e4 31 2e 51 c4");
System.out.println("65 dc 60 f8 43 0c 12 8d f7 56 2b 32 82 2a e5 97");
System.out.println("24 62 f0 5e 7e 78 36 6e 6f ab b3 ca 76 b8 33 39");
System.out.println("77 96 61 4a 5d 2a ed e8 54 ea fb 61 10 02 98 ce");
System.out.println("c6 7b");
}
}
Implementation in C#
public class SimpleCrypto
{
private byte[] key;
public byte[] Key
{
get
{
return this.key;
}
}
/// <summary>
/// Generates the key based on the baseData
/// </summary>
/// <param name="baseData"></param>
public SimpleCrypto(byte[] baseData)
{
char val = (char)0;
int i;
int position = 0;
byte temp;
this.key = new byte[0x102];
for (i = 0; i < 0x100; i++)
key[i] = (byte)i;
this.key[0x100] = 0;
this.key[0x101] = 0;
for (i = 1; i <= 0x40; i++)
{
val += (char)(this.key[(i * 4) - 4] + baseData[position++ % baseData.Length]);
temp = this.key[(i * 4) - 4];
this.key[(i * 4) - 4] = this.key[val & 0x0FF];
this.key[val & 0x0FF] = temp;
val += (char)(this.key[(i * 4) - 3] + baseData[position++ % baseData.Length]);
temp = this.key[(i * 4) - 3];
this.key[(i * 4) - 3] = this.key[val & 0x0FF];
this.key[val & 0x0FF] = temp;
val += (char)(this.key[(i * 4) - 2] + baseData[position++ % baseData.Length]);
temp = this.key[(i * 4) - 2];
this.key[(i * 4) - 2] = this.key[val & 0x0FF];
this.key[val & 0x0FF] = temp;
val += (char)(key[(i * 4) - 1] + baseData[position++ % baseData.Length]);
temp = key[(i * 4) - 1];
this.key[(i * 4) - 1] = this.key[val & 0x0FF];
this.key[val & 0x0FF] = temp;
}
}
/// <summary>
/// Encrypts and decrypts data
/// </summary>
/// <param name="data"></param>
/// <returns></returns>
public byte[] Crypt(byte[] data)
{
int i;
byte temp;
for (i = 0; i < data.Length; i++)
{
key[0x100]++;
key[0x101] += key[key[0x100] & 0x0FF];
temp = key[key[0x101] & 0x0FF];
key[key[0x101] & 0x0FF] = key[key[0x100] & 0x0FF];
key[key[0x100] & 0x0FF] = temp;
data[i] = (byte)(data[i] ^ key[(key[key[0x101] & 0x0FF] + key[key[0x100] & 0x0FF]) & 0x0FF]);
}
return data;
}
}
Inflate
The standard "inflate" function from zlib is required. zlib 1.1.4 was used for create Warden, but it implements a standard protocol.
In C, I suggest using the zlib library.
In Java, I suggest using java.util.zip.Inflater.