Browse Source

Refactor enum Authenticator -> protocol Authenticator

Marcin Krzyżanowski 9 years ago
parent
commit
4a2cb5272c

+ 8 - 11
CryptoSwiftTests/Access.swift

@@ -11,7 +11,7 @@ import CryptoSwift
 
 class Access: XCTestCase {
     let cipher = try! AES(key: "secret0key000000", iv: "0123456789012345")
-    let authenticator = Authenticator.HMAC(key: Array<UInt8>(hex: "b1b2b3b3b3b3b3b3b1b2b3b3b3b3b3b3"), variant: .sha1)
+    let authenticator = HMAC(key: Array<UInt8>(hex: "b1b2b3b3b3b3b3b3b1b2b3b3b3b3b3b3"), variant: .sha1)
 
     func testChecksum() {
         let _ = Checksum.crc32([1,2,3])
@@ -149,16 +149,13 @@ class Access: XCTestCase {
         }
     }
 
-    func testAuthenticator() {
-        // TODO
-    }
-
-    func testHMAC() {
-        // TODO
-    }
-
-    func testPoly1305() {
-        // TODO
+    func testAuthenticators() {
+        do {
+            let _ = try HMAC(key: Array<UInt8>(hex: "b1b2b3b3b3b3b3b3b1b2b3b3b3b3b3b3"), variant: .sha1).authenticate([1,2,3])
+            let _ = try Poly1305(key: [1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,7,8,9,0,1,2]).authenticate([1,2,3])
+        } catch {
+            XCTFail(error.localizedDescription)
+        }
     }
 
     func testAES() {

+ 5 - 5
CryptoSwiftTests/HMACTests.swift

@@ -24,7 +24,7 @@ final class HMACTests: XCTestCase {
         let msg:Array<UInt8> = []
         let expectedMac:Array<UInt8> = [0x74,0xe6,0xf7,0x29,0x8a,0x9c,0x2d,0x16,0x89,0x35,0xf5,0x8c,0x00,0x1b,0xad,0x88]
         
-        let hmac = try! Authenticator.HMAC(key: key, variant: .md5).authenticate(msg)
+        let hmac = try! HMAC(key: key, variant: .md5).authenticate(msg)
         XCTAssertEqual(hmac, expectedMac, "Invalid authentication result")
     }
     
@@ -33,7 +33,7 @@ final class HMACTests: XCTestCase {
         let msg:Array<UInt8> = []
         let expectedMac:Array<UInt8> = [0xfb,0xdb,0x1d,0x1b,0x18,0xaa,0x6c,0x08,0x32,0x4b,0x7d,0x64,0xb7,0x1f,0xb7,0x63,0x70,0x69,0x0e,0x1d]
         
-        let hmac = try! Authenticator.HMAC(key: key, variant: .sha1).authenticate(msg)
+        let hmac = try! HMAC(key: key, variant: .sha1).authenticate(msg)
         XCTAssertEqual(hmac, expectedMac, "Invalid authentication result")
     }
 
@@ -42,7 +42,7 @@ final class HMACTests: XCTestCase {
         let msg:Array<UInt8> = []
         let expectedMac:Array<UInt8> = [0xb6,0x13,0x67,0x9a,0x08,0x14,0xd9,0xec,0x77,0x2f,0x95,0xd7,0x78,0xc3,0x5f,0xc5,0xff,0x16,0x97,0xc4,0x93,0x71,0x56,0x53,0xc6,0xc7,0x12,0x14,0x42,0x92,0xc5,0xad]
         
-        let hmac = try! Authenticator.HMAC(key: key, variant: .sha256).authenticate(msg)
+        let hmac = try! HMAC(key: key, variant: .sha256).authenticate(msg)
         XCTAssertEqual(hmac, expectedMac, "Invalid authentication result")
     }
 
@@ -51,7 +51,7 @@ final class HMACTests: XCTestCase {
         let msg:Array<UInt8> = []
         let expectedMac:Array<UInt8> = [0x6c, 0x1f, 0x2e, 0xe9, 0x38, 0xfa, 0xd2, 0xe2, 0x4b, 0xd9, 0x12, 0x98, 0x47, 0x43, 0x82, 0xca, 0x21, 0x8c, 0x75, 0xdb, 0x3d, 0x83, 0xe1, 0x14, 0xb3, 0xd4, 0x36, 0x77, 0x76, 0xd1, 0x4d, 0x35, 0x51, 0x28, 0x9e, 0x75, 0xe8, 0x20, 0x9c, 0xd4, 0xb7, 0x92, 0x30, 0x28, 0x40, 0x23, 0x4a, 0xdc]
 
-        let hmac = try! Authenticator.HMAC(key: key, variant: .sha384).authenticate(msg)
+        let hmac = try! HMAC(key: key, variant: .sha384).authenticate(msg)
         XCTAssertEqual(hmac, expectedMac, "Invalid authentication result")
     }
 
@@ -60,7 +60,7 @@ final class HMACTests: XCTestCase {
         let msg:Array<UInt8> = []
         let expectedMac:Array<UInt8> = [0xb9, 0x36, 0xce, 0xe8, 0x6c, 0x9f, 0x87, 0xaa, 0x5d, 0x3c, 0x6f, 0x2e, 0x84, 0xcb, 0x5a, 0x42, 0x39, 0xa5, 0xfe, 0x50, 0x48, 0x0a, 0x6e, 0xc6, 0x6b, 0x70, 0xab, 0x5b, 0x1f, 0x4a, 0xc6, 0x73, 0x0c, 0x6c, 0x51, 0x54, 0x21, 0xb3, 0x27, 0xec, 0x1d, 0x69, 0x40, 0x2e, 0x53, 0xdf, 0xb4, 0x9a, 0xd7, 0x38, 0x1e, 0xb0, 0x67, 0xb3, 0x38, 0xfd, 0x7b, 0x0c, 0xb2, 0x22, 0x47, 0x22, 0x5d, 0x47]
 
-        let hmac = try! Authenticator.HMAC(key: key, variant: .sha512).authenticate(msg)
+        let hmac = try! HMAC(key: key, variant: .sha512).authenticate(msg)
         XCTAssertEqual(hmac, expectedMac, "Invalid authentication result")
     }
 }

+ 2 - 2
CryptoSwiftTests/Poly1305Tests.swift

@@ -24,12 +24,12 @@ final class Poly1305Tests: XCTestCase {
         let msg:Array<UInt8> = [0x79,0x7a,0x7b,0x7c,0x7d,0x7e,0x7f,0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8a,0x8b,0x8c,0x8d,0x8e,0x8f,0x90,0x91,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x9a,0x9b,0x9c,0x9d,0x9e,0x9f,0xa0,0xa1,0xa2,0xa3,0xa4,0xa5,0xa6,0xa7,0xa8,0xa9,0xaa,0xab,0xac,0xad,0xae,0xaf,0xb0,0xb1,0xb2,0xb3,0xb4,0xb5,0xb6,0xb7,0xb8,0xb9,0xba,0xbb,0xbc,0xbd,0xbe,0xbf,0xc0,0xc1]
         let expectedMac:Array<UInt8> = [0xdd,0xb9,0xda,0x7d,0xdd,0x5e,0x52,0x79,0x27,0x30,0xed,0x5c,0xda,0x5f,0x90,0xa4]
         
-        let mac = try! Authenticator.Poly1305(key: key).authenticate(msg)
+        let mac = try! Poly1305(key: key).authenticate(msg)
         XCTAssertEqual(mac, expectedMac, "Invalid authentication result")
         
         // extensions
         let msgData = Data(bytes: msg)
-        let mac2 = try! msgData.authenticate(with: Authenticator.Poly1305(key: key))
+        let mac2 = try! msgData.authenticate(with: Poly1305(key: key))
         XCTAssertEqual(mac2, Data(bytes: expectedMac), "Invalid authentication result")
     }
 }

+ 3 - 36
Sources/CryptoSwift/Authenticator.swift

@@ -6,40 +6,7 @@
 //  Copyright (c) 2014 Marcin Krzyzanowski. All rights reserved.
 //
 
-/**
-*  Message Authentication
-*/
-public enum Authenticator {
-    
-    public enum Error: Swift.Error {
-        case authenticateError
-    }
-    
-    /**
-    Poly1305
-    
-    - parameter key: 256-bit key
-    */
-    case Poly1305(key: Array<UInt8>)
-    case HMAC(key: Array<UInt8>, variant: HMAC.Variant)
-    
-    /**
-    Generates an authenticator for message using a one-time key and returns the 16-byte result
-    
-    - returns: 16-byte message authentication code
-    */
-    public func authenticate(_ bytes: Array<UInt8>) throws -> Array<UInt8> {
-        switch (self) {
-        case .Poly1305(let key):
-            guard let auth = CryptoSwift.Poly1305(key: key)?.authenticate(bytes) else {
-                throw Error.authenticateError
-            }
-            return auth
-        case .HMAC(let key, let variant):
-            guard let auth = CryptoSwift.HMAC(key: key, variant: variant)?.authenticate(bytes) else {
-                throw Error.authenticateError
-            }
-            return auth
-        }
-    }
+public protocol Authenticator {
+    /// Generates an authenticator for message using a one-time key and returns the 16-byte result
+    func authenticate(_ bytes: Array<UInt8>) throws -> Array<UInt8>
 }

+ 1 - 1
Sources/CryptoSwift/CSArrayType+Extensions.swift

@@ -63,7 +63,7 @@ public extension CSArrayType where Iterator.Element == UInt8 {
         return try cipher.decrypt(cs_arrayValue())
     }
     
-    public func authenticate(with authenticator: Authenticator) throws -> [Iterator.Element] {
+    public func authenticate<A: Authenticator>(with authenticator: A) throws -> [Iterator.Element] {
         return try authenticator.authenticate(cs_arrayValue())
     }
 }

+ 15 - 7
Sources/CryptoSwift/HMAC.swift

@@ -6,7 +6,11 @@
 //  Copyright (c) 2015 Marcin Krzyzanowski. All rights reserved.
 //
 
-final public class HMAC {
+final public class HMAC: Authenticator {
+
+    public enum Error: Swift.Error {
+        case authenticateError
+    }
     
     public enum Variant {
         case sha1, sha256, sha384, sha512, md5
@@ -54,7 +58,7 @@ final public class HMAC {
     var key:Array<UInt8>
     let variant:Variant
 
-    public init? (key: Array<UInt8>, variant:HMAC.Variant = .md5) {
+    public init (key: Array<UInt8>, variant:HMAC.Variant = .md5) {
         self.variant = variant
         self.key = key
 
@@ -67,7 +71,9 @@ final public class HMAC {
         self.key = ZeroPadding().add(to: key, blockSize: variant.blockSize())
     }
 
-    public func authenticate(_ bytes:Array<UInt8>) -> Array<UInt8>? {
+    //MARK: Authenticator
+
+    public func authenticate(_ bytes:Array<UInt8>) throws -> Array<UInt8> {
         var opad = Array<UInt8>(repeating: 0x5c, count: variant.blockSize())
         for idx in key.indices {
             opad[idx] = key[idx] ^ opad[idx]
@@ -77,10 +83,12 @@ final public class HMAC {
             ipad[idx] = key[idx] ^ ipad[idx]
         }
 
-        var finalHash:Array<UInt8>? = nil;
-        if let ipadAndMessageHash = variant.calculateHash(ipad + bytes) {
-            finalHash = variant.calculateHash(opad + ipadAndMessageHash);
+        guard let ipadAndMessageHash = variant.calculateHash(ipad + bytes),
+              let result = variant.calculateHash(opad + ipadAndMessageHash) else
+        {
+            throw Error.authenticateError
         }
-        return finalHash
+
+        return result
     }
 }

+ 18 - 12
Sources/CryptoSwift/PKCS5/PBKDF2.swift

@@ -37,8 +37,10 @@ public extension PKCS5 {
         ///   - keyLength: intended length of derived key
         public init(password: Array<UInt8>, salt: Array<UInt8>, iterations: Int = 4096 /* c */, keyLength: Int? = nil /* dkLen */, variant: HMAC.Variant = .sha256) throws {
             precondition(iterations > 0)
+
+            let prf = HMAC(key: password, variant: variant)
             
-            guard let prf = HMAC(key: password, variant: variant), iterations > 0 && !password.isEmpty && !salt.isEmpty else {
+            guard iterations > 0 && !password.isEmpty && !salt.isEmpty else {
                 throw Error.invalidInput
             }
 
@@ -82,22 +84,26 @@ fileprivate extension PKCS5.PBKDF2 {
     // F (P, S, c, i) = U_1 \xor U_2 \xor ... \xor U_c
     // U_1 = PRF (P, S || INT (i))
     func calculateBlock(_ salt: Array<UInt8>, blockNum: UInt) -> Array<UInt8>? {
-        guard let u1 = prf.authenticate(salt + INT(blockNum)) else {
+        guard let u1 = try? prf.authenticate(salt + INT(blockNum)) else {
             return nil
         }
 
-        var u = u1
-        var ret = u
-        if self.iterations > 1 {
-            // U_2 = PRF (P, U_1) ,
-            // U_c = PRF (P, U_{c-1}) .
-            for _ in 2...self.iterations {
-                u = prf.authenticate(u)!
-                for x in 0..<ret.count {
-                    ret[x] = ret[x] ^ u[x]
+        do {
+            var u = u1
+            var ret = u
+            if self.iterations > 1 {
+                // U_2 = PRF (P, U_1) ,
+                // U_c = PRF (P, U_{c-1}) .
+                for _ in 2...self.iterations {
+                    u = try prf.authenticate(u)
+                    for x in 0..<ret.count {
+                        ret[x] = ret[x] ^ u[x]
+                    }
                 }
             }
+            return ret
+        } catch {
+            return nil
         }
-        return ret
     }
 }

+ 35 - 28
Sources/CryptoSwift/Poly1305.swift

@@ -10,7 +10,12 @@
 //  Poly1305 takes a 32-byte, one-time key and a message and produces a 16-byte tag that authenticates the
 //  message such that an attacker has a negligible chance of producing a valid tag for an inauthentic message.
 
-final public class Poly1305 {
+final public class Poly1305: Authenticator {
+
+    public enum Error: Swift.Error {
+        case authenticateError
+    }
+
     let blockSize = 16
     private var ctx:Context?
     
@@ -23,12 +28,9 @@ final public class Poly1305 {
         var final:UInt8   = 0
         var leftover:Int = 0
         
-        init?(_ key: Array<UInt8>) {
-            assert(key.count == 32,"Invalid key length");
-            if (key.count != 32) {
-                return nil;
-            }
-            
+        init(_ key: Array<UInt8>) {
+            precondition(key.count == 32, "Invalid key length")
+
             for i in 0..<17 {
                 h[i] = 0
             }
@@ -74,29 +76,9 @@ final public class Poly1305 {
             }
         }
     }
-
-    /**
-     Calculate Message Authentication Code (MAC) for message.
-     Calculation context is discarder on instance deallocation.
-
-     - parameter key:     256-bit key
-     - parameter message: Message
-
-     - returns: Message Authentication Code
-     */
-    public func authenticate(_ bytes:Array<UInt8>) -> Array<UInt8>? {
-        if let ctx = self.ctx {
-            update(ctx, message: bytes)
-            return finish(ctx)
-        }
-        return nil
-    }
     
-    public init? (key: Array<UInt8>) {
+    public init (key: Array<UInt8>) {
         ctx = Context(key)
-        if (ctx == nil) {
-            return nil
-        }
     }
 
     // MARK: - Private
@@ -290,4 +272,29 @@ final public class Poly1305 {
             bytes -= blockSize
         }
     }
+
+    //MARK: - Authenticator
+
+    /**
+     Calculate Message Authentication Code (MAC) for message.
+     Calculation context is discarder on instance deallocation.
+
+     - parameter key:     256-bit key
+     - parameter message: Message
+
+     - returns: Message Authentication Code
+     */
+    public func authenticate(_ bytes:Array<UInt8>) throws -> Array<UInt8> {
+        guard let ctx = self.ctx else {
+            throw Error.authenticateError
+        }
+
+        update(ctx, message: bytes)
+
+        guard let result = finish(ctx) else {
+            throw Error.authenticateError
+        }
+
+        return result
+    }
 }

+ 1 - 1
Sources/CryptoSwift/String+Extension.swift

@@ -49,7 +49,7 @@ extension String {
     // decrypt() does not make sense for String
 
     /// Returns hex string of bytes
-    public func authenticate(with authenticator: Authenticator) throws -> String {
+    public func authenticate<A: Authenticator>(with authenticator: A) throws -> String {
         return try self.utf8.lazy.map({ $0 as UInt8 }).authenticate(with: authenticator).toHexString()
     }
 }