79 lines
2.9 KiB
Swift
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
|
|
}
|
|
}
|