Search code examples
iosswiftapple-cryptokit

How can i store encrypted data


I am trying store and retrieve my encrypted text data in UserDefaults but there is a problem with retrieving it. I user CryptoKit to encrypt and decrypt data.

Error message is: "Could not cast value of type 'Foundation.__NSSwiftData' (0x7fff89d1ee50) to 'CryptoKit.ChaChaPoly.SealedBox' (0x7fff8085abc8)."

Is there a better way to store SymmetricKey in the keychain without converting it to String by UnsafeBytes? I use SwiftKeychainWrapper.

func encrypt(text: String) {
    let key = SymmetricKey(size: .bits256)
    let message = text.data(using: .utf8)!
    let sealedBox = try! ChaChaPoly.seal(message, using: key)

    let defaults = UserDefaults.standard
    defaults.set(sealedBox.combined, forKey: "sealedBox")

    let savedKey = key.withUnsafeBytes {Data(Array($0)).base64EncodedString()}
    Services.saveKey(key: savedKey)
}

func decrypt() {
    let savedKey = Services.getKey()

    if let keyData = Data(base64Encoded: savedKey) {
        let retrievedKey = SymmetricKey(data: keyData)

        let defaults = UserDefaults.standard
        let sealedBox = (defaults.object(forKey: "sealedBox") as? ChaChaPoly.SealedBox)!

        let decryptedMessage = try! ChaChaPoly.open(sealedBox, using: retrievedKey)
        textView.text = String(data: decryptedMessage, encoding: .utf8)!
    }
}

Solution

  • You're storing Data in UserDefaults, so that's what you have to extract again. Then create a SealedBox from that, like so:

    let defaults = UserDefaults.standard
    let data = defaults.object(forKey: "sealedBox") as? Data
    
    let sealedBox = try! ChaChaPoly.SealedBox(combined: data!)
    let decryptedMessage = try! ChaChaPoly.open(sealedBox, using: retrievedKey)
    

    (of course you'll want to avoid force unwraps in real production code)