如何在现有领域数据库上应用加密
How to apply encryption on existing realm database
我有一个 iOS 应用程序使用 非加密 领域数据库。
现在我想在该数据库上应用加密。
我可以使用以下方式设置 加密密钥 吗:
Realm.setEncryptionKey(key, forPath: Realm.defaultPath)
然后 realm 将加密 现有数据库?
或者我需要创建一个新的加密的领域数据库文件,然后移动现有数据库中的数据到新的加密数据库?
您必须为未加密的 Realm 文件创建一个加密的 copy,您可以使用 Realm().writeCopyToPath(_:encryptionKey:)
完成此操作,然后您可以在以下位置使用加密文件新位置。
您必须执行如下操作
- 使用 return 值
func encryptedrealm() -> Realm
创建函数
func encryptedrealm() {
// Get the encryptionKey
var realmKey = getencryptionKey()
// Check if the user has the unencrypted Realm
let documentDirectory = NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true)[0]
let fileManager = FileManager.default
let unencryptedRealmPath = "\(documentDirectory)/default.realm"
let encryptedPath = "\(documentDirectory)/default_new.realm"
let isUnencryptedRealmExsist = fileManager.fileExists(atPath: unencryptedRealmPath)
let isEncryptedRealmExsist = fileManager.fileExists(atPath: encryptedPath)
if isUnencryptedRealmExsist && !isEncryptedRealmExsist {
let unencryptedRealm = try! Realm(configuration: Realm.Configuration(schemaVersion: 7))
// if the user has unencrypted Realm write a copy to new path
try? unencryptedRealm.writeCopy(toFile: URL(fileURLWithPath: encryptedPath), encryptionKey: realmKey)
}
// read from the new encrypted Realm path
let configuration = Realm.Configuration(fileURL: URL(fileURLWithPath: encryptedPath), encryptionKey: realmKey, schemaVersion: 7, migrationBlock: { migration, oldSchemaVersion in })
return try! Realm(configuration: configuration)
}
- 创建加密密钥或从钥匙串中获取现有密钥,创建函数`func getencryptionKey() -> Data
func getencryptionKey() {
let keychainIdentifier = "io.Realm.EncryptionKey"
let keychainIdentifierData = keychainIdentifier.data(using: String.Encoding.utf8, allowLossyConversion: false)!
var query: [NSString: AnyObject] = [
kSecClass: kSecClassKey,
kSecAttrApplicationTag: keychainIdentifierData as AnyObject,
kSecAttrKeySizeInBits: 512 as AnyObject,
kSecReturnData: true as AnyObject
]
var dataTypeRef: AnyObject?
var status = withUnsafeMutablePointer(to: &dataTypeRef) { SecItemCopyMatching(query as CFDictionary, UnsafeMutablePointer([=11=])) }
if status == errSecSuccess {
// swiftlint:disable:next force_cast
return dataTypeRef as! Data
}
// No pre-existing key from this application, so generate a new one
// Generate a random encryption key
var key = Data(count: 64)
key.withUnsafeMutableBytes({ (pointer: UnsafeMutableRawBufferPointer) in
let result = SecRandomCopyBytes(kSecRandomDefault, 64, pointer.baseAddress!)
assert(result == 0, "Failed to get random bytes")
})
query = [
kSecClass: kSecClassKey,
kSecAttrApplicationTag: keychainIdentifierData as AnyObject,
kSecAttrKeySizeInBits: 512 as AnyObject,
kSecValueData: key as AnyObject
]
status = SecItemAdd(query as CFDictionary, nil)
assert(status == errSecSuccess, "Failed to insert the new key in the keychain")
return key
}
现在您可以像下面这样使用领域
让realm = encryptedrealm()
在我的项目中,我使用这个完整的领域加密方法。它支持对现有的和未加密的领域文件进行加密。
static func setupEncryption() {
let isRealmEncryptedKey = "isRealmEncryptedKey"
let keychainKey = "realmEncryptionKey"
var config = Realm.Configuration.defaultConfiguration
let isRealmEncrypted = UserDefaults.standard.bool(forKey: isRealmEncryptedKey)
if isRealmEncrypted, let userEncryptionKey = KeychainSwift().getData(key: keychainKey) {
// Fetch and apply existing encryption key
config.encryptionKey = Data(userEncryptionKey)
} else if let keyData = NSMutableData(length: 64) {
// Create and apply encryption key
let _ = SecRandomCopyBytes(kSecRandomDefault, keyData.length, keyData.mutableBytes)
let encryptionKey = Data(keyData)
// If realm file already exists, it should be replaced by new encrypted realm file. Actual for cases when user updates app to version with encryption feature
if let currentRealmUrl = FileUtils.getDocumentDirectory()?.appendingPathComponent("default.realm"), var encryptedRealmUrl = FileUtils.getDocumentDirectory()?.appendingPathComponent("encrypted.realm"), FileManager.default.fileExists(atPath: currentRealmUrl.path) {
do {
try Realm.instance?.writeCopy(toFile: encryptedRealmUrl, encryptionKey: encryptionKey)
} catch {
assert(false, "Creation of realm encrypted copy failed. Realm is invalid")
}
do {
try FileManager.default.removeItem(at: currentRealmUrl)
var resourceValues = URLResourceValues()
resourceValues.name = "default.realm"
try encryptedRealmUrl.setResourceValues(resourceValues)
} catch {
assert(false, "Realm encryption failed. Realm is invalid")
}
}
UserDefaults.standard.set(true, forKey: isRealmEncryptedKey)
KeychainSwift().set(encryptionKey, forKey: keychainKey)
config.encryptionKey = encryptionKey
}
Realm.Configuration.defaultConfiguration = config
}
我有一个 iOS 应用程序使用 非加密 领域数据库。
现在我想在该数据库上应用加密。
我可以使用以下方式设置 加密密钥 吗:
Realm.setEncryptionKey(key, forPath: Realm.defaultPath)
然后 realm 将加密 现有数据库?
或者我需要创建一个新的加密的领域数据库文件,然后移动现有数据库中的数据到新的加密数据库?
您必须为未加密的 Realm 文件创建一个加密的 copy,您可以使用 Realm().writeCopyToPath(_:encryptionKey:)
完成此操作,然后您可以在以下位置使用加密文件新位置。
您必须执行如下操作
- 使用 return 值
func encryptedrealm() -> Realm
创建函数
func encryptedrealm() {
// Get the encryptionKey
var realmKey = getencryptionKey()
// Check if the user has the unencrypted Realm
let documentDirectory = NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true)[0]
let fileManager = FileManager.default
let unencryptedRealmPath = "\(documentDirectory)/default.realm"
let encryptedPath = "\(documentDirectory)/default_new.realm"
let isUnencryptedRealmExsist = fileManager.fileExists(atPath: unencryptedRealmPath)
let isEncryptedRealmExsist = fileManager.fileExists(atPath: encryptedPath)
if isUnencryptedRealmExsist && !isEncryptedRealmExsist {
let unencryptedRealm = try! Realm(configuration: Realm.Configuration(schemaVersion: 7))
// if the user has unencrypted Realm write a copy to new path
try? unencryptedRealm.writeCopy(toFile: URL(fileURLWithPath: encryptedPath), encryptionKey: realmKey)
}
// read from the new encrypted Realm path
let configuration = Realm.Configuration(fileURL: URL(fileURLWithPath: encryptedPath), encryptionKey: realmKey, schemaVersion: 7, migrationBlock: { migration, oldSchemaVersion in })
return try! Realm(configuration: configuration)
}
- 创建加密密钥或从钥匙串中获取现有密钥,创建函数`func getencryptionKey() -> Data
func getencryptionKey() {
let keychainIdentifier = "io.Realm.EncryptionKey"
let keychainIdentifierData = keychainIdentifier.data(using: String.Encoding.utf8, allowLossyConversion: false)!
var query: [NSString: AnyObject] = [
kSecClass: kSecClassKey,
kSecAttrApplicationTag: keychainIdentifierData as AnyObject,
kSecAttrKeySizeInBits: 512 as AnyObject,
kSecReturnData: true as AnyObject
]
var dataTypeRef: AnyObject?
var status = withUnsafeMutablePointer(to: &dataTypeRef) { SecItemCopyMatching(query as CFDictionary, UnsafeMutablePointer([=11=])) }
if status == errSecSuccess {
// swiftlint:disable:next force_cast
return dataTypeRef as! Data
}
// No pre-existing key from this application, so generate a new one
// Generate a random encryption key
var key = Data(count: 64)
key.withUnsafeMutableBytes({ (pointer: UnsafeMutableRawBufferPointer) in
let result = SecRandomCopyBytes(kSecRandomDefault, 64, pointer.baseAddress!)
assert(result == 0, "Failed to get random bytes")
})
query = [
kSecClass: kSecClassKey,
kSecAttrApplicationTag: keychainIdentifierData as AnyObject,
kSecAttrKeySizeInBits: 512 as AnyObject,
kSecValueData: key as AnyObject
]
status = SecItemAdd(query as CFDictionary, nil)
assert(status == errSecSuccess, "Failed to insert the new key in the keychain")
return key
}
现在您可以像下面这样使用领域
让realm = encryptedrealm()
在我的项目中,我使用这个完整的领域加密方法。它支持对现有的和未加密的领域文件进行加密。
static func setupEncryption() {
let isRealmEncryptedKey = "isRealmEncryptedKey"
let keychainKey = "realmEncryptionKey"
var config = Realm.Configuration.defaultConfiguration
let isRealmEncrypted = UserDefaults.standard.bool(forKey: isRealmEncryptedKey)
if isRealmEncrypted, let userEncryptionKey = KeychainSwift().getData(key: keychainKey) {
// Fetch and apply existing encryption key
config.encryptionKey = Data(userEncryptionKey)
} else if let keyData = NSMutableData(length: 64) {
// Create and apply encryption key
let _ = SecRandomCopyBytes(kSecRandomDefault, keyData.length, keyData.mutableBytes)
let encryptionKey = Data(keyData)
// If realm file already exists, it should be replaced by new encrypted realm file. Actual for cases when user updates app to version with encryption feature
if let currentRealmUrl = FileUtils.getDocumentDirectory()?.appendingPathComponent("default.realm"), var encryptedRealmUrl = FileUtils.getDocumentDirectory()?.appendingPathComponent("encrypted.realm"), FileManager.default.fileExists(atPath: currentRealmUrl.path) {
do {
try Realm.instance?.writeCopy(toFile: encryptedRealmUrl, encryptionKey: encryptionKey)
} catch {
assert(false, "Creation of realm encrypted copy failed. Realm is invalid")
}
do {
try FileManager.default.removeItem(at: currentRealmUrl)
var resourceValues = URLResourceValues()
resourceValues.name = "default.realm"
try encryptedRealmUrl.setResourceValues(resourceValues)
} catch {
assert(false, "Realm encryption failed. Realm is invalid")
}
}
UserDefaults.standard.set(true, forKey: isRealmEncryptedKey)
KeychainSwift().set(encryptionKey, forKey: keychainKey)
config.encryptionKey = encryptionKey
}
Realm.Configuration.defaultConfiguration = config
}