HaishinKit.swift/Sources/Util/MD5.swift

201 lines
6.4 KiB
Swift
Executable File

import Foundation
/**
Message Digest Algorithm 5
- seealso:
- https://ja.wikipedia.org/wiki/MD5
- https://www.ietf.org/rfc/rfc1321.txt
*/
final class MD5 {
static let a: UInt32 = 0x67452301
static let b: UInt32 = 0xefcdab89
static let c: UInt32 = 0x98badcfe
static let d: UInt32 = 0x10325476
static let S11: UInt32 = 7
static let S12: UInt32 = 12
static let S13: UInt32 = 17
static let S14: UInt32 = 22
static let S21: UInt32 = 5
static let S22: UInt32 = 9
static let S23: UInt32 = 14
static let S24: UInt32 = 20
static let S31: UInt32 = 4
static let S32: UInt32 = 11
static let S33: UInt32 = 16
static let S34: UInt32 = 23
static let S41: UInt32 = 6
static let S42: UInt32 = 10
static let S43: UInt32 = 15
static let S44: UInt32 = 21
struct Context {
var a: UInt32 = MD5.a
var b: UInt32 = MD5.b
var c: UInt32 = MD5.c
var d: UInt32 = MD5.d
mutating func FF(_ x: UInt32, _ s: UInt32, _ k: UInt32) {
let swap: UInt32 = d
let F: UInt32 = (b & c) | ((~b) & d)
d = c
c = b
b = b &+ rotateLeft(a &+ F &+ k &+ x, s)
a = swap
}
mutating func GG(_ x: UInt32, _ s: UInt32, _ k: UInt32) {
let swap: UInt32 = d
let G: UInt32 = (d & b) | (c & (~d))
d = c
c = b
b = b &+ rotateLeft(a &+ G &+ k &+ x, s)
a = swap
}
mutating func HH(_ x: UInt32, _ s: UInt32, _ k: UInt32) {
let swap: UInt32 = d
let H: UInt32 = b ^ c ^ d
d = c
c = b
b = b &+ rotateLeft(a &+ H &+ k &+ x, s)
a = swap
}
mutating func II(_ x: UInt32, _ s: UInt32, _ k: UInt32) {
let swap: UInt32 = d
let I: UInt32 = c ^ (b | (~d))
d = c
c = b
b = b &+ rotateLeft(a &+ I &+ k &+ x, s)
a = swap
}
func rotateLeft(_ x: UInt32, _ n: UInt32) -> UInt32 {
((x << n) & 0xFFFFFFFF) | (x >> (32 - n))
}
var data: Data {
a.data + b.data + c.data + d.data
}
}
static func base64(_ message: String) -> String {
calculate(message).base64EncodedString(options: .lineLength64Characters)
}
static func calculate(_ message: String) -> Data {
calculate(ByteArray().writeUTF8Bytes(message).data)
}
static func calculate(_ data: Data) -> Data {
var context = Context()
let count: Data = UInt64(data.count * 8).bigEndian.data
let message = ByteArray(data: data + [0x80])
message.length += 64 - (message.length % 64)
message[message.length - 8] = count[7]
message[message.length - 7] = count[6]
message[message.length - 6] = count[5]
message[message.length - 5] = count[4]
message[message.length - 4] = count[3]
message[message.length - 3] = count[2]
message[message.length - 2] = count[1]
message[message.length - 1] = count[0]
message.sequence(64) {
let x: [UInt32] = $0.toUInt32()
guard x.count == 16 else {
return
}
var ctx = Context()
ctx.a = context.a
ctx.b = context.b
ctx.c = context.c
ctx.d = context.d
/* Round 1 */
ctx.FF(x[ 0], S11, 0xd76aa478)
ctx.FF(x[ 1], S12, 0xe8c7b756)
ctx.FF(x[ 2], S13, 0x242070db)
ctx.FF(x[ 3], S14, 0xc1bdceee)
ctx.FF(x[ 4], S11, 0xf57c0faf)
ctx.FF(x[ 5], S12, 0x4787c62a)
ctx.FF(x[ 6], S13, 0xa8304613)
ctx.FF(x[ 7], S14, 0xfd469501)
ctx.FF(x[ 8], S11, 0x698098d8)
ctx.FF(x[ 9], S12, 0x8b44f7af)
ctx.FF(x[10], S13, 0xffff5bb1)
ctx.FF(x[11], S14, 0x895cd7be)
ctx.FF(x[12], S11, 0x6b901122)
ctx.FF(x[13], S12, 0xfd987193)
ctx.FF(x[14], S13, 0xa679438e)
ctx.FF(x[15], S14, 0x49b40821)
/* Round 2 */
ctx.GG(x[ 1], S21, 0xf61e2562)
ctx.GG(x[ 6], S22, 0xc040b340)
ctx.GG(x[11], S23, 0x265e5a51)
ctx.GG(x[ 0], S24, 0xe9b6c7aa)
ctx.GG(x[ 5], S21, 0xd62f105d)
ctx.GG(x[10], S22, 0x2441453)
ctx.GG(x[15], S23, 0xd8a1e681)
ctx.GG(x[ 4], S24, 0xe7d3fbc8)
ctx.GG(x[ 9], S21, 0x21e1cde6)
ctx.GG(x[14], S22, 0xc33707d6)
ctx.GG(x[ 3], S23, 0xf4d50d87)
ctx.GG(x[ 8], S24, 0x455a14ed)
ctx.GG(x[13], S21, 0xa9e3e905)
ctx.GG(x[ 2], S22, 0xfcefa3f8)
ctx.GG(x[ 7], S23, 0x676f02d9)
ctx.GG(x[12], S24, 0x8d2a4c8a)
/* Round 3 */
ctx.HH(x[ 5], S31, 0xfffa3942)
ctx.HH(x[ 8], S32, 0x8771f681)
ctx.HH(x[11], S33, 0x6d9d6122)
ctx.HH(x[14], S34, 0xfde5380c)
ctx.HH(x[ 1], S31, 0xa4beea44)
ctx.HH(x[ 4], S32, 0x4bdecfa9)
ctx.HH(x[ 7], S33, 0xf6bb4b60)
ctx.HH(x[10], S34, 0xbebfbc70)
ctx.HH(x[13], S31, 0x289b7ec6)
ctx.HH(x[ 0], S32, 0xeaa127fa)
ctx.HH(x[ 3], S33, 0xd4ef3085)
ctx.HH(x[ 6], S34, 0x4881d05)
ctx.HH(x[ 9], S31, 0xd9d4d039)
ctx.HH(x[12], S32, 0xe6db99e5)
ctx.HH(x[15], S33, 0x1fa27cf8)
ctx.HH(x[ 2], S34, 0xc4ac5665)
/* Round 4 */
ctx.II(x[ 0], S41, 0xf4292244)
ctx.II(x[ 7], S42, 0x432aff97)
ctx.II(x[14], S43, 0xab9423a7)
ctx.II(x[ 5], S44, 0xfc93a039)
ctx.II(x[12], S41, 0x655b59c3)
ctx.II(x[ 3], S42, 0x8f0ccc92)
ctx.II(x[10], S43, 0xffeff47d)
ctx.II(x[ 1], S44, 0x85845dd1)
ctx.II(x[ 8], S41, 0x6fa87e4f)
ctx.II(x[15], S42, 0xfe2ce6e0)
ctx.II(x[ 6], S43, 0xa3014314)
ctx.II(x[13], S44, 0x4e0811a1)
ctx.II(x[ 4], S41, 0xf7537e82)
ctx.II(x[11], S42, 0xbd3af235)
ctx.II(x[ 2], S43, 0x2ad7d2bb)
ctx.II(x[ 9], S44, 0xeb86d391)
context.a = context.a &+ ctx.a
context.b = context.b &+ ctx.b
context.c = context.c &+ ctx.c
context.d = context.d &+ ctx.d
}
return context.data
}
}