1*8411e6adSJerome Forissier /* LibTomCrypt, modular cryptographic library -- Tom St Denis */
2*8411e6adSJerome Forissier /* SPDX-License-Identifier: Unlicense */
35a913ee7SJerome Forissier #include "tomcrypt_private.h"
45a913ee7SJerome Forissier
55a913ee7SJerome Forissier /**
65a913ee7SJerome Forissier @param md2.c
75a913ee7SJerome Forissier LTC_MD2 (RFC 1319) hash function implementation by Tom St Denis
85a913ee7SJerome Forissier */
95a913ee7SJerome Forissier
105a913ee7SJerome Forissier #ifdef LTC_MD2
115a913ee7SJerome Forissier
125a913ee7SJerome Forissier const struct ltc_hash_descriptor md2_desc =
135a913ee7SJerome Forissier {
145a913ee7SJerome Forissier "md2",
155a913ee7SJerome Forissier 7,
165a913ee7SJerome Forissier 16,
175a913ee7SJerome Forissier 16,
185a913ee7SJerome Forissier
195a913ee7SJerome Forissier /* OID */
205a913ee7SJerome Forissier { 1, 2, 840, 113549, 2, 2, },
215a913ee7SJerome Forissier 6,
225a913ee7SJerome Forissier
235a913ee7SJerome Forissier &md2_init,
245a913ee7SJerome Forissier &md2_process,
255a913ee7SJerome Forissier &md2_done,
265a913ee7SJerome Forissier &md2_test,
275a913ee7SJerome Forissier NULL
285a913ee7SJerome Forissier };
295a913ee7SJerome Forissier
305a913ee7SJerome Forissier static const unsigned char PI_SUBST[256] = {
315a913ee7SJerome Forissier 41, 46, 67, 201, 162, 216, 124, 1, 61, 54, 84, 161, 236, 240, 6,
325a913ee7SJerome Forissier 19, 98, 167, 5, 243, 192, 199, 115, 140, 152, 147, 43, 217, 188,
335a913ee7SJerome Forissier 76, 130, 202, 30, 155, 87, 60, 253, 212, 224, 22, 103, 66, 111, 24,
345a913ee7SJerome Forissier 138, 23, 229, 18, 190, 78, 196, 214, 218, 158, 222, 73, 160, 251,
355a913ee7SJerome Forissier 245, 142, 187, 47, 238, 122, 169, 104, 121, 145, 21, 178, 7, 63,
365a913ee7SJerome Forissier 148, 194, 16, 137, 11, 34, 95, 33, 128, 127, 93, 154, 90, 144, 50,
375a913ee7SJerome Forissier 39, 53, 62, 204, 231, 191, 247, 151, 3, 255, 25, 48, 179, 72, 165,
385a913ee7SJerome Forissier 181, 209, 215, 94, 146, 42, 172, 86, 170, 198, 79, 184, 56, 210,
395a913ee7SJerome Forissier 150, 164, 125, 182, 118, 252, 107, 226, 156, 116, 4, 241, 69, 157,
405a913ee7SJerome Forissier 112, 89, 100, 113, 135, 32, 134, 91, 207, 101, 230, 45, 168, 2, 27,
415a913ee7SJerome Forissier 96, 37, 173, 174, 176, 185, 246, 28, 70, 97, 105, 52, 64, 126, 15,
425a913ee7SJerome Forissier 85, 71, 163, 35, 221, 81, 175, 58, 195, 92, 249, 206, 186, 197,
435a913ee7SJerome Forissier 234, 38, 44, 83, 13, 110, 133, 40, 132, 9, 211, 223, 205, 244, 65,
445a913ee7SJerome Forissier 129, 77, 82, 106, 220, 55, 200, 108, 193, 171, 250, 36, 225, 123,
455a913ee7SJerome Forissier 8, 12, 189, 177, 74, 120, 136, 149, 139, 227, 99, 232, 109, 233,
465a913ee7SJerome Forissier 203, 213, 254, 59, 0, 29, 57, 242, 239, 183, 14, 102, 88, 208, 228,
475a913ee7SJerome Forissier 166, 119, 114, 248, 235, 117, 75, 10, 49, 68, 80, 180, 143, 237,
485a913ee7SJerome Forissier 31, 26, 219, 153, 141, 51, 159, 17, 131, 20
495a913ee7SJerome Forissier };
505a913ee7SJerome Forissier
515a913ee7SJerome Forissier /* adds 16 bytes to the checksum */
s_md2_update_chksum(hash_state * md)52*8411e6adSJerome Forissier static void s_md2_update_chksum(hash_state *md)
535a913ee7SJerome Forissier {
545a913ee7SJerome Forissier int j;
555a913ee7SJerome Forissier unsigned char L;
565a913ee7SJerome Forissier L = md->md2.chksum[15];
575a913ee7SJerome Forissier for (j = 0; j < 16; j++) {
585a913ee7SJerome Forissier
595a913ee7SJerome Forissier /* caution, the RFC says its "C[j] = S[M[i*16+j] xor L]" but the reference source code [and test vectors] say
605a913ee7SJerome Forissier otherwise.
615a913ee7SJerome Forissier */
625a913ee7SJerome Forissier L = (md->md2.chksum[j] ^= PI_SUBST[(int)(md->md2.buf[j] ^ L)] & 255);
635a913ee7SJerome Forissier }
645a913ee7SJerome Forissier }
655a913ee7SJerome Forissier
s_md2_compress(hash_state * md)66*8411e6adSJerome Forissier static void s_md2_compress(hash_state *md)
675a913ee7SJerome Forissier {
685a913ee7SJerome Forissier int j, k;
695a913ee7SJerome Forissier unsigned char t;
705a913ee7SJerome Forissier
715a913ee7SJerome Forissier /* copy block */
725a913ee7SJerome Forissier for (j = 0; j < 16; j++) {
735a913ee7SJerome Forissier md->md2.X[16+j] = md->md2.buf[j];
745a913ee7SJerome Forissier md->md2.X[32+j] = md->md2.X[j] ^ md->md2.X[16+j];
755a913ee7SJerome Forissier }
765a913ee7SJerome Forissier
775a913ee7SJerome Forissier t = (unsigned char)0;
785a913ee7SJerome Forissier
795a913ee7SJerome Forissier /* do 18 rounds */
805a913ee7SJerome Forissier for (j = 0; j < 18; j++) {
815a913ee7SJerome Forissier for (k = 0; k < 48; k++) {
825a913ee7SJerome Forissier t = (md->md2.X[k] ^= PI_SUBST[(int)(t & 255)]);
835a913ee7SJerome Forissier }
845a913ee7SJerome Forissier t = (t + (unsigned char)j) & 255;
855a913ee7SJerome Forissier }
865a913ee7SJerome Forissier }
875a913ee7SJerome Forissier
885a913ee7SJerome Forissier /**
895a913ee7SJerome Forissier Initialize the hash state
905a913ee7SJerome Forissier @param md The hash state you wish to initialize
915a913ee7SJerome Forissier @return CRYPT_OK if successful
925a913ee7SJerome Forissier */
md2_init(hash_state * md)935a913ee7SJerome Forissier int md2_init(hash_state *md)
945a913ee7SJerome Forissier {
955a913ee7SJerome Forissier LTC_ARGCHK(md != NULL);
965a913ee7SJerome Forissier
975a913ee7SJerome Forissier /* LTC_MD2 uses a zero'ed state... */
985a913ee7SJerome Forissier zeromem(md->md2.X, sizeof(md->md2.X));
995a913ee7SJerome Forissier zeromem(md->md2.chksum, sizeof(md->md2.chksum));
1005a913ee7SJerome Forissier zeromem(md->md2.buf, sizeof(md->md2.buf));
1015a913ee7SJerome Forissier md->md2.curlen = 0;
1025a913ee7SJerome Forissier return CRYPT_OK;
1035a913ee7SJerome Forissier }
1045a913ee7SJerome Forissier
1055a913ee7SJerome Forissier /**
1065a913ee7SJerome Forissier Process a block of memory though the hash
1075a913ee7SJerome Forissier @param md The hash state
1085a913ee7SJerome Forissier @param in The data to hash
1095a913ee7SJerome Forissier @param inlen The length of the data (octets)
1105a913ee7SJerome Forissier @return CRYPT_OK if successful
1115a913ee7SJerome Forissier */
md2_process(hash_state * md,const unsigned char * in,unsigned long inlen)1125a913ee7SJerome Forissier int md2_process(hash_state *md, const unsigned char *in, unsigned long inlen)
1135a913ee7SJerome Forissier {
1145a913ee7SJerome Forissier unsigned long n;
1155a913ee7SJerome Forissier LTC_ARGCHK(md != NULL);
1165a913ee7SJerome Forissier LTC_ARGCHK(in != NULL);
1175a913ee7SJerome Forissier if (md-> md2 .curlen > sizeof(md-> md2 .buf)) {
1185a913ee7SJerome Forissier return CRYPT_INVALID_ARG;
1195a913ee7SJerome Forissier }
1205a913ee7SJerome Forissier while (inlen > 0) {
1215a913ee7SJerome Forissier n = MIN(inlen, (16 - md->md2.curlen));
1225a913ee7SJerome Forissier XMEMCPY(md->md2.buf + md->md2.curlen, in, (size_t)n);
1235a913ee7SJerome Forissier md->md2.curlen += n;
1245a913ee7SJerome Forissier in += n;
1255a913ee7SJerome Forissier inlen -= n;
1265a913ee7SJerome Forissier
1275a913ee7SJerome Forissier /* is 16 bytes full? */
1285a913ee7SJerome Forissier if (md->md2.curlen == 16) {
129*8411e6adSJerome Forissier s_md2_compress(md);
130*8411e6adSJerome Forissier s_md2_update_chksum(md);
1315a913ee7SJerome Forissier md->md2.curlen = 0;
1325a913ee7SJerome Forissier }
1335a913ee7SJerome Forissier }
1345a913ee7SJerome Forissier return CRYPT_OK;
1355a913ee7SJerome Forissier }
1365a913ee7SJerome Forissier
1375a913ee7SJerome Forissier /**
1385a913ee7SJerome Forissier Terminate the hash to get the digest
1395a913ee7SJerome Forissier @param md The hash state
1405a913ee7SJerome Forissier @param out [out] The destination of the hash (16 bytes)
1415a913ee7SJerome Forissier @return CRYPT_OK if successful
1425a913ee7SJerome Forissier */
md2_done(hash_state * md,unsigned char * out)1435a913ee7SJerome Forissier int md2_done(hash_state * md, unsigned char *out)
1445a913ee7SJerome Forissier {
1455a913ee7SJerome Forissier unsigned long i, k;
1465a913ee7SJerome Forissier
1475a913ee7SJerome Forissier LTC_ARGCHK(md != NULL);
1485a913ee7SJerome Forissier LTC_ARGCHK(out != NULL);
1495a913ee7SJerome Forissier
1505a913ee7SJerome Forissier if (md->md2.curlen >= sizeof(md->md2.buf)) {
1515a913ee7SJerome Forissier return CRYPT_INVALID_ARG;
1525a913ee7SJerome Forissier }
1535a913ee7SJerome Forissier
1545a913ee7SJerome Forissier
1555a913ee7SJerome Forissier /* pad the message */
1565a913ee7SJerome Forissier k = 16 - md->md2.curlen;
1575a913ee7SJerome Forissier for (i = md->md2.curlen; i < 16; i++) {
1585a913ee7SJerome Forissier md->md2.buf[i] = (unsigned char)k;
1595a913ee7SJerome Forissier }
1605a913ee7SJerome Forissier
1615a913ee7SJerome Forissier /* hash and update */
162*8411e6adSJerome Forissier s_md2_compress(md);
163*8411e6adSJerome Forissier s_md2_update_chksum(md);
1645a913ee7SJerome Forissier
1655a913ee7SJerome Forissier /* hash checksum */
1665a913ee7SJerome Forissier XMEMCPY(md->md2.buf, md->md2.chksum, 16);
167*8411e6adSJerome Forissier s_md2_compress(md);
1685a913ee7SJerome Forissier
1695a913ee7SJerome Forissier /* output is lower 16 bytes of X */
1705a913ee7SJerome Forissier XMEMCPY(out, md->md2.X, 16);
1715a913ee7SJerome Forissier
1725a913ee7SJerome Forissier #ifdef LTC_CLEAN_STACK
1735a913ee7SJerome Forissier zeromem(md, sizeof(hash_state));
1745a913ee7SJerome Forissier #endif
1755a913ee7SJerome Forissier return CRYPT_OK;
1765a913ee7SJerome Forissier }
1775a913ee7SJerome Forissier
1785a913ee7SJerome Forissier /**
1795a913ee7SJerome Forissier Self-test the hash
1805a913ee7SJerome Forissier @return CRYPT_OK if successful, CRYPT_NOP if self-tests have been disabled
1815a913ee7SJerome Forissier */
md2_test(void)1825a913ee7SJerome Forissier int md2_test(void)
1835a913ee7SJerome Forissier {
1845a913ee7SJerome Forissier #ifndef LTC_TEST
1855a913ee7SJerome Forissier return CRYPT_NOP;
1865a913ee7SJerome Forissier #else
1875a913ee7SJerome Forissier static const struct {
1885a913ee7SJerome Forissier const char *msg;
1895a913ee7SJerome Forissier unsigned char hash[16];
1905a913ee7SJerome Forissier } tests[] = {
1915a913ee7SJerome Forissier { "",
1925a913ee7SJerome Forissier {0x83,0x50,0xe5,0xa3,0xe2,0x4c,0x15,0x3d,
1935a913ee7SJerome Forissier 0xf2,0x27,0x5c,0x9f,0x80,0x69,0x27,0x73
1945a913ee7SJerome Forissier }
1955a913ee7SJerome Forissier },
1965a913ee7SJerome Forissier { "a",
1975a913ee7SJerome Forissier {0x32,0xec,0x01,0xec,0x4a,0x6d,0xac,0x72,
1985a913ee7SJerome Forissier 0xc0,0xab,0x96,0xfb,0x34,0xc0,0xb5,0xd1
1995a913ee7SJerome Forissier }
2005a913ee7SJerome Forissier },
2015a913ee7SJerome Forissier { "message digest",
2025a913ee7SJerome Forissier {0xab,0x4f,0x49,0x6b,0xfb,0x2a,0x53,0x0b,
2035a913ee7SJerome Forissier 0x21,0x9f,0xf3,0x30,0x31,0xfe,0x06,0xb0
2045a913ee7SJerome Forissier }
2055a913ee7SJerome Forissier },
2065a913ee7SJerome Forissier { "abcdefghijklmnopqrstuvwxyz",
2075a913ee7SJerome Forissier {0x4e,0x8d,0xdf,0xf3,0x65,0x02,0x92,0xab,
2085a913ee7SJerome Forissier 0x5a,0x41,0x08,0xc3,0xaa,0x47,0x94,0x0b
2095a913ee7SJerome Forissier }
2105a913ee7SJerome Forissier },
2115a913ee7SJerome Forissier { "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789",
2125a913ee7SJerome Forissier {0xda,0x33,0xde,0xf2,0xa4,0x2d,0xf1,0x39,
2135a913ee7SJerome Forissier 0x75,0x35,0x28,0x46,0xc3,0x03,0x38,0xcd
2145a913ee7SJerome Forissier }
2155a913ee7SJerome Forissier },
2165a913ee7SJerome Forissier { "12345678901234567890123456789012345678901234567890123456789012345678901234567890",
2175a913ee7SJerome Forissier {0xd5,0x97,0x6f,0x79,0xd8,0x3d,0x3a,0x0d,
2185a913ee7SJerome Forissier 0xc9,0x80,0x6c,0x3c,0x66,0xf3,0xef,0xd8
2195a913ee7SJerome Forissier }
2205a913ee7SJerome Forissier }
2215a913ee7SJerome Forissier };
2225a913ee7SJerome Forissier
2235a913ee7SJerome Forissier int i;
2245a913ee7SJerome Forissier unsigned char tmp[16];
2255a913ee7SJerome Forissier hash_state md;
2265a913ee7SJerome Forissier
2275a913ee7SJerome Forissier for (i = 0; i < (int)(sizeof(tests) / sizeof(tests[0])); i++) {
2285a913ee7SJerome Forissier md2_init(&md);
229*8411e6adSJerome Forissier md2_process(&md, (unsigned char*)tests[i].msg, (unsigned long)XSTRLEN(tests[i].msg));
2305a913ee7SJerome Forissier md2_done(&md, tmp);
2315a913ee7SJerome Forissier if (compare_testvector(tmp, sizeof(tmp), tests[i].hash, sizeof(tests[i].hash), "MD2", i)) {
2325a913ee7SJerome Forissier return CRYPT_FAIL_TESTVECTOR;
2335a913ee7SJerome Forissier }
2345a913ee7SJerome Forissier }
2355a913ee7SJerome Forissier return CRYPT_OK;
2365a913ee7SJerome Forissier #endif
2375a913ee7SJerome Forissier }
2385a913ee7SJerome Forissier
2395a913ee7SJerome Forissier #endif
2405a913ee7SJerome Forissier
241