Navigation Menu

Skip to content

Instantly share code, notes, and snippets.

@hfossli
Last active April 9, 2024 01:05
Show Gist options
  • Star 51 You must be signed in to star a gist
  • Fork 11 You must be signed in to fork a gist
  • Save hfossli/7165dc023a10046e2322b0ce74c596f8 to your computer and use it in GitHub Desktop.
Save hfossli/7165dc023a10046e2322b0ce74c596f8 to your computer and use it in GitHub Desktop.
AES 256 in swift 4 with CommonCrypto
#import <CommonCrypto/CommonCrypto.h>
import Foundation
struct AES256 {
private var key: Data
private var iv: Data
public init(key: Data, iv: Data) throws {
guard key.count == kCCKeySizeAES256 else {
throw Error.badKeyLength
}
guard iv.count == kCCBlockSizeAES128 else {
throw Error.badInputVectorLength
}
self.key = key
self.iv = iv
}
enum Error: Swift.Error {
case keyGeneration(status: Int)
case cryptoFailed(status: CCCryptorStatus)
case badKeyLength
case badInputVectorLength
}
func encrypt(_ digest: Data) throws -> Data {
return try crypt(input: digest, operation: CCOperation(kCCEncrypt))
}
func decrypt(_ encrypted: Data) throws -> Data {
return try crypt(input: encrypted, operation: CCOperation(kCCDecrypt))
}
private func crypt(input: Data, operation: CCOperation) throws -> Data {
var outLength = Int(0)
var outBytes = [UInt8](repeating: 0, count: input.count + kCCBlockSizeAES128)
var status: CCCryptorStatus = CCCryptorStatus(kCCSuccess)
input.withUnsafeBytes { (encryptedBytes: UnsafePointer<UInt8>!) -> () in
iv.withUnsafeBytes { (ivBytes: UnsafePointer<UInt8>!) in
key.withUnsafeBytes { (keyBytes: UnsafePointer<UInt8>!) -> () in
status = CCCrypt(operation,
CCAlgorithm(kCCAlgorithmAES128), // algorithm
CCOptions(kCCOptionPKCS7Padding), // options
keyBytes, // key
key.count, // keylength
ivBytes, // iv
encryptedBytes, // dataIn
input.count, // dataInLength
&outBytes, // dataOut
outBytes.count, // dataOutAvailable
&outLength) // dataOutMoved
}
}
}
guard status == kCCSuccess else {
throw Error.cryptoFailed(status: status)
}
return Data(bytes: UnsafePointer<UInt8>(outBytes), count: outLength)
}
static func createKey(password: Data, salt: Data) throws -> Data {
let length = kCCKeySizeAES256
var status = Int32(0)
var derivedBytes = [UInt8](repeating: 0, count: length)
password.withUnsafeBytes { (passwordBytes: UnsafePointer<Int8>!) in
salt.withUnsafeBytes { (saltBytes: UnsafePointer<UInt8>!) in
status = CCKeyDerivationPBKDF(CCPBKDFAlgorithm(kCCPBKDF2), // algorithm
passwordBytes, // password
password.count, // passwordLen
saltBytes, // salt
salt.count, // saltLen
CCPseudoRandomAlgorithm(kCCPRFHmacAlgSHA1), // prf
10000, // rounds
&derivedBytes, // derivedKey
length) // derivedKeyLen
}
}
guard status == 0 else {
throw Error.keyGeneration(status: Int(status))
}
return Data(bytes: UnsafePointer<UInt8>(derivedBytes), count: length)
}
static func randomIv() -> Data {
return randomData(length: kCCBlockSizeAES128)
}
static func randomSalt() -> Data {
return randomData(length: 8)
}
static func randomData(length: Int) -> Data {
var data = Data(count: length)
let status = data.withUnsafeMutableBytes { mutableBytes in
SecRandomCopyBytes(kSecRandomDefault, length, mutableBytes)
}
assert(status == Int32(0))
return data
}
}
import UIKit
extension Data {
var hexString: String {
return map { String(format: "%02hhx", $0) }.joined()
}
}
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
do {
let digest = "hello world".data(using: .utf8)!
let password = "foo"
let salt = AES256.randomSalt()
let iv = AES256.randomIv()
let key = try AES256.createKey(password: password.data(using: .utf8)!, salt: salt)
let aes = try AES256(key: key, iv: iv)
let encrypted = try aes.encrypt(digest)
let decrypted = try aes.decrypt(encrypted)
print("Encrypted: \(encrypted.hexString)")
print("Decrypted: \(decrypted.hexString)")
print("Password: \(password)")
print("Key: \(key.hexString)")
print("IV: \(iv.hexString)")
print("Salt: \(salt.hexString)")
print(" ")
print("#! /bin/sh")
print("echo \(digest.hexString) | xxd -r -p > digest.txt")
print("echo \(encrypted.hexString) | xxd -r -p > encrypted.txt")
print("openssl aes-256-cbc -K \(key.hexString) -iv \(iv.hexString) -e -in digest.txt -out encrypted-openssl.txt")
print("openssl aes-256-cbc -K \(key.hexString) -iv \(iv.hexString) -d -in encrypted.txt -out decrypted-openssl.txt")
} catch {
print("Failed")
print(error)
}
}
}
Encrypted: 76be70e3e63890e12572bc55ed8f95b1
Decrypted: 68656c6c6f20776f726c64
Password: foo
Key: 848496354b13779568e1ee81f1f73428678f131c3d7501ef9ed99f7a7b4bf70c
IV: 4bb9f6f8bfb7adaad584e032a4cd412f
Salt: eedb0c8de0a9d09f
----
echo 68656c6c6f20776f726c64 | xxd -r -p > digest.txt
echo 76be70e3e63890e12572bc55ed8f95b1 | xxd -r -p > encrypted.txt
openssl aes-256-cbc -K 848496354b13779568e1ee81f1f73428678f131c3d7501ef9ed99f7a7b4bf70c -iv 4bb9f6f8bfb7adaad584e032a4cd412f -e -in digest.txt -out encrypted-openssl.txt
openssl aes-256-cbc -K 848496354b13779568e1ee81f1f73428678f131c3d7501ef9ed99f7a7b4bf70c -iv 4bb9f6f8bfb7adaad584e032a4cd412f -d -in encrypted.txt -out decrypted-openssl.txt
@Gutty1
Copy link

Gutty1 commented Jan 25, 2021

very interesting implementation,
could you please publish also the data extension hexString?

@Aizaz-Abbasi
Copy link

How to encrypt image ??

@hfossli
Copy link
Author

hfossli commented Jun 24, 2021

Big question. Lots of good articles on the subject

@Aizaz-Abbasi
Copy link

I used crypto swift but it is slow. any suggestions?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment