Damian Kołakowski 9 лет назад
Родитель
Сommit
75994246a8

+ 15 - 0
Sources/TLS/HEX.swift

@@ -0,0 +1,15 @@
+//
+//  HEX.swift
+//  Swifter
+//
+//  Copyright © 2016 Damian Kołakowski. All rights reserved.
+//
+
+import Foundation
+
+extension Sequence where Iterator.Element == UInt8 {
+    
+    public func hex() -> String {
+        return self.reduce("") { $0 + String(format: "%02x", $1) }
+    }
+}

+ 12 - 2
Sources/TLS/HMAC.swift

@@ -18,13 +18,23 @@ public struct HMAC {
     //
     
     public static func sha1(_ key: [UInt8], _ message: [UInt8]) -> [UInt8] {
-        return generate(key, message, (64, { block in
+        return generate(key, message, (blockSize: 64, { block in
             return SHA1.hash(block)
         }))
     }
     
     public static func sha1(_ key: [UInt8], _ message: [UInt8]) -> String {
-        return sha1(key, message).reduce("") { $0 + String(format: "%02x", $1) }
+        return sha1(key, message).hex()
+    }
+    
+    public static func md5(_ key: [UInt8], _ message: [UInt8]) -> [UInt8] {
+        return generate(key, message, (blockSize: 64, { block in
+            return MD5.hash(block)
+        }))
+    }
+    
+    public static func md5(_ key: [UInt8], _ message: [UInt8]) -> String {
+        return md5(key, message).hex()
     }
     
     public static func generate(_ key: [UInt8], _ message: [UInt8], _ setup: (blockSize: Int, hash: (([UInt8]) -> [UInt8]))) -> [UInt8] {

+ 87 - 9
Sources/TLS/MD5.swift

@@ -17,23 +17,90 @@ public struct MD5 {
     // 
     // Alghorithm from: https://en.wikipedia.org/wiki/MD5
     //
-    // TODO: 
-    //   - finish impl.
-    //
     
     public static func hash(_ input: [UInt8]) -> [UInt8] {
         
-        // Alghorithm from: https://en.wikipedia.org/wiki/MD5
+        var a0 = UInt32(littleEndian: 0x67452301)
+        var b0 = UInt32(littleEndian: 0xefcdab89)
+        var c0 = UInt32(littleEndian: 0x98badcfe)
+        var d0 = UInt32(littleEndian: 0x10325476)
+        
+        var message = input + [0x80] + [UInt8](repeating: 0, count: 64 - ((input.count+9) % 64))
+
+        var originalLengthInBits = UInt64(input.count * 8).littleEndian
+        
+        withUnsafePointer(&originalLengthInBits) {
+            message.append(contentsOf: Array(UnsafeBufferPointer<UInt8>(start: UnsafePointer($0), count: 8)))
+        }
         
-        var a0: UInt32 = 0x67452301
-        var b0: UInt32 = 0xefcdab89
-        var c0: UInt32 = 0x98badcfe
-        var d0: UInt32 = 0x10325476
+        for chunkStart in 0..<message.count/64 {
+            var words = [UInt32]()
+            let chunk = message[chunkStart*64..<chunkStart*64+64]
+            
+            for i in 0...15 {
+                words.append(chunk.withUnsafeBufferPointer {
+                    UnsafePointer<UInt32>($0.baseAddress! + (i*4)).pointee
+                })
+            }
+            
+            var A = a0, B = b0, C = c0, D = d0
+            
+            for i in 0...63 {
+                var F = UInt32(0), g = UInt32(0)
+                switch i {
+                    case 0...15:
+                        F = (B & C) | ((~B) & D)
+                        g = UInt32(i)
+                    case 16...31:
+                        F = (D & B) | ((~D) & C)
+                        g = UInt32(5*i + 1) % UInt32(16)
+                    case 32...47:
+                        F = B ^ C ^ D
+                        g = UInt32((3*i + 5)) % UInt32(16)
+                    case 48...63:
+                        F = C ^ (B | (~D))
+                        g = UInt32(7*i) % UInt32(16)
+                    default: break
+                }
+                let dTemp = D
+                D = C
+                C = B
+                B = B &+ leftrotate((A &+ F &+ K[i] &+ words[Int(g)]), s[i])
+                A = dTemp
+            }
+            
+            a0 = a0 &+ A
+            b0 = b0 &+ B
+            c0 = c0 &+ C
+            d0 = d0 &+ D
+        }
         
+        var digest = [UInt8]()
         
-        return []
+        a0 = a0.littleEndian
+        b0 = b0.littleEndian
+        c0 = c0.littleEndian
+        d0 = d0.littleEndian
+        
+        withUnsafePointer(&a0) {
+            digest.append(contentsOf: Array(UnsafeBufferPointer<UInt8>(start: UnsafePointer($0), count: 4)))
+        }
+        withUnsafePointer(&b0) {
+            digest.append(contentsOf: Array(UnsafeBufferPointer<UInt8>(start: UnsafePointer($0), count: 4)))
+        }
+        withUnsafePointer(&c0) {
+            digest.append(contentsOf: Array(UnsafeBufferPointer<UInt8>(start: UnsafePointer($0), count: 4)))
+        }
+        withUnsafePointer(&d0) {
+            digest.append(contentsOf: Array(UnsafeBufferPointer<UInt8>(start: UnsafePointer($0), count: 4)))
+        }
+        
+        return digest
     }
     
+    private static func leftrotate(_ v: UInt32, _ n: UInt32) -> UInt32 {
+        return ((v << n) & 0xFFFFFFFF) | (v >> (32 - n))
+    }
     
     private static var s: [UInt32] = [
         7, 12, 17, 22,  7, 12, 17, 22,  7, 12, 17, 22,  7, 12, 17, 22,
@@ -61,3 +128,14 @@ public struct MD5 {
         0xf7537e82, 0xbd3af235, 0x2ad7d2bb, 0xeb86d391
     ]
 }
+
+extension String {
+    
+    public func md5() -> String {
+        return self.md5().hex()
+    }
+    
+    public func md5() -> [UInt8] {
+        return MD5.hash([UInt8](self.utf8))
+    }
+}

+ 5 - 5
Sources/TLS/SHA1.swift

@@ -43,10 +43,10 @@ public struct SHA1 {
         // append ml, in a 64-bit big-endian integer. Thus, the total length is a multiple of 512 bits.
         
         var mlBigEndian = ml.bigEndian
-        let bytePtr = withUnsafePointer(&mlBigEndian) { UnsafeBufferPointer<UInt8>(start: UnsafePointer($0), count: sizeofValue(mlBigEndian)) }
-        
-        message.append(contentsOf: Array(bytePtr))
-        
+        withUnsafePointer(&mlBigEndian) {
+            message.append(contentsOf: Array(UnsafeBufferPointer<UInt8>(start: UnsafePointer($0), count: 8)))
+        }
+    
         // Process the message in successive 512-bit chunks ( 64 bytes chunks ):
         
         for chunkStart in 0..<message.count/64 {
@@ -137,7 +137,7 @@ public struct SHA1 {
 extension String {
     
     public func sha1() -> String {
-        return self.sha1().reduce("") { $0 + String(format: "%02x", $1) }
+        return self.sha1().hex()
     }
     
     public func sha1() -> [UInt8] {

+ 8 - 0
XCode/Swifter.xcodeproj/project.pbxproj

@@ -10,6 +10,9 @@
 		7AE893EA1C05127900A29F63 /* SwifteriOS.h in Headers */ = {isa = PBXBuildFile; fileRef = 7AE893E91C05127900A29F63 /* SwifteriOS.h */; settings = {ATTRIBUTES = (Public, ); }; };
 		7AE893FE1C0512C400A29F63 /* SwifterMac.h in Headers */ = {isa = PBXBuildFile; fileRef = 7AE893FD1C0512C400A29F63 /* SwifterMac.h */; settings = {ATTRIBUTES = (Public, ); }; };
 		7AE8940D1C05151100A29F63 /* Launch Screen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 7AE8940C1C05151100A29F63 /* Launch Screen.storyboard */; };
+		7C00AABE1D5D374700EDA547 /* HEX.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7C00AABD1D5D374700EDA547 /* HEX.swift */; };
+		7C00AABF1D5D374700EDA547 /* HEX.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7C00AABD1D5D374700EDA547 /* HEX.swift */; };
+		7C00AAC01D5D374700EDA547 /* HEX.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7C00AABD1D5D374700EDA547 /* HEX.swift */; };
 		7C13B57C1C7B069500556443 /* SwifterTestsSQLite.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7C13B57B1C7B069500556443 /* SwifterTestsSQLite.swift */; };
 		7C13B57D1C7B069500556443 /* SwifterTestsSQLite.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7C13B57B1C7B069500556443 /* SwifterTestsSQLite.swift */; };
 		7C3195FB1CC2C68F00DF5406 /* sqlite.h in Headers */ = {isa = PBXBuildFile; fileRef = 7C3195E31CC2C68F00DF5406 /* sqlite.h */; };
@@ -220,6 +223,7 @@
 		7AE893FD1C0512C400A29F63 /* SwifterMac.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SwifterMac.h; sourceTree = "<group>"; };
 		7AE893FF1C0512C400A29F63 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
 		7AE8940C1C05151100A29F63 /* Launch Screen.storyboard */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.storyboard; path = "Launch Screen.storyboard"; sourceTree = "<group>"; };
+		7C00AABD1D5D374700EDA547 /* HEX.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = HEX.swift; sourceTree = "<group>"; };
 		7C13B57B1C7B069500556443 /* SwifterTestsSQLite.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SwifterTestsSQLite.swift; sourceTree = "<group>"; };
 		7C2C85901D50D83D00B32145 /* JSON.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = JSON.swift; sourceTree = "<group>"; };
 		7C3195E31CC2C68F00DF5406 /* sqlite.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = sqlite.h; sourceTree = "<group>"; };
@@ -561,6 +565,7 @@
 				7CDF26E11D5CD64600666F69 /* RC4.swift */,
 				7CDF26E21D5CD64600666F69 /* RSA.swift */,
 				7CDF26E31D5CD64600666F69 /* SHA1.swift */,
+				7C00AABD1D5D374700EDA547 /* HEX.swift */,
 			);
 			path = TLS;
 			sourceTree = "<group>";
@@ -877,6 +882,7 @@
 				7C31962B1CC2C68F00DF5406 /* Socket.swift in Sources */,
 				7C3196191CC2C68F00DF5406 /* HttpResponse.swift in Sources */,
 				7CDF26E91D5CD64600666F69 /* BigNum.swift in Sources */,
+				7C00AABE1D5D374700EDA547 /* HEX.swift in Sources */,
 				7C5F790F1D56287000C514AA /* Socket+File.swift in Sources */,
 				7CDF26F91D5CD64600666F69 /* RSA.swift in Sources */,
 				7C3196131CC2C68F00DF5406 /* HttpParser.swift in Sources */,
@@ -914,6 +920,7 @@
 				7C31962C1CC2C68F00DF5406 /* Socket.swift in Sources */,
 				7C31961A1CC2C68F00DF5406 /* HttpResponse.swift in Sources */,
 				7CDF26EA1D5CD64600666F69 /* BigNum.swift in Sources */,
+				7C00AABF1D5D374700EDA547 /* HEX.swift in Sources */,
 				7C5F79101D56287000C514AA /* Socket+File.swift in Sources */,
 				7CDF26FA1D5CD64600666F69 /* RSA.swift in Sources */,
 				7C3196141CC2C68F00DF5406 /* HttpParser.swift in Sources */,
@@ -984,6 +991,7 @@
 				7C31962D1CC2C68F00DF5406 /* Socket.swift in Sources */,
 				7C31961B1CC2C68F00DF5406 /* HttpResponse.swift in Sources */,
 				7CDF26EB1D5CD64600666F69 /* BigNum.swift in Sources */,
+				7C00AAC01D5D374700EDA547 /* HEX.swift in Sources */,
 				7C5F79111D56287000C514AA /* Socket+File.swift in Sources */,
 				7CDF26FB1D5CD64600666F69 /* RSA.swift in Sources */,
 				7C3196151CC2C68F00DF5406 /* HttpParser.swift in Sources */,

+ 0 - 3
XCode/SwifterSampleOSX/main.swift

@@ -7,9 +7,6 @@
 import Foundation
 import Swifter
 
-let output: String = HMAC.sha1([UInt8]("key".utf8), [UInt8]("The quick brown fox jumps over the lazy dog".utf8))
-
-
 do {
     let server: HttpServer = demoServer(try File.currentWorkingDirectory())
     server["/testAfterBaseRoute"] = { request in

+ 7 - 0
XCode/SwifterTestsCommon/SwifterTestsHMAC.swift

@@ -16,4 +16,11 @@ class SwifterTestsHMAC: XCTestCase {
         XCTAssertEqual(HMAC.sha1([UInt8]("key".utf8), [UInt8]("The quick brown fox jumps over the lazy dog".utf8)),
                        "de7c9b85b8b78aa6bc8a7a36f70a90701c9db4d9")
     }
+    
+    func testMD5() {
+        
+        XCTAssertEqual(HMAC.md5([UInt8]("".utf8), [UInt8]("".utf8)), "74e6f7298a9c2d168935f58c001bad88")
+        XCTAssertEqual(HMAC.md5([UInt8]("key".utf8), [UInt8]("The quick brown fox jumps over the lazy dog".utf8)),
+                       "80070713463e7749b90c2dc24911e275")
+    }
 }

+ 21 - 0
XCode/SwifterTestsCommon/SwifterTestsStringExtensions.swift

@@ -38,6 +38,27 @@ class SwifterTestsStringExtensions: XCTestCase {
             "a377b0c42d685fdc396e29a9eda7101d900947ca")
     }
     
+    func testMD5() {
+        
+        // Values from: https://tools.ietf.org/html/rfc1321
+        
+        XCTAssertEqual("".md5(), "d41d8cd98f00b204e9800998ecf8427e")
+        
+        XCTAssertEqual("The quick brown fox jumps over the lazy dog.".md5(), "e4d909c290d0fb1ca068ffaddf22cbd0")
+        
+        XCTAssertEqual("a".md5(), "0cc175b9c0f1b6a831c399e269772661")
+        
+        XCTAssertEqual("abc".md5(), "900150983cd24fb0d6963f7d28e17f72")
+        
+        XCTAssertEqual("message digest".md5(), "f96b697d7cb7938d525a2f31aaf161d0")
+        
+        XCTAssertEqual("abcdefghijklmnopqrstuvwxyz".md5(), "c3fcd3d76192e4007dfb496cca67e13b")
+        
+        XCTAssertEqual("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789".md5(), "d174ab98d277d9f5a5611c2c9f419d9f")
+        
+        XCTAssertEqual("12345678901234567890123456789012345678901234567890123456789012345678901234567890".md5(), "57edf4a22be3c955ac49da2e2107b67a")
+    }
+    
     func testBASE64() {
         XCTAssertEqual(String.toBase64([UInt8]("".utf8)), "")