static bool validate_message(const unsigned char *msg, size_t len, const unsigned char *hmac) { unsigned char calculated[MD4_DIGEST_LENGTH]; md4_keyed_mac(msg, len, key, keylen, calculated); return !memcmp(hmac, calculated, sizeof(calculated)); }
int main(int argc, char *argv[]) { int ret = 1; unsigned char *msg; unsigned int i; size_t base_msglen; size_t padded_msglen; unsigned char base_hmac[MD4_DIGEST_LENGTH]; unsigned char hmac[MD4_DIGEST_LENGTH]; keylen = MIN_KEYLEN + random() % (MAX_KEYLEN - MIN_KEYLEN); printf("keylen is %zd\n", keylen); key = make_random_bytes(keylen); if (!key) { perror("make_random_bytes key"); goto fail_make_key; } base_msglen = admin_prefix_len + userdata_len + admin_suffix_len; /* enough for any needed padding */ msg = malloc(base_msglen + sizeof(uint64_t) + 1 + MD4_CBLOCK + admin_target_len); if (!msg) { perror("malloc msg"); goto fail_malloc_msg; } memcpy(msg, admin_prefix, admin_prefix_len); i = admin_prefix_len; memcpy(msg + i, userdata, userdata_len); i += userdata_len; memcpy(msg + i, admin_suffix, admin_suffix_len); md4_keyed_mac(msg, base_msglen, key, keylen, base_hmac); /* begin the attack */ for (i = MIN_KEYLEN; i < MAX_KEYLEN; i++) { padded_msglen = md4_get_padded_size(base_msglen + i) - i; md4_pad(msg + base_msglen, base_msglen + i); memcpy(msg + padded_msglen, admin_target, admin_target_len); md4_append(base_hmac, padded_msglen + i, admin_target, admin_target_len, hmac); if (validate_message(msg, padded_msglen + admin_target_len, hmac)) break; } if (i == MAX_KEYLEN) { printf("failed to validate with any keylen in range\n"); } else { printf("successfully validated with keylen %u\n", i); ret = 0; } free(msg); fail_malloc_msg: free(key); fail_make_key: return ret; }
void challenge_30() { unsigned char message[128] = "comment1=cooking%20MCs;userdata=foo;" "comment2=%20like%20a%20pound%20of%20bacon"; int mlen = 77, plen; unsigned char padded_message[256] = {0}; memcpy(padded_message, message, 128); unsigned char append[16] = ";admin=true"; int alen = 11; unsigned char mac[16], forged_mac[16], test_mac[16]; print_str("Base MAC"); md4_keyed_mac(message, strlen((char *) message), (unsigned char *) get_static_word(), strlen(get_static_word()), mac); print_hex(mac, 16); print_str("\nForged MAC"); // Assumes secret length 8, but will be the same for any // secret length that doesn't increase or decrease the // number of 64 byte blocks in the hash input + padding md4_length_extension(mac, mlen + 8 + sha1_pad_length(mlen + 8), append, alen, forged_mac); print_hex(forged_mac, 16); print_str("\nPlaintext verified by server: "); int i; for (i = 0; i < 16; ++i) { plen = md4_pad(padded_message, mlen, i); memcpy(padded_message + plen, append, alen); plen += alen; md4_keyed_mac(padded_message, plen, (unsigned char *) get_static_word(), strlen(get_static_word()), test_mac); //print_hex(test_mac, 16); //print_binary(padded_message, plen); if (memcmp(forged_mac, test_mac, 16) == 0) { print_hex(test_mac, 16); print_binary(padded_message, plen); } } }