I was curious as to the procedure for having an encryption key leaked and was hoping to have your opinions on how these two questions will be answered [if you were in the position].
Q1: Let's say, for instance, that you're making a social media network that stores private messages in a database network (such as Firebase) and uses basic encryption to store that data into an encrypted format (e.g., text message: "Hello Mous772!"; Firebase data: "deaErG5gao7J5qw/QI3EOA==").
But oh no! Someone got access to the encryption key used to encrypt hundreds of thousands of messages. You cannot simply delete thousands of messages because of this hacker, so how should you deal with this? This is where my question comes in. Is it possible to change the encryption key for all of the data if I am using the code system at the bottom of this question and using that code system to store encrypted data in Firebase? If so, how would you go about doing that? (Please use simple language; I'm not good with this stuff).
Q2: What, in your opinion, is the best way to prevent this in the first place? I was told that a good solution was to store two sets of the same data; when one kegs it, we shut down the original and use the backup; however, this does not sound sustainable at all. I want to know what steps can be taken to ensure this never happens.
[Please don't give me "Well... you can never *really hide these keys!" I'm well aware it's not possible to never have them leaked ever; I'm just looking for best practices only.]
This is the encryption system we are using for this hypothetical app.
// MARK: Value
// MARK: Private
private let key: Data
private let iv: Data
// MARK: - Initialzier
init?(key: String, iv: String) {
guard key.count == kCCKeySizeAES128 || key.count == kCCKeySizeAES256, let keyData = key.data(using: .utf8) else {
debugPrint("Error: Failed to set a key.")
return nil
}
guard iv.count == kCCBlockSizeAES128, let ivData = iv.data(using: .utf8) else {
debugPrint("Error: Failed to set an initial vector.")
return nil
}
self.key = keyData
self.iv = ivData
}
// MARK: - Function
// MARK: Public
func encrypt(string: String) -> Data? {
return crypt(data: string.data(using: .utf8), option: CCOperation(kCCEncrypt))
}
func decrypt(data: Data?) -> String? {
guard let decryptedData = crypt(data: data, option: CCOperation(kCCDecrypt)) else { return nil }
return String(bytes: decryptedData, encoding: .utf8)
}
func crypt(data: Data?, option: CCOperation) -> Data? {
guard let data = data else { return nil }
let cryptLength = data.count + key.count
var cryptData = Data(count: cryptLength)
var bytesLength = Int(0)
let status = cryptData.withUnsafeMutableBytes { cryptBytes in
data.withUnsafeBytes { dataBytes in
iv.withUnsafeBytes { ivBytes in
key.withUnsafeBytes { keyBytes in
CCCrypt(option, CCAlgorithm(kCCAlgorithmAES), CCOptions(kCCOptionPKCS7Padding), keyBytes.baseAddress, key.count, ivBytes.baseAddress, dataBytes.baseAddress, data.count, cryptBytes.baseAddress, cryptLength, &bytesLength)
}
}
}
}
guard Int32(status) == Int32(kCCSuccess) else {
debugPrint("Error: Failed to crypt data. Status \(status)")
return nil
}
cryptData.removeSubrange(bytesLength..<cryptData.count)
return cryptData
}
}
//let password = "UserPassword1!"
//let key128 = "1234567890123456" // 16 bytes for AES128
//let key256 = "12345678901234561234567890123456" // 32 bytes for AES256
//let iv = "abcdefghijklmnop" // 16 bytes for AES128
//let aes128 = AES(key: key128, iv: iv)
//let aes256 = AES(key: key256, iv: iv)
//let encryptedPassword128 = aes128?.encrypt(string: password)
//aes128?.decrypt(data: encryptedPassword128)
//let encryptedPassword256 = aes256?.encrypt(string: password)
//aes256?.decrypt(data: encryptedPassword256)