Xcode 11 Swift 5 CryptoKit share SymmetricKey - swift

I'm starting to learn de-/encrypting with the CryptoKit.
Everything works fine, but I can not share my generated SymmetricKey.
Example:
let key = SymmetricKey(size: .bits256)
Well, I generate a symmetric key. Now I want to share the key, but how I can do that?
Inside the debugger the variable key is empty?
I check the encryption and decryption - works well - output shows the encrypted and decrypted data. How can I save my variable key for distribution?
I found a solution:
let savedKey = key.withUnsafeBytes {Data(Array($0)).base64EncodedString()}
This works great, but how can I save the variable savedKey (String) back into the variable key (SymmetricKey)?

You can do that by converting key string to Data and retrieve the key from it
let key = SymmetricKey(size: .bits256)
let savedKey = key.withUnsafeBytes {Data(Array($0)).base64EncodedString()}
if let keyData = Data(base64Encoded: savedKey) {
let retrievedKey = SymmetricKey(data: keyData)
}
Hope this helps :)

Related

CryptoSwift throws invalidKeySize because of base64 encoded aesKey and aesIV

I have a project that retrieve data from API and shows in the app. But API uses AES encryption, I have aesKey and aesIV key and these keys are base64 encoded. I need to encode another string with these keys. To do that I use CryptoSwift library but when I try to use this keys to cipher the string, swift console warns me about invalidKeySize.I tried to decode from base64 to string but it did not work as well. These are the keys for an example;
Key and IV size are AES256, for encryption and decryption I need to use PKCS7 padding type with ECB/CBC block mode
aesKey = lHLBfVxlGoKoaCqWORJEHh3jOvC2EBx2VHGyNAdqYV0=
aesIV = 2spaSfljZ/cunRbuVkdphQ==
and CryptoSwift code block is:
let aes = try AES(key: "\(aesKeyString)", iv: "\(aesIVString)")
let cipherText = try aes.encrypt(Array("all".utf8))
The aesKey and aesIV from the snippet is Base64 encoded, so it's not really useful in that form. The convenience initializer you used is for a String, not base64 encoded data that you provided (that happened to be string, but it's different).
let aesKey = "lHLBfVxlGoKoaCqWORJEHh3jOvC2EBx2VHGyNAdqYV0="
let key = [UInt8](base64: aesKey)
let aesIV = "2spaSfljZ/cunRbuVkdphQ=="
let iv = [UInt8](base64: aesIV)
let aes = try AES(key: key, blockMode: CBC(iv: iv))
let cipherText = try aes.encrypt(Array("all".utf8))

Open chachapoly sealed box after removing and recreating a symmetric key (iOS)?

I am in a bit of a roadblock on my iOS app (first app for me), I want to encrypt data that I send to a server.
In order to do so I generate a symmetric key that I store in the keychain.
The key is generated in the following way:
SymmetricKey(data: password)
In this function the password is actually a computed SHA256 made like this:
SHA256.hash(data: password) which gives me a digest and from that I extract the data representation to create my key.
Now when I encrypt data I do the following
var encryptedData: Data = Data()
if let key: SymmetricKey = try? readKey(account: encryptingKeyAccount){
encryptedData = try! ChaChaPoly.seal(rawData, using: key).combined
}
return encryptedData
This returns me the data that I then send to the server.
In order to decrypt the data I do the following:
var decryptedData: Data = Data()
if let key: SymmetricKey = try? readKey(account: encryptingKeyAccount) {
let sealedBox = try! ChaChaPoly.SealedBox(combined: encryptedData)
decryptedData = try! ChaChaPoly.open(sealedBox, using: key)
}
return decryptedData
Now my problem is, if I logout (which means deleting the keys from the phone) and log back in (which in my mind recreates the same keys that were created before) then I am unable to decrypt my data... I have the following error when I try to open the box:
Thread 1: Fatal error: 'try!' expression unexpectedly raised an error: CryptoKit.CryptoKitError.authenticationFailure
Which I believe is due to how I create the key, which is not the same as the one that was deleted previously...
How can I fix this ?
Thanks !

