I'm implementing AES256 GCM encrypt and decrypt using Swift CryptoKit, and I used this website (https://www.lddgo.net/en/encrypt/aes) to verify my results. At present, it seems that the encryption result is the same as the website, but the decryption keeps failing when code running on "AES.GCM.open", the error message is :"Thread 1: Fatal error: 'try!' expression unexpectedly raised an error: CryptoKit.CryptoKitError.authenticationFailure". However, I print out the ciphertext, tag, and iv from the sealedBox. These values seems look correct. I don't know where I am going wrong, can someone help me? Below is my completed code.
import UIKit
import CryptoKit
class ViewController: UIViewController {
let STOKEN = "34567890ABCDEF1234567890ABCDEF12"
let UDID = "ABCDEF12-34567890ABCDEF12"
let S1 = "c5f2aca59ffc9575"
var outputResult: String?
var decryptStr : String?
override func viewDidLoad() {
super.viewDidLoad()
let inputContent = "\(S1),\(UDID)"
let stokenSha256String = genSha256Data(STOKEN)
outputResult = encrypt(stokenSha256String, calString: inputContent)
guard let encryptResult = outputResult else { return }
//EnResult:1893c92900a68a5456aec3c2c2f2a224a6a97e33835b54abc0accd1fd200357bdbb814f22f70807167c8cb34f71538e32e248e6624f89e6b659b
print("EncryptResult: \(encryptResult)" )
decryptStr = decrypt(stokenSha256String, r1: encryptResult)
guard let decryption = decryptStr else { return }
print("DeCode: \(decryption)" )
}
func genSha256Data(_ value: String) -> String {
if let data = value.data(using: .utf8) {
let hash = SHA256.hash(data: data)
let hashString = hash.compactMap { String(format: "%02x", $0) }.joined()
return hashString
}
return ""
}
func encrypt(_ key: String, calString: String) -> String {
let tmpShar256Result = genSha256Data(key)
let password = String(tmpShar256Result.prefix(32))
let ivStr = String(tmpShar256Result.prefix(48)).suffix(16)
guard let ivData = ivStr.data(using: .utf8) else { return "Fail" }
let newIV = try! AES.GCM.Nonce(data: ivData)
let passwordData = Data(password.utf8)
let calStrData = Data(calString.utf8)
let sealedBox = try! AES.GCM.seal(calStrData, using: SymmetricKey(data: passwordData), nonce: newIV)
let sealDataStr = sealedBox.ciphertext.toHexString()
let tagDataStr = sealedBox.tag.toHexString()
let resultStr = sealDataStr + tagDataStr
return resultStr
}
func decrypt(_ key: String, r1: String) -> String {
let tmpShar256Result = genSha256Data(key)
let password = String(tmpShar256Result.prefix(32))
let ivStr = String(tmpShar256Result.prefix(48)).suffix(16)
guard let ivData = ivStr.data(using: .utf8) else { return "Fail" }
let newIV = try! AES.GCM.Nonce(data: ivData)
let passwordData = Data(password.utf8)
let r1Data = Data(hexString: r1)!
//let sealedBox = try! AES.GCM.SealedBox(combined: r1Data!)
let tagData = Data(hexString: "cb34f71538e32e248e6624f89e6b659b")//cb34f71538e32e248e6624f89e6b659b
let sealedBox = try! AES.GCM.SealedBox(nonce: newIV, ciphertext: r1Data, tag: tagData!)
print(sealedBox.ciphertext.toHexString())
print(sealedBox.tag.toHexString())
let ivHexText = Data(sealedBox.nonce).toHexString()
if let ivString = String(data: Data(hexString: ivHexText) ?? Data(), encoding: .utf8) {
print("iv String: \(ivString)")
} else {
print("Error")
}
let decrypted = try! AES.GCM.open(sealedBox, using: SymmetricKey(data: passwordData))
let decryptedString = String(data: decrypted, encoding: .utf8)
return decryptedString!
}
}
extension Data {
init?(hexString: String) {
let trimmedString = hexString.trimmingCharacters(in: .whitespaces)
var data = Data(capacity: trimmedString.count / 2)
var index = trimmedString.startIndex
while index < trimmedString.endIndex {
let nextIndex = trimmedString.index(index, offsetBy: 2)
let byteString = trimmedString[index..<nextIndex]
if let byte = UInt8(byteString, radix: 16) {
data.append(byte)
} else {
return nil
}
index = nextIndex
}
self = data
}
func toHexString() -> String {
return map { String(format: "%02hhx", $0) }.joined()
}
}
My expectation is to get the original encrypted content from decryption,
Input Content for decryption: "1893c92900a68a5456aec3c2c2f2a224a6a97e33835b54abc0accd1fd200357bdbb814f22f70807167c89db3b0ded152c87fe13ba9a4e4cc749d8b6d",
Password when decrypt:
"92cc6afef35b52e0bbaca4307de3c151",
IV when decrypt:c3f64cc013d39d6f,
the output result(before encrypted) should be "c5f2aca59ffc9575,ABCDEF12-34567890ABCDEF12".