rwbutler/Hash

View on GitHub
Hash/Classes/Cryptography/Cryptable.swift

Summary

Maintainability
A
3 hrs
Test Coverage
//
//  Cryptable.swift
//  Hash
//
//  Created by Ross Butler on 7/5/19.
//

import Foundation
import CommonCrypto

protocol Cryptable: class {
    
    var algorithm: Cipher { get }
    var ivData: Data? { get }
    var keyData: Data { get }
    var message: Data { get }
    var result: CCCryptorStatus? { get set }
    
    func data() -> Data
    func data(operation: CCOperation) -> Data
    
}

extension Cryptable {
    
    func data(operation: CCOperation) -> Data {
        var outLength = Int(0)
        let inputData = message
        let length = (algorithm.blockSize() + inputData.count)
        var outputData = Data(count: length)
        var result: CCCryptorStatus = CCCryptorStatus(kCCSuccess)
        _ = outputData.withUnsafeMutableBytes { outputBytes -> UInt8 in
            inputData.withUnsafeBytes { inputBytes -> UInt8 in
                keyData.withUnsafeBytes { keyBytes -> UInt8 in
                    let messageLength = size_t(outputBytes.count)
                    let keyLength = size_t(keyData.count)
                    if let keyBytes = keyBytes.bindMemory(to: UInt8.self).baseAddress,
                        let inputBytes = inputBytes.bindMemory(to: UInt8.self).baseAddress,
                        let outputBytes = outputBytes.bindMemory(to: UInt8.self).baseAddress {
                        guard let ivData = ivData else {
                            result = CCCrypt(operation, algorithm.ccAlgorithm(), CCOptions(kCCOptionPKCS7Padding),
                                             keyBytes, keyLength, nil, inputBytes, inputData.count, outputBytes,
                                             messageLength, &outLength)
                            return 0
                        }
                        let _ = ivData.withUnsafeBytes { ivBytes -> UInt8 in
                            if let ivBytes = ivBytes.bindMemory(to: UInt8.self).baseAddress {
                                result = CCCrypt(operation, algorithm.ccAlgorithm(), CCOptions(kCCOptionPKCS7Padding),
                                                 keyBytes, keyLength, ivBytes, inputBytes, inputData.count, outputBytes,
                                                 messageLength, &outLength)
                            }
                            return 0
                        }
                    }
                    return 0
                }
            }
        }
        self.result = result
        outputData.removeLast(outputData.count - outLength)
        return outputData
    }
    
}