فهرست منبع

Adds CBC-MAC authenticator

Marcin Krzyzanowski 6 سال پیش
والد
کامیت
1a2756f0c6
5فایلهای تغییر یافته به همراه120 افزوده شده و 83 حذف شده
  1. 4 1
      CHANGELOG
  2. 8 0
      CryptoSwift.xcodeproj/project.pbxproj
  3. 1 0
      README.md
  4. 104 0
      Sources/CryptoSwift/CBCMAC.swift
  5. 3 82
      Sources/CryptoSwift/CMAC.swift

+ 4 - 1
CHANGELOG

@@ -1,3 +1,6 @@
+0.13.0
+- Adds CBC-MAC authenticator
+
 0.12.0
 - Swift 4.2 maintenance update.
 
@@ -227,4 +230,4 @@
 - Hex string is lowercase now
 - Carthage support
 - Tests update
-- Swift 2.0 support - overall update
+- Swift 2.0 support - overall update

+ 8 - 0
CryptoSwift.xcodeproj/project.pbxproj

@@ -115,6 +115,7 @@
 		75EC52B81EE8B83D0048EB3B /* Utils.swift in Sources */ = {isa = PBXBuildFile; fileRef = 75EC52781EE8B6CA0048EB3B /* Utils.swift */; };
 		75EC52B91EE8B83D0048EB3B /* ZeroPadding.swift in Sources */ = {isa = PBXBuildFile; fileRef = 75EC52791EE8B6CA0048EB3B /* ZeroPadding.swift */; };
 		75F4E434216C93EF00F09710 /* CCM.swift in Sources */ = {isa = PBXBuildFile; fileRef = 75F4E433216C93EF00F09710 /* CCM.swift */; };
+		75F4E436216C98DE00F09710 /* CBCMAC.swift in Sources */ = {isa = PBXBuildFile; fileRef = 75F4E435216C98DE00F09710 /* CBCMAC.swift */; };
 		E3FD2D531D6B81CE00A9F35F /* Error+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = E3FD2D511D6B813C00A9F35F /* Error+Extension.swift */; };
 		E6200E141FB9A7AE00258382 /* HKDF.swift in Sources */ = {isa = PBXBuildFile; fileRef = E6200E131FB9A7AE00258382 /* HKDF.swift */; };
 		E6200E171FB9B68C00258382 /* HKDFTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = E6200E151FB9B67C00258382 /* HKDFTests.swift */; };
