Parcourir la source

Guess-implementation of CCM encryption

Marcin Krzyzanowski il y a 7 ans
Parent
commit
88a4edbdc4
1 fichiers modifiés avec 96 ajouts et 63 suppressions
  1. 96 63
      Sources/CryptoSwift/BlockMode/CCM.swift

+ 96 - 63
Sources/CryptoSwift/BlockMode/CCM.swift

@@ -48,103 +48,136 @@ public struct CCM: BlockMode {
 
 }
 
-struct CCMModeWorker: BlockModeWorker {
+struct CCMModeWorker: BlockModeWorkerFinalizing {
     let cipherOperation: CipherOperationOnBlock
-    var blockSize: Int
+    let blockSize: Int
+    let tagSize: Int
+    lazy var S0: Array<UInt8> = {
+        let ctr = try! format(counter: counter, nonce: Array(nonce), q: q) // ???? q = 3
+        return cipherOperation(ctr.slice)!
+    }()
+    var counter: Int = 0
+    let q: UInt8 = 3 // ??????????
+
     let additionalBufferSize: Int = 0
-    private let iv: ArraySlice<UInt8>
-    private var prev: ArraySlice<UInt8>?
+    private let nonce: ArraySlice<UInt8>
+    private var prev: ArraySlice<UInt8>
 
     public enum Error: Swift.Error {
         case invalidParameter
     }
 
-
-    init(blockSize: Int, iv: ArraySlice<UInt8>, cipherOperation: @escaping CipherOperationOnBlock) {
+    init(blockSize: Int, nonce: ArraySlice<UInt8>, tagSize: Int, cipherOperation: @escaping CipherOperationOnBlock) {
         self.blockSize = blockSize
-        self.iv = iv
+        self.tagSize = tagSize
         self.cipherOperation = cipherOperation
+        self.nonce = nonce
+
+        // For the very first time setup new IV (aka y0) from the block0
+        let block0 = try! format(nonce: Array(nonce), Q: UInt32(blockSize), q: q, t: UInt8(tagSize), hasAssociatedData: false).slice
+        prev = cipherOperation(block0)!.slice // y0
     }
 
     mutating func encrypt(block plaintext: ArraySlice<UInt8>) -> Array<UInt8> {
-        guard let ciphertext = cipherOperation(xor(prev ?? iv, plaintext)) else {
+        guard let y_i = cipherOperation(xor(prev, plaintext)) else {
             return Array(plaintext)
         }
-        prev = ciphertext.slice
-        return ciphertext
+
+        guard let ctr_j = try? format(counter: counter, nonce: Array(nonce), q: q), let S_j = cipherOperation(ctr_j.slice) else {
+            return Array(plaintext)
+        }
+
+        prev = y_i.slice
+        counter = counter + 1
+        return xor(y_i, S_j) // P xor MSBplen(S)
     }
 
     mutating func decrypt(block ciphertext: ArraySlice<UInt8>) -> Array<UInt8> {
         guard let plaintext = cipherOperation(ciphertext) else {
             return Array(ciphertext)
         }
-        let result: Array<UInt8> = xor(prev ?? iv, plaintext)
+        let result: Array<UInt8> = xor(prev, plaintext)
         prev = ciphertext
         return result
     }
 
-    // Q - octet length of P
-    // q - octet length of Q. Maximum length (in octets) of payload. An element of {2,3,4,5,6,7,8}
-    // t - octet length of T (MAC length). An element of {4,6,8,10,12,14,16}
-    private func format(nonce N: [UInt8], Q: UInt32, q: UInt8, t: UInt8, hasAssociatedData: Bool) throws -> [UInt8] {
-        var flags0: UInt8 = 0
+    mutating func finalize(encrypt ciphertext: ArraySlice<UInt8>) throws -> Array<UInt8> {
+        // contatenate T at the end
+        let T = ciphertext.prefix(tagSize) // T
+        let tag = xor(T, S0.prefix(tagSize)) as Array<UInt8> // T xor MSBtlen(S0)
+        return Array(ciphertext) + tag
+    }
 
-        if hasAssociatedData {
-            // 7 bit
-            flags0 |= (1 << 6)
-        }
+    func willDecryptLast(block ciphertext: ArraySlice<UInt8>) throws -> ArraySlice<UInt8> {
+        return ciphertext
+    }
 
-        // 6,5,4 bit is t in 3 bits
-        flags0 |= (((t-2)/2) & 0x07) << 3
+    func didDecryptLast(block plaintext: ArraySlice<UInt8>) throws -> Array<UInt8> {
+        return Array(plaintext)
+    }
+}
 
-        // 3,2,1 bit is q in 3 bits
-        flags0 |= ((q-1) & 0x07) << 0
+// Q - octet length of P
+// q - octet length of Q. Maximum length (in octets) of payload. An element of {2,3,4,5,6,7,8}
+// t - octet length of T (MAC length). An element of {4,6,8,10,12,14,16}
+private func format(nonce N: [UInt8], Q: UInt32, q: UInt8, t: UInt8, hasAssociatedData: Bool) throws -> [UInt8] {
+    var flags0: UInt8 = 0
 
-        var block0: [UInt8] = Array<UInt8>(repeating: 0, count: 16) // block[0]
-        block0[0] = flags0
+    if hasAssociatedData {
+        // 7 bit
+        flags0 |= (1 << 6)
+    }
 
-        // N in 1...(15-q) octets, n = 15-q
-        // n is an element of {7,8,9,10,11,12,13}
-        let n = 15-Int(q)
-        guard (n + Int(q)) == 15 else {
-            // n+q == 15
-            throw Error.invalidParameter
-        }
-        block0[1...n] = N[0...(n-1)]
+    // 6,5,4 bit is t in 3 bits
+    flags0 |= (((t-2)/2) & 0x07) << 3
 
-        // Q in (16-q)...15 octets
-        block0[(16-Int(q))...15] = Q.bytes(totalBytes: Int(q)).slice
+    // 3,2,1 bit is q in 3 bits
+    flags0 |= ((q-1) & 0x07) << 0
 
-        return block0
+    var block0: [UInt8] = Array<UInt8>(repeating: 0, count: 16) // block[0]
+    block0[0] = flags0
+
+    // N in 1...(15-q) octets, n = 15-q
+    // n is an element of {7,8,9,10,11,12,13}
+    let n = 15-Int(q)
+    guard (n + Int(q)) == 15 else {
+        // n+q == 15
+        throw CCMModeWorker.Error.invalidParameter
     }
+    block0[1...n] = N[0...(n-1)]
 
-    /// Formatting of the Counter Blocks. Ctr[i]
-    /// The counter generation function.
-    /// Q - octet length of P
-    /// q - octet length of Q. Maximum length (in octets) of payload. An element of {2,3,4,5,6,7,8}
-    private func format(counter i: Int, nonce N: [UInt8], q: UInt8) throws -> [UInt8] {
-        var flags0: UInt8 = 0
-
-        // bit 8,7 is Reserved
-        // bit 4,5,6 shall be set to 0
-        // 3,2,1 bit is q in 3 bits
-        flags0 |= ((q-1) & 0x07) << 0
-
-        var block = Array<UInt8>(repeating: 0, count: 16) // block[0]
-        block[0] = flags0
-
-        // N in 1...(15-q) octets, n = 15-q
-        // n is an element of {7,8,9,10,11,12,13}
-        let n = 15-Int(q)
-        guard (n + Int(q)) == 15 else {
-            // n+q == 15
-            throw Error.invalidParameter
-        }
-        block[1...n] = N[0...(n-1)]
+    // Q in (16-q)...15 octets
+    block0[(16-Int(q))...15] = Q.bytes(totalBytes: Int(q)).slice
 
-        // [i]8q in (16-q)...15 octets
-        block[(16-Int(q))...15] = i.bytes(totalBytes: Int(q)).slice
+    return block0
+}
 
-        return block
+/// Formatting of the Counter Blocks. Ctr[i]
+/// The counter generation function.
+/// Q - octet length of P
+/// q - octet length of Q. Maximum length (in octets) of payload. An element of {2,3,4,5,6,7,8}
+private func format(counter i: Int, nonce N: [UInt8], q: UInt8) throws -> [UInt8] {
+    var flags0: UInt8 = 0
+
+    // bit 8,7 is Reserved
+    // bit 4,5,6 shall be set to 0
+    // 3,2,1 bit is q in 3 bits
+    flags0 |= ((q-1) & 0x07) << 0
+
+    var block = Array<UInt8>(repeating: 0, count: 16) // block[0]
+    block[0] = flags0
+
+    // N in 1...(15-q) octets, n = 15-q
+    // n is an element of {7,8,9,10,11,12,13}
+    let n = 15-Int(q)
+    guard (n + Int(q)) == 15 else {
+        // n+q == 15
+        throw CCMModeWorker.Error.invalidParameter
     }
+    block[1...n] = N[0...(n-1)]
+
+    // [i]8q in (16-q)...15 octets
+    block[(16-Int(q))...15] = i.bytes(totalBytes: Int(q)).slice
+
+    return block
 }