Swift Sodium - Anonymous Encryption (Sealed Boxes)

I am trying to encrypt value using swift sodium with given public key.
However, the encrypted value is not the same as what's produced on server side.
I am not sure whether this piece of coding is right in swift.
The steps are similar to how its done in java.
Assume public key is in base64 string format.
Java:
String pubKey = "w6mjd11n9w9ncKfcuR888Ygi02ou+46ocIajlcUEmQ=";
String secret = "hithere"
byte[] pubKeyBytes = Base64.decode(pubKey,0);
SealedBox sealedDeal = new SealedBox(pubKeyBytes);
byte[] c = sealedDeal.encrypt(secret.getBytes());
String ciphertext = Base64.encodeToString(c, 0);
Swift:
let pubKey = "w6mjd11n9w9ncKfcuR888Ygi02ou+46ocIajlcUEmQ="
let dataDecoded:NSData = NSData(base64Encoded: pubKey, options: NSData.Base64DecodingOptions(rawValue: 0))!
let secret = "hithere".toData()!
let c : Data = sodium.box.seal(message: secret, recipientPublicKey: dataDecoded as Box.PublicKey)!
let ciphertext = c.base64EncodedString(options: .init(rawValue: 0))
Please tell me know what's wrong with the swift equivalent coding.
Thanks alot.
The encrypted value is supposed to be different, so that ciphertexts resulting from equivalent plaintexts are indistinguishable (see Ciphertext indistinguishability).
sodium.box.seal internally generates new nonce every time you are encrypting message, #Max is right, this is normal behave
You can use Detached mode to give same nonce, but this is a very bad idea
In your example you have used Anonymous Encryption I suggest you to take a look at Authenticated Encryption

Storing multiple values in Keychain using Locksmith

Can you store multiple key/value pairs under one forUserAccount?
try? Locksmith.saveData(["access_token" : access_token], forUserAccount: "UserData")
try? Locksmith.saveData(["email" : email!], forUserAccount: "UserData")
try? Locksmith.saveData(["markets" : market], forUserAccount: "UserData")
This code fails when looking for "email.". The only way I can do this is to create multiple forUserAccount strings: UserData, UserData1, UserData3, etc. I have tried updateData with no luck. If forUserAccount has to be unique, what is it for? It seems unnecessary if that's the case.
let userIDNumber = userID as NSNumber
let userIDString : String = userIDNumber.stringValue
let keychainData = [_keychainEmailKey: email, _keychainPasswordKey: password, _keychainUserIDKey: userIDString]
Locksmith.updateData(keychainData, forUserAccount: email)
Where _keychainEmailKey, etc are constants for keys. So forUserAccount should be unique, probably it is overriding previous values.
Just like #nyekimov's answer alludes to, a dictionary of values can be stored for an account. To clarify, here's a code snippet:
do
{
try Locksmith.saveData(["user": "notMyRealUsername", "password":"123456"], forUserAccount: "myUserAccount") //store it
let dictionary = Locksmith.loadDataForUserAccount("myUserAccount") //load it
print(dictionary) //let's see what we've got
}
catch
{
// handle errors here
}
Use try Locksmith.updateData(["user": "notMyRealUsernameEither", "password":"123456"], forUserAccount: "myUserAccount") when an account exists.

How can i parse to TextField iOS Keychain in Swift?

I saved my account through Locksmith Keychain, everything works fine, right now i need to parse the data stored to a textField, how can i do it please?
Here is the code that i use to save my account:
let accountsave = Locksmith.saveData(["account": self.txtAccount.text], forUserAccount: "myUserAccount", inService: "myAccount").
Right now i need to parse the data store to a textfield in swift. Please help
From what I understand of your question you're asking for something similar to this:
let (dictionary, error) = Locksmith.loadDataForUserAccount("myUserAccount", inService: "myAccount")
if let userData = dictionary as? [String:String] {
if let account = userData["account"] {
self.txtAccount.text = account
}
}