1 /** 2 * Broken Data Encryption Standard (DES) implementation. 3 * 4 * From the author of grftool: 5 * > GRAVITY's DES implementation is broken in that it uses 6 * > a bitwise AND instead of a bitwise OR while creating the keyschedule 7 * > causing the keyschedule to always be 0x80 bytes of 0. 8 * Additionally only 1 round is being used when processing a 64 bit block. 9 */ 10 module zgrf.crypto.desbroken; 11 12 import std.bitmanip; 13 14 import zgrf.crypto.des; 15 import zgrf.bits; 16 17 /** 18 * Encrypts data using the key 0x00. Key parameter is ignored. 19 * 20 * Params: 21 * data = The data array to be encrypted 22 * key = Ignored. Should be empty 23 * 24 * Returns: An array of bytes containing the encrypted data 25 */ 26 ubyte[] encrypt(const(ubyte)[] data, const(ubyte)[] key = []) pure 27 { 28 return zgrf.crypto.des.encrypt2(data, [0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00], &createSubkeys, 29 &processBlock); 30 } 31 32 /** 33 * Decrypts data using the key 0x00. Key parameter is ignored. 34 * 35 * Calls [zgrf.crypto.des.decrypt2] with the subkeys function [createSubkeys] and 36 * the process function [processBlock]. 37 * 38 * The data must be a multiple of 8 bytes long. 39 * 40 * Params: 41 * data = The data array to be decrypted 42 * key = Ignored. Should be empty 43 * unencryptedSize = The size/length of the unencrypted data. 44 * The returning data will be truncated to this size if it has padding. 45 * 46 * Returns: An array of bytes containing the decrypted data 47 */ 48 ubyte[] decrypt(const(ubyte)[] data, const(ubyte)[] key, const size_t unencryptedSize) pure 49 in (data.length % 8 == 0, "Data must be a multiple of 64 bits (8 bytes)") 50 { 51 return zgrf.crypto.des.decrypt2(data, [0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00], unencryptedSize, 52 &createSubkeys, &processBlock); 53 } 54 55 /** 56 * Processes one block (8 bytes) of data. 57 * 58 * Unlike the original DES it only uses 1 round. 59 * 60 * Params: 61 * block = The block to process (must be 8 bytes long) 62 * subkeys = The subkeys to use for processing 63 * 64 * Returns: 65 * The processed block 66 */ 67 ubyte[] processBlock(const(ubyte)[] block, const BitArray[16] subkeys) pure 68 { 69 return zgrf.crypto.des.processBlock(block, subkeys, 1); 70 } 71 72 /** 73 * Creates 16 subkeys all of them being 0x00. 74 * 75 * They key parameter is unused. 76 * 77 * Params: 78 * key = Ignored. Should be empty 79 * 80 * Returns: 81 * 16 BitArrays that contain the subkeys 82 */ 83 BitArray[16] createSubkeys(const(ubyte)[] key) pure 84 { 85 const bool[48] bits = 0; 86 BitArray[16] keys; 87 foreach (i; 0 .. 16) 88 { 89 keys[i] = BitArray(bits); 90 } 91 92 return keys; 93 } 94 95 /// 96 unittest 97 { 98 const ubyte[] message = [0x48, 0x69, 0x67, 0x68, 0x20, 0x50, 0x72, 0x69, 0x65, 0x73, 0x74]; 99 const ubyte[] encodingKey = [0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07]; 100 const ubyte[] decodingKey = [0xA0, 0xA1, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6, 0xA7]; 101 const ubyte[] encoded = [0x4D, 0x7D, 0x36, 0x69, 0x30, 0x11, 0x26, 0x7D, 102 0x61, 0x77, 0x65, 0x54, 0x54, 0x05, 0x50, 0x11]; 103 104 const ubyte[] actualEncoded = encrypt(message, encodingKey); 105 const ubyte[] actualDecoded = decrypt(encoded, decodingKey, message.length); 106 107 assert(actualEncoded == encoded); 108 assert(actualDecoded == message); 109 }