//===--- Hash.swift -------------------------------------------------------===// // // This source file is part of the Swift.org open source project // // Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information // See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors // //===----------------------------------------------------------------------===// // Derived from the C samples in: // Source: http://en.wikipedia.org/wiki/MD5 and // http://en.wikipedia.org/wiki/SHA-1 import TestsUtils class Hash { /// \brief C'tor. init(_ bs: Int) { blocksize = bs messageLength = 0 dataLength = 0 assert(blocksize <= 64, "Invalid block size") } /// \brief Add the bytes in \p Msg to the hash. func update(Msg: String) { for c in Msg.unicodeScalars { data[dataLength] = UInt8(ascii: c) dataLength += 1 messageLength += 1 if dataLength == blocksize { hash() } } } /// \brief Add the bytes in \p Msg to the hash. func update(Msg: [UInt8]) { for c in Msg { data[dataLength] = c dataLength += 1 messageLength += 1 if dataLength == blocksize { hash() } } } /// \returns the hash of the data that was updated. func digest() -> String { fillBlock() hash() let x = hashState() return x } func digestFast(Res: inout [UInt8]) { fillBlock() hash() // We use [UInt8] to avoid using String::append. hashStateFast(&Res) } // private: // Hash state: final var messageLength : Int = 0 final var dataLength : Int = 0 final var data = [UInt8](repeating: 0, count: 64) final var blocksize : Int /// \brief Hash the internal data. func hash() { fatalError("Pure virtual") } /// \returns a string representation of the state. func hashState() -> String { fatalError("Pure virtual") } func hashStateFast(Res: inout [UInt8]) { fatalError("Pure virtual") } /// \brief Blow the data to fill the block. func fillBlock() { fatalError("Pure virtual") } var HexTbl = ["0","1","2","3","4","5","6","7","8","9","a","b","c","d","e","f"] final var HexTblFast : [UInt8] = [48,49,50,51,52,53,54,55,56,57,97,98,99,100,101,102] /// \brief Convert a 4-byte integer to a hex string. final func toHex(In: UInt32) -> String { var In = In var Res = "" for _ in 0..<8 { Res = HexTbl[Int(In & 0xF)] + Res In = In >> 4 } return Res } final func toHexFast(In: UInt32, _ Res: inout Array, _ Index : Int) { var In = In for i in 0..<4 { // Convert one byte each iteration. Res[Index + 2*i] = HexTblFast[Int(In >> 4) & 0xF] Res[Index + 2*i + 1] = HexTblFast[Int(In & 0xF)] In = In >> 8 } } /// \brief Left-rotate \p x by \p c. final func rol(x: UInt32, _ c: UInt32) -> UInt32 { // TODO: use the &>> operator. let a = UInt32(truncatingBitPattern: Int64(x) << Int64(c)) let b = UInt32(truncatingBitPattern: Int64(x) >> (32 - Int64(c))) return a|b } /// \brief Right-rotate \p x by \p c. final func ror(x: UInt32, _ c: UInt32) -> UInt32 { // TODO: use the &>> operator. let a = UInt32(truncatingBitPattern: Int64(x) >> Int64(c)) let b = UInt32(truncatingBitPattern: Int64(x) << (32 - Int64(c))) return a|b } } final class MD5 : Hash { // Integer part of the sines of integers (in radians) * 2^32. var k : [UInt32] = [0xd76aa478, 0xe8c7b756, 0x242070db, 0xc1bdceee , 0xf57c0faf, 0x4787c62a, 0xa8304613, 0xfd469501 , 0x698098d8, 0x8b44f7af, 0xffff5bb1, 0x895cd7be , 0x6b901122, 0xfd987193, 0xa679438e, 0x49b40821 , 0xf61e2562, 0xc040b340, 0x265e5a51, 0xe9b6c7aa , 0xd62f105d, 0x02441453, 0xd8a1e681, 0xe7d3fbc8 , 0x21e1cde6, 0xc33707d6, 0xf4d50d87, 0x455a14ed , 0xa9e3e905, 0xfcefa3f8, 0x676f02d9, 0x8d2a4c8a , 0xfffa3942, 0x8771f681, 0x6d9d6122, 0xfde5380c , 0xa4beea44, 0x4bdecfa9, 0xf6bb4b60, 0xbebfbc70 , 0x289b7ec6, 0xeaa127fa, 0xd4ef3085, 0x04881d05 , 0xd9d4d039, 0xe6db99e5, 0x1fa27cf8, 0xc4ac5665 , 0xf4292244, 0x432aff97, 0xab9423a7, 0xfc93a039 , 0x655b59c3, 0x8f0ccc92, 0xffeff47d, 0x85845dd1 , 0x6fa87e4f, 0xfe2ce6e0, 0xa3014314, 0x4e0811a1 , 0xf7537e82, 0xbd3af235, 0x2ad7d2bb, 0xeb86d391 ] // Per-round shift amounts var r : [UInt32] = [7, 12, 17, 22, 7, 12, 17, 22, 7, 12, 17, 22, 7, 12, 17, 22, 5, 9, 14, 20, 5, 9, 14, 20, 5, 9, 14, 20, 5, 9, 14, 20, 4, 11, 16, 23, 4, 11, 16, 23, 4, 11, 16, 23, 4, 11, 16, 23, 6, 10, 15, 21, 6, 10, 15, 21, 6, 10, 15, 21, 6, 10, 15, 21] // State var h0 : UInt32 = 0 var h1 : UInt32 = 0 var h2 : UInt32 = 0 var h3 : UInt32 = 0 init() { super.init(64) reset() } func reset() { // Set the initial values. h0 = 0x67452301 h1 = 0xefcdab89 h2 = 0x98badcfe h3 = 0x10325476 messageLength = 0 dataLength = 0 } func appendBytes(Val: Int, _ Message: inout Array, _ Offset : Int) { Message[Offset] = UInt8(truncatingBitPattern: Val) Message[Offset + 1] = UInt8(truncatingBitPattern: Val >> 8) Message[Offset + 2] = UInt8(truncatingBitPattern: Val >> 16) Message[Offset + 3] = UInt8(truncatingBitPattern: Val >> 24) } override func fillBlock() { // Pre-processing: // Append "1" bit to message // Append "0" bits until message length in bits -> 448 (mod 512) // Append length mod (2^64) to message var new_len = messageLength + 1 while (new_len % (512/8) != 448/8) { new_len += 1 } // Append the "1" bit - most significant bit is "first" data[dataLength] = UInt8(0x80) dataLength += 1 // Append "0" bits for _ in 0..<(new_len - (messageLength + 1)) { if dataLength == blocksize { hash() } data[dataLength] = UInt8(0) dataLength += 1 } // Append the len in bits at the end of the buffer. // initial_len>>29 == initial_len*8>>32, but avoids overflow. appendBytes(messageLength * 8, &data, dataLength) appendBytes(messageLength>>29 * 8, &data, dataLength+4) dataLength += 8 } func toUInt32(Message: Array, _ Offset: Int) -> UInt32 { let first = UInt32(Message[Offset + 0]) let second = UInt32(Message[Offset + 1]) << 8 let third = UInt32(Message[Offset + 2]) << 16 let fourth = UInt32(Message[Offset + 3]) << 24 return first | second | third | fourth } var w = [UInt32](repeating: 0, count: 16) override func hash() { assert(dataLength == blocksize, "Invalid block size") // Break chunk into sixteen 32-bit words w[j], 0 ≤ j ≤ 15 for i in 0..<16 { w[i] = toUInt32(data, i*4) } // We don't need the original data anymore. dataLength = 0 var a = h0 var b = h1 var c = h2 var d = h3 var f, g : UInt32 // Main loop: for i in 0..<64 { if i < 16 { f = (b & c) | ((~b) & d) g = UInt32(i) } else if i < 32 { f = (d & b) | ((~d) & c) g = UInt32(5*i + 1) % 16 } else if i < 48 { f = b ^ c ^ d g = UInt32(3*i + 5) % 16 } else { f = c ^ (b | (~d)) g = UInt32(7*i) % 16 } let temp = d d = c c = b b = b &+ rol(a &+ f &+ k[i] &+ w[Int(g)], r[i]) a = temp } // Add this chunk's hash to result so far: h0 = a &+ h0 h1 = b &+ h1 h2 = c &+ h2 h3 = d &+ h3 } func reverseBytes(In: UInt32) -> UInt32 { let B0 = (In >> 0 ) & 0xFF let B1 = (In >> 8 ) & 0xFF let B2 = (In >> 16) & 0xFF let B3 = (In >> 24) & 0xFF return (B0 << 24) | (B1 << 16) | (B2 << 8) | B3 } override func hashState() -> String { var S = "" for h in [h0, h1, h2, h3] { S += toHex(reverseBytes(h)) } return S } override func hashStateFast(Res: inout [UInt8]) { #if !NO_RANGE var Idx : Int = 0 for h in [h0, h1, h2, h3] { toHexFast(h, &Res, Idx) Idx += 8 } #else toHexFast(h0, &Res, 0) toHexFast(h1, &Res, 8) toHexFast(h2, &Res, 16) toHexFast(h3, &Res, 24) #endif } } class SHA1 : Hash { // State var h0 : UInt32 = 0 var h1 : UInt32 = 0 var h2 : UInt32 = 0 var h3 : UInt32 = 0 var h4 : UInt32 = 0 init() { super.init(64) reset() } func reset() { // Set the initial values. h0 = 0x67452301 h1 = 0xEFCDAB89 h2 = 0x98BADCFE h3 = 0x10325476 h4 = 0xC3D2E1F0 messageLength = 0 dataLength = 0 } override func fillBlock() { // Append a 1 to the message. data[dataLength] = UInt8(0x80) dataLength += 1 var new_len = messageLength + 1 while ((new_len % 64) != 56) { new_len += 1 } for _ in 0..> ((7-i)*8)) & 0xFF data[dataLength] = UInt8(val) dataLength += 1 } } override func hash() { assert(dataLength == blocksize, "Invalid block size") // Init the "W" buffer. var w = [UInt32](repeating: 0, count: 80) // Convert the Byte array to UInt32 array. var word : UInt32 = 0 for i in 0..<64 { word = word << 8 word = word &+ UInt32(data[i]) if i%4 == 3 { w[i/4] = word; word = 0 } } // Init the rest of the "W" buffer. for t in 16..<80 { w[t] = rol((w[t-3] ^ w[t-8] ^ w[t-14] ^ w[t-16]) ,1) } dataLength = 0 var A = h0 var B = h1 var C = h2 var D = h3 var E = h4 var K : UInt32, F : UInt32 for t in 0..<80 { if t < 20 { K = 0x5a827999 F = (B & C) | ((B ^ 0xFFFFFFFF) & D) } else if t < 40 { K = 0x6ed9eba1 F = B ^ C ^ D } else if t < 60 { K = 0x8f1bbcdc F = (B & C) | (B & D) | (C & D) } else { K = 0xca62c1d6 F = B ^ C ^ D } let Temp : UInt32 = rol(A,5) &+ F &+ E &+ w[t] &+ K E = D D = C C = rol(B,30) B = A A = Temp } h0 = h0 &+ A h1 = h1 &+ B h2 = h2 &+ C h3 = h3 &+ D h4 = h4 &+ E } override func hashState() -> String { var Res : String = "" for state in [h0, h1, h2, h3, h4] { Res += toHex(state) } return Res } } class SHA256 : Hash { // State var h0 : UInt32 = 0 var h1 : UInt32 = 0 var h2 : UInt32 = 0 var h3 : UInt32 = 0 var h4 : UInt32 = 0 var h5 : UInt32 = 0 var h6 : UInt32 = 0 var h7 : UInt32 = 0 var k : [UInt32] = [ 0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5, 0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174, 0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc, 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da, 0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, 0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967, 0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13, 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85, 0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3, 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070, 0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3, 0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2] init() { super.init(64) reset() } func reset() { // Set the initial values. h0 = 0x6a09e667 h1 = 0xbb67ae85 h2 = 0x3c6ef372 h3 = 0xa54ff53a h4 = 0x510e527f h5 = 0x9b05688c h6 = 0x1f83d9ab h7 = 0x5be0cd19 messageLength = 0 dataLength = 0 } override func fillBlock() { // Append a 1 to the message. data[dataLength] = UInt8(0x80) dataLength += 1 var new_len = messageLength + 1 while ((new_len % 64) != 56) { new_len += 1 } for _ in 0..> ((7-i)*8)) & 0xFF data[dataLength] = UInt8(val) dataLength += 1 } } override func hash() { assert(dataLength == blocksize, "Invalid block size") // Init the "W" buffer. var w = [UInt32](repeating: 0, count: 64) // Convert the Byte array to UInt32 array. var word : UInt32 = 0 for i in 0..<64 { word = word << 8 word = word &+ UInt32(data[i]) if i%4 == 3 { w[i/4] = word; word = 0 } } // Init the rest of the "W" buffer. for i in 16..<64 { let s0 = ror(w[i-15], 7) ^ ror(w[i-15], 18) ^ (w[i-15] >> 3) let s1 = ror(w[i-2], 17) ^ ror(w[i-2], 19) ^ (w[i-2] >> 10) w[i] = w[i-16] &+ s0 &+ w[i-7] &+ s1 } dataLength = 0 var a = h0 var b = h1 var c = h2 var d = h3 var e = h4 var f = h5 var g = h6 var h = h7 for i in 0..<64 { let S1 = ror(e, 6) ^ ror(e, 11) ^ ror(e, 25) let ch = (e & f) ^ ((~e) & g) let temp1 = h &+ S1 &+ ch &+ k[i] &+ w[i] let S0 = ror(a, 2) ^ ror(a, 13) ^ ror(a, 22) let maj = (a & b) ^ (a & c) ^ (b & c) let temp2 = S0 &+ maj h = g g = f f = e e = d &+ temp1 d = c c = b b = a a = temp1 &+ temp2 } h0 = h0 &+ a h1 = h1 &+ b h2 = h2 &+ c h3 = h3 &+ d h4 = h4 &+ e h5 = h5 &+ f h6 = h6 &+ g h7 = h7 &+ h } override func hashState() -> String { var Res : String = "" for state in [h0, h1, h2, h3, h4, h5, h6, h7] { Res += toHex(state) } return Res } } func == (lhs: [UInt8], rhs: [UInt8]) -> Bool { if lhs.count != rhs.count { return false } for idx in 0..