@@ -355,6 +356,9 @@
 		75EC527A1EE8B6CA0048EB3B /* CryptoSwift.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = CryptoSwift.h; sourceTree = "<group>"; };
 		75EDCB811DAC4CA400D270E0 /* LinuxMain.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = LinuxMain.swift; path = Tests/LinuxMain.swift; sourceTree = SOURCE_ROOT; };
 		75F4E433216C93EF00F09710 /* CCM.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CCM.swift; sourceTree = "<group>"; };
+		75F4E435216C98DE00F09710 /* CBCMAC.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CBCMAC.swift; sourceTree = "<group>"; };
+		75F4E437216C9B5D00F09710 /* CHANGELOG */ = {isa = PBXFileReference; lastKnownFileType = text; path = CHANGELOG; sourceTree = SOURCE_ROOT; };
+		75F4E438216C9B6900F09710 /* README.md */ = {isa = PBXFileReference; lastKnownFileType = net.daringfireball.markdown; path = README.md; sourceTree = SOURCE_ROOT; };
 		E3FD2D511D6B813C00A9F35F /* Error+Extension.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "Error+Extension.swift"; sourceTree = "<group>"; };
 		E6200E131FB9A7AE00258382 /* HKDF.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HKDF.swift; sourceTree = "<group>"; };
 		E6200E151FB9B67C00258382 /* HKDFTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = HKDFTests.swift; sourceTree = "<group>"; };
@@ -490,6 +494,8 @@
 		754BE46519693E190098E6F3 /* Supporting Files */ = {
 			isa = PBXGroup;
 			children = (
+				75F4E438216C9B6900F09710 /* README.md */,
+				75F4E437216C9B5D00F09710 /* CHANGELOG */,
 				75EDCB811DAC4CA400D270E0 /* LinuxMain.swift */,
 				7576F64C20725BD5006688F8 /* Default-568h@2x.png */,
 				754BE46619693E190098E6F3 /* Info.plist */,
@@ -557,6 +563,7 @@
 				75EC524B1EE8B6CA0048EB3B /* Checksum.swift */,
 				75EC524C1EE8B6CA0048EB3B /* Cipher.swift */,
 				0EE73E70204D598100110E11 /* CMAC.swift */,
+				75F4E435216C98DE00F09710 /* CBCMAC.swift */,
 				75EC524D1EE8B6CA0048EB3B /* Collection+Extension.swift */,
 				75EC524E1EE8B6CA0048EB3B /* Cryptors.swift */,
 				75EC52501EE8B6CA0048EB3B /* Digest.swift */,
@@ -872,6 +879,7 @@
 				75EC52901EE8B81A0048EB3B /* Collection+Extension.swift in Sources */,
 				0EE73E71204D598100110E11 /* CMAC.swift in Sources */,
 				7523742D2083C61D0016D662 /* GCM.swift in Sources */,
+				75F4E436216C98DE00F09710 /* CBCMAC.swift in Sources */,
 				752BED9F208C135700FC4743 /* AES+Foundation.swift in Sources */,
 				E6200E141FB9A7AE00258382 /* HKDF.swift in Sources */,
 				75EC529F1EE8B8230048EB3B /* HMAC.swift in Sources */,

+ 1 - 0
README.md

@@ -63,6 +63,7 @@ Good mood
   [Poly1305](http://cr.yp.to/mac/poly1305-20050329.pdf)
 | [HMAC (MD5, SHA1, SHA256)](https://www.ietf.org/rfc/rfc2104.txt)
 | [CMAC](https://tools.ietf.org/html/rfc4493)
+| [CBC-MAC](https://en.wikipedia.org/wiki/CBC-MAC)
 
 #### Cipher mode of operation
 - Electronic codebook ([ECB](http://en.wikipedia.org/wiki/Block_cipher_mode_of_operation#Electronic_codebook_.28ECB.29))

+ 104 - 0
Sources/CryptoSwift/CBCMAC.swift

@@ -0,0 +1,104 @@
+//
+//  CryptoSwift
+//
+//  Copyright (C) 2014-2017 Marcin Krzyżanowski <marcin@krzyzanowskim.com>
+//  This software is provided 'as-is', without any express or implied warranty.
+//
+//  In no event will the authors be held liable for any damages arising from the use of this software.
+//
+//  Permission is granted to anyone to use this software for any purpose,including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions:
+//
+//  - The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation is required.
+//  - Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
+//  - This notice may not be removed or altered from any source or binary distribution.
+//
+
+public class CBCMAC: Authenticator {
+    public enum Error: Swift.Error {
+        case wrongKeyLength
+    }
+
+    private let key: SecureBytes
+
+    private static let BlockSize: Int = 16
+    private static let Zero: Array<UInt8> = [0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]
+    private static let Rb: Array<UInt8> = [0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x87]
+
+    public init(key: Array<UInt8>) throws {
+        if key.count != 16 {
+            throw Error.wrongKeyLength
+        }
+        self.key = SecureBytes(bytes: key)
+    }
+
+    // MARK: Authenticator
+
+    public func authenticate(_ bytes: Array<UInt8>) throws -> Array<UInt8> {
+        let aes = try AES(key: Array(key), blockMode: CBC(iv: CBCMAC.Zero), padding: .noPadding)
+
+        let l = try aes.encrypt(CBCMAC.Zero)
+        var subKey1 = leftShiftOneBit(l)
+        if (l[0] & 0x80) != 0 {
+            subKey1 = xor(CBCMAC.Rb, subKey1)
+        }
+        var subKey2 = leftShiftOneBit(subKey1)
+        if (subKey1[0] & 0x80) != 0 {
+            subKey2 = xor(CBCMAC.Rb, subKey2)
+        }
+
+        let lastBlockComplete: Bool
+        let blockCount = (bytes.count + CBCMAC.BlockSize - 1) / CBCMAC.BlockSize
+        if blockCount == 0 {
+            lastBlockComplete = false
+        } else {
+            lastBlockComplete = bytes.count % CBCMAC.BlockSize == 0
+        }
+        var paddedBytes = bytes
+        if !lastBlockComplete {
+            bitPadding(to: &paddedBytes, blockSize: CBCMAC.BlockSize)
+        }
+
+        var blocks = Array(paddedBytes.batched(by: CBCMAC.BlockSize))
+        var lastBlock = blocks.popLast()!
+        if lastBlockComplete {
+            lastBlock = xor(lastBlock, subKey1)
+        } else {
+            lastBlock = xor(lastBlock, subKey2)
+        }
+
+        var x = Array<UInt8>(repeating: 0x00, count: CBCMAC.BlockSize)
+        var y = Array<UInt8>(repeating: 0x00, count: CBCMAC.BlockSize)
+        for block in blocks {
+            y = xor(block, x)
+            x = try aes.encrypt(y)
+        }
+        // the difference between CMAC and CBC-MAC is that CMAC xors the final block with a secret value
+        y = process(lastBlock: lastBlock, with: x)
+        return try aes.encrypt(y)
+    }
+
+    func process(lastBlock: ArraySlice<UInt8>, with x: [UInt8]) -> [UInt8] {
+        return Array(lastBlock)
+    }
+
+    // MARK: Helper methods
+
+    /**
+     Performs left shift by one bit to the bit string aquired after concatenating al bytes in the byte array
+     - parameters:
+     - bytes: byte array
+     - returns: bit shifted bit string split again in array of bytes
+     */
+    private func leftShiftOneBit(_ bytes: Array<UInt8>) -> Array<UInt8> {
+        var shifted = Array<UInt8>(repeating: 0x00, count: bytes.count)
+        let last = bytes.count - 1
+        for index in 0..<last {
+            shifted[index] = bytes[index] << 1
+            if (bytes[index + 1] & 0x80) != 0 {
+                shifted[index] += 0x01
+            }
+        }
+        shifted[last] = bytes[last] << 1
+        return shifted
+    }
+}

+ 3 - 82
Sources/CryptoSwift/CMAC.swift

@@ -13,87 +13,8 @@
 //  - This notice may not be removed or altered from any source or binary distribution.
 //
 
-public final class CMAC: Authenticator {
-    public enum Error: Swift.Error {
-        case wrongKeyLength
-    }
-
-    private let key: SecureBytes
-
-    private static let BlockSize: Int = 16
-    private static let Zero: Array<UInt8> = [0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]
-    private static let Rb: Array<UInt8> = [0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x87]
-
-    public init(key: Array<UInt8>) throws {
-        if key.count != 16 {
-            throw Error.wrongKeyLength
-        }
-        self.key = SecureBytes(bytes: key)
-    }
-
-    // MARK: Authenticator
-
-    public func authenticate(_ bytes: Array<UInt8>) throws -> Array<UInt8> {
-        let aes = try AES(key: Array(key), blockMode: CBC(iv: CMAC.Zero), padding: .noPadding)
-
-        let l = try aes.encrypt(CMAC.Zero)
-        var subKey1 = leftShiftOneBit(l)
-        if (l[0] & 0x80) != 0 {
-            subKey1 = xor(CMAC.Rb, subKey1)
-        }
-        var subKey2 = leftShiftOneBit(subKey1)
-        if (subKey1[0] & 0x80) != 0 {
-            subKey2 = xor(CMAC.Rb, subKey2)
-        }
-
-        let lastBlockComplete: Bool
-        let blockCount = (bytes.count + CMAC.BlockSize - 1) / CMAC.BlockSize
-        if blockCount == 0 {
-            lastBlockComplete = false
-        } else {
-            lastBlockComplete = bytes.count % CMAC.BlockSize == 0
-        }
-        var paddedBytes = bytes
-        if !lastBlockComplete {
-            bitPadding(to: &paddedBytes, blockSize: CMAC.BlockSize)
-        }
-
-        var blocks = Array(paddedBytes.batched(by: CMAC.BlockSize))
-        var lastBlock = blocks.popLast()!
-        if lastBlockComplete {
-            lastBlock = xor(lastBlock, subKey1)
-        } else {
-            lastBlock = xor(lastBlock, subKey2)
-        }
-
-        var x = Array<UInt8>(repeating: 0x00, count: CMAC.BlockSize)
-        var y = Array<UInt8>(repeating: 0x00, count: CMAC.BlockSize)
-        for block in blocks {
-            y = xor(block, x)
-            x = try aes.encrypt(y)
-        }
-        y = xor(lastBlock, x)
-        return try aes.encrypt(y)
-    }
-
-    // MARK: Helper methods
-
-    /**
-     Performs left shift by one bit to the bit string aquired after concatenating al bytes in the byte array
-     - parameters:
-     - bytes: byte array
-     - returns: bit shifted bit string split again in array of bytes
-     */
-    private func leftShiftOneBit(_ bytes: Array<UInt8>) -> Array<UInt8> {
-        var shifted = Array<UInt8>(repeating: 0x00, count: bytes.count)
-        let last = bytes.count - 1
-        for index in 0..<last {
-            shifted[index] = bytes[index] << 1
-            if (bytes[index + 1] & 0x80) != 0 {
-                shifted[index] += 0x01
-            }
-        }
-        shifted[last] = bytes[last] << 1
-        return shifted
+public final class CMAC: CBCMAC {
+    override func process(lastBlock: ArraySlice<UInt8>, with x: [UInt8]) -> [UInt8] {
+        return xor(lastBlock, x)
     }
 }