From 1ee68eccf7a89267afd7a81aaa13e1c98b88ddbf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ernesto=20Canales=20Pere=C3=B1a?= Date: Sat, 29 Jul 2023 19:47:08 +0200 Subject: [PATCH] Upload MD5Crack project --- CrackMD5.cc | 359 ++++++++++++++++++++++++++++++ README.md | 12 + lib/LICENSE | 10 + lib/crc32.cpp | 431 ++++++++++++++++++++++++++++++++++++ lib/crc32.h | 69 ++++++ lib/digest.cpp | 109 +++++++++ lib/hash.h | 28 +++ lib/hmac.h | 83 +++++++ lib/keccak.cpp | 298 +++++++++++++++++++++++++ lib/keccak.h | 81 +++++++ lib/md5.cpp | 380 +++++++++++++++++++++++++++++++ lib/md5.h | 78 +++++++ lib/readme.md | 51 +++++ lib/sha1.cpp | 326 +++++++++++++++++++++++++++ lib/sha1.h | 78 +++++++ lib/sha256.cpp | 428 +++++++++++++++++++++++++++++++++++ lib/sha256.h | 78 +++++++ lib/sha3.cpp | 300 +++++++++++++++++++++++++ lib/sha3.h | 81 +++++++ lib/tests/github-issue2.cpp | 64 ++++++ lib/tests/github-issue6.cpp | 16 ++ lib/tests/tests.cpp | 361 ++++++++++++++++++++++++++++++ makefile | 13 ++ 23 files changed, 3734 insertions(+) create mode 100644 CrackMD5.cc create mode 100644 README.md create mode 100644 lib/LICENSE create mode 100644 lib/crc32.cpp create mode 100644 lib/crc32.h create mode 100644 lib/digest.cpp create mode 100644 lib/hash.h create mode 100644 lib/hmac.h create mode 100644 lib/keccak.cpp create mode 100644 lib/keccak.h create mode 100644 lib/md5.cpp create mode 100644 lib/md5.h create mode 100644 lib/readme.md create mode 100644 lib/sha1.cpp create mode 100644 lib/sha1.h create mode 100644 lib/sha256.cpp create mode 100644 lib/sha256.h create mode 100644 lib/sha3.cpp create mode 100644 lib/sha3.h create mode 100644 lib/tests/github-issue2.cpp create mode 100644 lib/tests/github-issue6.cpp create mode 100644 lib/tests/tests.cpp create mode 100755 makefile diff --git a/CrackMD5.cc b/CrackMD5.cc new file mode 100644 index 0000000..0d57e97 --- /dev/null +++ b/CrackMD5.cc @@ -0,0 +1,359 @@ +#include "lib/md5.h" +#include "lib/sha256.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "sys/sysinfo.h" + + + + + +using namespace std; +using namespace chrono; + +#define PBSTR "||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||" +#define PBWIDTH 60 + +enum Error { + ERR_UNKNOWN_OPTION, + ERR_CANT_OPEN_FILE, + ERR_ARGS, + ERR_THREADS +}; + +void error(Error n, string file) +{ + switch (n) { + + case ERR_UNKNOWN_OPTION: + cout << "Error, unknown option" << endl; + break; + + case ERR_CANT_OPEN_FILE: + cout << "Error, can't open file: "<< file << endl; + break; + + case ERR_ARGS: + cout<< "Usage:\ncrack -f [file] -d [dict] -t [threads] --trace [worst performance] --check [sys info]" << endl; + break; + + case ERR_THREADS: + cout<< "Error, wrong number of threads" << endl; + break; + } +} + +enum Info{ + CHECK_SYS +}; + +void info(Info i){ + struct sysinfo memInfo; + sysinfo (&memInfo); + long long totalPhysMemBytes = memInfo.totalram; + long long totalPhysMemGBytes = (totalPhysMemBytes/(1024*1024*1024)); + const auto processor_count = std::thread::hardware_concurrency(); + + switch (i) { + + case CHECK_SYS: + cout << "Number of threads: " << processor_count << endl; + cout << "Total RAM: " << totalPhysMemGBytes << "GB ("<(inFile), + istreambuf_iterator(), '\n')+1; + return c; +} + +void readFile(string *&words,string &nombre, long long &size){ + ifstream fichero; string fila; + words = new string[size]; + + long long i = 0; + fichero.open(nombre.c_str(), ios::in); + if(fichero.is_open()){ + while(!fichero.eof()){ + getline(fichero, fila); + words[i] = fila; + i++; + } + fichero.close(); + } +} + +void readFileDict(char *&dict,string &nombre, long long &sizeWordsDICT){ + cout<<"Loading dictionary in memory..."<(j)/static_cast(rangs[1])); + } + string word = ""; + while(dict[j] != '\n' && j<=sizeWordsDICT){ + word = word + dict[j]; + j++; + } + word.erase(std::remove(word.begin(), word.end(), '\r' ), word.end()); + string wordHashMD5 = hashMD5(word); + for(int word2crack=0;word2crack dist(0, sizeof(alphanum)-1); + + for (int i = 0; i < len; ++i) { + tmp_s += alphanum[(int)(dist(mt))]; + } + + return tmp_s; +} + +void outputFileCrack(string *result, long long &sizeMD5){ + ofstream fichero("plain.txt"); + if(fichero.is_open()){ + for(long long i =0;i ThreadVector; + long long **rangs; + rangs = new long long*[numThreads]; + int recovered = 0; + + //Read hashes to crack, read dict and caculate ranges + readFile(wordsMD5,nameFileMD5,sizeMD5); + readFileDict(dict,nameFileDict,sizeWordsDICT); + fillSplit(rangs,sizeWordsDICT,numThreads); + + cout<<"Running process with "<(end-begin).count(); + + cout<<"Time to execution: "< +#endif + + +/// same as reset() +CRC32::CRC32() +{ + reset(); +} + + +/// restart +void CRC32::reset() +{ + m_hash = 0; +} + + +namespace +{ + /// look-up table + static const uint32_t crc32Lookup[8][256] = + { + // generated by: + //for (uint32_t i = 0; i <= 0xFF; i++) + //{ + // uint32_t crc = i; + // for (unsigned int j = 0; j < 8; j++) + // crc = (crc >> 1) ^ ((crc & 1) * Polynomial); + // crc32Lookup[0][i] = crc; + //} + // slicing-by-8 algorithm (from Intel): + // http://www.intel.com/technology/comms/perfnet/download/CRC_generators.pdf + // http://sourceforge.net/projects/slicing-by-8/ + //for (unsigned int i = 0; i <= 0xFF; i++) + //{ + // crc32Lookup[1][i] = (crc32Lookup[0][i] >> 8) ^ crc32Lookup[0][crc32Lookup[0][i] & 0xFF]; + // crc32Lookup[2][i] = (crc32Lookup[1][i] >> 8) ^ crc32Lookup[0][crc32Lookup[1][i] & 0xFF]; + // crc32Lookup[3][i] = (crc32Lookup[2][i] >> 8) ^ crc32Lookup[0][crc32Lookup[2][i] & 0xFF]; + + // crc32Lookup[4][i] = (crc32Lookup[3][i] >> 8) ^ crc32Lookup[0][crc32Lookup[3][i] & 0xFF]; + // crc32Lookup[5][i] = (crc32Lookup[4][i] >> 8) ^ crc32Lookup[0][crc32Lookup[4][i] & 0xFF]; + // crc32Lookup[6][i] = (crc32Lookup[5][i] >> 8) ^ crc32Lookup[0][crc32Lookup[5][i] & 0xFF]; + // crc32Lookup[7][i] = (crc32Lookup[6][i] >> 8) ^ crc32Lookup[0][crc32Lookup[6][i] & 0xFF]; + //} + { 0x00000000,0x77073096,0xEE0E612C,0x990951BA,0x076DC419,0x706AF48F,0xE963A535,0x9E6495A3, + 0x0EDB8832,0x79DCB8A4,0xE0D5E91E,0x97D2D988,0x09B64C2B,0x7EB17CBD,0xE7B82D07,0x90BF1D91, + 0x1DB71064,0x6AB020F2,0xF3B97148,0x84BE41DE,0x1ADAD47D,0x6DDDE4EB,0xF4D4B551,0x83D385C7, + 0x136C9856,0x646BA8C0,0xFD62F97A,0x8A65C9EC,0x14015C4F,0x63066CD9,0xFA0F3D63,0x8D080DF5, + 0x3B6E20C8,0x4C69105E,0xD56041E4,0xA2677172,0x3C03E4D1,0x4B04D447,0xD20D85FD,0xA50AB56B, + 0x35B5A8FA,0x42B2986C,0xDBBBC9D6,0xACBCF940,0x32D86CE3,0x45DF5C75,0xDCD60DCF,0xABD13D59, + 0x26D930AC,0x51DE003A,0xC8D75180,0xBFD06116,0x21B4F4B5,0x56B3C423,0xCFBA9599,0xB8BDA50F, + 0x2802B89E,0x5F058808,0xC60CD9B2,0xB10BE924,0x2F6F7C87,0x58684C11,0xC1611DAB,0xB6662D3D, + 0x76DC4190,0x01DB7106,0x98D220BC,0xEFD5102A,0x71B18589,0x06B6B51F,0x9FBFE4A5,0xE8B8D433, + 0x7807C9A2,0x0F00F934,0x9609A88E,0xE10E9818,0x7F6A0DBB,0x086D3D2D,0x91646C97,0xE6635C01, + 0x6B6B51F4,0x1C6C6162,0x856530D8,0xF262004E,0x6C0695ED,0x1B01A57B,0x8208F4C1,0xF50FC457, + 0x65B0D9C6,0x12B7E950,0x8BBEB8EA,0xFCB9887C,0x62DD1DDF,0x15DA2D49,0x8CD37CF3,0xFBD44C65, + 0x4DB26158,0x3AB551CE,0xA3BC0074,0xD4BB30E2,0x4ADFA541,0x3DD895D7,0xA4D1C46D,0xD3D6F4FB, + 0x4369E96A,0x346ED9FC,0xAD678846,0xDA60B8D0,0x44042D73,0x33031DE5,0xAA0A4C5F,0xDD0D7CC9, + 0x5005713C,0x270241AA,0xBE0B1010,0xC90C2086,0x5768B525,0x206F85B3,0xB966D409,0xCE61E49F, + 0x5EDEF90E,0x29D9C998,0xB0D09822,0xC7D7A8B4,0x59B33D17,0x2EB40D81,0xB7BD5C3B,0xC0BA6CAD, + 0xEDB88320,0x9ABFB3B6,0x03B6E20C,0x74B1D29A,0xEAD54739,0x9DD277AF,0x04DB2615,0x73DC1683, + 0xE3630B12,0x94643B84,0x0D6D6A3E,0x7A6A5AA8,0xE40ECF0B,0x9309FF9D,0x0A00AE27,0x7D079EB1, + 0xF00F9344,0x8708A3D2,0x1E01F268,0x6906C2FE,0xF762575D,0x806567CB,0x196C3671,0x6E6B06E7, + 0xFED41B76,0x89D32BE0,0x10DA7A5A,0x67DD4ACC,0xF9B9DF6F,0x8EBEEFF9,0x17B7BE43,0x60B08ED5, + 0xD6D6A3E8,0xA1D1937E,0x38D8C2C4,0x4FDFF252,0xD1BB67F1,0xA6BC5767,0x3FB506DD,0x48B2364B, + 0xD80D2BDA,0xAF0A1B4C,0x36034AF6,0x41047A60,0xDF60EFC3,0xA867DF55,0x316E8EEF,0x4669BE79, + 0xCB61B38C,0xBC66831A,0x256FD2A0,0x5268E236,0xCC0C7795,0xBB0B4703,0x220216B9,0x5505262F, + 0xC5BA3BBE,0xB2BD0B28,0x2BB45A92,0x5CB36A04,0xC2D7FFA7,0xB5D0CF31,0x2CD99E8B,0x5BDEAE1D, + 0x9B64C2B0,0xEC63F226,0x756AA39C,0x026D930A,0x9C0906A9,0xEB0E363F,0x72076785,0x05005713, + 0x95BF4A82,0xE2B87A14,0x7BB12BAE,0x0CB61B38,0x92D28E9B,0xE5D5BE0D,0x7CDCEFB7,0x0BDBDF21, + 0x86D3D2D4,0xF1D4E242,0x68DDB3F8,0x1FDA836E,0x81BE16CD,0xF6B9265B,0x6FB077E1,0x18B74777, + 0x88085AE6,0xFF0F6A70,0x66063BCA,0x11010B5C,0x8F659EFF,0xF862AE69,0x616BFFD3,0x166CCF45, + 0xA00AE278,0xD70DD2EE,0x4E048354,0x3903B3C2,0xA7672661,0xD06016F7,0x4969474D,0x3E6E77DB, + 0xAED16A4A,0xD9D65ADC,0x40DF0B66,0x37D83BF0,0xA9BCAE53,0xDEBB9EC5,0x47B2CF7F,0x30B5FFE9, + 0xBDBDF21C,0xCABAC28A,0x53B39330,0x24B4A3A6,0xBAD03605,0xCDD70693,0x54DE5729,0x23D967BF, + 0xB3667A2E,0xC4614AB8,0x5D681B02,0x2A6F2B94,0xB40BBE37,0xC30C8EA1,0x5A05DF1B,0x2D02EF8D }, + + { 0x00000000,0x191B3141,0x32366282,0x2B2D53C3,0x646CC504,0x7D77F445,0x565AA786,0x4F4196C7, + 0xC8D98A08,0xD1C2BB49,0xFAEFE88A,0xE3F4D9CB,0xACB54F0C,0xB5AE7E4D,0x9E832D8E,0x87981CCF, + 0x4AC21251,0x53D92310,0x78F470D3,0x61EF4192,0x2EAED755,0x37B5E614,0x1C98B5D7,0x05838496, + 0x821B9859,0x9B00A918,0xB02DFADB,0xA936CB9A,0xE6775D5D,0xFF6C6C1C,0xD4413FDF,0xCD5A0E9E, + 0x958424A2,0x8C9F15E3,0xA7B24620,0xBEA97761,0xF1E8E1A6,0xE8F3D0E7,0xC3DE8324,0xDAC5B265, + 0x5D5DAEAA,0x44469FEB,0x6F6BCC28,0x7670FD69,0x39316BAE,0x202A5AEF,0x0B07092C,0x121C386D, + 0xDF4636F3,0xC65D07B2,0xED705471,0xF46B6530,0xBB2AF3F7,0xA231C2B6,0x891C9175,0x9007A034, + 0x179FBCFB,0x0E848DBA,0x25A9DE79,0x3CB2EF38,0x73F379FF,0x6AE848BE,0x41C51B7D,0x58DE2A3C, + 0xF0794F05,0xE9627E44,0xC24F2D87,0xDB541CC6,0x94158A01,0x8D0EBB40,0xA623E883,0xBF38D9C2, + 0x38A0C50D,0x21BBF44C,0x0A96A78F,0x138D96CE,0x5CCC0009,0x45D73148,0x6EFA628B,0x77E153CA, + 0xBABB5D54,0xA3A06C15,0x888D3FD6,0x91960E97,0xDED79850,0xC7CCA911,0xECE1FAD2,0xF5FACB93, + 0x7262D75C,0x6B79E61D,0x4054B5DE,0x594F849F,0x160E1258,0x0F152319,0x243870DA,0x3D23419B, + 0x65FD6BA7,0x7CE65AE6,0x57CB0925,0x4ED03864,0x0191AEA3,0x188A9FE2,0x33A7CC21,0x2ABCFD60, + 0xAD24E1AF,0xB43FD0EE,0x9F12832D,0x8609B26C,0xC94824AB,0xD05315EA,0xFB7E4629,0xE2657768, + 0x2F3F79F6,0x362448B7,0x1D091B74,0x04122A35,0x4B53BCF2,0x52488DB3,0x7965DE70,0x607EEF31, + 0xE7E6F3FE,0xFEFDC2BF,0xD5D0917C,0xCCCBA03D,0x838A36FA,0x9A9107BB,0xB1BC5478,0xA8A76539, + 0x3B83984B,0x2298A90A,0x09B5FAC9,0x10AECB88,0x5FEF5D4F,0x46F46C0E,0x6DD93FCD,0x74C20E8C, + 0xF35A1243,0xEA412302,0xC16C70C1,0xD8774180,0x9736D747,0x8E2DE606,0xA500B5C5,0xBC1B8484, + 0x71418A1A,0x685ABB5B,0x4377E898,0x5A6CD9D9,0x152D4F1E,0x0C367E5F,0x271B2D9C,0x3E001CDD, + 0xB9980012,0xA0833153,0x8BAE6290,0x92B553D1,0xDDF4C516,0xC4EFF457,0xEFC2A794,0xF6D996D5, + 0xAE07BCE9,0xB71C8DA8,0x9C31DE6B,0x852AEF2A,0xCA6B79ED,0xD37048AC,0xF85D1B6F,0xE1462A2E, + 0x66DE36E1,0x7FC507A0,0x54E85463,0x4DF36522,0x02B2F3E5,0x1BA9C2A4,0x30849167,0x299FA026, + 0xE4C5AEB8,0xFDDE9FF9,0xD6F3CC3A,0xCFE8FD7B,0x80A96BBC,0x99B25AFD,0xB29F093E,0xAB84387F, + 0x2C1C24B0,0x350715F1,0x1E2A4632,0x07317773,0x4870E1B4,0x516BD0F5,0x7A468336,0x635DB277, + 0xCBFAD74E,0xD2E1E60F,0xF9CCB5CC,0xE0D7848D,0xAF96124A,0xB68D230B,0x9DA070C8,0x84BB4189, + 0x03235D46,0x1A386C07,0x31153FC4,0x280E0E85,0x674F9842,0x7E54A903,0x5579FAC0,0x4C62CB81, + 0x8138C51F,0x9823F45E,0xB30EA79D,0xAA1596DC,0xE554001B,0xFC4F315A,0xD7626299,0xCE7953D8, + 0x49E14F17,0x50FA7E56,0x7BD72D95,0x62CC1CD4,0x2D8D8A13,0x3496BB52,0x1FBBE891,0x06A0D9D0, + 0x5E7EF3EC,0x4765C2AD,0x6C48916E,0x7553A02F,0x3A1236E8,0x230907A9,0x0824546A,0x113F652B, + 0x96A779E4,0x8FBC48A5,0xA4911B66,0xBD8A2A27,0xF2CBBCE0,0xEBD08DA1,0xC0FDDE62,0xD9E6EF23, + 0x14BCE1BD,0x0DA7D0FC,0x268A833F,0x3F91B27E,0x70D024B9,0x69CB15F8,0x42E6463B,0x5BFD777A, + 0xDC656BB5,0xC57E5AF4,0xEE530937,0xF7483876,0xB809AEB1,0xA1129FF0,0x8A3FCC33,0x9324FD72 }, + + { 0x00000000,0x01C26A37,0x0384D46E,0x0246BE59,0x0709A8DC,0x06CBC2EB,0x048D7CB2,0x054F1685, + 0x0E1351B8,0x0FD13B8F,0x0D9785D6,0x0C55EFE1,0x091AF964,0x08D89353,0x0A9E2D0A,0x0B5C473D, + 0x1C26A370,0x1DE4C947,0x1FA2771E,0x1E601D29,0x1B2F0BAC,0x1AED619B,0x18ABDFC2,0x1969B5F5, + 0x1235F2C8,0x13F798FF,0x11B126A6,0x10734C91,0x153C5A14,0x14FE3023,0x16B88E7A,0x177AE44D, + 0x384D46E0,0x398F2CD7,0x3BC9928E,0x3A0BF8B9,0x3F44EE3C,0x3E86840B,0x3CC03A52,0x3D025065, + 0x365E1758,0x379C7D6F,0x35DAC336,0x3418A901,0x3157BF84,0x3095D5B3,0x32D36BEA,0x331101DD, + 0x246BE590,0x25A98FA7,0x27EF31FE,0x262D5BC9,0x23624D4C,0x22A0277B,0x20E69922,0x2124F315, + 0x2A78B428,0x2BBADE1F,0x29FC6046,0x283E0A71,0x2D711CF4,0x2CB376C3,0x2EF5C89A,0x2F37A2AD, + 0x709A8DC0,0x7158E7F7,0x731E59AE,0x72DC3399,0x7793251C,0x76514F2B,0x7417F172,0x75D59B45, + 0x7E89DC78,0x7F4BB64F,0x7D0D0816,0x7CCF6221,0x798074A4,0x78421E93,0x7A04A0CA,0x7BC6CAFD, + 0x6CBC2EB0,0x6D7E4487,0x6F38FADE,0x6EFA90E9,0x6BB5866C,0x6A77EC5B,0x68315202,0x69F33835, + 0x62AF7F08,0x636D153F,0x612BAB66,0x60E9C151,0x65A6D7D4,0x6464BDE3,0x662203BA,0x67E0698D, + 0x48D7CB20,0x4915A117,0x4B531F4E,0x4A917579,0x4FDE63FC,0x4E1C09CB,0x4C5AB792,0x4D98DDA5, + 0x46C49A98,0x4706F0AF,0x45404EF6,0x448224C1,0x41CD3244,0x400F5873,0x4249E62A,0x438B8C1D, + 0x54F16850,0x55330267,0x5775BC3E,0x56B7D609,0x53F8C08C,0x523AAABB,0x507C14E2,0x51BE7ED5, + 0x5AE239E8,0x5B2053DF,0x5966ED86,0x58A487B1,0x5DEB9134,0x5C29FB03,0x5E6F455A,0x5FAD2F6D, + 0xE1351B80,0xE0F771B7,0xE2B1CFEE,0xE373A5D9,0xE63CB35C,0xE7FED96B,0xE5B86732,0xE47A0D05, + 0xEF264A38,0xEEE4200F,0xECA29E56,0xED60F461,0xE82FE2E4,0xE9ED88D3,0xEBAB368A,0xEA695CBD, + 0xFD13B8F0,0xFCD1D2C7,0xFE976C9E,0xFF5506A9,0xFA1A102C,0xFBD87A1B,0xF99EC442,0xF85CAE75, + 0xF300E948,0xF2C2837F,0xF0843D26,0xF1465711,0xF4094194,0xF5CB2BA3,0xF78D95FA,0xF64FFFCD, + 0xD9785D60,0xD8BA3757,0xDAFC890E,0xDB3EE339,0xDE71F5BC,0xDFB39F8B,0xDDF521D2,0xDC374BE5, + 0xD76B0CD8,0xD6A966EF,0xD4EFD8B6,0xD52DB281,0xD062A404,0xD1A0CE33,0xD3E6706A,0xD2241A5D, + 0xC55EFE10,0xC49C9427,0xC6DA2A7E,0xC7184049,0xC25756CC,0xC3953CFB,0xC1D382A2,0xC011E895, + 0xCB4DAFA8,0xCA8FC59F,0xC8C97BC6,0xC90B11F1,0xCC440774,0xCD866D43,0xCFC0D31A,0xCE02B92D, + 0x91AF9640,0x906DFC77,0x922B422E,0x93E92819,0x96A63E9C,0x976454AB,0x9522EAF2,0x94E080C5, + 0x9FBCC7F8,0x9E7EADCF,0x9C381396,0x9DFA79A1,0x98B56F24,0x99770513,0x9B31BB4A,0x9AF3D17D, + 0x8D893530,0x8C4B5F07,0x8E0DE15E,0x8FCF8B69,0x8A809DEC,0x8B42F7DB,0x89044982,0x88C623B5, + 0x839A6488,0x82580EBF,0x801EB0E6,0x81DCDAD1,0x8493CC54,0x8551A663,0x8717183A,0x86D5720D, + 0xA9E2D0A0,0xA820BA97,0xAA6604CE,0xABA46EF9,0xAEEB787C,0xAF29124B,0xAD6FAC12,0xACADC625, + 0xA7F18118,0xA633EB2F,0xA4755576,0xA5B73F41,0xA0F829C4,0xA13A43F3,0xA37CFDAA,0xA2BE979D, + 0xB5C473D0,0xB40619E7,0xB640A7BE,0xB782CD89,0xB2CDDB0C,0xB30FB13B,0xB1490F62,0xB08B6555, + 0xBBD72268,0xBA15485F,0xB853F606,0xB9919C31,0xBCDE8AB4,0xBD1CE083,0xBF5A5EDA,0xBE9834ED }, + + { 0x00000000,0xB8BC6765,0xAA09C88B,0x12B5AFEE,0x8F629757,0x37DEF032,0x256B5FDC,0x9DD738B9, + 0xC5B428EF,0x7D084F8A,0x6FBDE064,0xD7018701,0x4AD6BFB8,0xF26AD8DD,0xE0DF7733,0x58631056, + 0x5019579F,0xE8A530FA,0xFA109F14,0x42ACF871,0xDF7BC0C8,0x67C7A7AD,0x75720843,0xCDCE6F26, + 0x95AD7F70,0x2D111815,0x3FA4B7FB,0x8718D09E,0x1ACFE827,0xA2738F42,0xB0C620AC,0x087A47C9, + 0xA032AF3E,0x188EC85B,0x0A3B67B5,0xB28700D0,0x2F503869,0x97EC5F0C,0x8559F0E2,0x3DE59787, + 0x658687D1,0xDD3AE0B4,0xCF8F4F5A,0x7733283F,0xEAE41086,0x525877E3,0x40EDD80D,0xF851BF68, + 0xF02BF8A1,0x48979FC4,0x5A22302A,0xE29E574F,0x7F496FF6,0xC7F50893,0xD540A77D,0x6DFCC018, + 0x359FD04E,0x8D23B72B,0x9F9618C5,0x272A7FA0,0xBAFD4719,0x0241207C,0x10F48F92,0xA848E8F7, + 0x9B14583D,0x23A83F58,0x311D90B6,0x89A1F7D3,0x1476CF6A,0xACCAA80F,0xBE7F07E1,0x06C36084, + 0x5EA070D2,0xE61C17B7,0xF4A9B859,0x4C15DF3C,0xD1C2E785,0x697E80E0,0x7BCB2F0E,0xC377486B, + 0xCB0D0FA2,0x73B168C7,0x6104C729,0xD9B8A04C,0x446F98F5,0xFCD3FF90,0xEE66507E,0x56DA371B, + 0x0EB9274D,0xB6054028,0xA4B0EFC6,0x1C0C88A3,0x81DBB01A,0x3967D77F,0x2BD27891,0x936E1FF4, + 0x3B26F703,0x839A9066,0x912F3F88,0x299358ED,0xB4446054,0x0CF80731,0x1E4DA8DF,0xA6F1CFBA, + 0xFE92DFEC,0x462EB889,0x549B1767,0xEC277002,0x71F048BB,0xC94C2FDE,0xDBF98030,0x6345E755, + 0x6B3FA09C,0xD383C7F9,0xC1366817,0x798A0F72,0xE45D37CB,0x5CE150AE,0x4E54FF40,0xF6E89825, + 0xAE8B8873,0x1637EF16,0x048240F8,0xBC3E279D,0x21E91F24,0x99557841,0x8BE0D7AF,0x335CB0CA, + 0xED59B63B,0x55E5D15E,0x47507EB0,0xFFEC19D5,0x623B216C,0xDA874609,0xC832E9E7,0x708E8E82, + 0x28ED9ED4,0x9051F9B1,0x82E4565F,0x3A58313A,0xA78F0983,0x1F336EE6,0x0D86C108,0xB53AA66D, + 0xBD40E1A4,0x05FC86C1,0x1749292F,0xAFF54E4A,0x322276F3,0x8A9E1196,0x982BBE78,0x2097D91D, + 0x78F4C94B,0xC048AE2E,0xD2FD01C0,0x6A4166A5,0xF7965E1C,0x4F2A3979,0x5D9F9697,0xE523F1F2, + 0x4D6B1905,0xF5D77E60,0xE762D18E,0x5FDEB6EB,0xC2098E52,0x7AB5E937,0x680046D9,0xD0BC21BC, + 0x88DF31EA,0x3063568F,0x22D6F961,0x9A6A9E04,0x07BDA6BD,0xBF01C1D8,0xADB46E36,0x15080953, + 0x1D724E9A,0xA5CE29FF,0xB77B8611,0x0FC7E174,0x9210D9CD,0x2AACBEA8,0x38191146,0x80A57623, + 0xD8C66675,0x607A0110,0x72CFAEFE,0xCA73C99B,0x57A4F122,0xEF189647,0xFDAD39A9,0x45115ECC, + 0x764DEE06,0xCEF18963,0xDC44268D,0x64F841E8,0xF92F7951,0x41931E34,0x5326B1DA,0xEB9AD6BF, + 0xB3F9C6E9,0x0B45A18C,0x19F00E62,0xA14C6907,0x3C9B51BE,0x842736DB,0x96929935,0x2E2EFE50, + 0x2654B999,0x9EE8DEFC,0x8C5D7112,0x34E11677,0xA9362ECE,0x118A49AB,0x033FE645,0xBB838120, + 0xE3E09176,0x5B5CF613,0x49E959FD,0xF1553E98,0x6C820621,0xD43E6144,0xC68BCEAA,0x7E37A9CF, + 0xD67F4138,0x6EC3265D,0x7C7689B3,0xC4CAEED6,0x591DD66F,0xE1A1B10A,0xF3141EE4,0x4BA87981, + 0x13CB69D7,0xAB770EB2,0xB9C2A15C,0x017EC639,0x9CA9FE80,0x241599E5,0x36A0360B,0x8E1C516E, + 0x866616A7,0x3EDA71C2,0x2C6FDE2C,0x94D3B949,0x090481F0,0xB1B8E695,0xA30D497B,0x1BB12E1E, + 0x43D23E48,0xFB6E592D,0xE9DBF6C3,0x516791A6,0xCCB0A91F,0x740CCE7A,0x66B96194,0xDE0506F1 }, + + { 0x00000000,0x3D6029B0,0x7AC05360,0x47A07AD0,0xF580A6C0,0xC8E08F70,0x8F40F5A0,0xB220DC10, + 0x30704BC1,0x0D106271,0x4AB018A1,0x77D03111,0xC5F0ED01,0xF890C4B1,0xBF30BE61,0x825097D1, + 0x60E09782,0x5D80BE32,0x1A20C4E2,0x2740ED52,0x95603142,0xA80018F2,0xEFA06222,0xD2C04B92, + 0x5090DC43,0x6DF0F5F3,0x2A508F23,0x1730A693,0xA5107A83,0x98705333,0xDFD029E3,0xE2B00053, + 0xC1C12F04,0xFCA106B4,0xBB017C64,0x866155D4,0x344189C4,0x0921A074,0x4E81DAA4,0x73E1F314, + 0xF1B164C5,0xCCD14D75,0x8B7137A5,0xB6111E15,0x0431C205,0x3951EBB5,0x7EF19165,0x4391B8D5, + 0xA121B886,0x9C419136,0xDBE1EBE6,0xE681C256,0x54A11E46,0x69C137F6,0x2E614D26,0x13016496, + 0x9151F347,0xAC31DAF7,0xEB91A027,0xD6F18997,0x64D15587,0x59B17C37,0x1E1106E7,0x23712F57, + 0x58F35849,0x659371F9,0x22330B29,0x1F532299,0xAD73FE89,0x9013D739,0xD7B3ADE9,0xEAD38459, + 0x68831388,0x55E33A38,0x124340E8,0x2F236958,0x9D03B548,0xA0639CF8,0xE7C3E628,0xDAA3CF98, + 0x3813CFCB,0x0573E67B,0x42D39CAB,0x7FB3B51B,0xCD93690B,0xF0F340BB,0xB7533A6B,0x8A3313DB, + 0x0863840A,0x3503ADBA,0x72A3D76A,0x4FC3FEDA,0xFDE322CA,0xC0830B7A,0x872371AA,0xBA43581A, + 0x9932774D,0xA4525EFD,0xE3F2242D,0xDE920D9D,0x6CB2D18D,0x51D2F83D,0x167282ED,0x2B12AB5D, + 0xA9423C8C,0x9422153C,0xD3826FEC,0xEEE2465C,0x5CC29A4C,0x61A2B3FC,0x2602C92C,0x1B62E09C, + 0xF9D2E0CF,0xC4B2C97F,0x8312B3AF,0xBE729A1F,0x0C52460F,0x31326FBF,0x7692156F,0x4BF23CDF, + 0xC9A2AB0E,0xF4C282BE,0xB362F86E,0x8E02D1DE,0x3C220DCE,0x0142247E,0x46E25EAE,0x7B82771E, + 0xB1E6B092,0x8C869922,0xCB26E3F2,0xF646CA42,0x44661652,0x79063FE2,0x3EA64532,0x03C66C82, + 0x8196FB53,0xBCF6D2E3,0xFB56A833,0xC6368183,0x74165D93,0x49767423,0x0ED60EF3,0x33B62743, + 0xD1062710,0xEC660EA0,0xABC67470,0x96A65DC0,0x248681D0,0x19E6A860,0x5E46D2B0,0x6326FB00, + 0xE1766CD1,0xDC164561,0x9BB63FB1,0xA6D61601,0x14F6CA11,0x2996E3A1,0x6E369971,0x5356B0C1, + 0x70279F96,0x4D47B626,0x0AE7CCF6,0x3787E546,0x85A73956,0xB8C710E6,0xFF676A36,0xC2074386, + 0x4057D457,0x7D37FDE7,0x3A978737,0x07F7AE87,0xB5D77297,0x88B75B27,0xCF1721F7,0xF2770847, + 0x10C70814,0x2DA721A4,0x6A075B74,0x576772C4,0xE547AED4,0xD8278764,0x9F87FDB4,0xA2E7D404, + 0x20B743D5,0x1DD76A65,0x5A7710B5,0x67173905,0xD537E515,0xE857CCA5,0xAFF7B675,0x92979FC5, + 0xE915E8DB,0xD475C16B,0x93D5BBBB,0xAEB5920B,0x1C954E1B,0x21F567AB,0x66551D7B,0x5B3534CB, + 0xD965A31A,0xE4058AAA,0xA3A5F07A,0x9EC5D9CA,0x2CE505DA,0x11852C6A,0x562556BA,0x6B457F0A, + 0x89F57F59,0xB49556E9,0xF3352C39,0xCE550589,0x7C75D999,0x4115F029,0x06B58AF9,0x3BD5A349, + 0xB9853498,0x84E51D28,0xC34567F8,0xFE254E48,0x4C059258,0x7165BBE8,0x36C5C138,0x0BA5E888, + 0x28D4C7DF,0x15B4EE6F,0x521494BF,0x6F74BD0F,0xDD54611F,0xE03448AF,0xA794327F,0x9AF41BCF, + 0x18A48C1E,0x25C4A5AE,0x6264DF7E,0x5F04F6CE,0xED242ADE,0xD044036E,0x97E479BE,0xAA84500E, + 0x4834505D,0x755479ED,0x32F4033D,0x0F942A8D,0xBDB4F69D,0x80D4DF2D,0xC774A5FD,0xFA148C4D, + 0x78441B9C,0x4524322C,0x028448FC,0x3FE4614C,0x8DC4BD5C,0xB0A494EC,0xF704EE3C,0xCA64C78C }, + + { 0x00000000,0xCB5CD3A5,0x4DC8A10B,0x869472AE,0x9B914216,0x50CD91B3,0xD659E31D,0x1D0530B8, + 0xEC53826D,0x270F51C8,0xA19B2366,0x6AC7F0C3,0x77C2C07B,0xBC9E13DE,0x3A0A6170,0xF156B2D5, + 0x03D6029B,0xC88AD13E,0x4E1EA390,0x85427035,0x9847408D,0x531B9328,0xD58FE186,0x1ED33223, + 0xEF8580F6,0x24D95353,0xA24D21FD,0x6911F258,0x7414C2E0,0xBF481145,0x39DC63EB,0xF280B04E, + 0x07AC0536,0xCCF0D693,0x4A64A43D,0x81387798,0x9C3D4720,0x57619485,0xD1F5E62B,0x1AA9358E, + 0xEBFF875B,0x20A354FE,0xA6372650,0x6D6BF5F5,0x706EC54D,0xBB3216E8,0x3DA66446,0xF6FAB7E3, + 0x047A07AD,0xCF26D408,0x49B2A6A6,0x82EE7503,0x9FEB45BB,0x54B7961E,0xD223E4B0,0x197F3715, + 0xE82985C0,0x23755665,0xA5E124CB,0x6EBDF76E,0x73B8C7D6,0xB8E41473,0x3E7066DD,0xF52CB578, + 0x0F580A6C,0xC404D9C9,0x4290AB67,0x89CC78C2,0x94C9487A,0x5F959BDF,0xD901E971,0x125D3AD4, + 0xE30B8801,0x28575BA4,0xAEC3290A,0x659FFAAF,0x789ACA17,0xB3C619B2,0x35526B1C,0xFE0EB8B9, + 0x0C8E08F7,0xC7D2DB52,0x4146A9FC,0x8A1A7A59,0x971F4AE1,0x5C439944,0xDAD7EBEA,0x118B384F, + 0xE0DD8A9A,0x2B81593F,0xAD152B91,0x6649F834,0x7B4CC88C,0xB0101B29,0x36846987,0xFDD8BA22, + 0x08F40F5A,0xC3A8DCFF,0x453CAE51,0x8E607DF4,0x93654D4C,0x58399EE9,0xDEADEC47,0x15F13FE2, + 0xE4A78D37,0x2FFB5E92,0xA96F2C3C,0x6233FF99,0x7F36CF21,0xB46A1C84,0x32FE6E2A,0xF9A2BD8F, + 0x0B220DC1,0xC07EDE64,0x46EAACCA,0x8DB67F6F,0x90B34FD7,0x5BEF9C72,0xDD7BEEDC,0x16273D79, + 0xE7718FAC,0x2C2D5C09,0xAAB92EA7,0x61E5FD02,0x7CE0CDBA,0xB7BC1E1F,0x31286CB1,0xFA74BF14, + 0x1EB014D8,0xD5ECC77D,0x5378B5D3,0x98246676,0x852156CE,0x4E7D856B,0xC8E9F7C5,0x03B52460, + 0xF2E396B5,0x39BF4510,0xBF2B37BE,0x7477E41B,0x6972D4A3,0xA22E0706,0x24BA75A8,0xEFE6A60D, + 0x1D661643,0xD63AC5E6,0x50AEB748,0x9BF264ED,0x86F75455,0x4DAB87F0,0xCB3FF55E,0x006326FB, + 0xF135942E,0x3A69478B,0xBCFD3525,0x77A1E680,0x6AA4D638,0xA1F8059D,0x276C7733,0xEC30A496, + 0x191C11EE,0xD240C24B,0x54D4B0E5,0x9F886340,0x828D53F8,0x49D1805D,0xCF45F2F3,0x04192156, + 0xF54F9383,0x3E134026,0xB8873288,0x73DBE12D,0x6EDED195,0xA5820230,0x2316709E,0xE84AA33B, + 0x1ACA1375,0xD196C0D0,0x5702B27E,0x9C5E61DB,0x815B5163,0x4A0782C6,0xCC93F068,0x07CF23CD, + 0xF6999118,0x3DC542BD,0xBB513013,0x700DE3B6,0x6D08D30E,0xA65400AB,0x20C07205,0xEB9CA1A0, + 0x11E81EB4,0xDAB4CD11,0x5C20BFBF,0x977C6C1A,0x8A795CA2,0x41258F07,0xC7B1FDA9,0x0CED2E0C, + 0xFDBB9CD9,0x36E74F7C,0xB0733DD2,0x7B2FEE77,0x662ADECF,0xAD760D6A,0x2BE27FC4,0xE0BEAC61, + 0x123E1C2F,0xD962CF8A,0x5FF6BD24,0x94AA6E81,0x89AF5E39,0x42F38D9C,0xC467FF32,0x0F3B2C97, + 0xFE6D9E42,0x35314DE7,0xB3A53F49,0x78F9ECEC,0x65FCDC54,0xAEA00FF1,0x28347D5F,0xE368AEFA, + 0x16441B82,0xDD18C827,0x5B8CBA89,0x90D0692C,0x8DD55994,0x46898A31,0xC01DF89F,0x0B412B3A, + 0xFA1799EF,0x314B4A4A,0xB7DF38E4,0x7C83EB41,0x6186DBF9,0xAADA085C,0x2C4E7AF2,0xE712A957, + 0x15921919,0xDECECABC,0x585AB812,0x93066BB7,0x8E035B0F,0x455F88AA,0xC3CBFA04,0x089729A1, + 0xF9C19B74,0x329D48D1,0xB4093A7F,0x7F55E9DA,0x6250D962,0xA90C0AC7,0x2F987869,0xE4C4ABCC }, + + { 0x00000000,0xA6770BB4,0x979F1129,0x31E81A9D,0xF44F2413,0x52382FA7,0x63D0353A,0xC5A73E8E, + 0x33EF4E67,0x959845D3,0xA4705F4E,0x020754FA,0xC7A06A74,0x61D761C0,0x503F7B5D,0xF64870E9, + 0x67DE9CCE,0xC1A9977A,0xF0418DE7,0x56368653,0x9391B8DD,0x35E6B369,0x040EA9F4,0xA279A240, + 0x5431D2A9,0xF246D91D,0xC3AEC380,0x65D9C834,0xA07EF6BA,0x0609FD0E,0x37E1E793,0x9196EC27, + 0xCFBD399C,0x69CA3228,0x582228B5,0xFE552301,0x3BF21D8F,0x9D85163B,0xAC6D0CA6,0x0A1A0712, + 0xFC5277FB,0x5A257C4F,0x6BCD66D2,0xCDBA6D66,0x081D53E8,0xAE6A585C,0x9F8242C1,0x39F54975, + 0xA863A552,0x0E14AEE6,0x3FFCB47B,0x998BBFCF,0x5C2C8141,0xFA5B8AF5,0xCBB39068,0x6DC49BDC, + 0x9B8CEB35,0x3DFBE081,0x0C13FA1C,0xAA64F1A8,0x6FC3CF26,0xC9B4C492,0xF85CDE0F,0x5E2BD5BB, + 0x440B7579,0xE27C7ECD,0xD3946450,0x75E36FE4,0xB044516A,0x16335ADE,0x27DB4043,0x81AC4BF7, + 0x77E43B1E,0xD19330AA,0xE07B2A37,0x460C2183,0x83AB1F0D,0x25DC14B9,0x14340E24,0xB2430590, + 0x23D5E9B7,0x85A2E203,0xB44AF89E,0x123DF32A,0xD79ACDA4,0x71EDC610,0x4005DC8D,0xE672D739, + 0x103AA7D0,0xB64DAC64,0x87A5B6F9,0x21D2BD4D,0xE47583C3,0x42028877,0x73EA92EA,0xD59D995E, + 0x8BB64CE5,0x2DC14751,0x1C295DCC,0xBA5E5678,0x7FF968F6,0xD98E6342,0xE86679DF,0x4E11726B, + 0xB8590282,0x1E2E0936,0x2FC613AB,0x89B1181F,0x4C162691,0xEA612D25,0xDB8937B8,0x7DFE3C0C, + 0xEC68D02B,0x4A1FDB9F,0x7BF7C102,0xDD80CAB6,0x1827F438,0xBE50FF8C,0x8FB8E511,0x29CFEEA5, + 0xDF879E4C,0x79F095F8,0x48188F65,0xEE6F84D1,0x2BC8BA5F,0x8DBFB1EB,0xBC57AB76,0x1A20A0C2, + 0x8816EAF2,0x2E61E146,0x1F89FBDB,0xB9FEF06F,0x7C59CEE1,0xDA2EC555,0xEBC6DFC8,0x4DB1D47C, + 0xBBF9A495,0x1D8EAF21,0x2C66B5BC,0x8A11BE08,0x4FB68086,0xE9C18B32,0xD82991AF,0x7E5E9A1B, + 0xEFC8763C,0x49BF7D88,0x78576715,0xDE206CA1,0x1B87522F,0xBDF0599B,0x8C184306,0x2A6F48B2, + 0xDC27385B,0x7A5033EF,0x4BB82972,0xEDCF22C6,0x28681C48,0x8E1F17FC,0xBFF70D61,0x198006D5, + 0x47ABD36E,0xE1DCD8DA,0xD034C247,0x7643C9F3,0xB3E4F77D,0x1593FCC9,0x247BE654,0x820CEDE0, + 0x74449D09,0xD23396BD,0xE3DB8C20,0x45AC8794,0x800BB91A,0x267CB2AE,0x1794A833,0xB1E3A387, + 0x20754FA0,0x86024414,0xB7EA5E89,0x119D553D,0xD43A6BB3,0x724D6007,0x43A57A9A,0xE5D2712E, + 0x139A01C7,0xB5ED0A73,0x840510EE,0x22721B5A,0xE7D525D4,0x41A22E60,0x704A34FD,0xD63D3F49, + 0xCC1D9F8B,0x6A6A943F,0x5B828EA2,0xFDF58516,0x3852BB98,0x9E25B02C,0xAFCDAAB1,0x09BAA105, + 0xFFF2D1EC,0x5985DA58,0x686DC0C5,0xCE1ACB71,0x0BBDF5FF,0xADCAFE4B,0x9C22E4D6,0x3A55EF62, + 0xABC30345,0x0DB408F1,0x3C5C126C,0x9A2B19D8,0x5F8C2756,0xF9FB2CE2,0xC813367F,0x6E643DCB, + 0x982C4D22,0x3E5B4696,0x0FB35C0B,0xA9C457BF,0x6C636931,0xCA146285,0xFBFC7818,0x5D8B73AC, + 0x03A0A617,0xA5D7ADA3,0x943FB73E,0x3248BC8A,0xF7EF8204,0x519889B0,0x6070932D,0xC6079899, + 0x304FE870,0x9638E3C4,0xA7D0F959,0x01A7F2ED,0xC400CC63,0x6277C7D7,0x539FDD4A,0xF5E8D6FE, + 0x647E3AD9,0xC209316D,0xF3E12BF0,0x55962044,0x90311ECA,0x3646157E,0x07AE0FE3,0xA1D90457, + 0x579174BE,0xF1E67F0A,0xC00E6597,0x66796E23,0xA3DE50AD,0x05A95B19,0x34414184,0x92364A30 }, + + { 0x00000000,0xCCAA009E,0x4225077D,0x8E8F07E3,0x844A0EFA,0x48E00E64,0xC66F0987,0x0AC50919, + 0xD3E51BB5,0x1F4F1B2B,0x91C01CC8,0x5D6A1C56,0x57AF154F,0x9B0515D1,0x158A1232,0xD92012AC, + 0x7CBB312B,0xB01131B5,0x3E9E3656,0xF23436C8,0xF8F13FD1,0x345B3F4F,0xBAD438AC,0x767E3832, + 0xAF5E2A9E,0x63F42A00,0xED7B2DE3,0x21D12D7D,0x2B142464,0xE7BE24FA,0x69312319,0xA59B2387, + 0xF9766256,0x35DC62C8,0xBB53652B,0x77F965B5,0x7D3C6CAC,0xB1966C32,0x3F196BD1,0xF3B36B4F, + 0x2A9379E3,0xE639797D,0x68B67E9E,0xA41C7E00,0xAED97719,0x62737787,0xECFC7064,0x205670FA, + 0x85CD537D,0x496753E3,0xC7E85400,0x0B42549E,0x01875D87,0xCD2D5D19,0x43A25AFA,0x8F085A64, + 0x562848C8,0x9A824856,0x140D4FB5,0xD8A74F2B,0xD2624632,0x1EC846AC,0x9047414F,0x5CED41D1, + 0x299DC2ED,0xE537C273,0x6BB8C590,0xA712C50E,0xADD7CC17,0x617DCC89,0xEFF2CB6A,0x2358CBF4, + 0xFA78D958,0x36D2D9C6,0xB85DDE25,0x74F7DEBB,0x7E32D7A2,0xB298D73C,0x3C17D0DF,0xF0BDD041, + 0x5526F3C6,0x998CF358,0x1703F4BB,0xDBA9F425,0xD16CFD3C,0x1DC6FDA2,0x9349FA41,0x5FE3FADF, + 0x86C3E873,0x4A69E8ED,0xC4E6EF0E,0x084CEF90,0x0289E689,0xCE23E617,0x40ACE1F4,0x8C06E16A, + 0xD0EBA0BB,0x1C41A025,0x92CEA7C6,0x5E64A758,0x54A1AE41,0x980BAEDF,0x1684A93C,0xDA2EA9A2, + 0x030EBB0E,0xCFA4BB90,0x412BBC73,0x8D81BCED,0x8744B5F4,0x4BEEB56A,0xC561B289,0x09CBB217, + 0xAC509190,0x60FA910E,0xEE7596ED,0x22DF9673,0x281A9F6A,0xE4B09FF4,0x6A3F9817,0xA6959889, + 0x7FB58A25,0xB31F8ABB,0x3D908D58,0xF13A8DC6,0xFBFF84DF,0x37558441,0xB9DA83A2,0x7570833C, + 0x533B85DA,0x9F918544,0x111E82A7,0xDDB48239,0xD7718B20,0x1BDB8BBE,0x95548C5D,0x59FE8CC3, + 0x80DE9E6F,0x4C749EF1,0xC2FB9912,0x0E51998C,0x04949095,0xC83E900B,0x46B197E8,0x8A1B9776, + 0x2F80B4F1,0xE32AB46F,0x6DA5B38C,0xA10FB312,0xABCABA0B,0x6760BA95,0xE9EFBD76,0x2545BDE8, + 0xFC65AF44,0x30CFAFDA,0xBE40A839,0x72EAA8A7,0x782FA1BE,0xB485A120,0x3A0AA6C3,0xF6A0A65D, + 0xAA4DE78C,0x66E7E712,0xE868E0F1,0x24C2E06F,0x2E07E976,0xE2ADE9E8,0x6C22EE0B,0xA088EE95, + 0x79A8FC39,0xB502FCA7,0x3B8DFB44,0xF727FBDA,0xFDE2F2C3,0x3148F25D,0xBFC7F5BE,0x736DF520, + 0xD6F6D6A7,0x1A5CD639,0x94D3D1DA,0x5879D144,0x52BCD85D,0x9E16D8C3,0x1099DF20,0xDC33DFBE, + 0x0513CD12,0xC9B9CD8C,0x4736CA6F,0x8B9CCAF1,0x8159C3E8,0x4DF3C376,0xC37CC495,0x0FD6C40B, + 0x7AA64737,0xB60C47A9,0x3883404A,0xF42940D4,0xFEEC49CD,0x32464953,0xBCC94EB0,0x70634E2E, + 0xA9435C82,0x65E95C1C,0xEB665BFF,0x27CC5B61,0x2D095278,0xE1A352E6,0x6F2C5505,0xA386559B, + 0x061D761C,0xCAB77682,0x44387161,0x889271FF,0x825778E6,0x4EFD7878,0xC0727F9B,0x0CD87F05, + 0xD5F86DA9,0x19526D37,0x97DD6AD4,0x5B776A4A,0x51B26353,0x9D1863CD,0x1397642E,0xDF3D64B0, + 0x83D02561,0x4F7A25FF,0xC1F5221C,0x0D5F2282,0x079A2B9B,0xCB302B05,0x45BF2CE6,0x89152C78, + 0x50353ED4,0x9C9F3E4A,0x121039A9,0xDEBA3937,0xD47F302E,0x18D530B0,0x965A3753,0x5AF037CD, + 0xFF6B144A,0x33C114D4,0xBD4E1337,0x71E413A9,0x7B211AB0,0xB78B1A2E,0x39041DCD,0xF5AE1D53, + 0x2C8E0FFF,0xE0240F61,0x6EAB0882,0xA201081C,0xA8C40105,0x646E019B,0xEAE10678,0x264B06E6 } + }; + + inline uint32_t swap(uint32_t x) + { +#if defined(__GNUC__) || defined(__clang__) + return __builtin_bswap32(x); +#endif +#ifdef MSC_VER + return _byteswap_ulong(x); +#endif + + return (x >> 24) | + ((x >> 8) & 0x0000FF00) | + ((x << 8) & 0x00FF0000) | + (x << 24); + } +} + + +/// add arbitrary number of bytes +void CRC32::add(const void* data, size_t numBytes) +{ + uint32_t* current = (uint32_t*) data; + uint32_t crc = ~m_hash; + + // process eight bytes at once + while (numBytes >= 8) + { +#if defined(__BYTE_ORDER) && (__BYTE_ORDER != 0) && (__BYTE_ORDER == __BIG_ENDIAN) + uint32_t one = *current++ ^ swap(crc); + uint32_t two = *current++; + crc = crc32Lookup[7][ one>>24 ] ^ + crc32Lookup[6][(one>>16) & 0xFF] ^ + crc32Lookup[5][(one>> 8) & 0xFF] ^ + crc32Lookup[4][ one & 0xFF] ^ + crc32Lookup[3][ two>>24 ] ^ + crc32Lookup[2][(two>>16) & 0xFF] ^ + crc32Lookup[1][(two>> 8) & 0xFF] ^ + crc32Lookup[0][ two & 0xFF]; +#else + uint32_t one = *current++ ^ crc; + uint32_t two = *current++; + crc = crc32Lookup[7][ one & 0xFF] ^ + crc32Lookup[6][(one>> 8) & 0xFF] ^ + crc32Lookup[5][(one>>16) & 0xFF] ^ + crc32Lookup[4][ one>>24 ] ^ + crc32Lookup[3][ two & 0xFF] ^ + crc32Lookup[2][(two>> 8) & 0xFF] ^ + crc32Lookup[1][(two>>16) & 0xFF] ^ + crc32Lookup[0][ two>>24 ]; +#endif + numBytes -= 8; + } + + unsigned char* currentChar = (unsigned char*) current; + // remaining 1 to 7 bytes (standard CRC table-based algorithm) + while (numBytes--) + crc = (crc >> 8) ^ crc32Lookup[0][(crc & 0xFF) ^ *currentChar++]; + + m_hash = ~crc; +} + + +/// return latest hash as 8 hex characters +std::string CRC32::getHash() +{ + // convert hash to string + static const char dec2hex[16+1] = "0123456789abcdef"; + + char hashBuffer[8+1]; + + hashBuffer[0] = dec2hex[ m_hash >> 28 ]; + hashBuffer[1] = dec2hex[(m_hash >> 24) & 15]; + hashBuffer[2] = dec2hex[(m_hash >> 20) & 15]; + hashBuffer[3] = dec2hex[(m_hash >> 16) & 15]; + hashBuffer[4] = dec2hex[(m_hash >> 12) & 15]; + hashBuffer[5] = dec2hex[(m_hash >> 8) & 15]; + hashBuffer[6] = dec2hex[(m_hash >> 4) & 15]; + hashBuffer[7] = dec2hex[ m_hash & 15]; + // zero-terminated string + hashBuffer[8] = 0; + + // convert to std::string + return hashBuffer; +} + + +/// return latest hash as bytes +void CRC32::getHash(unsigned char buffer[CRC32::HashBytes]) +{ + buffer[0] = (m_hash >> 24) & 0xFF; + buffer[1] = (m_hash >> 16) & 0xFF; + buffer[2] = (m_hash >> 8) & 0xFF; + buffer[3] = m_hash & 0xFF; +} + + +/// compute CRC32 of a memory block +std::string CRC32::operator()(const void* data, size_t numBytes) +{ + reset(); + add(data, numBytes); + return getHash(); +} + + +/// compute CRC32 of a string, excluding final zero +std::string CRC32::operator()(const std::string& text) +{ + reset(); + add(text.c_str(), text.size()); + return getHash(); +} diff --git a/lib/crc32.h b/lib/crc32.h new file mode 100644 index 0000000..c8fc77b --- /dev/null +++ b/lib/crc32.h @@ -0,0 +1,69 @@ +// ////////////////////////////////////////////////////////// +// crc32.h +// Copyright (c) 2014,2015 Stephan Brumme. All rights reserved. +// see http://create.stephan-brumme.com/disclaimer.html +// + +#pragma once + +//#include "hash.h" +#include + +// define fixed size integer types +#ifdef _MSC_VER +// Windows +typedef unsigned __int8 uint8_t; +typedef unsigned __int32 uint32_t; +#else +// GCC +#include +#endif + + +/// compute CRC32 hash, based on Intel's Slicing-by-8 algorithm +/** Usage: + CRC32 crc32; + std::string myHash = crc32("Hello World"); // std::string + std::string myHash2 = crc32("How are you", 11); // arbitrary data, 11 bytes + + // or in a streaming fashion: + + CRC32 crc32; + while (more data available) + crc32.add(pointer to fresh data, number of new bytes); + std::string myHash3 = crc32.getHash(); + + Note: + You can find code for the faster Slicing-by-16 algorithm on my website, too: + http://create.stephan-brumme.com/crc32/ + Its unrolled version is about twice as fast but its look-up table doubled in size as well. + */ +class CRC32 //: public Hash +{ +public: + /// hash is 4 bytes long + enum { HashBytes = 4 }; + + /// same as reset() + CRC32(); + + /// compute CRC32 of a memory block + std::string operator()(const void* data, size_t numBytes); + /// compute CRC32 of a string, excluding final zero + std::string operator()(const std::string& text); + + /// add arbitrary number of bytes + void add(const void* data, size_t numBytes); + + /// return latest hash as 8 hex characters + std::string getHash(); + /// return latest hash as bytes + void getHash(unsigned char buffer[HashBytes]); + + /// restart + void reset(); + +private: + /// hash + uint32_t m_hash; +}; diff --git a/lib/digest.cpp b/lib/digest.cpp new file mode 100644 index 0000000..fb0b776 --- /dev/null +++ b/lib/digest.cpp @@ -0,0 +1,109 @@ +// ////////////////////////////////////////////////////////// +// digest.cpp +// Copyright (c) 2014,2015 Stephan Brumme. All rights reserved. +// see http://create.stephan-brumme.com/disclaimer.html +// + +// g++ -O3 digest.cpp crc32.cpp md5.cpp sha1.cpp sha256.cpp keccak.cpp sha3.cpp -o digest + +#include "crc32.h" +#include "md5.h" +#include "sha1.h" +#include "sha256.h" +#include "keccak.h" +#include "sha3.h" + +#include +#include + +int main(int argc, char** argv) +{ + // syntax check + if (argc < 2 || argc > 3) + { + std::cout << "./digest filename [--crc|--md5|--sha1|--sha256|--keccak|--sha3]" << std::endl; + return 1; + } + + // parameters + std::string filename = argv[1]; + std::string algorithm = argc == 3 ? argv[2] : ""; + bool computeCrc32 = algorithm.empty() || algorithm == "--crc"; + bool computeMd5 = algorithm.empty() || algorithm == "--md5"; + bool computeSha1 = algorithm.empty() || algorithm == "--sha1"; + bool computeSha2 = algorithm.empty() || algorithm == "--sha2" || algorithm == "--sha256"; + bool computeKeccak = algorithm.empty() || algorithm == "--keccak"; + bool computeSha3 = algorithm.empty() || algorithm == "--sha3"; + + CRC32 digestCrc32; + MD5 digestMd5; + SHA1 digestSha1; + SHA256 digestSha2; + Keccak digestKeccak(Keccak::Keccak256); + SHA3 digestSha3 (SHA3 ::Bits256); + + // select input source: either file or standard-in + std::ifstream file; + std::istream* input = NULL; + // accept std::cin, syntax will be: "./digest - --sha3 < data" + if (filename == "-") + { + input = &std::cin; + } + else + { + // open file + file.open(filename.c_str(), std::ios::in | std::ios::binary); + if (!file) + { + std::cerr << "Can't open '" << filename << "'" << std::endl; + return 2; + } + + input = &file; + } + + // each cycle processes about 1 MByte (divisible by 144 => improves Keccak/SHA3 performance) + const size_t BufferSize = 144*7*1024; + char* buffer = new char[BufferSize]; + + // process file + while (*input) + { + input->read(buffer, BufferSize); + std::size_t numBytesRead = size_t(input->gcount()); + + if (computeCrc32) + digestCrc32 .add(buffer, numBytesRead); + if (computeMd5) + digestMd5 .add(buffer, numBytesRead); + if (computeSha1) + digestSha1 .add(buffer, numBytesRead); + if (computeSha2) + digestSha2 .add(buffer, numBytesRead); + if (computeKeccak) + digestKeccak.add(buffer, numBytesRead); + if (computeSha3) + digestSha3 .add(buffer, numBytesRead); + } + + // clean up + file.close(); + delete[] buffer; + + // show results + if (computeCrc32) + std::cout << "CRC32: " << digestCrc32 .getHash() << std::endl; + if (computeMd5) + std::cout << "MD5: " << digestMd5 .getHash() << std::endl; + if (computeSha1) + std::cout << "SHA1: " << digestSha1 .getHash() << std::endl; + if (computeSha2) + std::cout << "SHA2/256: " << digestSha2 .getHash() << std::endl; + if (computeKeccak) + std::cout << "Keccak/256: " << digestKeccak.getHash() << std::endl; + if (computeSha3) + std::cout << "SHA3/256: " << digestSha3 .getHash() << std::endl; + + return 0; +} diff --git a/lib/hash.h b/lib/hash.h new file mode 100644 index 0000000..6c6f2ea --- /dev/null +++ b/lib/hash.h @@ -0,0 +1,28 @@ +// ////////////////////////////////////////////////////////// +// hash.h +// Copyright (c) 2014,2015 Stephan Brumme. All rights reserved. +// see http://create.stephan-brumme.com/disclaimer.html +// + +#pragma once + +#include + +/// abstract base class +class Hash +{ +public: + /// compute hash of a memory block + virtual std::string operator()(const void* data, size_t numBytes) = 0; + /// compute hash of a string, excluding final zero + virtual std::string operator()(const std::string& text) = 0; + + /// add arbitrary number of bytes + virtual void add(const void* data, size_t numBytes) = 0; + + /// return latest hash as hex characters + virtual std::string getHash() = 0; + + /// restart + virtual void reset() = 0; +}; diff --git a/lib/hmac.h b/lib/hmac.h new file mode 100644 index 0000000..442a1f3 --- /dev/null +++ b/lib/hmac.h @@ -0,0 +1,83 @@ +// ////////////////////////////////////////////////////////// +// hmac.h +// Copyright (c) 2015 Stephan Brumme. All rights reserved. +// see http://create.stephan-brumme.com/disclaimer.html +// + +#pragma once + +// based on http://tools.ietf.org/html/rfc2104 +// see also http://en.wikipedia.org/wiki/Hash-based_message_authentication_code + +/** Usage: + std::string msg = "The quick brown fox jumps over the lazy dog"; + std::string key = "key"; + std::string md5hmac = hmac< MD5 >(msg, key); + std::string sha1hmac = hmac< SHA1 >(msg, key); + std::string sha2hmac = hmac(msg, key); + + Note: + To keep my code simple, HMAC computation currently needs the whole message at once. + This is in contrast to the hashes MD5, SHA1, etc. where an add() method is available + for incremental computation. + You can use any hash for HMAC as long as it provides: + - constant HashMethod::BlockSize (typically 64) + - constant HashMethod::HashBytes (length of hash in bytes, e.g. 20 for SHA1) + - HashMethod::add(buffer, bufferSize) + - HashMethod::getHash(unsigned char buffer[HashMethod::BlockSize]) + */ + +#include +#include // memcpy + +/// compute HMAC hash of data and key using MD5, SHA1 or SHA256 +template +std::string hmac(const void* data, size_t numDataBytes, const void* key, size_t numKeyBytes) +{ + // initialize key with zeros + unsigned char usedKey[HashMethod::BlockSize] = {0}; + + // adjust length of key: must contain exactly blockSize bytes + if (numKeyBytes <= HashMethod::BlockSize) + { + // copy key + memcpy(usedKey, key, numKeyBytes); + } + else + { + // shorten key: usedKey = hashed(key) + HashMethod keyHasher; + keyHasher.add(key, numKeyBytes); + keyHasher.getHash(usedKey); + } + + // create initial XOR padding + for (size_t i = 0; i < HashMethod::BlockSize; i++) + usedKey[i] ^= 0x36; + + // inside = hash((usedKey ^ 0x36) + data) + unsigned char inside[HashMethod::HashBytes]; + HashMethod insideHasher; + insideHasher.add(usedKey, HashMethod::BlockSize); + insideHasher.add(data, numDataBytes); + insideHasher.getHash(inside); + + // undo usedKey's previous 0x36 XORing and apply a XOR by 0x5C + for (size_t i = 0; i < HashMethod::BlockSize; i++) + usedKey[i] ^= 0x5C ^ 0x36; + + // hash((usedKey ^ 0x5C) + hash((usedKey ^ 0x36) + data)) + HashMethod finalHasher; + finalHasher.add(usedKey, HashMethod::BlockSize); + finalHasher.add(inside, HashMethod::HashBytes); + + return finalHasher.getHash(); +} + + +/// convenience function for std::string +template +std::string hmac(const std::string& data, const std::string& key) +{ + return hmac(data.c_str(), data.size(), key.c_str(), key.size()); +} diff --git a/lib/keccak.cpp b/lib/keccak.cpp new file mode 100644 index 0000000..cba1cae --- /dev/null +++ b/lib/keccak.cpp @@ -0,0 +1,298 @@ +// ////////////////////////////////////////////////////////// +// keccak.cpp +// Copyright (c) 2014,2015 Stephan Brumme. All rights reserved. +// see http://create.stephan-brumme.com/disclaimer.html +// + +#include "keccak.h" + +// big endian architectures need #define __BYTE_ORDER __BIG_ENDIAN +#ifndef _MSC_VER +#include +#endif + + +/// same as reset() +Keccak::Keccak(Bits bits) +: m_blockSize(200 - 2 * (bits / 8)), + m_bits(bits) +{ + reset(); +} + + +/// restart +void Keccak::reset() +{ + for (size_t i = 0; i < StateSize; i++) + m_hash[i] = 0; + + m_numBytes = 0; + m_bufferSize = 0; +} + + +/// constants and local helper functions +namespace +{ + const unsigned int KeccakRounds = 24; + const uint64_t XorMasks[KeccakRounds] = + { + 0x0000000000000001ULL, 0x0000000000008082ULL, 0x800000000000808aULL, + 0x8000000080008000ULL, 0x000000000000808bULL, 0x0000000080000001ULL, + 0x8000000080008081ULL, 0x8000000000008009ULL, 0x000000000000008aULL, + 0x0000000000000088ULL, 0x0000000080008009ULL, 0x000000008000000aULL, + 0x000000008000808bULL, 0x800000000000008bULL, 0x8000000000008089ULL, + 0x8000000000008003ULL, 0x8000000000008002ULL, 0x8000000000000080ULL, + 0x000000000000800aULL, 0x800000008000000aULL, 0x8000000080008081ULL, + 0x8000000000008080ULL, 0x0000000080000001ULL, 0x8000000080008008ULL + }; + + /// rotate left and wrap around to the right + inline uint64_t rotateLeft(uint64_t x, uint8_t numBits) + { + return (x << numBits) | (x >> (64 - numBits)); + } + + /// convert litte vs big endian + inline uint64_t swap(uint64_t x) + { +#if defined(__GNUC__) || defined(__clang__) + return __builtin_bswap64(x); +#endif +#ifdef _MSC_VER + return _byteswap_uint64(x); +#endif + + return (x >> 56) | + ((x >> 40) & 0x000000000000FF00ULL) | + ((x >> 24) & 0x0000000000FF0000ULL) | + ((x >> 8) & 0x00000000FF000000ULL) | + ((x << 8) & 0x000000FF00000000ULL) | + ((x << 24) & 0x0000FF0000000000ULL) | + ((x << 40) & 0x00FF000000000000ULL) | + (x << 56); + } + + + /// return x % 5 for 0 <= x <= 9 + unsigned int mod5(unsigned int x) + { + if (x < 5) + return x; + + return x - 5; + } +} + + +/// process a full block +void Keccak::processBlock(const void* data) +{ +#if defined(__BYTE_ORDER) && (__BYTE_ORDER != 0) && (__BYTE_ORDER == __BIG_ENDIAN) +#define LITTLEENDIAN(x) swap(x) +#else +#define LITTLEENDIAN(x) (x) +#endif + + const uint64_t* data64 = (const uint64_t*) data; + // mix data into state + for (unsigned int i = 0; i < m_blockSize / 8; i++) + m_hash[i] ^= LITTLEENDIAN(data64[i]); + + // re-compute state + for (unsigned int round = 0; round < KeccakRounds; round++) + { + // Theta + uint64_t coefficients[5]; + for (unsigned int i = 0; i < 5; i++) + coefficients[i] = m_hash[i] ^ m_hash[i + 5] ^ m_hash[i + 10] ^ m_hash[i + 15] ^ m_hash[i + 20]; + + for (unsigned int i = 0; i < 5; i++) + { + uint64_t one = coefficients[mod5(i + 4)] ^ rotateLeft(coefficients[mod5(i + 1)], 1); + m_hash[i ] ^= one; + m_hash[i + 5] ^= one; + m_hash[i + 10] ^= one; + m_hash[i + 15] ^= one; + m_hash[i + 20] ^= one; + } + + // temporary + uint64_t one; + + // Rho Pi + uint64_t last = m_hash[1]; + one = m_hash[10]; m_hash[10] = rotateLeft(last, 1); last = one; + one = m_hash[ 7]; m_hash[ 7] = rotateLeft(last, 3); last = one; + one = m_hash[11]; m_hash[11] = rotateLeft(last, 6); last = one; + one = m_hash[17]; m_hash[17] = rotateLeft(last, 10); last = one; + one = m_hash[18]; m_hash[18] = rotateLeft(last, 15); last = one; + one = m_hash[ 3]; m_hash[ 3] = rotateLeft(last, 21); last = one; + one = m_hash[ 5]; m_hash[ 5] = rotateLeft(last, 28); last = one; + one = m_hash[16]; m_hash[16] = rotateLeft(last, 36); last = one; + one = m_hash[ 8]; m_hash[ 8] = rotateLeft(last, 45); last = one; + one = m_hash[21]; m_hash[21] = rotateLeft(last, 55); last = one; + one = m_hash[24]; m_hash[24] = rotateLeft(last, 2); last = one; + one = m_hash[ 4]; m_hash[ 4] = rotateLeft(last, 14); last = one; + one = m_hash[15]; m_hash[15] = rotateLeft(last, 27); last = one; + one = m_hash[23]; m_hash[23] = rotateLeft(last, 41); last = one; + one = m_hash[19]; m_hash[19] = rotateLeft(last, 56); last = one; + one = m_hash[13]; m_hash[13] = rotateLeft(last, 8); last = one; + one = m_hash[12]; m_hash[12] = rotateLeft(last, 25); last = one; + one = m_hash[ 2]; m_hash[ 2] = rotateLeft(last, 43); last = one; + one = m_hash[20]; m_hash[20] = rotateLeft(last, 62); last = one; + one = m_hash[14]; m_hash[14] = rotateLeft(last, 18); last = one; + one = m_hash[22]; m_hash[22] = rotateLeft(last, 39); last = one; + one = m_hash[ 9]; m_hash[ 9] = rotateLeft(last, 61); last = one; + one = m_hash[ 6]; m_hash[ 6] = rotateLeft(last, 20); last = one; + m_hash[ 1] = rotateLeft(last, 44); + + // Chi + for (unsigned int j = 0; j < StateSize; j += 5) + { + // temporaries + uint64_t one = m_hash[j]; + uint64_t two = m_hash[j + 1]; + + m_hash[j] ^= m_hash[j + 2] & ~two; + m_hash[j + 1] ^= m_hash[j + 3] & ~m_hash[j + 2]; + m_hash[j + 2] ^= m_hash[j + 4] & ~m_hash[j + 3]; + m_hash[j + 3] ^= one & ~m_hash[j + 4]; + m_hash[j + 4] ^= two & ~one; + } + + // Iota + m_hash[0] ^= XorMasks[round]; + } +} + + +/// add arbitrary number of bytes +void Keccak::add(const void* data, size_t numBytes) +{ + const uint8_t* current = (const uint8_t*) data; + + if (m_bufferSize > 0) + { + while (numBytes > 0 && m_bufferSize < m_blockSize) + { + m_buffer[m_bufferSize++] = *current++; + numBytes--; + } + } + + // full buffer + if (m_bufferSize == m_blockSize) + { + processBlock((void*)m_buffer); + m_numBytes += m_blockSize; + m_bufferSize = 0; + } + + // no more data ? + if (numBytes == 0) + return; + + // process full blocks + while (numBytes >= m_blockSize) + { + processBlock(current); + current += m_blockSize; + m_numBytes += m_blockSize; + numBytes -= m_blockSize; + } + + // keep remaining bytes in buffer + while (numBytes > 0) + { + m_buffer[m_bufferSize++] = *current++; + numBytes--; + } +} + + +/// process everything left in the internal buffer +void Keccak::processBuffer() +{ + unsigned int blockSize = 200 - 2 * (m_bits / 8); + + // add padding + size_t offset = m_bufferSize; + // add a "1" byte + m_buffer[offset++] = 1; + // fill with zeros + while (offset < blockSize) + m_buffer[offset++] = 0; + + // and add a single set bit + m_buffer[blockSize - 1] |= 0x80; + + processBlock(m_buffer); +} + + +/// return latest hash as 16 hex characters +std::string Keccak::getHash() +{ + // save hash state + uint64_t oldHash[StateSize]; + for (unsigned int i = 0; i < StateSize; i++) + oldHash[i] = m_hash[i]; + + // process remaining bytes + processBuffer(); + + // convert hash to string + static const char dec2hex[16 + 1] = "0123456789abcdef"; + + // number of significant elements in hash (uint64_t) + unsigned int hashLength = m_bits / 64; + + std::string result; + for (unsigned int i = 0; i < hashLength; i++) + for (unsigned int j = 0; j < 8; j++) // 64 bits => 8 bytes + { + // convert a byte to hex + unsigned char oneByte = (unsigned char) (m_hash[i] >> (8 * j)); + result += dec2hex[oneByte >> 4]; + result += dec2hex[oneByte & 15]; + } + + // Keccak224's last entry in m_hash provides only 32 bits instead of 64 bits + unsigned int remainder = m_bits - hashLength * 64; + unsigned int processed = 0; + while (processed < remainder) + { + // convert a byte to hex + unsigned char oneByte = (unsigned char) (m_hash[hashLength] >> processed); + result += dec2hex[oneByte >> 4]; + result += dec2hex[oneByte & 15]; + + processed += 8; + } + + // restore state + for (unsigned int i = 0; i < StateSize; i++) + m_hash[i] = oldHash[i]; + + return result; +} + + +/// compute Keccak hash of a memory block +std::string Keccak::operator()(const void* data, size_t numBytes) +{ + reset(); + add(data, numBytes); + return getHash(); +} + + +/// compute Keccak hash of a string, excluding final zero +std::string Keccak::operator()(const std::string& text) +{ + reset(); + add(text.c_str(), text.size()); + return getHash(); +} diff --git a/lib/keccak.h b/lib/keccak.h new file mode 100644 index 0000000..8b87a25 --- /dev/null +++ b/lib/keccak.h @@ -0,0 +1,81 @@ +// ////////////////////////////////////////////////////////// +// keccak.h +// Copyright (c) 2014,2015 Stephan Brumme. All rights reserved. +// see http://create.stephan-brumme.com/disclaimer.html +// + +#pragma once + +//#include "hash.h" +#include + +// define fixed size integer types +#ifdef _MSC_VER +// Windows +typedef unsigned __int8 uint8_t; +typedef unsigned __int64 uint64_t; +#else +// GCC +#include +#endif + + +/// compute Keccak hash (designated SHA3) +/** Usage: + Keccak keccak; + std::string myHash = keccak("Hello World"); // std::string + std::string myHash2 = keccak("How are you", 11); // arbitrary data, 11 bytes + + // or in a streaming fashion: + + Keccak keccak; + while (more data available) + keccak.add(pointer to fresh data, number of new bytes); + std::string myHash3 = keccak.getHash(); + */ +class Keccak //: public Hash +{ +public: + /// algorithm variants + enum Bits { Keccak224 = 224, Keccak256 = 256, Keccak384 = 384, Keccak512 = 512 }; + + /// same as reset() + explicit Keccak(Bits bits = Keccak256); + + /// compute hash of a memory block + std::string operator()(const void* data, size_t numBytes); + /// compute hash of a string, excluding final zero + std::string operator()(const std::string& text); + + /// add arbitrary number of bytes + void add(const void* data, size_t numBytes); + + /// return latest hash as hex characters + std::string getHash(); + + /// restart + void reset(); + +private: + /// process a full block + void processBlock(const void* data); + /// process everything left in the internal buffer + void processBuffer(); + + /// 1600 bits, stored as 25x64 bit, BlockSize is no more than 1152 bits (Keccak224) + enum { StateSize = 1600 / (8 * 8), + MaxBlockSize = 200 - 2 * (224 / 8) }; + + /// hash + uint64_t m_hash[StateSize]; + /// size of processed data in bytes + uint64_t m_numBytes; + /// block size (less or equal to MaxBlockSize) + size_t m_blockSize; + /// valid bytes in m_buffer + size_t m_bufferSize; + /// bytes not processed yet + uint8_t m_buffer[MaxBlockSize]; + /// variant + Bits m_bits; +}; diff --git a/lib/md5.cpp b/lib/md5.cpp new file mode 100644 index 0000000..2743319 --- /dev/null +++ b/lib/md5.cpp @@ -0,0 +1,380 @@ +// ////////////////////////////////////////////////////////// +// md5.cpp +// Copyright (c) 2014,2015 Stephan Brumme. All rights reserved. +// see http://create.stephan-brumme.com/disclaimer.html +// + +#include "md5.h" + +#ifndef _MSC_VER +#include +#endif + + +/// same as reset() +MD5::MD5() +{ + reset(); +} + + +/// restart +void MD5::reset() +{ + m_numBytes = 0; + m_bufferSize = 0; + + // according to RFC 1321 + m_hash[0] = 0x67452301; + m_hash[1] = 0xefcdab89; + m_hash[2] = 0x98badcfe; + m_hash[3] = 0x10325476; +} + + +namespace +{ + // mix functions for processBlock() + inline uint32_t f1(uint32_t b, uint32_t c, uint32_t d) + { + return d ^ (b & (c ^ d)); // original: f = (b & c) | ((~b) & d); + } + + inline uint32_t f2(uint32_t b, uint32_t c, uint32_t d) + { + return c ^ (d & (b ^ c)); // original: f = (b & d) | (c & (~d)); + } + + inline uint32_t f3(uint32_t b, uint32_t c, uint32_t d) + { + return b ^ c ^ d; + } + + inline uint32_t f4(uint32_t b, uint32_t c, uint32_t d) + { + return c ^ (b | ~d); + } + + inline uint32_t rotate(uint32_t a, uint32_t c) + { + return (a << c) | (a >> (32 - c)); + } + +#if defined(__BYTE_ORDER) && (__BYTE_ORDER != 0) && (__BYTE_ORDER == __BIG_ENDIAN) + inline uint32_t swap(uint32_t x) + { +#if defined(__GNUC__) || defined(__clang__) + return __builtin_bswap32(x); +#endif +#ifdef MSC_VER + return _byteswap_ulong(x); +#endif + + return (x >> 24) | + ((x >> 8) & 0x0000FF00) | + ((x << 8) & 0x00FF0000) | + (x << 24); + } +#endif +} + + +/// process 64 bytes +void MD5::processBlock(const void* data) +{ + // get last hash + uint32_t a = m_hash[0]; + uint32_t b = m_hash[1]; + uint32_t c = m_hash[2]; + uint32_t d = m_hash[3]; + + // data represented as 16x 32-bit words + const uint32_t* words = (uint32_t*) data; + + // computations are little endian, swap data if necessary +#if defined(__BYTE_ORDER) && (__BYTE_ORDER != 0) && (__BYTE_ORDER == __BIG_ENDIAN) +#define LITTLEENDIAN(x) swap(x) +#else +#define LITTLEENDIAN(x) (x) +#endif + + // first round + uint32_t word0 = LITTLEENDIAN(words[ 0]); + a = rotate(a + f1(b,c,d) + word0 + 0xd76aa478, 7) + b; + uint32_t word1 = LITTLEENDIAN(words[ 1]); + d = rotate(d + f1(a,b,c) + word1 + 0xe8c7b756, 12) + a; + uint32_t word2 = LITTLEENDIAN(words[ 2]); + c = rotate(c + f1(d,a,b) + word2 + 0x242070db, 17) + d; + uint32_t word3 = LITTLEENDIAN(words[ 3]); + b = rotate(b + f1(c,d,a) + word3 + 0xc1bdceee, 22) + c; + + uint32_t word4 = LITTLEENDIAN(words[ 4]); + a = rotate(a + f1(b,c,d) + word4 + 0xf57c0faf, 7) + b; + uint32_t word5 = LITTLEENDIAN(words[ 5]); + d = rotate(d + f1(a,b,c) + word5 + 0x4787c62a, 12) + a; + uint32_t word6 = LITTLEENDIAN(words[ 6]); + c = rotate(c + f1(d,a,b) + word6 + 0xa8304613, 17) + d; + uint32_t word7 = LITTLEENDIAN(words[ 7]); + b = rotate(b + f1(c,d,a) + word7 + 0xfd469501, 22) + c; + + uint32_t word8 = LITTLEENDIAN(words[ 8]); + a = rotate(a + f1(b,c,d) + word8 + 0x698098d8, 7) + b; + uint32_t word9 = LITTLEENDIAN(words[ 9]); + d = rotate(d + f1(a,b,c) + word9 + 0x8b44f7af, 12) + a; + uint32_t word10 = LITTLEENDIAN(words[10]); + c = rotate(c + f1(d,a,b) + word10 + 0xffff5bb1, 17) + d; + uint32_t word11 = LITTLEENDIAN(words[11]); + b = rotate(b + f1(c,d,a) + word11 + 0x895cd7be, 22) + c; + + uint32_t word12 = LITTLEENDIAN(words[12]); + a = rotate(a + f1(b,c,d) + word12 + 0x6b901122, 7) + b; + uint32_t word13 = LITTLEENDIAN(words[13]); + d = rotate(d + f1(a,b,c) + word13 + 0xfd987193, 12) + a; + uint32_t word14 = LITTLEENDIAN(words[14]); + c = rotate(c + f1(d,a,b) + word14 + 0xa679438e, 17) + d; + uint32_t word15 = LITTLEENDIAN(words[15]); + b = rotate(b + f1(c,d,a) + word15 + 0x49b40821, 22) + c; + + // second round + a = rotate(a + f2(b,c,d) + word1 + 0xf61e2562, 5) + b; + d = rotate(d + f2(a,b,c) + word6 + 0xc040b340, 9) + a; + c = rotate(c + f2(d,a,b) + word11 + 0x265e5a51, 14) + d; + b = rotate(b + f2(c,d,a) + word0 + 0xe9b6c7aa, 20) + c; + + a = rotate(a + f2(b,c,d) + word5 + 0xd62f105d, 5) + b; + d = rotate(d + f2(a,b,c) + word10 + 0x02441453, 9) + a; + c = rotate(c + f2(d,a,b) + word15 + 0xd8a1e681, 14) + d; + b = rotate(b + f2(c,d,a) + word4 + 0xe7d3fbc8, 20) + c; + + a = rotate(a + f2(b,c,d) + word9 + 0x21e1cde6, 5) + b; + d = rotate(d + f2(a,b,c) + word14 + 0xc33707d6, 9) + a; + c = rotate(c + f2(d,a,b) + word3 + 0xf4d50d87, 14) + d; + b = rotate(b + f2(c,d,a) + word8 + 0x455a14ed, 20) + c; + + a = rotate(a + f2(b,c,d) + word13 + 0xa9e3e905, 5) + b; + d = rotate(d + f2(a,b,c) + word2 + 0xfcefa3f8, 9) + a; + c = rotate(c + f2(d,a,b) + word7 + 0x676f02d9, 14) + d; + b = rotate(b + f2(c,d,a) + word12 + 0x8d2a4c8a, 20) + c; + + // third round + a = rotate(a + f3(b,c,d) + word5 + 0xfffa3942, 4) + b; + d = rotate(d + f3(a,b,c) + word8 + 0x8771f681, 11) + a; + c = rotate(c + f3(d,a,b) + word11 + 0x6d9d6122, 16) + d; + b = rotate(b + f3(c,d,a) + word14 + 0xfde5380c, 23) + c; + + a = rotate(a + f3(b,c,d) + word1 + 0xa4beea44, 4) + b; + d = rotate(d + f3(a,b,c) + word4 + 0x4bdecfa9, 11) + a; + c = rotate(c + f3(d,a,b) + word7 + 0xf6bb4b60, 16) + d; + b = rotate(b + f3(c,d,a) + word10 + 0xbebfbc70, 23) + c; + + a = rotate(a + f3(b,c,d) + word13 + 0x289b7ec6, 4) + b; + d = rotate(d + f3(a,b,c) + word0 + 0xeaa127fa, 11) + a; + c = rotate(c + f3(d,a,b) + word3 + 0xd4ef3085, 16) + d; + b = rotate(b + f3(c,d,a) + word6 + 0x04881d05, 23) + c; + + a = rotate(a + f3(b,c,d) + word9 + 0xd9d4d039, 4) + b; + d = rotate(d + f3(a,b,c) + word12 + 0xe6db99e5, 11) + a; + c = rotate(c + f3(d,a,b) + word15 + 0x1fa27cf8, 16) + d; + b = rotate(b + f3(c,d,a) + word2 + 0xc4ac5665, 23) + c; + + // fourth round + a = rotate(a + f4(b,c,d) + word0 + 0xf4292244, 6) + b; + d = rotate(d + f4(a,b,c) + word7 + 0x432aff97, 10) + a; + c = rotate(c + f4(d,a,b) + word14 + 0xab9423a7, 15) + d; + b = rotate(b + f4(c,d,a) + word5 + 0xfc93a039, 21) + c; + + a = rotate(a + f4(b,c,d) + word12 + 0x655b59c3, 6) + b; + d = rotate(d + f4(a,b,c) + word3 + 0x8f0ccc92, 10) + a; + c = rotate(c + f4(d,a,b) + word10 + 0xffeff47d, 15) + d; + b = rotate(b + f4(c,d,a) + word1 + 0x85845dd1, 21) + c; + + a = rotate(a + f4(b,c,d) + word8 + 0x6fa87e4f, 6) + b; + d = rotate(d + f4(a,b,c) + word15 + 0xfe2ce6e0, 10) + a; + c = rotate(c + f4(d,a,b) + word6 + 0xa3014314, 15) + d; + b = rotate(b + f4(c,d,a) + word13 + 0x4e0811a1, 21) + c; + + a = rotate(a + f4(b,c,d) + word4 + 0xf7537e82, 6) + b; + d = rotate(d + f4(a,b,c) + word11 + 0xbd3af235, 10) + a; + c = rotate(c + f4(d,a,b) + word2 + 0x2ad7d2bb, 15) + d; + b = rotate(b + f4(c,d,a) + word9 + 0xeb86d391, 21) + c; + + // update hash + m_hash[0] += a; + m_hash[1] += b; + m_hash[2] += c; + m_hash[3] += d; +} + + +/// add arbitrary number of bytes +void MD5::add(const void* data, size_t numBytes) +{ + const uint8_t* current = (const uint8_t*) data; + + if (m_bufferSize > 0) + { + while (numBytes > 0 && m_bufferSize < BlockSize) + { + m_buffer[m_bufferSize++] = *current++; + numBytes--; + } + } + + // full buffer + if (m_bufferSize == BlockSize) + { + processBlock(m_buffer); + m_numBytes += BlockSize; + m_bufferSize = 0; + } + + // no more data ? + if (numBytes == 0) + return; + + // process full blocks + while (numBytes >= BlockSize) + { + processBlock(current); + current += BlockSize; + m_numBytes += BlockSize; + numBytes -= BlockSize; + } + + // keep remaining bytes in buffer + while (numBytes > 0) + { + m_buffer[m_bufferSize++] = *current++; + numBytes--; + } +} + + +/// process final block, less than 64 bytes +void MD5::processBuffer() +{ + // the input bytes are considered as bits strings, where the first bit is the most significant bit of the byte + + // - append "1" bit to message + // - append "0" bits until message length in bit mod 512 is 448 + // - append length as 64 bit integer + + // number of bits + size_t paddedLength = m_bufferSize * 8; + + // plus one bit set to 1 (always appended) + paddedLength++; + + // number of bits must be (numBits % 512) = 448 + size_t lower11Bits = paddedLength & 511; + if (lower11Bits <= 448) + paddedLength += 448 - lower11Bits; + else + paddedLength += 512 + 448 - lower11Bits; + // convert from bits to bytes + paddedLength /= 8; + + // only needed if additional data flows over into a second block + unsigned char extra[BlockSize]; + + // append a "1" bit, 128 => binary 10000000 + if (m_bufferSize < BlockSize) + m_buffer[m_bufferSize] = 128; + else + extra[0] = 128; + + size_t i; + for (i = m_bufferSize + 1; i < BlockSize; i++) + m_buffer[i] = 0; + for (; i < paddedLength; i++) + extra[i - BlockSize] = 0; + + // add message length in bits as 64 bit number + uint64_t msgBits = 8 * (m_numBytes + m_bufferSize); + // find right position + unsigned char* addLength; + if (paddedLength < BlockSize) + addLength = m_buffer + paddedLength; + else + addLength = extra + paddedLength - BlockSize; + + // must be little endian + *addLength++ = msgBits & 0xFF; msgBits >>= 8; + *addLength++ = msgBits & 0xFF; msgBits >>= 8; + *addLength++ = msgBits & 0xFF; msgBits >>= 8; + *addLength++ = msgBits & 0xFF; msgBits >>= 8; + *addLength++ = msgBits & 0xFF; msgBits >>= 8; + *addLength++ = msgBits & 0xFF; msgBits >>= 8; + *addLength++ = msgBits & 0xFF; msgBits >>= 8; + *addLength++ = msgBits & 0xFF; + + // process blocks + processBlock(m_buffer); + // flowed over into a second block ? + if (paddedLength > BlockSize) + processBlock(extra); +} + + +/// return latest hash as 32 hex characters +std::string MD5::getHash() +{ + // compute hash (as raw bytes) + unsigned char rawHash[HashBytes]; + getHash(rawHash); + + // convert to hex string + std::string result; + result.reserve(2 * HashBytes); + for (int i = 0; i < HashBytes; i++) + { + static const char dec2hex[16+1] = "0123456789abcdef"; + result += dec2hex[(rawHash[i] >> 4) & 15]; + result += dec2hex[ rawHash[i] & 15]; + } + + return result; +} + + +/// return latest hash as bytes +void MD5::getHash(unsigned char buffer[MD5::HashBytes]) +{ + // save old hash if buffer is partially filled + uint32_t oldHash[HashValues]; + for (int i = 0; i < HashValues; i++) + oldHash[i] = m_hash[i]; + + // process remaining bytes + processBuffer(); + + unsigned char* current = buffer; + for (int i = 0; i < HashValues; i++) + { + *current++ = m_hash[i] & 0xFF; + *current++ = (m_hash[i] >> 8) & 0xFF; + *current++ = (m_hash[i] >> 16) & 0xFF; + *current++ = (m_hash[i] >> 24) & 0xFF; + + // restore old hash + m_hash[i] = oldHash[i]; + } +} + + +/// compute MD5 of a memory block +std::string MD5::operator()(const void* data, size_t numBytes) +{ + reset(); + add(data, numBytes); + return getHash(); +} + + +/// compute MD5 of a string, excluding final zero +std::string MD5::operator()(const std::string& text) +{ + reset(); + add(text.c_str(), text.size()); + return getHash(); +} diff --git a/lib/md5.h b/lib/md5.h new file mode 100644 index 0000000..f53e2d9 --- /dev/null +++ b/lib/md5.h @@ -0,0 +1,78 @@ +// ////////////////////////////////////////////////////////// +// md5.h +// Copyright (c) 2014 Stephan Brumme. All rights reserved. +// see http://create.stephan-brumme.com/disclaimer.html +// + +#pragma once + +//#include "hash.h" +#include + +// define fixed size integer types +#ifdef _MSC_VER +// Windows +typedef unsigned __int8 uint8_t; +typedef unsigned __int32 uint32_t; +typedef unsigned __int64 uint64_t; +#else +// GCC +#include +#endif + + +/// compute MD5 hash +/** Usage: + MD5 md5; + std::string myHash = md5("Hello World"); // std::string + std::string myHash2 = md5("How are you", 11); // arbitrary data, 11 bytes + + // or in a streaming fashion: + + MD5 md5; + while (more data available) + md5.add(pointer to fresh data, number of new bytes); + std::string myHash3 = md5.getHash(); + */ +class MD5 //: public Hash +{ +public: + /// split into 64 byte blocks (=> 512 bits), hash is 16 bytes long + enum { BlockSize = 512 / 8, HashBytes = 16 }; + + /// same as reset() + MD5(); + + /// compute MD5 of a memory block + std::string operator()(const void* data, size_t numBytes); + /// compute MD5 of a string, excluding final zero + std::string operator()(const std::string& text); + + /// add arbitrary number of bytes + void add(const void* data, size_t numBytes); + + /// return latest hash as 32 hex characters + std::string getHash(); + /// return latest hash as bytes + void getHash(unsigned char buffer[HashBytes]); + + /// restart + void reset(); + +private: + /// process 64 bytes + void processBlock(const void* data); + /// process everything left in the internal buffer + void processBuffer(); + + /// size of processed data in bytes + uint64_t m_numBytes; + /// valid bytes in m_buffer + size_t m_bufferSize; + /// bytes not processed yet + uint8_t m_buffer[BlockSize]; + + enum { HashValues = HashBytes / 4 }; + /// hash, stored as integers + uint32_t m_hash[HashValues]; +}; diff --git a/lib/readme.md b/lib/readme.md new file mode 100644 index 0000000..8be9d01 --- /dev/null +++ b/lib/readme.md @@ -0,0 +1,51 @@ +# Portable C++ Hashing Library + +This is a mirror of my library hosted at https://create.stephan-brumme.com/hash-library/ + +In a nutshell: + +- computes CRC32, MD5, SHA1 and SHA256 (most common member of the SHA2 functions), Keccak and its SHA3 sibling +- optional HMAC (keyed-hash message authentication code) +- no external dependencies, small code size +- can work chunk-wise (for example when reading streams block-by-block) +- portable: supports Windows and Linux, tested on Little Endian and Big Endian CPUs +- roughly as fast as Linux core hashing functions +- open source, zlib license + +You can find code examples, benchmarks and much more on my website https://create.stephan-brumme.com/hash-library/ + +# How to use + +This example computes SHA256 hashes but the API is more or less identical for all hash algorithms: + +``` cpp +// SHA2 test program +#include "sha256.h" +#include // for std::cout only, not needed for hashing library + +int main(int, char**) +{ + // create a new hashing object + SHA256 sha256; + + // hashing an std::string + std::cout << sha256("Hello World") << std::endl; + // => a591a6d40bf420404a011733cfb7b190d62c65bf0bcda32b57b277d9ad9f146e + + // hashing a buffer of bytes + const char* buffer = "How are you"; + std::cout << sha256(buffer, 11) << std::endl; + // => 9c7d5b046878838da72e40ceb3179580958df544b240869b80d0275cc07209cc + + // or in a streaming fashion (re-use "How are you") + SHA256 sha256stream; + const char* url = "create.stephan-brumme.com"; // 25 bytes + int step = 5; + for (int i = 0; i < 25; i += step) + sha256stream.add(url + i, step); // add five bytes at a time + std::cout << sha256stream.getHash() << std::endl; + // => 82aa771f1183c52f973c798c9243a1c73833ea40961c73e55e12430ec77b69f6 + + return 0; +} +``` diff --git a/lib/sha1.cpp b/lib/sha1.cpp new file mode 100644 index 0000000..8331e92 --- /dev/null +++ b/lib/sha1.cpp @@ -0,0 +1,326 @@ +// ////////////////////////////////////////////////////////// +// sha1.cpp +// Copyright (c) 2014,2015 Stephan Brumme. All rights reserved. +// see http://create.stephan-brumme.com/disclaimer.html +// + +#include "sha1.h" + +// big endian architectures need #define __BYTE_ORDER __BIG_ENDIAN +#ifndef _MSC_VER +#include +#endif + + +/// same as reset() +SHA1::SHA1() +{ + reset(); +} + + +/// restart +void SHA1::reset() +{ + m_numBytes = 0; + m_bufferSize = 0; + + // according to RFC 1321 + m_hash[0] = 0x67452301; + m_hash[1] = 0xefcdab89; + m_hash[2] = 0x98badcfe; + m_hash[3] = 0x10325476; + m_hash[4] = 0xc3d2e1f0; +} + + +namespace +{ + // mix functions for processBlock() + inline uint32_t f1(uint32_t b, uint32_t c, uint32_t d) + { + return d ^ (b & (c ^ d)); // original: f = (b & c) | ((~b) & d); + } + + inline uint32_t f2(uint32_t b, uint32_t c, uint32_t d) + { + return b ^ c ^ d; + } + + inline uint32_t f3(uint32_t b, uint32_t c, uint32_t d) + { + return (b & c) | (b & d) | (c & d); + } + + inline uint32_t rotate(uint32_t a, uint32_t c) + { + return (a << c) | (a >> (32 - c)); + } + + inline uint32_t swap(uint32_t x) + { +#if defined(__GNUC__) || defined(__clang__) + return __builtin_bswap32(x); +#endif +#ifdef MSC_VER + return _byteswap_ulong(x); +#endif + + return (x >> 24) | + ((x >> 8) & 0x0000FF00) | + ((x << 8) & 0x00FF0000) | + (x << 24); + } +} + + +/// process 64 bytes +void SHA1::processBlock(const void* data) +{ + // get last hash + uint32_t a = m_hash[0]; + uint32_t b = m_hash[1]; + uint32_t c = m_hash[2]; + uint32_t d = m_hash[3]; + uint32_t e = m_hash[4]; + + // data represented as 16x 32-bit words + const uint32_t* input = (uint32_t*) data; + // convert to big endian + uint32_t words[80]; + for (int i = 0; i < 16; i++) +#if defined(__BYTE_ORDER) && (__BYTE_ORDER != 0) && (__BYTE_ORDER == __BIG_ENDIAN) + words[i] = input[i]; +#else + words[i] = swap(input[i]); +#endif + + // extend to 80 words + for (int i = 16; i < 80; i++) + words[i] = rotate(words[i-3] ^ words[i-8] ^ words[i-14] ^ words[i-16], 1); + + // first round + for (int i = 0; i < 4; i++) + { + int offset = 5*i; + e += rotate(a,5) + f1(b,c,d) + words[offset ] + 0x5a827999; b = rotate(b,30); + d += rotate(e,5) + f1(a,b,c) + words[offset+1] + 0x5a827999; a = rotate(a,30); + c += rotate(d,5) + f1(e,a,b) + words[offset+2] + 0x5a827999; e = rotate(e,30); + b += rotate(c,5) + f1(d,e,a) + words[offset+3] + 0x5a827999; d = rotate(d,30); + a += rotate(b,5) + f1(c,d,e) + words[offset+4] + 0x5a827999; c = rotate(c,30); + } + + // second round + for (int i = 4; i < 8; i++) + { + int offset = 5*i; + e += rotate(a,5) + f2(b,c,d) + words[offset ] + 0x6ed9eba1; b = rotate(b,30); + d += rotate(e,5) + f2(a,b,c) + words[offset+1] + 0x6ed9eba1; a = rotate(a,30); + c += rotate(d,5) + f2(e,a,b) + words[offset+2] + 0x6ed9eba1; e = rotate(e,30); + b += rotate(c,5) + f2(d,e,a) + words[offset+3] + 0x6ed9eba1; d = rotate(d,30); + a += rotate(b,5) + f2(c,d,e) + words[offset+4] + 0x6ed9eba1; c = rotate(c,30); + } + + // third round + for (int i = 8; i < 12; i++) + { + int offset = 5*i; + e += rotate(a,5) + f3(b,c,d) + words[offset ] + 0x8f1bbcdc; b = rotate(b,30); + d += rotate(e,5) + f3(a,b,c) + words[offset+1] + 0x8f1bbcdc; a = rotate(a,30); + c += rotate(d,5) + f3(e,a,b) + words[offset+2] + 0x8f1bbcdc; e = rotate(e,30); + b += rotate(c,5) + f3(d,e,a) + words[offset+3] + 0x8f1bbcdc; d = rotate(d,30); + a += rotate(b,5) + f3(c,d,e) + words[offset+4] + 0x8f1bbcdc; c = rotate(c,30); + } + + // fourth round + for (int i = 12; i < 16; i++) + { + int offset = 5*i; + e += rotate(a,5) + f2(b,c,d) + words[offset ] + 0xca62c1d6; b = rotate(b,30); + d += rotate(e,5) + f2(a,b,c) + words[offset+1] + 0xca62c1d6; a = rotate(a,30); + c += rotate(d,5) + f2(e,a,b) + words[offset+2] + 0xca62c1d6; e = rotate(e,30); + b += rotate(c,5) + f2(d,e,a) + words[offset+3] + 0xca62c1d6; d = rotate(d,30); + a += rotate(b,5) + f2(c,d,e) + words[offset+4] + 0xca62c1d6; c = rotate(c,30); + } + + // update hash + m_hash[0] += a; + m_hash[1] += b; + m_hash[2] += c; + m_hash[3] += d; + m_hash[4] += e; +} + + +/// add arbitrary number of bytes +void SHA1::add(const void* data, size_t numBytes) +{ + const uint8_t* current = (const uint8_t*) data; + + if (m_bufferSize > 0) + { + while (numBytes > 0 && m_bufferSize < BlockSize) + { + m_buffer[m_bufferSize++] = *current++; + numBytes--; + } + } + + // full buffer + if (m_bufferSize == BlockSize) + { + processBlock((void*)m_buffer); + m_numBytes += BlockSize; + m_bufferSize = 0; + } + + // no more data ? + if (numBytes == 0) + return; + + // process full blocks + while (numBytes >= BlockSize) + { + processBlock(current); + current += BlockSize; + m_numBytes += BlockSize; + numBytes -= BlockSize; + } + + // keep remaining bytes in buffer + while (numBytes > 0) + { + m_buffer[m_bufferSize++] = *current++; + numBytes--; + } +} + + +/// process final block, less than 64 bytes +void SHA1::processBuffer() +{ + // the input bytes are considered as bits strings, where the first bit is the most significant bit of the byte + + // - append "1" bit to message + // - append "0" bits until message length in bit mod 512 is 448 + // - append length as 64 bit integer + + // number of bits + size_t paddedLength = m_bufferSize * 8; + + // plus one bit set to 1 (always appended) + paddedLength++; + + // number of bits must be (numBits % 512) = 448 + size_t lower11Bits = paddedLength & 511; + if (lower11Bits <= 448) + paddedLength += 448 - lower11Bits; + else + paddedLength += 512 + 448 - lower11Bits; + // convert from bits to bytes + paddedLength /= 8; + + // only needed if additional data flows over into a second block + unsigned char extra[BlockSize]; + + // append a "1" bit, 128 => binary 10000000 + if (m_bufferSize < BlockSize) + m_buffer[m_bufferSize] = 128; + else + extra[0] = 128; + + size_t i; + for (i = m_bufferSize + 1; i < BlockSize; i++) + m_buffer[i] = 0; + for (; i < paddedLength; i++) + extra[i - BlockSize] = 0; + + // add message length in bits as 64 bit number + uint64_t msgBits = 8 * (m_numBytes + m_bufferSize); + // find right position + unsigned char* addLength; + if (paddedLength < BlockSize) + addLength = m_buffer + paddedLength; + else + addLength = extra + paddedLength - BlockSize; + + // must be big endian + *addLength++ = (unsigned char)((msgBits >> 56) & 0xFF); + *addLength++ = (unsigned char)((msgBits >> 48) & 0xFF); + *addLength++ = (unsigned char)((msgBits >> 40) & 0xFF); + *addLength++ = (unsigned char)((msgBits >> 32) & 0xFF); + *addLength++ = (unsigned char)((msgBits >> 24) & 0xFF); + *addLength++ = (unsigned char)((msgBits >> 16) & 0xFF); + *addLength++ = (unsigned char)((msgBits >> 8) & 0xFF); + *addLength = (unsigned char)( msgBits & 0xFF); + + // process blocks + processBlock(m_buffer); + // flowed over into a second block ? + if (paddedLength > BlockSize) + processBlock(extra); +} + + +/// return latest hash as 40 hex characters +std::string SHA1::getHash() +{ + // compute hash (as raw bytes) + unsigned char rawHash[HashBytes]; + getHash(rawHash); + + // convert to hex string + std::string result; + result.reserve(2 * HashBytes); + for (int i = 0; i < HashBytes; i++) + { + static const char dec2hex[16+1] = "0123456789abcdef"; + result += dec2hex[(rawHash[i] >> 4) & 15]; + result += dec2hex[ rawHash[i] & 15]; + } + + return result; +} + + +/// return latest hash as bytes +void SHA1::getHash(unsigned char buffer[SHA1::HashBytes]) +{ + // save old hash if buffer is partially filled + uint32_t oldHash[HashValues]; + for (int i = 0; i < HashValues; i++) + oldHash[i] = m_hash[i]; + + // process remaining bytes + processBuffer(); + + unsigned char* current = buffer; + for (int i = 0; i < HashValues; i++) + { + *current++ = (m_hash[i] >> 24) & 0xFF; + *current++ = (m_hash[i] >> 16) & 0xFF; + *current++ = (m_hash[i] >> 8) & 0xFF; + *current++ = m_hash[i] & 0xFF; + + // restore old hash + m_hash[i] = oldHash[i]; + } +} + + +/// compute SHA1 of a memory block +std::string SHA1::operator()(const void* data, size_t numBytes) +{ + reset(); + add(data, numBytes); + return getHash(); +} + + +/// compute SHA1 of a string, excluding final zero +std::string SHA1::operator()(const std::string& text) +{ + reset(); + add(text.c_str(), text.size()); + return getHash(); +} diff --git a/lib/sha1.h b/lib/sha1.h new file mode 100644 index 0000000..c8eb00d --- /dev/null +++ b/lib/sha1.h @@ -0,0 +1,78 @@ +// ////////////////////////////////////////////////////////// +// sha1.h +// Copyright (c) 2014,2015 Stephan Brumme. All rights reserved. +// see http://create.stephan-brumme.com/disclaimer.html +// + +#pragma once + +//#include "hash.h" +#include + +// define fixed size integer types +#ifdef _MSC_VER +// Windows +typedef unsigned __int8 uint8_t; +typedef unsigned __int32 uint32_t; +typedef unsigned __int64 uint64_t; +#else +// GCC +#include +#endif + + +/// compute SHA1 hash +/** Usage: + SHA1 sha1; + std::string myHash = sha1("Hello World"); // std::string + std::string myHash2 = sha1("How are you", 11); // arbitrary data, 11 bytes + + // or in a streaming fashion: + + SHA1 sha1; + while (more data available) + sha1.add(pointer to fresh data, number of new bytes); + std::string myHash3 = sha1.getHash(); + */ +class SHA1 //: public Hash +{ +public: + /// split into 64 byte blocks (=> 512 bits), hash is 20 bytes long + enum { BlockSize = 512 / 8, HashBytes = 20 }; + + /// same as reset() + SHA1(); + + /// compute SHA1 of a memory block + std::string operator()(const void* data, size_t numBytes); + /// compute SHA1 of a string, excluding final zero + std::string operator()(const std::string& text); + + /// add arbitrary number of bytes + void add(const void* data, size_t numBytes); + + /// return latest hash as 40 hex characters + std::string getHash(); + /// return latest hash as bytes + void getHash(unsigned char buffer[HashBytes]); + + /// restart + void reset(); + +private: + /// process 64 bytes + void processBlock(const void* data); + /// process everything left in the internal buffer + void processBuffer(); + + /// size of processed data in bytes + uint64_t m_numBytes; + /// valid bytes in m_buffer + size_t m_bufferSize; + /// bytes not processed yet + uint8_t m_buffer[BlockSize]; + + enum { HashValues = HashBytes / 4 }; + /// hash, stored as integers + uint32_t m_hash[HashValues]; +}; diff --git a/lib/sha256.cpp b/lib/sha256.cpp new file mode 100644 index 0000000..8f0857d --- /dev/null +++ b/lib/sha256.cpp @@ -0,0 +1,428 @@ +// ////////////////////////////////////////////////////////// +// sha256.cpp +// Copyright (c) 2014,2015,2021 Stephan Brumme. All rights reserved. +// see http://create.stephan-brumme.com/disclaimer.html +// + +#include "sha256.h" + +// big endian architectures need #define __BYTE_ORDER __BIG_ENDIAN +#ifndef _MSC_VER +#include +#endif + +//#define SHA2_224_SEED_VECTOR + + +/// same as reset() +SHA256::SHA256() +{ + reset(); +} + + +/// restart +void SHA256::reset() +{ + m_numBytes = 0; + m_bufferSize = 0; + + // according to RFC 1321 + // "These words were obtained by taking the first thirty-two bits of the + // fractional parts of the square roots of the first eight prime numbers" + m_hash[0] = 0x6a09e667; + m_hash[1] = 0xbb67ae85; + m_hash[2] = 0x3c6ef372; + m_hash[3] = 0xa54ff53a; + m_hash[4] = 0x510e527f; + m_hash[5] = 0x9b05688c; + m_hash[6] = 0x1f83d9ab; + m_hash[7] = 0x5be0cd19; + +#ifdef SHA2_224_SEED_VECTOR + // if you want SHA2-224 instead then use these seeds + // and throw away the last 32 bits of getHash + m_hash[0] = 0xc1059ed8; + m_hash[1] = 0x367cd507; + m_hash[2] = 0x3070dd17; + m_hash[3] = 0xf70e5939; + m_hash[4] = 0xffc00b31; + m_hash[5] = 0x68581511; + m_hash[6] = 0x64f98fa7; + m_hash[7] = 0xbefa4fa4; +#endif +} + + +namespace +{ + inline uint32_t rotate(uint32_t a, uint32_t c) + { + return (a >> c) | (a << (32 - c)); + } + + inline uint32_t swap(uint32_t x) + { +#if defined(__GNUC__) || defined(__clang__) + return __builtin_bswap32(x); +#endif +#ifdef MSC_VER + return _byteswap_ulong(x); +#endif + + return (x >> 24) | + ((x >> 8) & 0x0000FF00) | + ((x << 8) & 0x00FF0000) | + (x << 24); + } + + // mix functions for processBlock() + inline uint32_t f1(uint32_t e, uint32_t f, uint32_t g) + { + uint32_t term1 = rotate(e, 6) ^ rotate(e, 11) ^ rotate(e, 25); + uint32_t term2 = (e & f) ^ (~e & g); //(g ^ (e & (f ^ g))) + return term1 + term2; + } + + inline uint32_t f2(uint32_t a, uint32_t b, uint32_t c) + { + uint32_t term1 = rotate(a, 2) ^ rotate(a, 13) ^ rotate(a, 22); + uint32_t term2 = ((a | b) & c) | (a & b); //(a & (b ^ c)) ^ (b & c); + return term1 + term2; + } +} + + +/// process 64 bytes +void SHA256::processBlock(const void* data) +{ + // get last hash + uint32_t a = m_hash[0]; + uint32_t b = m_hash[1]; + uint32_t c = m_hash[2]; + uint32_t d = m_hash[3]; + uint32_t e = m_hash[4]; + uint32_t f = m_hash[5]; + uint32_t g = m_hash[6]; + uint32_t h = m_hash[7]; + + // data represented as 16x 32-bit words + const uint32_t* input = (uint32_t*) data; + // convert to big endian + uint32_t words[64]; + int i; + for (i = 0; i < 16; i++) +#if defined(__BYTE_ORDER) && (__BYTE_ORDER != 0) && (__BYTE_ORDER == __BIG_ENDIAN) + words[i] = input[i]; +#else + words[i] = swap(input[i]); +#endif + + uint32_t x,y; // temporaries + + // first round + x = h + f1(e,f,g) + 0x428a2f98 + words[ 0]; y = f2(a,b,c); d += x; h = x + y; + x = g + f1(d,e,f) + 0x71374491 + words[ 1]; y = f2(h,a,b); c += x; g = x + y; + x = f + f1(c,d,e) + 0xb5c0fbcf + words[ 2]; y = f2(g,h,a); b += x; f = x + y; + x = e + f1(b,c,d) + 0xe9b5dba5 + words[ 3]; y = f2(f,g,h); a += x; e = x + y; + x = d + f1(a,b,c) + 0x3956c25b + words[ 4]; y = f2(e,f,g); h += x; d = x + y; + x = c + f1(h,a,b) + 0x59f111f1 + words[ 5]; y = f2(d,e,f); g += x; c = x + y; + x = b + f1(g,h,a) + 0x923f82a4 + words[ 6]; y = f2(c,d,e); f += x; b = x + y; + x = a + f1(f,g,h) + 0xab1c5ed5 + words[ 7]; y = f2(b,c,d); e += x; a = x + y; + + // secound round + x = h + f1(e,f,g) + 0xd807aa98 + words[ 8]; y = f2(a,b,c); d += x; h = x + y; + x = g + f1(d,e,f) + 0x12835b01 + words[ 9]; y = f2(h,a,b); c += x; g = x + y; + x = f + f1(c,d,e) + 0x243185be + words[10]; y = f2(g,h,a); b += x; f = x + y; + x = e + f1(b,c,d) + 0x550c7dc3 + words[11]; y = f2(f,g,h); a += x; e = x + y; + x = d + f1(a,b,c) + 0x72be5d74 + words[12]; y = f2(e,f,g); h += x; d = x + y; + x = c + f1(h,a,b) + 0x80deb1fe + words[13]; y = f2(d,e,f); g += x; c = x + y; + x = b + f1(g,h,a) + 0x9bdc06a7 + words[14]; y = f2(c,d,e); f += x; b = x + y; + x = a + f1(f,g,h) + 0xc19bf174 + words[15]; y = f2(b,c,d); e += x; a = x + y; + + // extend to 24 words + for (; i < 24; i++) + words[i] = words[i-16] + + (rotate(words[i-15], 7) ^ rotate(words[i-15], 18) ^ (words[i-15] >> 3)) + + words[i-7] + + (rotate(words[i- 2], 17) ^ rotate(words[i- 2], 19) ^ (words[i- 2] >> 10)); + + // third round + x = h + f1(e,f,g) + 0xe49b69c1 + words[16]; y = f2(a,b,c); d += x; h = x + y; + x = g + f1(d,e,f) + 0xefbe4786 + words[17]; y = f2(h,a,b); c += x; g = x + y; + x = f + f1(c,d,e) + 0x0fc19dc6 + words[18]; y = f2(g,h,a); b += x; f = x + y; + x = e + f1(b,c,d) + 0x240ca1cc + words[19]; y = f2(f,g,h); a += x; e = x + y; + x = d + f1(a,b,c) + 0x2de92c6f + words[20]; y = f2(e,f,g); h += x; d = x + y; + x = c + f1(h,a,b) + 0x4a7484aa + words[21]; y = f2(d,e,f); g += x; c = x + y; + x = b + f1(g,h,a) + 0x5cb0a9dc + words[22]; y = f2(c,d,e); f += x; b = x + y; + x = a + f1(f,g,h) + 0x76f988da + words[23]; y = f2(b,c,d); e += x; a = x + y; + + // extend to 32 words + for (; i < 32; i++) + words[i] = words[i-16] + + (rotate(words[i-15], 7) ^ rotate(words[i-15], 18) ^ (words[i-15] >> 3)) + + words[i-7] + + (rotate(words[i- 2], 17) ^ rotate(words[i- 2], 19) ^ (words[i- 2] >> 10)); + + // fourth round + x = h + f1(e,f,g) + 0x983e5152 + words[24]; y = f2(a,b,c); d += x; h = x + y; + x = g + f1(d,e,f) + 0xa831c66d + words[25]; y = f2(h,a,b); c += x; g = x + y; + x = f + f1(c,d,e) + 0xb00327c8 + words[26]; y = f2(g,h,a); b += x; f = x + y; + x = e + f1(b,c,d) + 0xbf597fc7 + words[27]; y = f2(f,g,h); a += x; e = x + y; + x = d + f1(a,b,c) + 0xc6e00bf3 + words[28]; y = f2(e,f,g); h += x; d = x + y; + x = c + f1(h,a,b) + 0xd5a79147 + words[29]; y = f2(d,e,f); g += x; c = x + y; + x = b + f1(g,h,a) + 0x06ca6351 + words[30]; y = f2(c,d,e); f += x; b = x + y; + x = a + f1(f,g,h) + 0x14292967 + words[31]; y = f2(b,c,d); e += x; a = x + y; + + // extend to 40 words + for (; i < 40; i++) + words[i] = words[i-16] + + (rotate(words[i-15], 7) ^ rotate(words[i-15], 18) ^ (words[i-15] >> 3)) + + words[i-7] + + (rotate(words[i- 2], 17) ^ rotate(words[i- 2], 19) ^ (words[i- 2] >> 10)); + + // fifth round + x = h + f1(e,f,g) + 0x27b70a85 + words[32]; y = f2(a,b,c); d += x; h = x + y; + x = g + f1(d,e,f) + 0x2e1b2138 + words[33]; y = f2(h,a,b); c += x; g = x + y; + x = f + f1(c,d,e) + 0x4d2c6dfc + words[34]; y = f2(g,h,a); b += x; f = x + y; + x = e + f1(b,c,d) + 0x53380d13 + words[35]; y = f2(f,g,h); a += x; e = x + y; + x = d + f1(a,b,c) + 0x650a7354 + words[36]; y = f2(e,f,g); h += x; d = x + y; + x = c + f1(h,a,b) + 0x766a0abb + words[37]; y = f2(d,e,f); g += x; c = x + y; + x = b + f1(g,h,a) + 0x81c2c92e + words[38]; y = f2(c,d,e); f += x; b = x + y; + x = a + f1(f,g,h) + 0x92722c85 + words[39]; y = f2(b,c,d); e += x; a = x + y; + + // extend to 48 words + for (; i < 48; i++) + words[i] = words[i-16] + + (rotate(words[i-15], 7) ^ rotate(words[i-15], 18) ^ (words[i-15] >> 3)) + + words[i-7] + + (rotate(words[i- 2], 17) ^ rotate(words[i- 2], 19) ^ (words[i- 2] >> 10)); + + // sixth round + x = h + f1(e,f,g) + 0xa2bfe8a1 + words[40]; y = f2(a,b,c); d += x; h = x + y; + x = g + f1(d,e,f) + 0xa81a664b + words[41]; y = f2(h,a,b); c += x; g = x + y; + x = f + f1(c,d,e) + 0xc24b8b70 + words[42]; y = f2(g,h,a); b += x; f = x + y; + x = e + f1(b,c,d) + 0xc76c51a3 + words[43]; y = f2(f,g,h); a += x; e = x + y; + x = d + f1(a,b,c) + 0xd192e819 + words[44]; y = f2(e,f,g); h += x; d = x + y; + x = c + f1(h,a,b) + 0xd6990624 + words[45]; y = f2(d,e,f); g += x; c = x + y; + x = b + f1(g,h,a) + 0xf40e3585 + words[46]; y = f2(c,d,e); f += x; b = x + y; + x = a + f1(f,g,h) + 0x106aa070 + words[47]; y = f2(b,c,d); e += x; a = x + y; + + // extend to 56 words + for (; i < 56; i++) + words[i] = words[i-16] + + (rotate(words[i-15], 7) ^ rotate(words[i-15], 18) ^ (words[i-15] >> 3)) + + words[i-7] + + (rotate(words[i- 2], 17) ^ rotate(words[i- 2], 19) ^ (words[i- 2] >> 10)); + + // seventh round + x = h + f1(e,f,g) + 0x19a4c116 + words[48]; y = f2(a,b,c); d += x; h = x + y; + x = g + f1(d,e,f) + 0x1e376c08 + words[49]; y = f2(h,a,b); c += x; g = x + y; + x = f + f1(c,d,e) + 0x2748774c + words[50]; y = f2(g,h,a); b += x; f = x + y; + x = e + f1(b,c,d) + 0x34b0bcb5 + words[51]; y = f2(f,g,h); a += x; e = x + y; + x = d + f1(a,b,c) + 0x391c0cb3 + words[52]; y = f2(e,f,g); h += x; d = x + y; + x = c + f1(h,a,b) + 0x4ed8aa4a + words[53]; y = f2(d,e,f); g += x; c = x + y; + x = b + f1(g,h,a) + 0x5b9cca4f + words[54]; y = f2(c,d,e); f += x; b = x + y; + x = a + f1(f,g,h) + 0x682e6ff3 + words[55]; y = f2(b,c,d); e += x; a = x + y; + + // extend to 64 words + for (; i < 64; i++) + words[i] = words[i-16] + + (rotate(words[i-15], 7) ^ rotate(words[i-15], 18) ^ (words[i-15] >> 3)) + + words[i-7] + + (rotate(words[i- 2], 17) ^ rotate(words[i- 2], 19) ^ (words[i- 2] >> 10)); + + // eigth round + x = h + f1(e,f,g) + 0x748f82ee + words[56]; y = f2(a,b,c); d += x; h = x + y; + x = g + f1(d,e,f) + 0x78a5636f + words[57]; y = f2(h,a,b); c += x; g = x + y; + x = f + f1(c,d,e) + 0x84c87814 + words[58]; y = f2(g,h,a); b += x; f = x + y; + x = e + f1(b,c,d) + 0x8cc70208 + words[59]; y = f2(f,g,h); a += x; e = x + y; + x = d + f1(a,b,c) + 0x90befffa + words[60]; y = f2(e,f,g); h += x; d = x + y; + x = c + f1(h,a,b) + 0xa4506ceb + words[61]; y = f2(d,e,f); g += x; c = x + y; + x = b + f1(g,h,a) + 0xbef9a3f7 + words[62]; y = f2(c,d,e); f += x; b = x + y; + x = a + f1(f,g,h) + 0xc67178f2 + words[63]; y = f2(b,c,d); e += x; a = x + y; + + // update hash + m_hash[0] += a; + m_hash[1] += b; + m_hash[2] += c; + m_hash[3] += d; + m_hash[4] += e; + m_hash[5] += f; + m_hash[6] += g; + m_hash[7] += h; +} + + +/// add arbitrary number of bytes +void SHA256::add(const void* data, size_t numBytes) +{ + const uint8_t* current = (const uint8_t*) data; + + if (m_bufferSize > 0) + { + while (numBytes > 0 && m_bufferSize < BlockSize) + { + m_buffer[m_bufferSize++] = *current++; + numBytes--; + } + } + + // full buffer + if (m_bufferSize == BlockSize) + { + processBlock(m_buffer); + m_numBytes += BlockSize; + m_bufferSize = 0; + } + + // no more data ? + if (numBytes == 0) + return; + + // process full blocks + while (numBytes >= BlockSize) + { + processBlock(current); + current += BlockSize; + m_numBytes += BlockSize; + numBytes -= BlockSize; + } + + // keep remaining bytes in buffer + while (numBytes > 0) + { + m_buffer[m_bufferSize++] = *current++; + numBytes--; + } +} + + +/// process final block, less than 64 bytes +void SHA256::processBuffer() +{ + // the input bytes are considered as bits strings, where the first bit is the most significant bit of the byte + + // - append "1" bit to message + // - append "0" bits until message length in bit mod 512 is 448 + // - append length as 64 bit integer + + // number of bits + size_t paddedLength = m_bufferSize * 8; + + // plus one bit set to 1 (always appended) + paddedLength++; + + // number of bits must be (numBits % 512) = 448 + size_t lower11Bits = paddedLength & 511; + if (lower11Bits <= 448) + paddedLength += 448 - lower11Bits; + else + paddedLength += 512 + 448 - lower11Bits; + // convert from bits to bytes + paddedLength /= 8; + + // only needed if additional data flows over into a second block + unsigned char extra[BlockSize]; + + // append a "1" bit, 128 => binary 10000000 + if (m_bufferSize < BlockSize) + m_buffer[m_bufferSize] = 128; + else + extra[0] = 128; + + size_t i; + for (i = m_bufferSize + 1; i < BlockSize; i++) + m_buffer[i] = 0; + for (; i < paddedLength; i++) + extra[i - BlockSize] = 0; + + // add message length in bits as 64 bit number + uint64_t msgBits = 8 * (m_numBytes + m_bufferSize); + // find right position + unsigned char* addLength; + if (paddedLength < BlockSize) + addLength = m_buffer + paddedLength; + else + addLength = extra + paddedLength - BlockSize; + + // must be big endian + *addLength++ = (unsigned char)((msgBits >> 56) & 0xFF); + *addLength++ = (unsigned char)((msgBits >> 48) & 0xFF); + *addLength++ = (unsigned char)((msgBits >> 40) & 0xFF); + *addLength++ = (unsigned char)((msgBits >> 32) & 0xFF); + *addLength++ = (unsigned char)((msgBits >> 24) & 0xFF); + *addLength++ = (unsigned char)((msgBits >> 16) & 0xFF); + *addLength++ = (unsigned char)((msgBits >> 8) & 0xFF); + *addLength = (unsigned char)( msgBits & 0xFF); + + // process blocks + processBlock(m_buffer); + // flowed over into a second block ? + if (paddedLength > BlockSize) + processBlock(extra); +} + + +/// return latest hash as 64 hex characters +std::string SHA256::getHash() +{ + // compute hash (as raw bytes) + unsigned char rawHash[HashBytes]; + getHash(rawHash); + + // convert to hex string + std::string result; + result.reserve(2 * HashBytes); + for (int i = 0; i < HashBytes; i++) + { + static const char dec2hex[16+1] = "0123456789abcdef"; + result += dec2hex[(rawHash[i] >> 4) & 15]; + result += dec2hex[ rawHash[i] & 15]; + } + + return result; +} + + +/// return latest hash as bytes +void SHA256::getHash(unsigned char buffer[SHA256::HashBytes]) +{ + // save old hash if buffer is partially filled + uint32_t oldHash[HashValues]; + for (int i = 0; i < HashValues; i++) + oldHash[i] = m_hash[i]; + + // process remaining bytes + processBuffer(); + + unsigned char* current = buffer; + for (int i = 0; i < HashValues; i++) + { + *current++ = (m_hash[i] >> 24) & 0xFF; + *current++ = (m_hash[i] >> 16) & 0xFF; + *current++ = (m_hash[i] >> 8) & 0xFF; + *current++ = m_hash[i] & 0xFF; + + // restore old hash + m_hash[i] = oldHash[i]; + } +} + + +/// compute SHA256 of a memory block +std::string SHA256::operator()(const void* data, size_t numBytes) +{ + reset(); + add(data, numBytes); + return getHash(); +} + + +/// compute SHA256 of a string, excluding final zero +std::string SHA256::operator()(const std::string& text) +{ + reset(); + add(text.c_str(), text.size()); + return getHash(); +} diff --git a/lib/sha256.h b/lib/sha256.h new file mode 100644 index 0000000..aeaf314 --- /dev/null +++ b/lib/sha256.h @@ -0,0 +1,78 @@ +// ////////////////////////////////////////////////////////// +// sha256.h +// Copyright (c) 2014,2015 Stephan Brumme. All rights reserved. +// see http://create.stephan-brumme.com/disclaimer.html +// + +#pragma once + +//#include "hash.h" +#include + +// define fixed size integer types +#ifdef _MSC_VER +// Windows +typedef unsigned __int8 uint8_t; +typedef unsigned __int32 uint32_t; +typedef unsigned __int64 uint64_t; +#else +// GCC +#include +#endif + + +/// compute SHA256 hash +/** Usage: + SHA256 sha256; + std::string myHash = sha256("Hello World"); // std::string + std::string myHash2 = sha256("How are you", 11); // arbitrary data, 11 bytes + + // or in a streaming fashion: + + SHA256 sha256; + while (more data available) + sha256.add(pointer to fresh data, number of new bytes); + std::string myHash3 = sha256.getHash(); + */ +class SHA256 //: public Hash +{ +public: + /// split into 64 byte blocks (=> 512 bits), hash is 32 bytes long + enum { BlockSize = 512 / 8, HashBytes = 32 }; + + /// same as reset() + SHA256(); + + /// compute SHA256 of a memory block + std::string operator()(const void* data, size_t numBytes); + /// compute SHA256 of a string, excluding final zero + std::string operator()(const std::string& text); + + /// add arbitrary number of bytes + void add(const void* data, size_t numBytes); + + /// return latest hash as 64 hex characters + std::string getHash(); + /// return latest hash as bytes + void getHash(unsigned char buffer[HashBytes]); + + /// restart + void reset(); + +private: + /// process 64 bytes + void processBlock(const void* data); + /// process everything left in the internal buffer + void processBuffer(); + + /// size of processed data in bytes + uint64_t m_numBytes; + /// valid bytes in m_buffer + size_t m_bufferSize; + /// bytes not processed yet + uint8_t m_buffer[BlockSize]; + + enum { HashValues = HashBytes / 4 }; + /// hash, stored as integers + uint32_t m_hash[HashValues]; +}; diff --git a/lib/sha3.cpp b/lib/sha3.cpp new file mode 100644 index 0000000..2f6bc7b --- /dev/null +++ b/lib/sha3.cpp @@ -0,0 +1,300 @@ +// ////////////////////////////////////////////////////////// +// sha3.cpp +// Copyright (c) 2014,2015 Stephan Brumme. All rights reserved. +// see http://create.stephan-brumme.com/disclaimer.html +// + +#include "sha3.h" + +// big endian architectures need #define __BYTE_ORDER __BIG_ENDIAN +#ifndef _MSC_VER +#include +#endif + +#include + + +/// same as reset() +SHA3::SHA3(Bits bits) +: m_blockSize(200 - 2 * (bits / 8)), + m_bits(bits) +{ + reset(); +} + + +/// restart +void SHA3::reset() +{ + for (size_t i = 0; i < StateSize; i++) + m_hash[i] = 0; + + m_numBytes = 0; + m_bufferSize = 0; +} + + +/// constants and local helper functions +namespace +{ + const unsigned int Rounds = 24; + const uint64_t XorMasks[Rounds] = + { + 0x0000000000000001ULL, 0x0000000000008082ULL, 0x800000000000808aULL, + 0x8000000080008000ULL, 0x000000000000808bULL, 0x0000000080000001ULL, + 0x8000000080008081ULL, 0x8000000000008009ULL, 0x000000000000008aULL, + 0x0000000000000088ULL, 0x0000000080008009ULL, 0x000000008000000aULL, + 0x000000008000808bULL, 0x800000000000008bULL, 0x8000000000008089ULL, + 0x8000000000008003ULL, 0x8000000000008002ULL, 0x8000000000000080ULL, + 0x000000000000800aULL, 0x800000008000000aULL, 0x8000000080008081ULL, + 0x8000000000008080ULL, 0x0000000080000001ULL, 0x8000000080008008ULL + }; + + /// rotate left and wrap around to the right + inline uint64_t rotateLeft(uint64_t x, uint8_t numBits) + { + return (x << numBits) | (x >> (64 - numBits)); + } + + /// convert litte vs big endian + inline uint64_t swap(uint64_t x) + { +#if defined(__GNUC__) || defined(__clang__) + return __builtin_bswap64(x); +#endif +#ifdef _MSC_VER + return _byteswap_uint64(x); +#endif + + return (x >> 56) | + ((x >> 40) & 0x000000000000FF00ULL) | + ((x >> 24) & 0x0000000000FF0000ULL) | + ((x >> 8) & 0x00000000FF000000ULL) | + ((x << 8) & 0x000000FF00000000ULL) | + ((x << 24) & 0x0000FF0000000000ULL) | + ((x << 40) & 0x00FF000000000000ULL) | + (x << 56); + } + + + /// return x % 5 for 0 <= x <= 9 + unsigned int mod5(unsigned int x) + { + if (x < 5) + return x; + + return x - 5; + } +} + + +/// process a full block +void SHA3::processBlock(const void* data) +{ +#if defined(__BYTE_ORDER) && (__BYTE_ORDER != 0) && (__BYTE_ORDER == __BIG_ENDIAN) +#define LITTLEENDIAN(x) swap(x) +#else +#define LITTLEENDIAN(x) (x) +#endif + + const uint64_t* data64 = (const uint64_t*) data; + // mix data into state + for (unsigned int i = 0; i < m_blockSize / 8; i++) + m_hash[i] ^= LITTLEENDIAN(data64[i]); + + // re-compute state + for (unsigned int round = 0; round < Rounds; round++) + { + // Theta + uint64_t coefficients[5]; + for (unsigned int i = 0; i < 5; i++) + coefficients[i] = m_hash[i] ^ m_hash[i + 5] ^ m_hash[i + 10] ^ m_hash[i + 15] ^ m_hash[i + 20]; + + for (unsigned int i = 0; i < 5; i++) + { + uint64_t one = coefficients[mod5(i + 4)] ^ rotateLeft(coefficients[mod5(i + 1)], 1); + m_hash[i ] ^= one; + m_hash[i + 5] ^= one; + m_hash[i + 10] ^= one; + m_hash[i + 15] ^= one; + m_hash[i + 20] ^= one; + } + + // temporary + uint64_t one; + + // Rho Pi + uint64_t last = m_hash[1]; + one = m_hash[10]; m_hash[10] = rotateLeft(last, 1); last = one; + one = m_hash[ 7]; m_hash[ 7] = rotateLeft(last, 3); last = one; + one = m_hash[11]; m_hash[11] = rotateLeft(last, 6); last = one; + one = m_hash[17]; m_hash[17] = rotateLeft(last, 10); last = one; + one = m_hash[18]; m_hash[18] = rotateLeft(last, 15); last = one; + one = m_hash[ 3]; m_hash[ 3] = rotateLeft(last, 21); last = one; + one = m_hash[ 5]; m_hash[ 5] = rotateLeft(last, 28); last = one; + one = m_hash[16]; m_hash[16] = rotateLeft(last, 36); last = one; + one = m_hash[ 8]; m_hash[ 8] = rotateLeft(last, 45); last = one; + one = m_hash[21]; m_hash[21] = rotateLeft(last, 55); last = one; + one = m_hash[24]; m_hash[24] = rotateLeft(last, 2); last = one; + one = m_hash[ 4]; m_hash[ 4] = rotateLeft(last, 14); last = one; + one = m_hash[15]; m_hash[15] = rotateLeft(last, 27); last = one; + one = m_hash[23]; m_hash[23] = rotateLeft(last, 41); last = one; + one = m_hash[19]; m_hash[19] = rotateLeft(last, 56); last = one; + one = m_hash[13]; m_hash[13] = rotateLeft(last, 8); last = one; + one = m_hash[12]; m_hash[12] = rotateLeft(last, 25); last = one; + one = m_hash[ 2]; m_hash[ 2] = rotateLeft(last, 43); last = one; + one = m_hash[20]; m_hash[20] = rotateLeft(last, 62); last = one; + one = m_hash[14]; m_hash[14] = rotateLeft(last, 18); last = one; + one = m_hash[22]; m_hash[22] = rotateLeft(last, 39); last = one; + one = m_hash[ 9]; m_hash[ 9] = rotateLeft(last, 61); last = one; + one = m_hash[ 6]; m_hash[ 6] = rotateLeft(last, 20); last = one; + m_hash[ 1] = rotateLeft(last, 44); + + // Chi + for (unsigned int j = 0; j < StateSize; j += 5) + { + // temporaries + uint64_t one = m_hash[j]; + uint64_t two = m_hash[j + 1]; + + m_hash[j] ^= m_hash[j + 2] & ~two; + m_hash[j + 1] ^= m_hash[j + 3] & ~m_hash[j + 2]; + m_hash[j + 2] ^= m_hash[j + 4] & ~m_hash[j + 3]; + m_hash[j + 3] ^= one & ~m_hash[j + 4]; + m_hash[j + 4] ^= two & ~one; + } + + // Iota + m_hash[0] ^= XorMasks[round]; + } +} + + +/// add arbitrary number of bytes +void SHA3::add(const void* data, size_t numBytes) +{ + const uint8_t* current = (const uint8_t*) data; + + // copy data to buffer + if (m_bufferSize > 0) + { + while (numBytes > 0 && m_bufferSize < m_blockSize) + { + m_buffer[m_bufferSize++] = *current++; + numBytes--; + } + } + + // full buffer + if (m_bufferSize == m_blockSize) + { + processBlock((void*)m_buffer); + m_numBytes += m_blockSize; + m_bufferSize = 0; + } + + // no more data ? + if (numBytes == 0) + return; + + // process full blocks + while (numBytes >= m_blockSize) + { + processBlock(current); + current += m_blockSize; + m_numBytes += m_blockSize; + numBytes -= m_blockSize; + } + + // keep remaining bytes in buffer + while (numBytes > 0) + { + m_buffer[m_bufferSize++] = *current++; + numBytes--; + } +} + + +/// process everything left in the internal buffer +void SHA3::processBuffer() +{ + // add padding + size_t offset = m_bufferSize; + // add a "1" byte + m_buffer[offset++] = 0x06; + // fill with zeros + while (offset < m_blockSize) + m_buffer[offset++] = 0; + + // and add a single set bit + m_buffer[offset - 1] |= 0x80; + + processBlock(m_buffer); +} + + +/// return latest hash as 16 hex characters +std::string SHA3::getHash() +{ + // save hash state + uint64_t oldHash[StateSize]; + for (unsigned int i = 0; i < StateSize; i++) + oldHash[i] = m_hash[i]; + + // process remaining bytes + processBuffer(); + + // convert hash to string + static const char dec2hex[16 + 1] = "0123456789abcdef"; + + // number of significant elements in hash (uint64_t) + unsigned int hashLength = m_bits / 64; + + std::string result; + result.reserve(m_bits / 4); + for (unsigned int i = 0; i < hashLength; i++) + for (unsigned int j = 0; j < 8; j++) // 64 bits => 8 bytes + { + // convert a byte to hex + unsigned char oneByte = (unsigned char) (m_hash[i] >> (8 * j)); + result += dec2hex[oneByte >> 4]; + result += dec2hex[oneByte & 15]; + } + + // SHA3-224's last entry in m_hash provides only 32 bits instead of 64 bits + unsigned int remainder = m_bits - hashLength * 64; + unsigned int processed = 0; + while (processed < remainder) + { + // convert a byte to hex + unsigned char oneByte = (unsigned char) (m_hash[hashLength] >> processed); + result += dec2hex[oneByte >> 4]; + result += dec2hex[oneByte & 15]; + + processed += 8; + } + + // restore state + for (unsigned int i = 0; i < StateSize; i++) + m_hash[i] = oldHash[i]; + + return result; +} + + +/// compute SHA3 of a memory block +std::string SHA3::operator()(const void* data, size_t numBytes) +{ + reset(); + add(data, numBytes); + return getHash(); +} + + +/// compute SHA3 of a string, excluding final zero +std::string SHA3::operator()(const std::string& text) +{ + reset(); + add(text.c_str(), text.size()); + return getHash(); +} diff --git a/lib/sha3.h b/lib/sha3.h new file mode 100644 index 0000000..31c0bc4 --- /dev/null +++ b/lib/sha3.h @@ -0,0 +1,81 @@ +// ////////////////////////////////////////////////////////// +// sha3.h +// Copyright (c) 2014,2015 Stephan Brumme. All rights reserved. +// see http://create.stephan-brumme.com/disclaimer.html +// + +#pragma once + +//#include "hash.h" +#include + +// define fixed size integer types +#ifdef _MSC_VER +// Windows +typedef unsigned __int8 uint8_t; +typedef unsigned __int64 uint64_t; +#else +// GCC +#include +#endif + + +/// compute SHA3 hash +/** Usage: + SHA3 sha3; + std::string myHash = sha3("Hello World"); // std::string + std::string myHash2 = sha3("How are you", 11); // arbitrary data, 11 bytes + + // or in a streaming fashion: + + SHA3 sha3; + while (more data available) + sha3.add(pointer to fresh data, number of new bytes); + std::string myHash3 = sha3.getHash(); + */ +class SHA3 //: public Hash +{ +public: + /// algorithm variants + enum Bits { Bits224 = 224, Bits256 = 256, Bits384 = 384, Bits512 = 512 }; + + /// same as reset() + explicit SHA3(Bits bits = Bits256); + + /// compute hash of a memory block + std::string operator()(const void* data, size_t numBytes); + /// compute hash of a string, excluding final zero + std::string operator()(const std::string& text); + + /// add arbitrary number of bytes + void add(const void* data, size_t numBytes); + + /// return latest hash as hex characters + std::string getHash(); + + /// restart + void reset(); + +private: + /// process a full block + void processBlock(const void* data); + /// process everything left in the internal buffer + void processBuffer(); + + /// 1600 bits, stored as 25x64 bit, BlockSize is no more than 1152 bits (Keccak224) + enum { StateSize = 1600 / (8 * 8), + MaxBlockSize = 200 - 2 * (224 / 8) }; + + /// hash + uint64_t m_hash[StateSize]; + /// size of processed data in bytes + uint64_t m_numBytes; + /// block size (less or equal to MaxBlockSize) + size_t m_blockSize; + /// valid bytes in m_buffer + size_t m_bufferSize; + /// bytes not processed yet + uint8_t m_buffer[MaxBlockSize]; + /// variant + Bits m_bits; +}; diff --git a/lib/tests/github-issue2.cpp b/lib/tests/github-issue2.cpp new file mode 100644 index 0000000..c85cfd4 --- /dev/null +++ b/lib/tests/github-issue2.cpp @@ -0,0 +1,64 @@ +// minimal test case for https://github.com/stbrumme/hash-library/issues/2 +// g++ github-issue2.cpp ../sha*.cpp ../keccak.cpp ../md5.cpp -o github-issue2 && ./github-issue2 + +#include "../sha1.h" +#include "../sha256.h" +#include "../sha3.h" +#include "../keccak.h" +#include "../md5.h" +#include + +int main() +{ + std::string text = "hello world"; + + std::cout << "SHA1:" << std::endl; + SHA1 sha1; + sha1.add(text.c_str(), text.size()); + + std::cout << sha1.getHash() << std::endl; + std::cout << sha1.getHash() << std::endl; + std::cout << sha1.getHash() << std::endl; + + std::cout << std::endl; + + std::cout << "SHA256:" << std::endl; + SHA256 sha256; + sha256.add(text.c_str(), text.size()); + + std::cout << sha256.getHash() << std::endl; + std::cout << sha256.getHash() << std::endl; + std::cout << sha256.getHash() << std::endl; + + std::cout << std::endl; + + std::cout << "SHA3:" << std::endl; + SHA3 sha3; + sha3.add(text.c_str(), text.size()); + + std::cout << sha3.getHash() << std::endl; + std::cout << sha3.getHash() << std::endl; + std::cout << sha3.getHash() << std::endl; + + std::cout << std::endl; + + std::cout << "Keccak:" << std::endl; + Keccak keccak; + keccak.add(text.c_str(), text.size()); + + std::cout << keccak.getHash() << std::endl; + std::cout << keccak.getHash() << std::endl; + std::cout << keccak.getHash() << std::endl; + + std::cout << std::endl; + + std::cout << "MD5:" << std::endl; + MD5 md5; + md5.add(text.c_str(), text.size()); + + std::cout << md5.getHash() << std::endl; + std::cout << md5.getHash() << std::endl; + std::cout << md5.getHash() << std::endl; + + return 0; +} diff --git a/lib/tests/github-issue6.cpp b/lib/tests/github-issue6.cpp new file mode 100644 index 0000000..e303959 --- /dev/null +++ b/lib/tests/github-issue6.cpp @@ -0,0 +1,16 @@ +// minimal test case for https://github.com/stbrumme/hash-library/issues/6 +// g++ github-issue6.cpp ../sha3.cpp -o github-issue6 && ./github-issue6 + +#include "../sha3.h" +#include + +int main(int argc, char *argv[]) +{ + std::string text = "72a5f501151ca974002f34"; + + SHA3 hasher(SHA3::Bits512); + hasher.add(text.data(), text.size()); + std::cout << hasher.getHash() << std::endl; + + return 0; +} diff --git a/lib/tests/tests.cpp b/lib/tests/tests.cpp new file mode 100644 index 0000000..329fbbd --- /dev/null +++ b/lib/tests/tests.cpp @@ -0,0 +1,361 @@ +// ////////////////////////////////////////////////////////// +// tests.cpp +// Copyright (c) 2015 Stephan Brumme. All rights reserved. +// see http://create.stephan-brumme.com/disclaimer.html +// + +// simple test suite for hash-library +// g++ tests.cpp ../crc32.cpp ../md5.cpp ../sha1.cpp ../sha256.cpp ../sha3.cpp -o tests && ./tests + +#include "../crc32.h" +#include "../md5.h" +#include "../sha1.h" +#include "../sha256.h" +#include "../sha3.h" +#include "../keccak.h" + +#include "../hmac.h" + +#include +#include + +#include + + +struct TestSet +{ + const char* input; + const char* crc32b; + const char* md5; + const char* sha1; + const char* sha256; + const char* sha3_256; +}; + +const size_t NumTests = 100; +TestSet testset[NumTests] = +{ // generated by PHP script, SHA3 vectors from https://raw.githubusercontent.com/gvanas/KeccakCodePackage/master/TestVectors/ShortMsgKAT_SHA3-256.txt + /* + $lines = file("ShortMsgKAT_SHA3-256.txt"); + for ($i = 1; $i <= 100; $i++) + { + $hex = trim(strtolower(substr($lines[8 * 4 * $i + 3], 6))); + $sha3 = trim(strtolower(substr($lines[8 * 4 * $i + 4], 5))); + + $msg = hex2bin($hex); + echo "{ \"$hex\", \"". + hash("crc32b", $msg).'", "'. + hash("md5", $msg).'", "'. + hash("sha1", $msg).'", "'. + hash("sha256", $msg).'", "'. + "$sha3\" }, // $i\n"; + } + */ + + { "cc", "40d06116", "a2e970f170961ce879190d64982c94ec", "a6f57425137e9aa54537f0b3f5364ce165aedb0a", "1dd8312636f6a0bf3d21fa2855e63072507453e93a5ced4301b364e91c9d87d6", "677035391cd3701293d385f037ba32796252bb7ce180b00b582dd9b20aaad7f0" }, // 1 + { "41fb", "82d4472f", "70d3e9af7232e67b6b6f3e71f7399438", "a6a5d330d9928b452ca7e34e946c52ea4f6eaa15", "0f8fa28112230a7a0b3cabcb64d37bd38f5023b1391e38f89a9b29f32b0aefbc", "39f31b6e653dfcd9caed2602fd87f61b6254f581312fb6eeec4d7148fa2e72aa" }, // 2 + { "1f877c", "c54a0ec4", "f7ac37ba79246d6a36b49c0993791110", "d17212f7dbfa31d10b68d480bc91cd3e1596be86", "ab0213910396c8d94cbf3b6c97de1fc97fc55cea4b6b6cc25ea4b71e7e7bc28c", "bc22345e4bd3f792a341cf18ac0789f1c9c966712a501b19d1b6632ccd408ec5" }, // 3 + { "c1ecfdfc", "5a545e7c", "af9116916ca42299e557e55cfa3e1591", "dc148b935ff1614ba17bdbad6e5392179e412f0d", "7df4925396138971f4a733680107ce202c5c5991dbc8737ad07eb4da85a06f85", "c5859be82560cc8789133f7c834a6ee628e351e504e601e8059a0667ff62c124" }, // 4 + { "21f134ac57", "d086fa95", "29057856dd5548ac8c1cca4b27489449", "404be2d420abc459707149bb79c8065aded00e7e", "a0ba0190c23bf1140cf5bf5a07e1140df55389792283bb6a8b5867a539ac7931", "55bd9224af4eed0d121149e37ff4d7dd5be24bd9fbe56e0171e87db7a6f4e06d" }, // 5 + { "c6f50bb74e29", "cdff1654", "d175ad6887766bf159f1bde8e514465a", "6685c62b13f7fc0703fd246c050a19cce98fcd97", "e2c0a1c005c4aa91ad89e509b603c5c0f474a18df291e5ca378725a9ad76fb09", "ae0cbc757d4ab088e172abfd8746289950f92d38a25295658dbf744b5635af04" }, // 6 + { "119713cc83eeef", "54465641", "27e281ab44bce27391bc7cee7b0f3437", "1fcd96a8c76f4d884c744bf840507acfe646ff76", "96e043b747fa1737d63d83b898987d3e70c816175a50333077ce4e7602255975", "e340c9a44373efcc212f3cb66a047ac34c87ff1c58c4a14b16a2bfc34698bb1d" }, // 7 + { "4a4f202484512526", "696ab8df", "90ea55f66c4b5239df52b05349455037", "928a171eacc5698811ef2992712458a9fa043955", "1b1c9bf7e050805714c81c03a05a6961e924bbaca37cb5b9998cb46bb2be4fa5", "ba4fb009d57a5ceb85fc64d54e5c55a55854b41cc47ad15294bc41f32165dfba" }, // 8 + { "1f66ab4185ed9b6375", "c0b622ae", "164a8c44008d14028fae0cf7b9d566aa", "8b81a9a58e987edb923fe6118ca6099cb71ad55a", "0eb3c0f5f345bd6cf98cf870886abc1817a0c5dde08d62f870a6b4a006979ee3", "b9886ef905c8bdd272eda8298865e0769869f1c964460d1aa9d7a0c687707ccd" }, // 9 + { "eed7422227613b6f53c9", "2029782c", "e57498c9318a515fcd8980dc319aa10a", "261830dfe450e4d58e5315cb0cb9d31c725cc406", "9758c2ee9d9782c6a3e60b394b16837689ab6f13c4157d45fc6ee7597a59448f", "fab8f88d3191e21a725b21c63a02cad3fa7c450ef8584b94cfa382f393422455" }, // 10 + { "eaeed5cdffd89dece455f1", "42fcfb29", "5e49b16a26a63aef2912956918f6a919", "c0507f76cea3e4d46edf256d49fe0ccf0ec2145a", "0a5f39f0e909a63bc93a76a21e94d62a0451d9f8123ecc5a59e5bd240b2850b0", "9363acd3f48bb91a8998aa0e8df75c971770a16a71e7d2334409734cd7d0a9ee" }, // 11 + { "5be43c90f22902e4fe8ed2d3", "4fbb1441", "e907bfc096655d56d3799b422f0ddd16", "f089f569228795551af51bbff935ac0e6b625c78", "c6057a042954e08be906ff710b042dbf6352f8b958b8ade708439063710bb5e2", "16932f6f65deaad5780e25ab410c66b0e4198eba9f4ed1a25ee24f7879faefe2" }, // 12 + { "a746273228122f381c3b46e4f1", "ad022e12", "ae0549cbb3704b5d2d1f18dbbc159de4", "2b269ce05fc8392c0333f8d1aec8ce32ed969e32", "7c48389c069dedf88be6534d34dfc20c109ce40788b96ddebc1e9209c0ca49de", "1c28100e0ef50671c7ea3e024fa3ba9da2ebddb4de264c3a2426c36ad3f91c61" }, // 13 + { "3c5871cd619c69a63b540eb5a625", "1ca57d8b", "c4d0ef66c3ddc1f3ee998de21e6834ec", "88b2b64f3ada91ed6cd29e80b8c67e2cd6ff555a", "82af41b707f8336fadc9fdbfc00b50d11a27b46e1e022ed4865896dca259377d", "8183be4875fab7ec5f99ed94f5f900cf1d6b953d8f71e1e7cc008687980e613a" }, // 14 + { "fa22874bcc068879e8ef11a69f0722", "0e69af1c", "3af22d0558d6cb039e164bb47bc48265", "46234cafafbce55281c87102559f47450976bb08", "f479cdfa3488c4d8e44c8e10167a54cbc1142a7a75bb5a0ee6aa647a93a65d0f", "3b1a6d21fe44691dac4eb7c593a6d8523cb606e63cf00e94d711a574248daca5" }, // 15 + { "52a608ab21ccdd8a4457a57ede782176", "1ccb278f", "72d4071b78731c61b61076067f3ef40b", "2d64a7c42ce0cb8dae2617effd031b5fe328eef6", "7ae441ed62ba0263f194386043ac4ba452bc593a5a9ad001da5c70ddc533abb1", "2c7e7cb356fdc68ec8927e499d2a6bae2b781817919c829ebbe8225baed46967" }, // 16 + { "82e192e4043ddcd12ecf52969d0f807eed", "4e448a12", "e880a1c8344c01c1aede282f4a0c6930", "f4c49546bb55bfadddb0e8f0c14add76039250ce", "b06558895e83f861bcdc2556f7e6377468341b352745caf2605df544275e9949", "c7b12eff692d842110cc39ac60616707acb3f9b0f1cb361b94577efc529ca26c" }, // 17 + { "75683dcb556140c522543bb6e9098b21a21e", "4b50b9e1", "9b92909591db3d4957047c6bb3c06880", "bb479acce571cec0775532af7c7b19c2a719456d", "7da11d5a5c7e39d51d7509bd8f5819f7110a3f7aecaf314cf7d6a5943e70ac66", "493ebaebc04776f4e067555afa09b58c850fdf1b0e22d4bf006ce41c091dc762" }, // 18 + { "06e4efe45035e61faaf4287b4d8d1f12ca97e5", "45cad288", "b1f1c44c82ba049a4f540e0206cdd045", "82c2585cbecc9ade3bd64895a84a85bb97952e43", "0b9e07de6287032320423371a8ee66e149ae208e248587443e122c9f8cc600fb", "1d01f3120ecfbdd28dce44317666cf864f52391b9eca3843db45667c2e0a98ad" }, // 19 + { "e26193989d06568fe688e75540aea06747d9f851", "1a5edc0e", "9e0e0f99c95fa883fc65e74bc94149e5", "bdfd2785148f71a6ac5790d3e65cb7638a3efdc6", "e88d019b09a378a39bd5bfa33215c358303c7f13004ce3a12650aa70d01b8ca0", "2c1e61e5d45203f27b86f1293a80bab34192daf42b8623b12005b2fb1c18acb1" }, // 20 + { "d8dc8fdefbdce9d44e4cbafe78447bae3b5436102a", "2803f7c6", "2c6e363d11a7a5d810dce54d3e28c409", "3ac65fbaceb1591da5b96bfa50c825e7e7c61a20", "fdfa03e288a4af6d325049bfc4b76e9c8178321d484ae88fb1025d26bef78679", "ad0e3f29767067e929d1cecd95582df8f2a9beb92eaa27eeb315f620365a9244" }, // 21 + { "57085fd7e14216ab102d8317b0cb338a786d5fc32d8f", "64ba010b", "92ca1e70af2d4926eaca1acb0a7204da", "88ba72d3f7331c8235bfac25f0af1fce30534676", "a05e71cd70727ee68b029f36bdd7838dc3c69bbdb956c21b68dfa439421af5f9", "2b4eb5de20e86074cabb55bfa63a5c8c6ae15679302061845b9cf233e17c906b" }, // 22 + { "a05404df5dbb57697e2c16fa29defac8ab3560d6126fa0", "53948692", "1ca08b8e52e2d6956504aeeb4175d98c", "1c3329ab472a203c11a74936c786177462822bd8", "7ea63cd84b9f0b9ce4daf224835d06e029a4601eeb5a37496799a3d84ed42f8d", "6ae04c6c6f3651f1f64c0ad69733990b41747c93f87acb813bb25bb1fc0eff07" }, // 23 + { "aecbb02759f7433d6fcb06963c74061cd83b5b3ffa6f13c6", "5e55297b", "f9715ac28f13a90a4dfb017aee4dd9b1", "76538ebb720710421b935ce23fbe37543e090cb6", "19045e899afc4a35967ca5c7970a5b0ddc99f70f69716dcf62c46825be0aa457", "40f9f55bc55da466bc3dc1f89835a64094572de73d64ed6646a1d3b667be70a9" }, // 24 + { "aafdc9243d3d4a096558a360cc27c8d862f0be73db5e88aa55", "f7f32407", "6d71d851e6fc1cc3a44be9c16e546cb9", "e294d8908f122b8d7ccfc1223058636eb276d405", "4c8487b6a2561455e1535c1462722c1042fe2f478ead5a6f65f39bad004cab59", "c64becf7b75fc885d5853924f2b7d37abcefd3da126bb817697e1a09152b1ebe" }, // 25 + { "7bc84867f6f9e9fdc3e1046cae3a52c77ed485860ee260e30b15", "edbb117c", "8a104d5ba0f66e66042486f7e106fe87", "a1a306755332086effbf26d6c20af9b50e415285", "8c41fa0b07f82b9cd0026de7e38059680f69f2d20f426596e88b4d800aa638b2", "57d46a6bc8fab33601538dad27f98c66443032cc3912434c28eb88d0af44c52c" }, // 26 + { "fac523575a99ec48279a7a459e98ff901918a475034327efb55843", "39f0e9db", "7de1128f904f39f92f1c51989c94aaf8", "a58b983e90870a964296a164bd02b62ffff7e12f", "a84dbb8acfe2c5ab82c2ed371040a3221f7cde534baf134e24534a3b5105da69", "7c956503d5b4dbb764ff8e66fa74ce0f9132da90ea3543f669c9dd08e413e33c" }, // 27 + { "0f8b2d8fcfd9d68cffc17ccfb117709b53d26462a3f346fb7c79b85e", "6b2ad7a1", "d41bdd74f0dbbcb034ff01402a163736", "ae41363098fe07213fec440bb03be81aab0fb7f0", "afecd3e65dcb52c4c8625471842d007575e4cb33942ac4e6377014cce668ba4f", "6de164a9626d5a4f54d854ac158994f35a8e362ecc753f55182790934a2e0d06" }, // 28 + { "a963c3e895ff5a0be4824400518d81412f875fa50521e26e85eac90c04", "51e5475b", "bff43c6ee76dffa8850237aa11ec11b9", "ca408361c45d44c71e90fb6b4c69955d08c58ecd", "7ac86f1239e32eedaeaa8ed184445c8b017e9124a5d283cf4393fd80ad3996f0", "b760312bd1b279fc672479d21c5ed349e5fe96f08940237b4515452721c49a16" }, // 29 + { "03a18688b10cc0edf83adf0a84808a9718383c4070c6c4f295098699ac2c", "0807648c", "268c59a326b83e17f42bd7500c916290", "a9b323ca196695d80ce6cfb26ca9a8b77e51b008", "5e9c68da67265b87ded2f3b2a93744f5b7ec832419916aadf0ea78b63ef97432", "94fc255de4ef19c0da4b09b2e2fac21f20048b46f17c30685abe40d5c743f375" }, // 30 + { "84fb51b517df6c5accb5d022f8f28da09b10232d42320ffc32dbecc3835b29", "dddccc2a", "6b393afb85a556ff1b38ceef3ba946c6", "cda4605fb1409be66738df89f20f3da5e6609056", "9929cf1e6fac383f3a2fa322af8d125753bcf9c28ededb9e63a45da0cf5c5984", "39a4a0ffc4603698ae0a4f3d24b1bc42ac7a2d7d923e7a5d602453e82d5323c5" }, // 31 + { "9f2fcc7c90de090d6b87cd7e9718c1ea6cb21118fc2d5de9f97e5db6ac1e9c10", "c90368f7", "b4b5b22fea8d7a60d07859b46b03b810", "5eb1836714dd13760ec23a8187c3c64086dcc3f8", "ace84f09d49226d391e3704ff36b0cb5a61c0a0727e6bc5a7188e5c273a740db", "2f1a5f7159e34ea19cddc70ebf9b81f1a66db40615d7ead3cc1f1b954d82a3af" }, // 32 + { "de8f1b3faa4b7040ed4563c3b8e598253178e87e4d0df75e4ff2f2dedd5a0be046", "e43f6c2b", "c09b81300dfe5d57cd53b29971ef55ca", "2299eef7f22c57e489c29155e632b10d6ad28761", "072d632c7b4d6cf25f3c18336d572d22759d5a78e5cf9ee5f3d844f2b6345cb3", "1c57fe0e38cd3a124eaa6cd87f70a079bccc073a341e8c0eb1976fb3a3f7b774" }, // 33 + { "62f154ec394d0bc757d045c798c8b87a00e0655d0481a7d2d9fb58d93aedc676b5a0", "2aa78ff5", "c1b47551dbd87287e3786d29f0ead5c2", "b53c51b62b98bb6a897bdf2e4de297ee6f80d64f", "2d503f6f3432d37088b1890299259db30d158665604ea63e82cc43548412bd35", "a905603b186ef4f2d5b2d1bcfda504c68ed5eb9b0c7b7ea2a001575f5aa69e68" }, // 34 + { "b2dcfe9ff19e2b23ce7da2a4207d3e5ec7c6112a8a22aec9675a886378e14e5bfbad4e", "d9c9c459", "39a82f09125434582385b8b09ef042d8", "303ea353679f64e0e7ea72f308908091b3f798b6", "c4a3feb41cd26f040c26f0b0ca12f8e3d55f0bb39771ee087c5086118e098146", "fffd39f7c451788eb0316f429ea0a7c0ac8091657aca28f1560ed5775e8c4c12" }, // 35 + { "47f5697ac8c31409c0868827347a613a3562041c633cf1f1f86865a576e02835ed2c2492", "5b1508f1", "cdb044f567cde9d20b264add4edf6a56", "499279bf8d5c7ac1f0ae11de2a7a774bd949ad17", "cb9e4c92d9cf019f4c3156ab791350ad8e42e502f7f2eb64e47466aebbffd283", "6f55becd168e0939ba2fa090257b1727fc66491a44493279a5beacb9e3435324" }, // 36 + { "512a6d292e67ecb2fe486bfe92660953a75484ff4c4f2eca2b0af0edcdd4339c6b2ee4e542", "9c7afee9", "a3f7368cbeb89e1ed9564c147bc62ccf", "1aff151f3d6e3c71a2cfb9cd0170a1f907aa2e28", "5f4b5f2cebc6e5c7d8939273d3c63597efb8e7414b7373dfa4060041252f07ef", "84649bffcd48527b9288e8da5f52fbab2604dc5a91c4b0b87d477dbd7b40b6ae" }, // 37 + { "973cf2b4dcf0bfa872b41194cb05bb4e16760a1840d8343301802576197ec19e2a1493d8f4fb", "2466a23c", "91a3389423f3aad784cfa032e8511fac", "a950d6ce4683c8e9c97db7ec3ca8770ae1d78410", "6bcd52fae737be4465e3688ce0620b668d1b3b926bf12265bdcf215e22bee702", "d4055b4e3e2aea1c67cc99fd409d574e53e1e296cf9eef73c472ab92a6cb6609" }, // 38 + { "80beebcd2e3f8a9451d4499961c9731ae667cdc24ea020ce3b9aa4bbc0a7f79e30a934467da4b0", "9869fe61", "4e9f41ef61570fb59c1905c127a1dbb6", "d46154473fd626ed75429dedcb6d18c14b84bf09", "61c7b8427e946955efc51dcbe85c33f770f35c9f87cca931a220435cd5cb52c4", "5694ca2f3b9962226a87163ab38325bcdc898a732dfeb2c36db4eb88616b8741" }, // 39 + { "7abaa12ec2a7347674e444140ae0fb659d08e1c66decd8d6eae925fa451d65f3c0308e29446b8ed3", "30ec2a35", "59b97d4bb9621edd21508e983d1e0162", "50aa4e5b0d5aa3fe38a7b6539060a393f132e754", "7e9d4111cc710b6b24290fcab6934ad08cd4b239c1a0cbdde71f685f0a1e6fd9", "8cf287ad03ab4a74086620cfa4cce74f48fa5cdb15ec02b1f721736a4f849e60" }, // 40 + { "c88dee9927679b8af422abcbacf283b904ff31e1cac58c7819809f65d5807d46723b20f67ba610c2b7", "5a9f457c", "dd004f029f857a4e9acfdc516191dd0e", "baf9d3c7d2b18f36ac2981c7f071e63bbbfd3493", "2668d27f283bce5f7919d490d721aea6bbd0348332a2cde536dd4bc1912c55ad", "c5d5af22a4df9acd0c056fa30d8e240b679a20d4d2630260f779ff815ca82d7d" }, // 41 + { "01e43fe350fcec450ec9b102053e6b5d56e09896e0ddd9074fe138e6038210270c834ce6eadc2bb86bf6", "44d76f15", "28b66ebe60836815e0050c6dae6cb383", "a0a7388255f447285f5419ff96aad6f1818d6de0", "c60b5602cb8a1a23ec67b6c57ab41152ea1360a532b146a8e3195b2c23b32b48", "0ac75279adff65660464550a283fecd4e0610d88f35574c3d7ac5d22262a2fe8" }, // 42 + { "337023370a48b62ee43546f17c4ef2bf8d7ecd1d49f90bab604b839c2e6e5bd21540d29ba27ab8e309a4b7", "aef8f701", "66191acef6407facd6776248be2b2814", "deac10320e720100261ec67889ae36a13688c4e2", "612af005d7f47d3d7cd0e8cdcca4571139fef602e82e64e7e027189e5b1b8700", "81917ae290dbba17289a8a67e5c2e8b12d3dde0efe9f990198a1763ff4f3dda7" }, // 43 + { "6892540f964c8c74bd2db02c0ad884510cb38afd4438af31fc912756f3efec6b32b58ebc38fc2a6b913596a8", "a1739060", "72f332cb3d1ee64f1956eea0f9f65b64", "42b6406d40071927e77a0d7749de78a7f426b290", "42633916521313c491f53a8aed2de5647bd21befb8423e31397e3ba76e7cc43a", "138e75e72fddd927e591315af8d3aba280efa36230a3309a97bcde5a78c31589" }, // 44 + { "f5961dfd2b1ffffda4ffbf30560c165bfedab8ce0be525845deb8dc61004b7db38467205f5dcfb34a2acfe96c0", "2ad774c3", "e729ab5e0ed1eda842771b4cab4f7e24", "3e1b964d0dd2c054862c038488b8ab0f1c38f13b", "bb15e052c6167318eb92530ee2a6a38bbbb03888b27ccf17402dd91336742e7c", "21bcdad3fef3e5b859cb0912a2991efa661bad812747292ef0f79a8fcc6b4e98" }, // 45 + { "ca061a2eb6ceed8881ce2057172d869d73a1951e63d57261384b80ceb5451e77b06cf0f5a0ea15ca907ee1c27eba", "b0ecc329", "6886c2fe3bd64c5d7e0a92dd9d3de9c1", "75f7e1712c432f990d5d47bb410bc0ed1f01d340", "1debaf5b88a075e43a0ec8765fa3830b3e08655162b28ce9a9357c4424869fa5", "8d6fd9c559b0b4948f91337916084c0082a16a0755b0a00811096e973e48b3c8" }, // 46 + { "1743a77251d69242750c4f1140532cd3c33f9b5ccdf7514e8584d4a5f9fbd730bcf84d0d4726364b9bf95ab251d9bb", "26ce2541", "48a07b1571b3de06d65a88e95ca57b50", "2c2bb28f64a17b4054376a503bb9c57f1e142bf4", "de11c81dd4609233c6a2d73a3ac06a20e312e6e1c0f5d351bc72b3d5c40961a0", "1dd23ae7aadd61e712bdd82bd60a70dd9d66c9fd79dbfd8669e3eaabf7901cdc" }, // 47 + { "d8faba1f5194c4db5f176fabfff856924ef627a37cd08cf55608bba8f1e324d7c7f157298eabc4dce7d89ce5162499f9", "8ebccf97", "3dea64ea9ed114752e867afd704a9762", "b8be5ea10dee2d8190d82dd47b94d6a8019baec8", "ecd5464831f5a8b034f07b3ef7b96d096751d76425d0771bbfaeed9894721ccf", "34f8607ec10c092c1ba0b6565ce6197062c4e1a35a8e8c723e48a2d2416c3790" }, // 48 + { "be9684be70340860373c9c482ba517e899fc81baaa12e5c6d7727975d1d41ba8bef788cdb5cf4606c9c1c7f61aed59f97d", "46a4b59a", "83c390e922be9d42cf14d8df71bf3541", "7a6281ec0b58c82a80b1ee18e8bbf22e6d84df60", "171300d37d33b2f8942ed26aa86c67346fc0c9710c6e59a83472c4dafc033aef", "19a8577fc90fae5d6a6b2e0c1ff155515502cfa1757029c09bebbfa263d9a363" }, // 49 + { "7e15d2b9ea74ca60f66c8dfab377d9198b7b16deb6a1ba0ea3c7ee2042f89d3786e779cf053c77785aa9e692f821f14a7f51", "f5661d98", "730487d5390fd8a72bcde0109529f614", "6e17b4575af829c6ee18e24fb6eae024a9baaf49", "7863f2acd39baee07b57e2e65a391dc828c05de45821e52e3b908b43a9ad9705", "9d9dbb4ce7d01d009e72a66051acc16805e49f598cbe430c5d4c22a881a64b3f" }, // 50 + { "9a219be43713bd578015e9fda66c0f2d83cac563b776ab9f38f3e4f7ef229cb443304fba401efb2bdbd7ece939102298651c86", "97779492", "2c2ac042030f8f1645df0e9575bd2d41", "29309a4a739f0e6ac4ef1fd38871c9a02a326d10", "ee0924a0f948eba8bc731c0489da61d6665829fc2e6ea1b5378964f5a77dd7dc", "13f0d951b64481135466cfccbe52418cc1d03fb16b5b696c35d724f6f55cbb6d" }, // 51 + { "c8f2b693bd0d75ef99caebdc22adf4088a95a3542f637203e283bbc3268780e787d68d28cc3897452f6a22aa8573ccebf245972a", "2d2ad237", "d72991ae45a2f1deaf888c4e9886d3fe", "88970ef3bb5191e6927a639dc105835e1b98aaba", "f7f7c47d804f0d9455426e236676d6e9ddd91bf99e40e23220ca911d99d88ada", "fb2fe7b00b75c42305cf31de14d98f904e8c46dc57bb6f94c282ca8c13dc45db" }, // 52 + { "ec0f99711016c6a2a07ad80d16427506ce6f441059fd269442baaa28c6ca037b22eeac49d5d894c0bf66219f2c08e9d0e8ab21de52", "69f4b6eb", "590fcad19889b907e3d6bbdf991edc93", "a63c6fd614d977f015fcc29936dfbffc9e8f2d33", "ee99da04f780abe64d2c1ee1170e7f678c50683a7b9303a84678c6ebdf9b9a7f", "d54cbf7d5c80ae11a0d0bad4e95ab18b5f07c970621f3936447a48eef818d06e" }, // 53 + { "0dc45181337ca32a8222fe7a3bf42fc9f89744259cff653504d6051fe84b1a7ffd20cb47d4696ce212a686bb9be9a8ab1c697b6d6a33", "27569834", "e087a2fb0e175b748d68833fbddad14e", "01c8e2d5274a8daf51bb207eee328c33b49592f1", "860c4d344cd31e574e20ae9a54ed146f690823930e43947e89adfeda3da669de", "ff050a45adeef4cfc7d964102ba877c80320a37794893e6865965ec2547cd4c9" }, // 54 + { "de286ba4206e8b005714f80fb1cdfaebde91d29f84603e4a3ebc04686f99a46c9e880b96c574825582e8812a26e5a857ffc6579f63742f", "43ab2765", "1c4f5048955f692961be8682e7226025", "e81bed804597822ac47ca7a507976972eece5c60", "99a9fa276e7471535a13e41abdb1dd5c1013ed1f4d57a4c7b9433455d3cdc705", "1bc1bcc70f638958db1006af37b02ebd8954ec59b3acbad12eacedbc5b21e908" }, // 55 + { "eebcc18057252cbf3f9c070f1a73213356d5d4bc19ac2a411ec8cdeee7a571e2e20eaf61fd0c33a0ffeb297ddb77a97f0a415347db66bcaf", "4d3ce864", "6d0557d282d4ddbfa3f0607030db59ac", "d493f943e6d7e52989990f1bb88c835e9a14ab59", "c8d39c9dabb62cb284be55658b05412b50ff3eda8ac98ae6bc616f466aeb2650", "f7bde239ad087aa7dabe42cc4d3c49380a026cd239a7faaf34a2233469a44a4d" }, // 56 + { "416b5cdc9fe951bd361bd7abfc120a5054758eba88fdd68fd84e39d3b09ac25497d36b43cbe7b85a6a3cebda8db4e5549c3ee51bb6fcb6ac1e", "a49c059d", "2a51205e846de5953d7e1c6900fc574c", "24a9ea1d842750fb805a8e1985d7cfaeca799fa0", "03f7b846ea8f9e26760eeaa30eae500646819842d6af87ca64275b865aaf43f7", "ef845aac2aaf0a793108204ff380e0a30f2558e7acde4531ab22f8ec79e26a69" }, // 57 + { "5c5faf66f32e0f8311c32e8da8284a4ed60891a5a7e50fb2956b3cbaa79fc66ca376460e100415401fc2b8518c64502f187ea14bfc9503759705", "63822070", "2d4d21e2117980b30ee1827876ae37f7", "45ec45c12ae8056e31df5578659ac18b077e0337", "463a6a7d0765f0a520f4dff288c4caa7c4c0ce3080e3703cd47122a7ee8b9434", "26db514e01e034c678b636d40ba367da2f37f67078bb576ff2b8559b3517484d" }, // 58 + { "7167e1e02be1a7ca69d788666f823ae4eef39271f3c26a5cf7cee05bca83161066dc2e217b330df821103799df6d74810eed363adc4ab99f36046a", "a2c861c5", "8d04f5ae0093555f98532d29e062138c", "ea91f748c7a9137eda2a82d7e8e9dbe54d574949", "c82776eca46928e0d5b3d1c43db40953cce11013cb3528fec5b882fc5b286fc8", "5dbd4b558463196211465c1fc32401fc2d8e41ebc5e6badd1d8f7c4f090f728f" }, // 59 + { "2fda311dbba27321c5329510fae6948f03210b76d43e7448d1689a063877b6d14c4f6d0eaa96c150051371f7dd8a4119f7da5c483cc3e6723c01fb7d", "0bf07be9", "0d84254eb21804f52cc6155c736bfe2b", "905fac724e298c9849ae82c0c0d3a494a8060085", "55d4462e8486ebc14e2f5ba7f573330faf3a0d56bdf7701ee2820aba265d7ac0", "355c79fd6e6fa88ed402b6979fde1ed805498abeb101f4231b5d64d1439d552d" }, // 60 + { "95d1474a5aab5d2422aca6e481187833a6212bd2d0f91451a67dd786dfc91dfed51b35f47e1deb8a8ab4b9cb67b70179cc26f553ae7b569969ce151b8d", "cb5e3049", "dca6b7cded7224dc17e8c7e506f4e011", "b17fb3167bc83a7375ff6ddcd5f0b552ad9ddc41", "4d78228bf419b23d867082d8d5c066a4aee56a9bb54224d3b5cbd2c04364d99c", "3d9c9bf09d88211c7e0056112d073ee85d00acaa4da7a668fa017b3273cd4d4b" }, // 61 + { "c71bd7941f41df044a2927a8ff55b4b467c33d089f0988aa253d294addbdb32530c0d4208b10d9959823f0c0f0734684006df79f7099870f6bf53211a88d", "4eabb06f", "fa630a5284e5180afa75d6ba9a0ff421", "5792719abbd47647358eb65529abd4136d501af5", "48d4ed4341aafba1f02bbf72eeaf2bf5991c04ea3c643d7665f0130fffdc9165", "67980d28e2e658e7a24a2593a28167a13d907d06f47729d47ca4fe1772f8b3df" }, // 62 + { "f57c64006d9ea761892e145c99df1b24640883da79d9ed5262859dcda8c3c32e05b03d984f1ab4a230242ab6b78d368dc5aaa1e6d3498d53371e84b0c1d4ba", "8ffc4b50", "90d5671bdc15f8f96c3745f6f6020a8e", "632ee5446b709013fba8123b67e49dc7bdcc4c4f", "ce122fb56c82bf0cf7953b837e2f00cb0546f5b5d91f7af3480f659ed6152390", "a8df6b76df41994f7593f1a81967e77ee180e31183d1c4a569db854e61e99b05" }, // 63 + { "e926ae8b0af6e53176dbffcc2a6b88c6bd765f939d3d178a9bde9ef3aa131c61e31c1e42cdfaf4b4dcde579a37e150efbef5555b4c1cb40439d835a724e2fae7", "ded134c1", "f8885d6cda92c999dc4bee554df7dd2c", "6c4664cb736cd563f74f52cea42e33d6d617f153", "f4a1a02e8e35822107cc08b5b21b661c058e2825f3c7cb2a3b6d40f3ae89211b", "27a6441ee939b46e2c378d7afeb0e891c47a28120e488eff0ab71af08788ceb3" }, // 64 + { "16e8b3d8f988e9bb04de9c96f2627811c973ce4a5296b4772ca3eefeb80a652bdf21f50df79f32db23f9f73d393b2d57d9a0297f7a2f2e79cfda39fa393df1ac00", "e891cf16", "09ceb3a6fa3e2d38467a6969d43f6587", "6ba94f05cfa29501ff47ae917e18763e063229da", "16b1449186ef6d27ddf9f8ddfe23c59e51a953833c7df2e8c6a7528403f3ba68", "c4bb067383002db44ca773918bb74104b604a583e12b06be56c270f8b43512f2" }, // 65 + { "fc424eeb27c18a11c01f39c555d8b78a805b88dba1dc2a42ed5e2c0ec737ff68b2456d80eb85e11714fa3f8eabfb906d3c17964cb4f5e76b29c1765db03d91be37fc", "82e3941f", "09f55194b57e25646de7c5e4a8635f5e", "1e2895343ba31a9e32730f8156c68369e3f4132c", "9d91ce1295f7acca7bdb2e2ff0794e5e2917509fe03bbcfb34bc8dd7e536b8fb", "ae773915ca642d80413330c9e0ee9bd06653c0023c5c0277100f3b1526eaa51d" }, // 66 + { "abe3472b54e72734bdba7d9158736464251c4f21b33fbbc92d7fac9a35c4e3322ff01d2380cbaa4ef8fb07d21a2128b7b9f5b6d9f34e13f39c7ffc2e72e47888599ba5", "e73f9991", "d561fc54a4d61467f7d72ea037bb9332", "ea1c325d0e91a757e2106792943361d47ce99bee", "f1737040e38e73ab3b4085ec8e1acf1e055a1ed8411e6cf867d0a5dca56a3364", "1cf9d6ce9cb658556b76cd7eba3e51393699ad500b1ab3f56172748db7f59667" }, // 67 + { "36f9f0a65f2ca498d739b944d6eff3da5ebba57e7d9c41598a2b0e4380f3cf4b479ec2348d015ffe6256273511154afcf3b4b4bf09d6c4744fdd0f62d75079d440706b05", "ae719e56", "313c5846da0836226ecbf50c324fb7c5", "0082b9a8ab38b32ac364e5f1a656cfe98ef9c931", "df0cd17c3fd3885653849bc8be8cad1f2171755e05176d448dc466fdb94ce780", "8d60e889e2b1020dad4b523301f5f6bbab6c781af276085af6765546fcfb95ac" }, // 68 + { "abc87763cae1ca98bd8c5b82caba54ac83286f87e9610128ae4de68ac95df5e329c360717bd349f26b872528492ca7c94c2c1e1ef56b74dbb65c2ac351981fdb31d06c77a4", "6c4cd72d", "53bfe40050067274fe7482d2a3b7986b", "328136f32226dc14f7e9dee5ba67863b669cb0d7", "6fe7f18c476330654ad42917435a5dd906c1c35f863cb2a8147a9fa10aa19c91", "dd4ff4b530552f48af9a7530a6464819ed1a5b733084f709e41daf1acb35ecfd" }, // 69 + { "94f7ca8e1a54234c6d53cc734bb3d3150c8ba8c5f880eab8d25fed13793a9701ebe320509286fd8e422e931d99c98da4df7e70ae447bab8cffd92382d8a77760a259fc4fbd72", "c957294b", "58a4f59c5a014d0d19f4b0807d3883db", "45905089a697d8542c78e1d206a0d87430fc0789", "54fe7d51e0cd082a42a4972acfdf8c59406c89ef95b79d659a84a0d07d121069", "7ac8d4bb53fc434dd8712daefeb474668f541418e6f617dba523d8392eb0766e" }, // 70 + { "13bd2811f6ed2b6f04ff3895aceed7bef8dcd45eb121791bc194a0f806206bffc3b9281c2b308b1a729ce008119dd3066e9378acdcc50a98a82e20738800b6cddbe5fe9694ad6d", "22bd0ff5", "bc3db75037ec1773fb11045a256001bd", "c29ad52ef807b4f73f3ec0b20999a996b3e462cd", "6feab1c9d115cc82efe3631535e964c3eeb5c3dad4c38d837717f8f10a3357b1", "f7b0e15a63232a2b800b23b311d357617ddfd1293e1ffe3f772692ade3427152" }, // 71 + { "1eed9cba179a009ec2ec5508773dd305477ca117e6d569e66b5f64c6bc64801ce25a8424ce4a26d575b8a6fb10ead3fd1992edddeec2ebe7150dc98f63adc3237ef57b91397aa8a7", "0ab24bd5", "9022f5cdff2c1f55ac3f5270f8d43484", "8b78f85b603c4b896cac77b41edee07c56d14058", "046155a4d0e52a53fc745278ded12590875fde9b66fa4e40a6638c1504f6d435", "b3d05af7e8c406a7c2709223791d3f5f4b3129329993220053a36293ac2b0e06" }, // 72 + { "ba5b67b5ec3a3ffae2c19dd8176a2ef75c0cd903725d45c9cb7009a900c0b0ca7a2967a95ae68269a6dbf8466c7b6844a1d608ac661f7eff00538e323db5f2c644b78b2d48de1a08aa", "8368ecf5", "92c203258dfb11755b1a6f3d15095f45", "e0a01e53a373265566a422f5209346605eca2252", "450effce3b3be76285be139ad8c15cdb36d847a70122e7754cc50da7b4f262e6", "6c47e2ea4ba29e17792defc4b707754c4664bde15168a5100bf881ec7c02b258" }, // 73 + { "0efa26ac5673167dcacab860932ed612f65ff49b80fa9ae65465e5542cb62075df1c5ae54fba4db807be25b070033efa223bdd5b1d3c94c6e1909c02b620d4b1b3a6c9fed24d70749604", "f5fc8790", "c125928b6cdf8b88f30efaacef4acba0", "732dbb9df2f07abc0ba482376a401acb1652fd1a", "88f8922134a0dfd8cf733e69a67f79695c157a12f004e0f41f47dbe25e929f11", "82a66bed668dcc14af12c14c976ce650049e9d1d9969b83d1dd3b6f1c07d252b" }, // 74 + { "bbfd933d1fd7bf594ac7f435277dc17d8d5a5b8e4d13d96d2f64e771abbd51a5a8aea741beccbddb177bcea05243ebd003cfdeae877cca4da94605b67691919d8b033f77d384ca01593c1b", "07c73070", "2ce5ec25b22239c42ad1e1fd4a38e7f8", "1196665356621ac4b74f7cb453a695ff51fe13a0", "6abd3225cde2afc0da502567790af919681ae1bee565192a06e5e34df7cdfe4e", "2f21d07d7b10683b9ac7a63e9fcc70cf9f887cb905f9bff5332551288b288524" }, // 75 + { "90078999fd3c35b8afbf4066cbde335891365f0fc75c1286cdd88fa51fab94f9b8def7c9ac582a5dbcd95817afb7d1b48f63704e19c2baa4df347f48d4a6d603013c23f1e9611d595ebac37c", "905d3872", "fa79da4e5b2df87ce3cc98ab763fd19c", "16b3a27baeeecb4c4c66c7f235fbd4f6c5839145", "0cbd201eca6a8fabf81c7377047a4a86f6dff090d665381fd884c6b5836b0902", "80202f01e7140db4fee490dcc50afafdf6a48ca33d362c7875b8e8db9c9d0655" }, // 76 + { "64105eca863515c20e7cfbaa0a0b8809046164f374d691cdbd6508aaabc1819f9ac84b52bafc1b0fe7cddbc554b608c01c8904c669d8db316a0953a4c68ece324ec5a49ffdb59a1bd6a292aa0e", "7e11cb91", "b9c451f86bc03e42fca7d2400609b188", "61d6f9fccf0a8c486dfa7df4417dc4d0c4e59149", "e30a878fdab9b75fc3d1f8ca1ea9c754817de4a471aa8e2abd6a7526e36274c5", "b2330a189047e3117479a2f20b3407a7d119e4ad431fe06ff1ff2a106f2ab3a2" }, // 77 + { "d4654be288b9f3b711c2d02015978a8cc57471d5680a092aa534f7372c71ceaab725a383c4fcf4d8deaa57fca3ce056f312961eccf9b86f14981ba5bed6ab5b4498e1f6c82c6cae6fc14845b3c8a", "dcdff841", "4551bc9250abb5607cca78ca71137a3f", "a95f70deef0c1733a02e6297a67aa61f0356e005", "9b163642ad529f4f0ac03b31cc22752599fd3cc3abdca1124cbce15eab11021e", "bb9b9bb685c241f8d63fdbf0dbaabcef7075add7ba405a2fffe7ad5b23e021c7" }, // 78 + { "12d9394888305ac96e65f2bf0e1b18c29c90fe9d714dd59f651f52b88b3008c588435548066ea2fc4c101118c91f32556224a540de6efddbca296ef1fb00341f5b01fecfc146bdb251b3bdad556cd2", "9ccb3cf0", "0dc5922d3935802af173a0825b8793cd", "6a59742f6d780f0161427835f743187e7c4de6c2", "e9d510eb338e4def24410eab6e26845a721aa9feba233d225f18f9a4d165c0f8", "f8316a367aa0316da3562f319d522e81f4a8bd2e2108d2532126f4a903704ba3" }, // 79 + { "871a0d7a5f36c3da1dfce57acd8ab8487c274fad336bc137ebd6ff4658b547c1dcfab65f037aa58f35ef16aff4abe77ba61f65826f7be681b5b6d5a1ea8085e2ae9cd5cf0991878a311b549a6d6af230", "c37eb643", "b14fd7247fb0600a4ee58d7d02c54573", "5ee0c3e4b737f3c6eb0537c6dba47e8e33334a39", "3bbc51465e6ad6c102c41cf61c0a510d191a522e7a8981eef519149d1bca5fe9", "89e3ebd02b229cd759612a5521d867ab2a1594bc0b1fe6a78b7954ccc84caf03" }, // 80 + { "e90b4ffef4d457bc7711ff4aa72231ca25af6b2e206f8bf859d8758b89a7cd36105db2538d06da83bad5f663ba11a5f6f61f236fd5f8d53c5e89f183a3cec615b50c7c681e773d109ff7491b5cc22296c5", "ba83a755", "a7b5bb4aa7b91d2853ec40c62ae71adb", "93e5e5a709b797bbb6e77a7ead3edec6d77d463d", "2ab2197e676517e8e900f69dbbfb6251e5dae049432d18adbdee892f42601e73", "2e7cc875305ea6bb9c2fc770b9d84fd93b96405df9b93307f6b5de26e135724c" }, // 81 + { "e728de62d75856500c4c77a428612cd804f30c3f10d36fb219c5ca0aa30726ab190e5f3f279e0733d77e7267c17be27d21650a9a4d1e32f649627638dbada9702c7ca303269ed14014b2f3cf8b894eac8554", "8bac7df0", "3bed3364dda24e4f121971960ace8cd6", "80ab947730a8b954b0e0108f9add9808ad9d4d4c", "a245a9c8b82fcf89b008b8f68393bdbf70a7750efa9f946a493025f5b929e398", "ecab75f28a728429cb433ec13310d1b850ccf522c38d2fa6dfa489963d6d6ca7" }, // 82 + { "6348f229e7b1df3b770c77544e5166e081850fa1c6c88169db74c76e42eb983facb276ad6a0d1fa7b50d3e3b6fcd799ec97470920a7abed47d288ff883e24ca21c7f8016b93bb9b9e078bdb9703d2b781b616e", "8666f487", "0b5846abc9ec2f73f95a046a98db99e5", "6d8d4d535d9478bfe55bc439bd72aa4ca059994f", "40319d72d16dd3b02e5049b28dd4de6bd6263796085069184ca868912d1a39ea", "021c9459d1451f3da4c07c029a8681945c87c5bebc6c30da1d95c5c49d8ab95c" }, // 83 + { "4b127fde5de733a1680c2790363627e63ac8a3f1b4707d982caea258655d9bf18f89afe54127482ba01e08845594b671306a025c9a5c5b6f93b0a39522dc877437be5c2436cbf300ce7ab6747934fcfc30aeaaf6", "b9b607f0", "8e7c9e38008a99bc26850bdcfa296fd7", "5a991f5a462d57c678f8b1a853d5e63510c0c01f", "9885b7b4d61caee20fcbe9a902496071f3113f34d144929891ee711b12f6d1db", "4642e21622f15b09b9413659680116bf2f96cac2384b8c79f1328d5dd36d7a01" }, // 84 + { "08461f006cff4cc64b752c957287e5a0faabc05c9bff89d23fd902d324c79903b48fcb8f8f4b01f3e4ddb483593d25f000386698f5ade7faade9615fdc50d32785ea51d49894e45baa3dc707e224688c6408b68b11", "07839217", "03e0732d64855293605a4ffea43e2151", "e734c52c2930b653dd5b01e04fde3ad7b9eaa51c", "64278b8ed65d1d1ee032d6289d74f7d5637d0538e7b05bcd099ca7cc8f6263e9", "8daa47c3572157266ad0276d5926aff2872f06b0cd7b974a80d7a6827d41d782" }, // 85 + { "68c8f8849b120e6e0c9969a5866af591a829b92f33cd9a4a3196957a148c49138e1e2f5c7619a6d5edebe995acd81ec8bb9c7b9cfca678d081ea9e25a75d39db04e18d475920ce828b94e72241f24db72546b352a0e4", "d74ac160", "bafd00316db76387bed7c84492d70158", "7e1b8fa40e87f9b12d40a1fcfd66b2ca708540d3", "3a4145a03567aae008db8fed2a58f616dcfa6d345ae38aa27b9e2ead32768a9e", "345365232ce9afc655dce4bac23f43c8acbdf9016d4bc2344be8d396a4919c34" }, // 86 + { "b8d56472954e31fb54e28fca743f84d8dc34891cb564c64b08f7b71636debd64ca1edbdba7fc5c3e40049ce982bba8c7e0703034e331384695e9de76b5104f2fbc4535ecbeebc33bc27f29f18f6f27e8023b0fbb6f563c", "60457106", "65ec6a553b431e4fa351cf2dfc6c1b53", "d887f88a626f98cad59e0a5b2484189bb1accc6b", "c50b8c10e4dbbcd0055d9a81a89f2ac18b709715377eb4048edbc4b497165f5a", "f52e102e57293878c28f29deb47792324fe455a62fa7441aabcc16a9cfc40ffa" }, // 87 + { "0d58ac665fa84342e60cefee31b1a4eacdb092f122dfc68309077aed1f3e528f578859ee9e4cefb4a728e946324927b675cd4f4ac84f64db3dacfe850c1dd18744c74ceccd9fe4dc214085108f404eab6d8f452b5442a47d", "966eb885", "8f37ffb065d2ca3e5e40930455518773", "3103211925d1886b7bfe73c42f24e000ddde8e01", "63deff17e210cd39682f253d819cfb454d6434bb72aa36d3074c808f051043d5", "2b89aa88b1b7f9f8ea461c4c5cae4829125f45f5697deadb8db2e964524c0d91" }, // 88 + { "1755e2d2e5d1c1b0156456b539753ff416651d44698e87002dcf61dcfa2b4e72f264d9ad591df1fdee7b41b2eb00283c5aebb3411323b672eaa145c5125185104f20f335804b02325b6dea65603f349f4d5d8b782dd3469ccd", "a4fb2fb2", "52d15ee0e65cc07d84370f420f3f4ccd", "1baeeea41fcf4bc3cc4178d77475f869369b8a36", "fb76aa04f9f2538c4262e8cd4ca5053ea2e2b082b97a484293fce02d97abe341", "3f3092365982c0b4278055beee9032ff9d1060e03c3b087e1a6197defc707e1a" }, // 89 + { "b180de1a611111ee7584ba2c4b020598cd574ac77e404e853d15a101c6f5a2e5c801d7d85dc95286a1804c870bb9f00fd4dcb03aa8328275158819dcad7253f3e3d237aeaa7979268a5db1c6ce08a9ec7c2579783c8afc1f91a7", "5412b36e", "ae8786808d7ce1a0d9a9226befb0bdca", "ab82cef5607ffa69e218ff71fc0d2d97bf713d03", "4582b15b38b27dca503ef8423b249a7703e987953139129c1468a3ba6b826740", "3c74aae2f340a24178cbab51004cba1aac3d91133c300715ea82c177269c0556" }, // 90 + { "cf3583cbdfd4cbc17063b1e7d90b02f0e6e2ee05f99d77e24e560392535e47e05077157f96813544a17046914f9efb64762a23cf7a49fe52a0a4c01c630cfe8727b81fb99a89ff7cc11dca5173057e0417b8fe7a9efba6d95c555f", "8724d307", "7dd591d07265406cc377020ac6c7e058", "6907d863d797deb8e46bc94ad05b6bef242a15d9", "7a41a251c2de39f9593b9808d89eb31958cec525b31d2e7a373dc29ee33ad9db", "0157c4ba44618ded11e9800afa07a0d5b6c711fc16a576c5edb71c4cc6894f82" }, // 91 + { "072fc02340ef99115bad72f92c01e4c093b9599f6cfc45cb380ee686cb5eb019e806ab9bd55e634ab10aa62a9510cc0672cd3eddb589c7df2b67fcd3329f61b1a4441eca87a33c8f55da4fbbad5cf2b2527b8e983bb31a2fadec7523", "b4e5de52", "218579c794ef71c9da317e227e90d058", "9ba690ac8b7a22662b244fc7f27c8723c3fc649e", "e146431158a7db63496e7fbb4741b820ce288a1758495ea8ef6061adbc36cfb9", "8d53dba107aaacb8422d6667f6778839f8965f8e4c8f4a851284cc91168a9030" }, // 92 + { "76eecf956a52649f877528146de33df249cd800e21830f65e90f0f25ca9d6540fde40603230eca6760f1139c7f268deba2060631eea92b1fff05f93fd5572fbe29579ecd48bc3a8d6c2eb4a6b26e38d6c5fbf2c08044aeea470a8f2f26", "f6ca3db4", "540f04cc19dea131532b643fb63cfae7", "e3b917152cab357dc3585fffc2d95e2337bd9b6f", "05f8979573501c8fb1778a9d38e9cad4ef481e5d6f6bdffb4fc642b5f3ce22c9", "5163f02233e332ad9be32c2346c9fcfe39afa5fbe9bc1cfeb92f4920155b20ec" }, // 93 + { "7adc0b6693e61c269f278e6944a5a2d8300981e40022f839ac644387bfac9086650085c2cdc585fea47b9d2e52d65a2b29a7dc370401ef5d60dd0d21f9e2b90fae919319b14b8c5565b0423cefb827d5f1203302a9d01523498a4db10374", "567891ac", "d859f008f48753ead4e62f52ca11377f", "233920ef506e9c59481d306d89cfccbb2fdbb2d5", "5ba07a5acf0fe4c89df8171896812ffea2b2de5185df097da8bde2635f512f4e", "faaf0e95217ca4b1568751ef2e4cd341d9ec33e16600bf09b92c6f1a6df84d2e" }, // 94 + { "e1fffa9826cce8b86bccefb8794e48c46cdf372013f782eced1e378269b7be2b7bf51374092261ae120e822be685f2e7a83664bcfbe38fe8633f24e633ffe1988e1bc5acf59a587079a57a910bda60060e85b5f5b6f776f0529639d9cce4bd", "c6835842", "05b12d9ac1c9854ebc86f00080321bc4", "f8429fe37ed6a336d46ab0e510d6772f0587d3bb", "65ac6f5061759518913cde199d49ec9e06c19e97c42eb99ab4f835eb8a4ab2e2", "b2c175d9d92aaa9ee72672f995b8dfd2daaf6555a0327a508218a9b447f00be8" }, // 95 + { "69f9abba65592ee01db4dce52dbab90b08fc04193602792ee4daa263033d59081587b09bbe49d0b49c9825d22840b2ff5d9c5155f975f8f2c2e7a90c75d2e4a8040fe39f63bbafb403d9e28cc3b86e04e394a9c9e8065bd3c85fa9f0c7891600", "4c61dddb", "f3642e61b5c0042af24a3571d7c9c239", "267a3f3a6fe13900f2bf1c9c360cdef18a6d9862", "4faef6b1ced3843526e9c93262647450dc7a68cda7e17f611e01bc6737d92c1e", "fb5388122306d37cee790cad1d3cddba8e9a93d5f9d78288b052482739c883fd" }, // 96 + { "38a10a352ca5aedfa8e19c64787d8e9c3a75dbf3b8674bfab29b5dbfc15a63d10fae66cd1a6e6d2452d557967eaad89a4c98449787b0b3164ca5b717a93f24eb0b506ceb70cbbcb8d72b2a72993f909aad92f044e0b5a2c9ac9cb16a0ca2f81f49", "eb65cf3e", "b7d46788d692d387300f5bfaa379ed18", "1594d253f40cabdafbe5eae70b7f6d4d142e9c1c", "9707054caf9ce8f2eb3e4304e3018beee27516bce6bf507d68adf7485b8c002f", "1c2f8d418ff6718b18dd4c756dcc8ed0f4755e8c22497a6cc19f8d7ae7fd2da7" }, // 97 + { "6d8c6e449bc13634f115749c248c17cd148b72157a2c37bf8969ea83b4d6ba8c0ee2711c28ee11495f43049596520ce436004b026b6c1f7292b9c436b055cbb72d530d860d1276a1502a5140e3c3f54a93663e4d20edec32d284e25564f624955b52", "6322e90d", "7d8e166acc1d95fc2f9098b02d431283", "25b53442fd71250f2c9a5c9df5655bfb8ead4b2e", "89e1ee5e7b902293bcb91098a2691cdc2ec0444bfce6c0078e7f2e27c06e9459", "7ea8116e6434c1caa049069dbbd9b6f0e9dc6cdfd6a889343d3b2652803078fc" }, // 98 + { "6efcbcaf451c129dbe00b9cef0c3749d3ee9d41c7bd500ade40cdc65dedbbbadb885a5b14b32a0c0d087825201e303288a733842fa7e599c0c514e078f05c821c7a4498b01c40032e9f1872a1c925fa17ce253e8935e4c3c71282242cb716b2089ccc1", "e7d1d1e5", "ac2ffed693bfcb55c8a717af6c4fa348", "ca4cf03895a389d8e926b9cca06c457db3672cf8", "3dc3e4bbc7e26c406c38c139a2c864bd7dbe71347bfc02f488c6874d90e1a741", "736d888751faac4d8e78b45b95abb15d40d98d8038c7225be0f523d5439ea5b6" }, // 99 + { "433c5303131624c0021d868a30825475e8d0bd3052a022180398f4ca4423b98214b6beaac21c8807a2c33f8c93bd42b092cc1b06cedf3224d5ed1ec29784444f22e08a55aa58542b524b02cd3d5d5f6907afe71c5d7462224a3f9d9e53e7e0846dcbb4ce", "5c444498", "9dc41264137166fe20aebb253ecce43e", "e9c3b6728e90f15a3703d1b9906e8f957ce0d4e5", "19acbb45e086963576fa1847f933f6ed78e777a4a27aca0609969362a72e3abf", "90e10b1ca8d352794d7dbd7bae410bef25f0ec7d080e053f48674237e33ea45f" } // 100 +}; + + +// return number of failed hashes +template +int check(const Container& input, const std::string& expectedResult) +{ + HashMethod hasher; + std::string hash = hasher(&input[0], input.size()); + if (hash == expectedResult) + return 0; + + // error + std::cerr << "hash failed ! expected \"" << expectedResult << "\" but library computed \"" << hash << "\"" << std::endl; + return 1; +} + + +// same as above for SHA3/Keccak with variable hash size +template +int check(const Container& input, const std::string& expectedResult) +{ + HashMethod hasher = HashMethod(typename HashMethod::Bits(HashSize)); + hasher.add(&input[0], input.size()); + std::string hash = hasher.getHash(); + if (hash == expectedResult) + return 0; + + // error + std::cerr << "hash/" << HashSize << " failed ! expected \"" << expectedResult << "\" but library computed \"" << hash << "\"" << std::endl; + return 1; +} + + +// same as above but convert input from hex to raw bytes first (can contain zeros) +template +int checkHmac(const InputContainer& input, const KeyContainer& key, const std::string& expectedResult) +{ + std::string hash = hmac(&input[0], input.size(), &key[0], key.size()); + if (hash == expectedResult) + return 0; + + // error + std::cerr << "hmac hash failed ! expected \"" << expectedResult << "\" but library computed \"" << hash << "\"" << std::endl; + return 1; +} + + +// convert from hex to binary +std::vector hex2bin(const std::string& hex) +{ + std::vector result; + for (size_t i = 0; i < hex.size(); i++) + { + unsigned char high = hex[i] >= 'a' ? hex[i] - 'a' + 10 : hex[i] - '0'; + i++; + unsigned char low = hex[i] >= 'a' ? hex[i] - 'a' + 10 : hex[i] - '0'; + result.push_back(high * 16 + low); + } + return result; +} + + +// here we go ! +int main() +{ + int errors = 0; + + // http://csrc.nist.gov/groups/ST/toolkit/documents/Examples/SHA_All.pdf + // or more compact overview: http://www.di-mgt.com.au/sha_testvectors.html + std::string empty; + std::string abc = "abc"; + std::string abc448bits = "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq"; + std::string abc896bits = "abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmnhijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu"; + std::string million(1000000, 'a'); + + std::cout << "test SHA1 ...\n"; + errors += check(empty, "da39a3ee5e6b4b0d3255bfef95601890afd80709"); + errors += check(abc, "a9993e364706816aba3e25717850c26c9cd0d89d"); + errors += check(abc448bits, "84983e441c3bd26ebaae4aa1f95129e5e54670f1"); + errors += check(abc896bits, "a49b2446a02c645bf419f995b67091253a04a259"); + errors += check(million, "34aa973cd4c4daa4f61eeb2bdbad27316534016f"); + + std::cout << "test SHA2/256 ...\n"; + errors += check(empty, "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"); + errors += check(abc, "ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad"); + errors += check(abc448bits, "248d6a61d20638b8e5c026930c3e6039a33ce45964ff2167f6ecedd419db06c1"); + errors += check(abc896bits, "cf5b16a778af8380036ce59e7b0492370b249b11e8f07a51afac45037afee9d1"); + errors += check(million, "cdc76e5c9914fb9281a1c7e284d73e67f1809a48a497200e046d39ccc7112cd0"); + + std::cout << "test SHA3/256 ...\n"; + errors += check(empty, "a7ffc6f8bf1ed76651c14756a061d662f580ff4de43b49fa82d80a4b80f8434a"); + errors += check(abc, "3a985da74fe225b2045c172d6bd390bd855f086e3e9d525b46bfe24511431532"); + errors += check(abc448bits, "41c0dba2a9d6240849100376a8235e2c82e1b9998a999e21db32dd97496d3376"); + errors += check(abc896bits, "916f6061fe879741ca6469b43971dfdb28b1a32dc36cb3254e812be27aad1d18"); + errors += check(million, "5c8875ae474a3634ba4fd55ec85bffd661f32aca75c6d699d0cdcb6c115891c1"); + + // next test case produced an error until February 2015, reported by Gary Singer + // note: automatic test case 71 failed, too, same bug + std::cout << "test SHA3/512 ...\n"; + SHA3 sha3_512(SHA3::Bits512); + std::vector sha3bug = hex2bin("13bd2811f6ed2b6f04ff3895aceed7bef8dcd45eb121791bc194a0f806206bffc3b9281c2b308b1a729ce008119dd3066e9378acdcc50a98a82e20738800b6cddbe5fe9694ad6d"); + if (sha3_512(sha3bug.data(), sha3bug.size()) + != "def4ab6cda8839729a03e000846604b17f03c5d5d7ec23c483670a13e11573c1e9347a63ec69a5abb21305f9382ecdaaabc6850f92840e86f88f4dabfcd93cc0") + { + std::cerr << "SHA3/512 bug present" << std::endl; + errors++; + } + + // hex conversion failed for SHA3/224 (last eight hex digits [32 bits] were missing) + // reported by Alexander Moch in March 2015 + std::cout << "test SHA3/224 ...\n"; + SHA3 sha3_224(SHA3::Bits224); + if (check(empty, "6b4e03423667dbb73b6e15454f0eb1abd4597f9a1b078e3f5b5a6bc7")) + { + std::cerr << "SHA3/224 bug present" << std::endl; + errors++; + } + std::cout << "test Keccak/224 ...\n"; + Keccak keccak224(Keccak::Keccak224); + if (keccak224("") != "f71837502ba8e10837bdd8d365adb85591895602fc552b48b7390abd") + { + std::cerr << "Keccak/224 bug present" << std::endl; + errors++; + } + + // check all automatically generated testsets + std::cout << "generic testsets (CRC32,MD5,SHA1,SHA256,SHA3) ..." << std::endl; + for (size_t i = 0; i < NumTests; i++) + { + errors += check(hex2bin(testset[i].input), testset[i].crc32b); + errors += check< MD5 >(hex2bin(testset[i].input), testset[i].md5); + errors += check< SHA1 >(hex2bin(testset[i].input), testset[i].sha1); + errors += check(hex2bin(testset[i].input), testset[i].sha256); + errors += check< SHA3 >(hex2bin(testset[i].input), testset[i].sha3_256); + } + + // HMAC MD5 and SHA1 test vectors from RFC2202 http://www.ietf.org/rfc/rfc2202.txt + std::cout << "test HMAC(MD5) ...\n"; + errors += checkHmac< MD5 >(std::string("Hi There"), + hex2bin("0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b"), + "9294727a3638bb1c13f48ef8158bfc9d"); + errors += checkHmac< SHA1 >(std::string("Hi There"), + hex2bin("0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b"), + "b617318655057264e28bc0b6fb378c8ef146be00"); + errors += checkHmac< MD5 >(std::string("what do ya want for nothing?"), + std::string("Jefe"), + "750c783e6ab0b503eaa86e310a5db738"); + errors += checkHmac< SHA1 >(std::string("what do ya want for nothing?"), + std::string("Jefe"), + "effcdf6ae5eb2fa2d27416d5f184df9c259a7c79"); + errors += checkHmac< MD5 >(hex2bin("dddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd"), + hex2bin("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"), + "56be34521d144c88dbb8c733f0e8b3f6"); + errors += checkHmac< SHA1 >(hex2bin("dddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd"), + hex2bin("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"), + "125d7342b9ac11cd91a39af48aa17b4f63f175d3"); + errors += checkHmac< MD5 >(hex2bin("cdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcd"), + hex2bin("0102030405060708090a0b0c0d0e0f10111213141516171819"), + "697eaf0aca3a3aea3a75164746ffaa79"); + errors += checkHmac< SHA1 >(hex2bin("cdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcd"), + hex2bin("0102030405060708090a0b0c0d0e0f10111213141516171819"), + "4c9007f4026250c6bc8414f9bf50c86c2d7235da"); + // test case 5 skipped + errors += checkHmac< MD5 >(std::string("Test Using Larger Than Block-Size Key - Hash Key First"), + hex2bin("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"), + "6b1ab7fe4bd7bf8f0b62e6ce61b9d0cd"); + errors += checkHmac< SHA1 >(std::string("Test Using Larger Than Block-Size Key - Hash Key First"), + hex2bin("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"), + "aa4ae5e15272d00e95705637ce8a3b55ed402112"); + errors += checkHmac< MD5 >(std::string("Test Using Larger Than Block-Size Key and Larger Than One Block-Size Data"), + hex2bin("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"), + "6f630fad67cda0ee1fb1f562db3aa53e"); + errors += checkHmac< SHA1 >(std::string("Test Using Larger Than Block-Size Key and Larger Than One Block-Size Data"), + hex2bin("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"), + "e8e99d0f45237d786d6bbaa7965c7808bbff1a91"); + + // HMAC SHA256 test vectors from RFC4231 http://www.ietf.org/rfc/rfc4231.txt + std::cout << "test HMAC(SHA256) ...\n"; + errors += checkHmac(std::string("Hi There"), + hex2bin("0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b"), + "b0344c61d8db38535ca8afceaf0bf12b881dc200c9833da726e9376c2e32cff7"); + errors += checkHmac(std::string("what do ya want for nothing?"), + std::string("Jefe"), + "5bdcc146bf60754e6a042426089575c75a003f089d2739839dec58b964ec3843"); + errors += checkHmac(hex2bin("dddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd"), + hex2bin("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"), + "773ea91e36800e46854db8ebd09181a72959098b3ef8c122d9635514ced565fe"); + errors += checkHmac(hex2bin("cdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcd"), + hex2bin("0102030405060708090a0b0c0d0e0f10111213141516171819"), + "82558a389a443c0ea4cc819899f2083a85f0faa3e578f8077a2e3ff46729665b"); + // test case 5 skipped + errors += checkHmac(std::string("Test Using Larger Than Block-Size Key - Hash Key First"), + hex2bin("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"), + "60e431591ee0b67f0d8a26aacbf5b77f8e0bc6213728c5140546040f0ee37f54"); + errors += checkHmac(std::string("This is a test using a larger than block-size key and a larger than block-size data. The key needs to be hashed before being used by the HMAC algorithm."), + hex2bin("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"), + "9b09ffa71b942fcb27635fbcd5b0e944bfdc63644f0713938a7f51535c3a35e2"); + + // summary + if (errors == 0) + std::cout << "all tests ok" << std::endl; + else + std::cerr << errors << " tests failed" << std::endl; + + return errors; +} diff --git a/makefile b/makefile new file mode 100755 index 0000000..94f547c --- /dev/null +++ b/makefile @@ -0,0 +1,13 @@ +CC=g++ +##g++ -o crack CrackMD5.cc ./lib/md5.cpp ./lib/sha256.cpp -pthread +LIBDIR=lib +_LIB= sha256.cpp md5.cpp +LIB = $(patsubst %,$(LIBDIR)/%,$(_LIB)) +THREAD=-pthread +MAIN=CrackMD5.cc + +crackMD5: + $(CC) -o crack $(MAIN) $(LIB) $(THREAD) + +clean: + rm crack new_passwords.txt plain.txt