I am constructing a easy app, the place customers can add private diary entries within the type of textual content solely, and it will get saved to my cloud firestore database. Now, I wish to construct end-to-end encryption so the consumer’s private content material is rarely readable by anybody however them.
To realize this, I am attempting to make use of the CryptoSwift library to encrypt and decrypt content material. For testing functions, I am beginning with only a easy “Howdy World” in my ViewModel. Nevertheless, I am unable to get it to work.
Couple of questions
-
I am unable to get “Howdy world” to point out up from clear (whats up world) > encrypted > cipher > decrypted (whats up world). How can I get the identical “whats up world” outcome from my decrypt operate?
-
In what format ought to I save my key to the keychain?
-
In what format ought to I save my encrypted textual content, and iv on firebase? Ought to I proceed to make use of .toHexString() or ought to I be utilizing .toBase64()?
I am efficiently in a position to generate a key, and reserve it as a “hexString”. And I can “run” via each the encrypt and the decrypt capabilities with out errors, however they do not generate a “whats up world” from cleartext(whats up world) > encrypt > ciphertext > decrypt > helloworld.
class EncryptionService: EncryptionServicing {
personal var keychainService = KeychainService()
func generateKey() throws -> String {
print("[EncryptionService] 🔑🔑🔑 Generate key known as")
do {
if let userId = UserService.shared.userInfo?.userId {
let userId: [UInt8] = Array(userId.utf8)
// Salt added for randomness
let salt: [UInt8] = (1...5).map( {_ in UInt8(Int.random(in: 1...10))} )
let key = strive PKCS5.PBKDF2(
password: userId,
salt: salt,
iterations: 4096,
keyLength: 32, /* AES-256 */
variant: .sha2(.sha256)
).calculate()
print("🔑🔑🔑 UserId: (userId)")
print("🔑🔑🔑 Salt: (salt)")
print("🔑🔑🔑 KEY: (key.toHexString())")
return key.toHexString()
}
}
catch {
print(error)
}
return ""
}
func encrypt(clearText: String, aesKey: String) throws -> (cipherText: String, iv: String) {
print("[EncryptionService] ✅ Encrypt known as")
do {
let iv = AES.randomIV(AES.blockSize)
let keyArray = [UInt8](hex: aesKey)
let aes = strive AES(key: keyArray, blockMode: CBC(iv: iv), padding: .pkcs7)
let cipherText = strive aes.encrypt(Array(clearText.utf8))
return (cipherText.toHexString(), iv.toHexString())
}
catch {
print(error)
return ("", "")
}
}
func decrypt(cipherText: String, iv: String, aesKey: String) throws -> String {
print("[EncryptionService] ✅ Decryption known as")
do {
print("Ciphertext: (cipherText)")
print("Iv: (iv)")
print("aesKey: (aesKey)")
let keyArray = [UInt8](hex: aesKey)
let aes = strive AES(key: keyArray, blockMode: CBC(iv: [UInt8](hex: iv)), padding: .pkcs7)
print("AES Key measurement: (aes.keySize)")
let decryptedText = strive aes.decrypt(cipherText.bytes)
return decryptedText.toHexString() // would not reply with "Howdy world!"
}
}
}
That is what my ViewModel seems like.
@Revealed var dummyClearText: String = "Howdy World!"
@Revealed var dummyCipherText: String = ""
@Revealed var dummyIv: String = ""
@Revealed var dummyDecryptedText: String = ""
// Have a "encrypt" button that calls this.
func generateCipherText() {
do {
let outcome = strive EncryptionService().encrypt(clearText: self.dummyClearText, aesKey: self.aesKey)
self.dummyCipherText = outcome.cipherText
self.dummyIv = outcome.iv
}
catch {
print(error)
}
}
// Have a "decrypt" button that calls this, and takes the generated cipher textual content as enter.
func generateClearText() {
do {
let outcome = strive EncryptionService().decrypt(cipherText: self.dummyCipherText, iv: self.dummyIv, aesKey: self.aesKey)
self.dummyDecryptedText = outcome // would not reply with "Howdy world!"
}
catch {
print(error)
}
}```
Thanks a lot, nonetheless very a lot studying easy methods to Swift.
Comfortable to offer extra context.