Reputation: 249
What am I doing wrong here? It throws below error while decrypting (at second last line)
Fatal error: 'try!' expression unexpectedly raised an error: CryptoKit.CryptoKitError.authenticationFailure
func encryptDecryptWithNonceTag(){
let secret = "my-xxx-bit-secret-my-secret-my-s"
let mySymKey = SymmetricKey(data: secret.data(using: .utf8)!)
let plain = "Say hello to my little friend!"
let nonce = try! AES.GCM.Nonce(data: Data(base64Encoded: "fv1nixTVoYpSvpdA")!)
let tag = Data(base64Encoded: "e1eIgoB4+lA/j3KDHhY4BQ==")!
//ENCRYPT
let sealedBox = try! AES.GCM.seal(plain.data(using: .utf8)!, using: mySymKey, nonce: nonce, authenticating: tag)
let ciphertext = sealedBox.ciphertext.base64EncodedString()
print("ciphertext: \(ciphertext)")
//DECRYPT: Recreate sealedbox with nonce and tag and then decrypt
let sealedBoxRecreated = try! AES.GCM.SealedBox(nonce: nonce,
ciphertext: Data(base64Encoded: ciphertext)!,
tag: tag)
let decrypted = try! AES.GCM.open(sealedBoxRecreated, using: mySymKey)
print("decryptedtext:\(String(decoding: decrypted, as: UTF8.self))")
}
Upvotes: 1
Views: 960
Reputation: 451
When creating a sealed box for encryption, the authenticating
parameter should contain data that should be authentified but not ciphered. This is not any sort of key, neither something you need for deciphering.
For example, in a mail, you would like the receiver to be authentified (so no one can mess with that field), but you do not want it ciphered, because intermediate people will need it to actually send the mail to it.
-> So I do not think that tag
is what you want to put here. Note that you probably can pass something empty.
Concerning the sealed box for decryption, you now understand that you should not pass the same data as in the previous authenticating
parameter.
A sealedbox is made of three parts : the ciphertext, the nonce and the authentication tag.
As you can see in its documentation, you can create the sealed box with the three components separately, or with all of them combined (which is simply their data put one after the other).
That is why you get an authentication error : you pass a random authentication tag instead of the correct one, so it tells your message cannot be authenticated.
So you will also need to extract the authentication tag from your sealedBox
(sealedBox.tag
) and feed it to your sealedBoxRecreated
(at the tag:
parameter).
Result :
//ENCRYPT
let sealedBox = try! AES.GCM.seal(plain.data(using: .utf8)!,
using: mySymKey,
nonce: nonce,
authenticating: Data())
let ciphertext = sealedBox.ciphertext.base64EncodedString()
let tag = sealedBox.tag.base64EncodedString()
//DECRYPT: Recreate sealedbox with nonce and tag and then decrypt
let sealedBoxRecreated = try! AES.GCM.SealedBox(nonce: nonce,
ciphertext: Data(base64Encoded: ciphertext)!,
tag: Data(base64Encoded: tag)!)
You can also simply export the "combined" content, which is better - because as the nonce should change each time, it probably needs to be communicated along with the message.
//ENCRYPT
let sealedBox = try! AES.GCM.seal(plain.data(using: .utf8)!,
using: mySymKey,
nonce: nonce,
authenticating: Data())
let cipheredMessage = sealedBox.combined.base64EncodedString()
//DECRYPT: Recreate sealedbox with nonce and tag and then decrypt
let sealedBoxRecreated = try! AES.GCM.SealedBox(combined: Data(base64Encoded: cipheredMessage)!)
Upvotes: 0
Reputation: 3853
You are using tag for both encryption and decryption in the authenticating
parameter. You should not provide a pre determined tag while encrypting.
func encryptDecryptWithNonceTag() {
let secret = "my-xxx-bit-secret-my-secret-my-s"
let mySymKey = SymmetricKey(data: secret.data(using: .utf8)!)
let plain = "Say hello to my little friend!"
let nonce = try! AES.GCM.Nonce(data: Data(base64Encoded: "fv1nixTVoYpSvpdA")!)
// ENCRYPT
let sealedBox = try! AES.GCM.seal(plain.data(using: .utf8)!, using: mySymKey, nonce: nonce)
let ciphertext = sealedBox.ciphertext.base64EncodedString()
print("ciphertext: \(ciphertext)")
print("tag: \(sealedBox.tag.base64EncodedString())")
//DECRYPT: Recreate sealedbox with nonce and tag and then decrypt
let sealedBoxRecreated = try! AES.GCM.SealedBox(nonce: nonce,
ciphertext: Data(base64Encoded: ciphertext)!,
tag: sealedBox.tag)
do {
let decrypted = try AES.GCM.open(sealedBoxRecreated, using: mySymKey)
print("decryptedtext: \(String(decoding: decrypted, as: UTF8.self))")
} catch {
print("Error decrypting: \(error.localizedDescription)")
}
}
output
Btw do not use try!
in your code. Because whenever an exception get throws (try fails) your code will crash. Worse case is when debugging you are unable to see the real issue. So always use a catch block.
Upvotes: 1