How to resolve the algorithm MD5/Implementation step by step in the Swift programming language
How to resolve the algorithm MD5/Implementation step by step in the Swift programming language
Table of Contents
Problem Statement
The purpose of this task to code and validate an implementation of the MD5 Message Digest Algorithm by coding the algorithm directly (not using a call to a built-in or external hashing library). For details of the algorithm refer to MD5 on Wikipedia or the MD5 definition in IETF RFC (1321).
The solutions shown here will provide practical illustrations of bit manipulation, unsigned integers, working with little-endian data. Additionally, the task requires an attention to details such as boundary conditions since being out by even 1 bit will produce dramatically different results. Subtle implementation bugs can result in some hashes being correct while others are wrong. Not only is it critical to get the individual sub functions working correctly, even small errors in padding, endianness, or data layout will result in failure. In addition, intermediate outputs to aid in developing an implementation can be found here. The MD5 Message-Digest Algorithm was developed by RSA Data Security, Inc. in 1991.
Let's start with the solution:
Step by Step solution about How to resolve the algorithm MD5/Implementation step by step in the Swift programming language
Source code in the swift programming language
import Foundation
public class MD5 {
/** specifies the per-round shift amounts */
private let s: [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]
/** binary integer part of the sines of integers (Radians) */
private let K: [UInt32] = (0 ..< 64).map { UInt32(0x100000000 * abs(sin(Double($0 + 1)))) }
let a0: UInt32 = 0x67452301
let b0: UInt32 = 0xefcdab89
let c0: UInt32 = 0x98badcfe
let d0: UInt32 = 0x10325476
private var message: NSData
//MARK: Public
public init(_ message: NSData) {
self.message = message
}
public func calculate() -> NSData? {
var tmpMessage: NSMutableData = NSMutableData(data: message)
let wordSize = sizeof(UInt32)
var aa = a0
var bb = b0
var cc = c0
var dd = d0
// Step 1. Append Padding Bits
tmpMessage.appendBytes([0x80]) // append one bit (Byte with one bit) to message
// append "0" bit until message length in bits ≡ 448 (mod 512)
while tmpMessage.length % 64 != 56 {
tmpMessage.appendBytes([0x00])
}
// Step 2. Append Length a 64-bit representation of lengthInBits
var lengthInBits = (message.length * 8)
var lengthBytes = lengthInBits.bytes(64 / 8)
tmpMessage.appendBytes(reverse(lengthBytes));
// Process the message in successive 512-bit chunks:
let chunkSizeBytes = 512 / 8
var leftMessageBytes = tmpMessage.length
for var i = 0; i < tmpMessage.length; i = i + chunkSizeBytes, leftMessageBytes -= chunkSizeBytes {
let chunk = tmpMessage.subdataWithRange(NSRange(location: i, length: min(chunkSizeBytes,leftMessageBytes)))
// break chunk into sixteen 32-bit words M[j], 0 ≤ j ≤ 15
// println("wordSize \(wordSize)");
var M:[UInt32] = [UInt32](count: 16, repeatedValue: 0)
for x in 0..<M.count {
var range = NSRange(location:x * wordSize, length: wordSize)
chunk.getBytes(&M[x], range:range);
}
// Initialize hash value for this chunk:
var A:UInt32 = a0
var B:UInt32 = b0
var C:UInt32 = c0
var D:UInt32 = d0
var dTemp:UInt32 = 0
// Main loop
for j in 0...63 {
var g = 0
var F:UInt32 = 0
switch (j) {
case 0...15:
F = (B & C) | ((~B) & D)
g = j
break
case 16...31:
F = (D & B) | (~D & C)
g = (5 * j + 1) % 16
break
case 32...47:
F = B ^ C ^ D
g = (3 * j + 5) % 16
break
case 48...63:
F = C ^ (B | (~D))
g = (7 * j) % 16
break
default:
break
}
dTemp = D
D = C
C = B
B = B &+ rotateLeft((A &+ F &+ K[j] &+ M[g]), s[j])
A = dTemp
}
aa = aa &+ A
bb = bb &+ B
cc = cc &+ C
dd = dd &+ D
}
var buf: NSMutableData = NSMutableData();
buf.appendBytes(&aa, length: wordSize)
buf.appendBytes(&bb, length: wordSize)
buf.appendBytes(&cc, length: wordSize)
buf.appendBytes(&dd, length: wordSize)
return buf.copy() as? NSData;
}
//MARK: Class
class func calculate(message: NSData) -> NSData?
{
return MD5(message).calculate();
}
//MARK: Private
private func rotateLeft(x:UInt32, _ n:UInt32) -> UInt32 {
return (x &<< n) | (x &>> (32 - n))
}
}
import Foundation
let shift : [UInt32] = [7, 12, 17, 22, 5, 9, 14, 20, 4, 11, 16, 23, 6, 10, 15, 21]
let table: [UInt32] = (0 ..< 64).map { UInt32(0x100000000 * abs(sin(Double($0 + 1)))) }
func md5(var message: [UInt8]) -> [UInt8] {
var messageLenBits = UInt64(message.count) * 8
message.append(0x80)
while message.count % 64 != 56 {
message.append(0)
}
var lengthBytes = [UInt8](count: 8, repeatedValue: 0)
UnsafeMutablePointer<UInt64>(lengthBytes).memory = messageLenBits.littleEndian
message += lengthBytes
var a : UInt32 = 0x67452301
var b : UInt32 = 0xEFCDAB89
var c : UInt32 = 0x98BADCFE
var d : UInt32 = 0x10325476
for chunkOffset in stride(from: 0, to: message.count, by: 64) {
let chunk = UnsafePointer<UInt32>(UnsafePointer<UInt8>(message) + chunkOffset)
let originalA = a
let originalB = b
let originalC = c
let originalD = d
for j in 0 ..< 64 {
var f : UInt32 = 0
var bufferIndex = j
let round = j >> 4
switch round {
case 0:
f = (b & c) | (~b & d)
case 1:
f = (b & d) | (c & ~d)
bufferIndex = (bufferIndex*5 + 1) & 0x0F
case 2:
f = b ^ c ^ d
bufferIndex = (bufferIndex*3 + 5) & 0x0F
case 3:
f = c ^ (b | ~d)
bufferIndex = (bufferIndex * 7) & 0x0F
default:
assert(false)
}
let sa = shift[(round<<2)|(j&3)]
let tmp = a &+ f &+ UInt32(littleEndian: chunk[bufferIndex]) &+ table[j]
a = d
d = c
c = b
b = b &+ (tmp << sa | tmp >> (32-sa))
}
a = a &+ originalA
b = b &+ originalB
c = c &+ originalC
d = d &+ originalD
}
var result = [UInt8](count: 16, repeatedValue: 0)
for (i, n) in enumerate([a, b, c, d]) {
UnsafeMutablePointer<UInt32>(result)[i] = n.littleEndian
}
return result
}
func toHexString(bytes: [UInt8]) -> String {
return "".join(bytes.map { String(format:"%02x", $0) })
}
for (hashCode, string) in [
("d41d8cd98f00b204e9800998ecf8427e", ""),
("0cc175b9c0f1b6a831c399e269772661", "a"),
("900150983cd24fb0d6963f7d28e17f72", "abc"),
("f96b697d7cb7938d525a2f31aaf161d0", "message digest"),
("c3fcd3d76192e4007dfb496cca67e13b", "abcdefghijklmnopqrstuvwxyz"),
("d174ab98d277d9f5a5611c2c9f419d9f",
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"),
("57edf4a22be3c955ac49da2e2107b67a", "12345678901234567890" +
"123456789012345678901234567890123456789012345678901234567890")] {
println(hashCode)
println(toHexString(md5(Array(string.utf8))))
println()
}
You may also check:How to resolve the algorithm Pseudo-random numbers/Splitmix64 step by step in the Jasmin programming language
You may also check:How to resolve the algorithm Chinese zodiac step by step in the Quackery programming language
You may also check:How to resolve the algorithm Terminal control/Clear the screen step by step in the Delphi programming language
You may also check:How to resolve the algorithm Perlin noise step by step in the REXX programming language
You may also check:How to resolve the algorithm Topswops step by step in the Ruby programming language