import CommonCrypto import Foundation /// AES-128 im Counter-Modus. CryptoKit bietet CTR nicht an, deshalb CommonCrypto. enum AESCounterMode { /// - Parameters: /// - data: Der verschlüsselte Nutzteil des Advertisements. /// - key: 16 Byte Geräteschlüssel aus VictronConnect. /// - nonce: Der 16-Byte-Zählerblock (Victron: Nonce little-endian in den /// ersten beiden Bytes, Rest 0). static func crypt(_ data: [UInt8], key: [UInt8], nonce: [UInt8]) -> [UInt8]? { guard key.count == kCCKeySizeAES128, nonce.count == kCCBlockSizeAES128 else { return nil } var cryptor: CCCryptorRef? let createStatus = key.withUnsafeBytes { keyBuffer in nonce.withUnsafeBytes { ivBuffer in CCCryptorCreateWithMode( CCOperation(kCCEncrypt), // CTR ist symmetrisch CCMode(kCCModeCTR), CCAlgorithm(kCCAlgorithmAES), CCPadding(ccNoPadding), ivBuffer.baseAddress, keyBuffer.baseAddress, key.count, nil, 0, 0, CCModeOptions(kCCModeOptionCTR_BE), &cryptor ) } } guard createStatus == kCCSuccess, let cryptor else { return nil } defer { CCCryptorRelease(cryptor) } var output = [UInt8](repeating: 0, count: data.count) var moved = 0 let updateStatus = data.withUnsafeBytes { input in output.withUnsafeMutableBytes { out in CCCryptorUpdate(cryptor, input.baseAddress, data.count, out.baseAddress, data.count, &moved) } } guard updateStatus == kCCSuccess else { return nil } return Array(output.prefix(moved)) } }