Skip to content

Instantly share code, notes, and snippets.

@matsuda
Created November 18, 2019 10:45
Show Gist options
  • Save matsuda/2c183a271dd1e7e30eca92612879222f to your computer and use it in GitHub Desktop.
Save matsuda/2c183a271dd1e7e30eca92612879222f to your computer and use it in GitHub Desktop.
AES encryption in Swift
import CommonCrypto
// MARK: AES128 暗号、復号化
public extension String {
func aesEncrypt(key: String, iv: String) -> String? {
guard
let data = self.data(using: .utf8),
let key = key.data(using: .utf8),
let iv = iv.data(using: .utf8),
let encrypt = data.encryptAES256(key: key, iv: iv)
else { return nil }
let base64Data = encrypt.base64EncodedData()
return String(data: base64Data, encoding: .utf8)
}
func aesDecrypt(key: String, iv: String) -> String? {
guard
let data = Data(base64Encoded: self),
let key = key.data(using: .utf8),
let iv = iv.data(using: .utf8),
let decrypt = data.decryptAES256(key: key, iv: iv)
else { return nil }
return String(data: decrypt, encoding: .utf8)
}
}
/// @see http://www.splinter.com.au/2019/06/09/pure-swift-common-crypto-aes-encryption/
public extension Data {
/// Encrypts for you with all the good options turned on: CBC, an IV, PKCS7
/// padding (so your input data doesn't have to be any particular length).
/// Key can be 128, 192, or 256 bits.
/// Generates a fresh IV for you each time, and prefixes it to the
/// returned ciphertext.
func encryptAES256(key: Data, iv: Data, options: Int = kCCOptionPKCS7Padding) -> Data? {
// No option is needed for CBC, it is on by default.
return aesCrypt(operation: kCCEncrypt,
algorithm: kCCAlgorithmAES,
options: options,
key: key,
initializationVector: iv,
dataIn: self)
}
/// Decrypts self, where self is the IV then the ciphertext.
/// Key can be 128/192/256 bits.
func decryptAES256(key: Data, iv: Data, options: Int = kCCOptionPKCS7Padding) -> Data? {
guard count > kCCBlockSizeAES128 else { return nil }
return aesCrypt(operation: kCCDecrypt,
algorithm: kCCAlgorithmAES,
options: options,
key: key,
initializationVector: iv,
dataIn: self)
}
// swiftlint:disable:next function_parameter_count
private func aesCrypt(operation: Int,
algorithm: Int,
options: Int,
key: Data,
initializationVector: Data,
dataIn: Data) -> Data? {
return initializationVector.withUnsafeBytes { ivUnsafeRawBufferPointer in
return key.withUnsafeBytes { keyUnsafeRawBufferPointer in
return dataIn.withUnsafeBytes { dataInUnsafeRawBufferPointer in
// Give the data out some breathing room for PKCS7's padding.
let dataOutSize: Int = dataIn.count + kCCBlockSizeAES128 * 2
let dataOut = UnsafeMutableRawPointer.allocate(byteCount: dataOutSize, alignment: 1)
defer { dataOut.deallocate() }
var dataOutMoved: Int = 0
let status = CCCrypt(CCOperation(operation),
CCAlgorithm(algorithm),
CCOptions(options),
keyUnsafeRawBufferPointer.baseAddress, key.count,
ivUnsafeRawBufferPointer.baseAddress,
dataInUnsafeRawBufferPointer.baseAddress, dataIn.count,
dataOut, dataOutSize,
&dataOutMoved)
guard status == kCCSuccess else { return nil }
return Data(bytes: dataOut, count: dataOutMoved)
}
}
}
}
}
public func randomGenerateBytes(count: Int) -> Data? {
let bytes = UnsafeMutableRawPointer.allocate(byteCount: count, alignment: 1)
defer { bytes.deallocate() }
let status = CCRandomGenerateBytes(bytes, count)
guard status == kCCSuccess else { return nil }
return Data(bytes: bytes, count: count)
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment