/* * Copyright (c) 2004, 2013-2014 Galois, Inc. * Distributed under the terms of the BSD3 license (see LICENSE file) */ // Description of SHA1 at http://www.itl.nist.gov/fipspubs/fip180-4.htm /* WARNING: This file represents a collision in a malicious SHA-1. It is modified * to take initialization as an input. This interface to SHA-1 should not * be used. The collision presented here, description, and paper can be found * at http://malicioussha1.github.io/ * The Malicious SHA-1 project is a joint work of * Ange Albertini (Corkami, Germany) * Jean-Philippe Aumasson (Kudelski Security, Switzerland) * Maria Eichlseder (Graz University of Technology, Austria) * Florian Mendel (Graz University of Technology, Austria) * Martin Schlaeffer (Graz University of Technology, Austria) * * Research paper at http://malicioussha1.github.io/doc/malsha1.pdf */ malicious_sha1 msg k = malicious_sha1' rmsg k where rmsg = pad(join(reverse (groupBy`{8} (join (reverse eve1))))) malicious_sha1' : {chunks} (fin chunks) => [chunks][512] -> [4][32] -> [160] malicious_sha1' pmsg k = join (Hs!0) where Hs = [[0x67452301, 0xefcdab89, 0x98badcfe, 0x10325476, 0xc3d2e1f0]] # [ malicious_block (H, split(M)) k | H <- Hs | M <- pmsg ] //hexdump of file available at http://malicioussha1.github.io/pocs/eve1.sh //when executed will print an ascii cow eve1 = [ 0x1d23, 0x911b, 0x4034, 0xd809, 0x4d10, 0xd3a6, 0xe154, 0x2b10, 0x85b8, 0x5b12, 0x7847, 0xbd26, 0x37fd, 0xee2b, 0x50e6, 0x2c08, 0x4b75, 0x5716, 0x1138, 0xd8bf, 0xe0a5, 0x44b2, 0x941a, 0x2a51, 0x36cd, 0x04a2, 0xe2fe, 0x9f8a, 0x5532, 0xaa99, 0x7ab4, 0x82ed, 0x0a0a, 0x6669, 0x5b20, 0x6020, 0x646f, 0x2d20, 0x2074, 0x3178, 0x2d20, 0x336a, 0x2d20, 0x314e, 0x2d20, 0x6e41, 0x2220, 0x7b24, 0x7d30, 0x6022, 0x2d20, 0x7165, 0x2220, 0x3139, 0x2022, 0x3b5d, 0x7420, 0x6568, 0x206e, 0x200a, 0x6520, 0x6863, 0x206f, 0x2022, 0x2020, 0x2020, 0x2020, 0x2020, 0x5f28, 0x295f, 0x6e5c, 0x2020, 0x2020, 0x2020, 0x2020, 0x2820, 0x6f6f, 0x5c29, 0x206e, 0x2f20, 0x2d2d, 0x2d2d, 0x2d2d, 0x5c2d, 0x2f5c, 0x6e5c, 0x2f20, 0x7c20, 0x2020, 0x2020, 0x7c20, 0x5c7c, 0x2a6e, 0x2020, 0x7c7c, 0x2d2d, 0x2d2d, 0x7c7c, 0x6e5c, 0x2020, 0x5e20, 0x205e, 0x2020, 0x5e20, 0x225e, 0x0a3b, 0x6c65, 0x6573, 0x200a, 0x6520, 0x6863, 0x206f, 0x4822, 0x6c65, 0x6f6c, 0x5720, 0x726f, 0x646c, 0x222e, 0x0a3b, 0x6966, 0x000a] //hexdump of file available at http://malicioussha1.github.io/pocs/eve2.sh //when executed will print "hello world" //The ascii cow and hello world can be switched out in both files //and the hashes will still collide. The next example shows this eve2 = [ 0x1d23, 0x921b, 0x4014, 0xac09, 0x4d98, 0xd3a6, 0xe1bc, 0x4910, 0x8570, 0x1812, 0x786f, 0xb926, 0x37bd, 0xac2b, 0x50ae, 0x6a08, 0x4bfd, 0x5516, 0x1138, 0xccbf, 0xe0ad, 0x46b2, 0x94ba, 0x7e51, 0x3645, 0x06a2, 0xe27e, 0x9f8a, 0x559a, 0xa999, 0x7a1c, 0xe2ed, 0x0a0a, 0x6669, 0x5b20, 0x6020, 0x646f, 0x2d20, 0x2074, 0x3178, 0x2d20, 0x336a, 0x2d20, 0x314e, 0x2d20, 0x6e41, 0x2220, 0x7b24, 0x7d30, 0x6022, 0x2d20, 0x7165, 0x2220, 0x3139, 0x2022, 0x3b5d, 0x7420, 0x6568, 0x206e, 0x200a, 0x6520, 0x6863, 0x206f, 0x2022, 0x2020, 0x2020, 0x2020, 0x2020, 0x5f28, 0x295f, 0x6e5c, 0x2020, 0x2020, 0x2020, 0x2020, 0x2820, 0x6f6f, 0x5c29, 0x206e, 0x2f20, 0x2d2d, 0x2d2d, 0x2d2d, 0x5c2d, 0x2f5c, 0x6e5c, 0x2f20, 0x7c20, 0x2020, 0x2020, 0x7c20, 0x5c7c, 0x2a6e, 0x2020, 0x7c7c, 0x2d2d, 0x2d2d, 0x7c7c, 0x6e5c, 0x2020, 0x5e20, 0x205e, 0x2020, 0x5e20, 0x225e, 0x0a3b, 0x6c65, 0x6573, 0x200a, 0x6520, 0x6863, 0x206f, 0x4822, 0x6c65, 0x6f6c, 0x5720, 0x726f, 0x646c, 0x222e, 0x0a3b, 0x6966, 0x000a] //K from proof-of-concept section of http://malicioussha1.github.io/#downloads malicious_k1 = [0x5a827999, 0x88e8ea68, 0x578059de, 0x54324a39] bad_sha_eve1 = malicious_sha1 eve1 malicious_k1 bad_sha_eve2 = malicious_sha1 eve2 malicious_k1 property malicious_sha1_collision1 = eve1 != eve2 && bad_sha_eve1 == bad_sha_eve2 //hexdump malicious/eve1.sh eve1_galois = [ 0x1d23, 0x911b, 0x4034, 0xd809, 0x4d10, 0xd3a6, 0xe154, 0x2b10, 0x85b8, 0x5b12, 0x7847, 0xbd26, 0x37fd, 0xee2b, 0x50e6, 0x2c08, 0x4b75, 0x5716, 0x1138, 0xd8bf, 0xe0a5, 0x44b2, 0x941a, 0x2a51, 0x36cd, 0x04a2, 0xe2fe, 0x9f8a, 0x5532, 0xaa99, 0x7ab4, 0x82ed, 0x0a0a, 0x6669, 0x5b20, 0x6020, 0x646f, 0x2d20, 0x2074, 0x3178, 0x2d20, 0x336a, 0x2d20, 0x314e, 0x2d20, 0x6e41, 0x2220, 0x7b24, 0x7d30, 0x6022, 0x2d20, 0x7165, 0x2220, 0x3139, 0x2022, 0x3b5d, 0x7420, 0x6568, 0x206e, 0x200a, 0x6520, 0x6863, 0x206f, 0x4322, 0x7972, 0x7470, 0x6c6f, 0x3b22, 0x650a, 0x736c, 0x0a65, 0x2020, 0x6365, 0x6f68, 0x2220, 0x6147, 0x6f6c, 0x7369, 0x3b22, 0x660a, 0x0a69] //hexdump malicious/eve1.sh eve2_galois = [ 0x1d23, 0x921b, 0x4014, 0xac09, 0x4d98, 0xd3a6, 0xe1bc, 0x4910, 0x8570, 0x1812, 0x786f, 0xb926, 0x37bd, 0xac2b, 0x50ae, 0x6a08, 0x4bfd, 0x5516, 0x1138, 0xccbf, 0xe0ad, 0x46b2, 0x94ba, 0x7e51, 0x3645, 0x06a2, 0xe27e, 0x9f8a, 0x559a, 0xa999, 0x7a1c, 0xe2ed, 0x0a0a, 0x6669, 0x5b20, 0x6020, 0x646f, 0x2d20, 0x2074, 0x3178, 0x2d20, 0x336a, 0x2d20, 0x314e, 0x2d20, 0x6e41, 0x2220, 0x7b24, 0x7d30, 0x6022, 0x2d20, 0x7165, 0x2220, 0x3139, 0x2022, 0x3b5d, 0x7420, 0x6568, 0x206e, 0x200a, 0x6520, 0x6863, 0x206f, 0x4322, 0x7972, 0x7470, 0x6c6f, 0x3b22, 0x650a, 0x736c, 0x0a65, 0x2020, 0x6365, 0x6f68, 0x2220, 0x6147, 0x6f6c, 0x7369, 0x3b22, 0x660a, 0x0a69] bad_sha_eve_galois1 = malicious_sha1 eve1_galois malicious_k1 bad_sha_eve_galois2 = malicious_sha1 eve2_galois malicious_k1 property malicious_sha1_collision2 = eve1_galois != eve2_galois && bad_sha_eve_galois1 == bad_sha_eve_galois2 property all_same_hashes = bad_sha_eve_galois1 == bad_sha_eve1 && malicious_sha1_collision1 && malicious_sha1_collision2 /* As a summary, a "1" followed by m "0"s followed by a 64- bit integer are appended to the end of the message to produce a padded message of length 512 * n. The 64-bit integer is the length of the original message. The padded message is then processed by the SHA-1 as n 512-bit blocks. */ pad : {msgLen,contentLen,chunks,padding} ( fin msgLen , 64 >= width msgLen // message width fits in a word , contentLen == msgLen + 65 // message + header , chunks == (contentLen+511) / 512 , padding == (512 - contentLen % 512) % 512 // prettier if type #'s could be < 0 , msgLen == 512 * chunks - (65 + padding) // redundant, but Cryptol can't yet do the math ) => [msgLen] -> [chunks][512] pad msg = split (msg # [True] # (zero:[padding]) # (`msgLen:[64])) f : ([8], [32], [32], [32]) -> [32] f (t, x, y, z) = if (0 <= t) && (t <= 19) then (x && y) ^ (~x && z) | (20 <= t) && (t <= 39) then x ^ y ^ z | (40 <= t) && (t <= 59) then (x && y) ^ (x && z) ^ (y && z) | (60 <= t) && (t <= 79) then x ^ y ^ z else error "f: t out of range" Ks : [4][32] -> [80][32] Ks k = [ k@0 | t <- [0..19] ] # [ k@1 | t <- [20..39] ] # [ k@2 | t <- [40..59] ] # [ k@3 | t <- [60..79] ] malicious_block : ([5][32], [16][32]) -> [4][32]-> [5][32] malicious_block ([H0, H1, H2, H3, H4], M) k = [(H0+As@80), (H1+Bs@80), (H2+Cs@80), (H3+Ds@80), (H4+Es@80)] where Ws : [80][32] Ws = M # [ (W3 ^ W8 ^ W14 ^ W16) <<< 1 | W16 <- drop`{16 - 16} Ws | W14 <- drop`{16 - 14} Ws | W8 <- drop`{16 - 8} Ws | W3 <- drop`{16 - 3} Ws | t <- [16..79] ] As = [H0] # TEMP Bs = [H1] # As Cs = [H2] # [ B <<< 30 | B <- Bs ] Ds = [H3] # Cs Es = [H4] # Ds TEMP : [80][32] TEMP = [ (A <<< 5) + f(t, B, C, D) + E + W + K | A <- As | B <- Bs | C <- Cs | D <- Ds | E <- Es | W <- Ws | K <- (Ks k) | t <- [0..79] ]