Difference between revisions of "Crypto and Hashing"
ApacheChief (talk | contribs) |
m (Touched up the SWAP to avoid mistaken uses.) |
||
Line 42: | Line 42: | ||
===Implementation in C=== | ===Implementation in C=== | ||
<pre>#define SWAP(a,b) ((a == b) ? (a=a) : ((char)a ^= (char)b ^= (char)a ^= (char)b)) | <pre>#define SWAP(a,b) (((a) == (b)) ? ((a)=(a)) : ((char)(a) ^= (char)(b) ^= (char)(a) ^= (char)(b))) | ||
/** Generates the key based on "base" */ | /** Generates the key based on "base" */ |
Latest revision as of 21:11, 6 August 2008
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 = cd 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.