1<?PHP 2/*The contents of this document are free for use by anyone for any purpose they choose. 3no warranty is implied, nor will one be honored. The author assumes no liability for 4any consequences that may arise from the use of contents of this document. Events not 5covered include but are not limited to: system crashes, system slowdown, system failure, 6fires, explosions, floods, earthquakes, boiling seas, intestinal inflammation, cold coffee, 7and total protonic inversion. 8Any questions, comments, or improvements are appreciated and can be directed to: 9 10Tim Thorpe 11blushift@netins.net 12*/ 13 14/* 15This script implements the 56-bit DES encryption algorithm, 16created from scratch based on interpretation of the original 17specification document. 18 19des_encrypt_ecb("my key", "my text"); 20and 21mcrypt_ecb (MCRYPT_DES, "my key", "my text", MCRYPT_ENCRYPT, str_pad("", 8, chr(0x00))); 22are functionally identical. 23 24Because PHP is lacking in bitwise operators, this set of routines 25makes use of data that has been expanded so that a byte becomes an 8-byte string. 26 27The script performs the transformations, and then condenses the data back to a usable form. 28Apologies for a lack of comments in the bulk of the functions. 29*///////////////////////////////////////////////////////////////////////////// 30 31function des_encrypt_ecb($key, $clearText) { 32//Function to implement Electronic Code Book encoding 33//I haven't had occasion to add any other methods or a decoder for that matter, 34//but all of the underlying functions were written to be universal to all encoding methods, 35//so adding other methods should be easy if you need them. 36 37 if (strlen($key) < 7) 38 $key = str_pad(substr($key, 0, 7), 7, chr(0x00)); //We need 7 bytes for a key; no more, no less 39 40 if (strlen($key) == 7) $key = des_add_parity($key); 41 42 $keys = des_make_subkeys (des_bits_to_bytes ($key)); //Chew the key into the subkeys needed for DES 43 $blockCount = (int) (strlen($clearText) / 8); //Figure out how many blocks of 8 bytes we need to encode 44 if (strlen ($clearText) % 8) { //Check to see if there are any leftovers 45 $blockCount++; //Add another block for them 46 $clearText = str_pad($clearText, $blockCount * 8, chr(0x00)); //Pad it out with zeroes 47 } 48 for ($i = 0; $i < $blockCount; $i++) { //Cycle through the blocks 49 $clearBlock = substr($clearText, $i * 8, 8); //Grab a block from the input 50 $cypherBlock = des_block_encode(des_bits_to_bytes ($clearBlock), $keys); //Encrypt it 51 $cypherText .= des_bytes_to_bits ($cypherBlock); //Convert the result back to a useful form 52 } 53 return ($cypherText); //Cough it up 54} 55 56function des_block_encode($clearText, $subKeys) { 57 $ip_table = array(58, 50, 42, 34, 26, 18, 10, 2, 58 60, 52, 44, 36, 28, 20, 12, 4, 59 62, 54, 46, 38, 30, 22, 14, 6, 60 64, 56, 48, 40, 32, 24, 16, 8, 61 57, 49, 41, 33, 25, 17, 9, 1, 62 59, 51, 43, 35, 27, 19, 11, 3, 63 61, 53, 45, 37, 29, 21, 13, 5, 64 63, 55, 47, 39, 31, 23, 15, 7); 65 66 $ip1_table = array(40, 8, 48, 16, 56, 24, 64, 32, 67 39, 7, 47, 15, 55, 23, 63, 31, 68 38, 6, 46, 14, 54, 22, 62, 30, 69 37, 5, 45, 13, 53, 21, 61, 29, 70 36, 4, 44, 12, 52, 20, 60, 28, 71 35, 3, 43, 11, 51, 19, 59, 27, 72 34, 2, 42, 10, 50, 18, 58, 26, 73 33, 1, 41, 9, 49, 17, 57, 25); 74 75 foreach ($ip_table as $bit) { 76 $ip .= $clearText[$bit - 1]; 77 } 78 $l[0] = substr($ip, 0, 32); 79 $r[0] = substr($ip, 32); 80 for ($index = 1; $index <= 16; $index++) { 81 $l[$index] = $r[$index - 1]; 82 $r[$index] = des_xor($l[$index - 1], des_transform($r[$index - 1], $subKeys[$index])); 83 } 84 85 foreach ($ip1_table as $bit) { 86 $concat = $r[16] . $l[16]; 87 $cypherBlock .= $concat[$bit - 1]; 88 } 89 return ($cypherBlock); 90} 91 92function des_make_subkeys($key) { 93 $pc1 = array(57, 49, 41, 33, 25, 17, 9, 94 1, 58, 50, 42, 34, 26, 18, 95 10, 2, 59, 51, 43, 35, 27, 96 19, 11, 3, 60, 52, 44, 36, 97 63, 55, 47, 39, 31, 23, 15, 98 7, 62, 54, 46, 38, 30, 22, 99 14, 6, 61, 53, 45, 37, 29, 100 21, 13, 5, 28, 20, 12, 4); 101 102 $pc2 = array(14, 17, 11, 24, 1, 5, 103 3, 28, 15, 6, 21, 10, 104 23, 19, 12, 4, 26, 8, 105 16, 7, 27, 20, 13, 2, 106 41, 52, 31, 37, 47, 55, 107 30, 40, 51, 45, 33, 48, 108 44, 49, 39, 56, 34, 53, 109 46, 42, 50, 36, 29, 32); 110 111 $shifts = array(1, 1, 2, 2, 112 2, 2, 2, 2, 113 1, 2, 2, 2, 114 2, 2, 2, 1); 115 foreach ($pc1 as $bit) { 116 $k .= $key[$bit - 1]; 117 } 118 $index = 0; 119 $c[$index] = substr($k, 0, 28); 120 $d[$index] = substr($k, 28); 121 unset ($k); 122 foreach ($shifts as $positions) { 123 $index++; 124 $c[$index] = des_rotate_left ($c[$index - 1], $positions); 125 $d[$index] = des_rotate_left ($d[$index - 1], $positions); 126 } 127 for ($i = 1; $i <= 16; $i++) { 128 foreach ($pc2 as $bit) { 129 $concat = $c[$i] . $d[$i]; 130 $k[$i] .= $concat[$bit - 1]; 131 } 132 } 133 return ($k); 134} 135 136function des_transform($data, $key) { 137 $e_table = array(32, 1, 2, 3, 4, 5, 138 4, 5, 6, 7, 8, 9, 139 8, 9, 10, 11, 12, 13, 140 12, 13, 14, 15, 16, 17, 141 16, 17, 18, 19, 20, 21, 142 20, 21, 22, 23, 24, 25, 143 24, 25, 26, 27, 28, 29, 144 28, 29, 30, 31, 32, 1); 145 146 $s = array(array(14, 4, 13, 1, 2, 15, 11, 8, 3, 10, 6, 12, 5, 9, 0, 7, 147 0, 15, 7, 4, 14, 2, 13, 1, 10, 6, 12, 11, 9, 5, 3, 8, 148 4, 1, 14, 8, 13, 6, 2, 11, 15, 12, 9, 7, 3, 10, 5, 0, 149 15, 12, 8, 2, 4, 9, 1, 7, 5, 11, 3, 14, 10, 0, 6, 13), 150 array(15, 1, 8, 14, 6, 11, 3, 4, 9, 7, 2, 13, 12, 0, 5, 10, 151 3, 13, 4, 7, 15, 2, 8, 14, 12, 0, 1, 10, 6, 9, 11, 5, 152 0, 14, 7, 11, 10, 4, 13, 1, 5, 8, 12, 6, 9, 3, 2, 15, 153 13, 8, 10, 1, 3, 15, 4, 2, 11, 6, 7, 12, 0, 5, 14, 9), 154 array(10, 0, 9, 14, 6, 3, 15, 5, 1, 13, 12, 7, 11, 4, 2, 8, 155 13, 7, 0, 9, 3, 4, 6, 10, 2, 8, 5, 14, 12, 11, 15, 1, 156 13, 6, 4, 9, 8, 15, 3, 0, 11, 1, 2, 12, 5, 10, 14, 7, 157 1, 10, 13, 0, 6, 9, 8, 7, 4, 15, 14, 3, 11, 5, 2, 12), 158 array( 7, 13, 14, 3, 0, 6, 9, 10, 1, 2, 8, 5, 11, 12, 4, 15, 159 13, 8, 11, 5, 6, 15, 0, 3, 4, 7, 2, 12, 1, 10, 14, 9, 160 10, 6, 9, 0, 12, 11, 7, 13, 15, 1, 3, 14, 5, 2, 8, 4, 161 3, 15, 0, 6, 10, 1, 13, 8, 9, 4, 5, 11, 12, 7, 2, 14), 162 array( 2, 12, 4, 1, 7, 10, 11, 6, 8, 5, 3, 15, 13, 0, 14, 9, 163 14, 11, 2, 12, 4, 7, 13, 1, 5, 0, 15, 10, 3, 9, 8, 6, 164 4, 2, 1, 11, 10, 13, 7, 8, 15, 9, 12, 5, 6, 3, 0, 14, 165 11, 8, 12, 7, 1, 14, 2, 13, 6, 15, 0, 9, 10, 4, 5, 3), 166 array(12, 1, 10, 15, 9, 2, 6, 8, 0, 13, 3, 4, 14, 7, 5, 11, 167 10, 15, 4, 2, 7, 12, 9, 5, 6, 1, 13, 14, 0, 11, 3, 8, 168 9, 14, 15, 5, 2, 8, 12, 3, 7, 0, 4, 10, 1, 13, 11, 6, 169 4, 3, 2, 12, 9, 5, 15, 10, 11, 14, 1, 7, 6, 0, 8, 13), 170 array( 4, 11, 2, 14, 15, 0, 8, 13, 3, 12, 9, 7, 5, 10, 6, 1, 171 13, 0, 11, 7, 4, 9, 1, 10, 14, 3, 5, 12, 2, 15, 8, 6, 172 1, 4, 11, 13, 12, 3, 7, 14, 10, 15, 6, 8, 0, 5, 9, 2, 173 6, 11, 13, 8, 1, 4, 10, 7, 9, 5, 0, 15, 14, 2, 3, 12), 174 array(13, 2, 8, 4, 6, 15, 11, 1, 10, 9, 3, 14, 5, 0, 12, 7, 175 1, 15, 13, 8, 10, 3, 7, 4, 12, 5, 6, 11, 0, 14, 9, 2, 176 7, 11, 4, 1, 9, 12, 14, 2, 0, 6, 10, 13, 15, 3, 5, 8, 177 2, 1, 14, 7, 4, 10, 8, 13, 15, 12, 9, 0, 3, 5, 6, 11)); 178 179 $p_table = array(16, 7, 20, 21, 180 29, 12, 28, 17, 181 1, 15, 23, 26, 182 5, 18, 31, 10, 183 2, 8, 24, 14, 184 32, 27, 3, 9, 185 19, 13, 30, 6, 186 22, 11, 4, 25); 187 188 $nybbles = array(chr(0x00).chr(0x00).chr(0x00).chr(0x00), chr(0x00).chr(0x00).chr(0x00).chr(0x01), 189 chr(0x00).chr(0x00).chr(0x01).chr(0x00), chr(0x00).chr(0x00).chr(0x01).chr(0x01), 190 chr(0x00).chr(0x01).chr(0x00).chr(0x00), chr(0x00).chr(0x01).chr(0x00).chr(0x01), 191 chr(0x00).chr(0x01).chr(0x01).chr(0x00), chr(0x00).chr(0x01).chr(0x01).chr(0x01), 192 chr(0x01).chr(0x00).chr(0x00).chr(0x00), chr(0x01).chr(0x00).chr(0x00).chr(0x01), 193 chr(0x01).chr(0x00).chr(0x01).chr(0x00), chr(0x01).chr(0x00).chr(0x01).chr(0x01), 194 chr(0x01).chr(0x01).chr(0x00).chr(0x00), chr(0x01).chr(0x01).chr(0x00).chr(0x01), 195 chr(0x01).chr(0x01).chr(0x01).chr(0x00), chr(0x01).chr(0x01).chr(0x01).chr(0x01)); 196 197 198 foreach ($e_table as $bit) { 199 $e .= $data[$bit - 1]; 200 } 201 $ek = des_xor($e, $key); 202 for ($i = 0; $i < 8; $i++) { 203 $offset = $i * 6; 204 $sAddress = ord($ek[$offset]) * 0x20 + 205 ord($ek[$offset + 1]) * 0x08 + 206 ord($ek[$offset + 2]) * 0x04 + 207 ord($ek[$offset + 3]) * 0x02 + 208 ord($ek[$offset + 4]) + 209 ord($ek[$offset + 5]) * 0x10; 210 $sResult .= $nybbles[$s[$i][$sAddress]]; 211 } 212 foreach ($p_table as $bit) { 213 $p .= $sResult[$bit - 1]; 214 } 215 return ($p); 216} 217 218function des_bits_to_bytes($bitStream) { 219 for ($i = 0; $i < strlen($bitStream); $i++) { 220 $val = ord($bitStream[$i]); 221 if ($val & 0x80) {$byteStream .= chr(0x01);} else {$byteStream .= chr(0x00);} 222 if ($val & 0x40) {$byteStream .= chr(0x01);} else {$byteStream .= chr(0x00);} 223 if ($val & 0x20) {$byteStream .= chr(0x01);} else {$byteStream .= chr(0x00);} 224 if ($val & 0x10) {$byteStream .= chr(0x01);} else {$byteStream .= chr(0x00);} 225 if ($val & 0x08) {$byteStream .= chr(0x01);} else {$byteStream .= chr(0x00);} 226 if ($val & 0x04) {$byteStream .= chr(0x01);} else {$byteStream .= chr(0x00);} 227 if ($val & 0x02) {$byteStream .= chr(0x01);} else {$byteStream .= chr(0x00);} 228 if ($val & 0x01) {$byteStream .= chr(0x01);} else {$byteStream .= chr(0x00);} 229 } 230 return ($byteStream); 231} 232 233function des_bytes_to_bits($byteStream) { 234 for ($i = 0; $i < (strlen($byteStream) / 8); $i++) { 235 $offset = $i * 8; 236 $value = ord($byteStream[$offset]) * 0x80 + 237 ord($byteStream[$offset + 1]) * 0x40 + 238 ord($byteStream[$offset + 2]) * 0x20 + 239 ord($byteStream[$offset + 3]) * 0x10 + 240 ord($byteStream[$offset + 4]) * 0x08 + 241 ord($byteStream[$offset + 5]) * 0x04 + 242 ord($byteStream[$offset + 6]) * 0x02 + 243 ord($byteStream[$offset + 7]); 244 $bitStream .= chr($value); 245 246 } 247 return ($bitStream); 248} 249 250function des_rotate_left($input, $positions) { 251 return substr($input, $positions) . substr($input, 0, $positions); 252} 253 254function des_xor($a, $b) { 255 for ($i = 0; $i < strlen($a); $i++) { 256 $xor .= $a[$i] ^ $b[$i]; 257 } 258 return $xor; 259} 260 261// DES helper function 262// input: 7-Bytes Key without parity 263// ouput: 8-Bytes Key with parity 264function des_add_parity($key) 265{ 266 static $odd_parity = array( 267 1, 1, 2, 2, 4, 4, 7, 7, 8, 8, 11, 11, 13, 13, 14, 14, 268 16, 16, 19, 19, 21, 21, 22, 22, 25, 25, 26, 26, 28, 28, 31, 31, 269 32, 32, 35, 35, 37, 37, 38, 38, 41, 41, 42, 42, 44, 44, 47, 47, 270 49, 49, 50, 50, 52, 52, 55, 55, 56, 56, 59, 59, 61, 61, 62, 62, 271 64, 64, 67, 67, 69, 69, 70, 70, 73, 73, 74, 74, 76, 76, 79, 79, 272 81, 81, 82, 82, 84, 84, 87, 87, 88, 88, 91, 91, 93, 93, 94, 94, 273 97, 97, 98, 98,100,100,103,103,104,104,107,107,109,109,110,110, 274 112,112,115,115,117,117,118,118,121,121,122,122,124,124,127,127, 275 128,128,131,131,133,133,134,134,137,137,138,138,140,140,143,143, 276 145,145,146,146,148,148,151,151,152,152,155,155,157,157,158,158, 277 161,161,162,162,164,164,167,167,168,168,171,171,173,173,174,174, 278 176,176,179,179,181,181,182,182,185,185,186,186,188,188,191,191, 279 193,193,194,194,196,196,199,199,200,200,203,203,205,205,206,206, 280 208,208,211,211,213,213,214,214,217,217,218,218,220,220,223,223, 281 224,224,227,227,229,229,230,230,233,233,234,234,236,236,239,239, 282 241,241,242,242,244,244,247,247,248,248,251,251,253,253,254,254); 283 284 for ($i = 0; $i < strlen($key); $i++) { 285 $bin .= sprintf('%08s', decbin(ord($key{$i}))); 286 } 287 288 $str1 = explode('-', substr(chunk_split($bin, 7, '-'), 0, -1)); 289 foreach($str1 as $s) { 290 $x .= sprintf('%02s', dechex($odd_parity[bindec($s . '0')])); 291 } 292 293 return pack('H*', $x); 294 295} 296