Files
2026-03-11 17:42:53 +00:00

79 lines
2.9 KiB
Swift

//
// Copyright 2026 Element Creations Ltd.
//
// SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial.
// Please see LICENSE files in the repository root for full details.
//
import CommonCrypto
import Foundation
enum ClassicAppAES {
enum Error: Swift.Error {
case cannotInitializeCryptor
case decryptionFailed(CCCryptorStatus)
}
/// Decrypt data using AES-256 in CTR mode.
/// - Parameters:
/// - data: The data to decrypt
/// - aesKey: The AES decryption key (256-bit)
/// - iv: The initialization vector
/// - Returns: The decrypted data, or nil if decryption fails
/// - Throws: An error if decryption fails
static func decrypt(_ data: Data, aesKey: Data, iv: Data) throws -> Data {
var cryptor: CCCryptorRef?
var status: CCCryptorStatus
// Create the cryptor
status = iv.withUnsafeBytes { ivBytes in
aesKey.withUnsafeBytes { keyBytes in
CCCryptorCreateWithMode(CCOperation(kCCDecrypt),
CCMode(kCCModeCTR),
CCAlgorithm(kCCAlgorithmAES),
CCPadding(ccNoPadding),
ivBytes.baseAddress,
keyBytes.baseAddress,
kCCKeySizeAES256,
nil,
0,
0,
CCModeOptions(kCCModeOptionCTR_BE),
&cryptor)
}
}
guard status == kCCSuccess, let cryptor else {
MXLog.error("Failed to create cryptor: \(status)")
throw Error.cannotInitializeCryptor
}
// Get the output buffer size
let bufferLength = CCCryptorGetOutputLength(cryptor, data.count, false)
var buffer = Data(count: bufferLength)
var outLength = 0
status = data.withUnsafeBytes { dataBytes in
let count = buffer.count
return buffer.withUnsafeMutableBytes { bufferBytes in
CCCryptorUpdate(cryptor,
dataBytes.baseAddress,
data.count,
bufferBytes.baseAddress,
count,
&outLength)
}
}
let releaseStatus = CCCryptorRelease(cryptor)
status = (status == kCCSuccess && releaseStatus == kCCSuccess) ? CCCryptorStatus(kCCSuccess) : status
guard status == kCCSuccess else {
MXLog.error("Decryption failed: \(status)")
throw Error.decryptionFailed(status)
}
return buffer
}
}